OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Compare Revisions

Ignore whitespace Rev 173 → Rev 174

/trunk/OpenConcerto/lib/jOpenDocument-1.4rc2.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/lib/jOpenCalendar.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/jopendocument/link/OOConnexion.java
84,8 → 84,14
perms.add(new RuntimePermission("modifyThread"));
// needed by PrinterJob.getPrinterJob()
perms.add(new RuntimePermission("queuePrintJob"));
 
// ProcessBuilder.start() calls SecurityManager.checkExec() which requires
// absolute path (or execute on "<<ALL FILES>>")
 
// needed by OOConnexion.init() to find the port
perms.add(new FilePermission("/usr/bin/lsof", "execute"));
// macOS path
perms.add(new FilePermission("/usr/sbin/lsof", "execute"));
perms.add(new FilePermission("/bin/ps", "execute"));
perms.add(new FilePermission("C:/Windows/System32/tasklist.exe", "execute"));
perms.add(new RuntimePermission("getenv.*"));
/trunk/OpenConcerto/src/org/jopendocument/link/OOInstallation.java
102,10 → 102,14
rootPaths.addAll(Arrays.asList(loRootPaths));
rootPaths.addAll(Arrays.asList(ooRootPaths));
}
 
for (final String p : rootPaths) {
if (DesktopEnvironment.test("reg", "query", p))
// On force à chercher dans le registre 64 bits sinon il va chercher dans le registre 32
// bits si os 64b et VM 32b
if (DesktopEnvironment.test("reg", "query", p, "/reg:64"))
return p;
}
 
return null;
}
 
123,7 → 127,8
// all string values for the passed registry path
private static Map<String, String> getStringValues(final String path, final String option) throws IOException {
final Map<String, String> values = new HashMap<String, String>();
final String out = DesktopEnvironment.cmdSubstitution(Runtime.getRuntime().exec(new String[] { "reg", "query", path, option }));
// On force /reg:64 (utile si on utilise une VM 32 avec un systeme 64 bits)
final String out = DesktopEnvironment.cmdSubstitution(Runtime.getRuntime().exec(new String[] { "reg", "query", path, option, "/reg:64" }));
final Matcher matcher = stringValuePattern.matcher(out);
while (matcher.find()) {
values.put(matcher.group(1), matcher.group(2));
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/view/BaseGenerationRapport.java
93,7 → 93,7
private JComboBox<FileAction> fileActionCombo;
 
private JList<GenerationTask> tasksView;
private JLabel status;
private final JLabel status;
 
// le groupe dans lequel doivent être toutes les thread de la génération
private final ThreadGroup thg;
100,7 → 100,7
 
public BaseGenerationRapport() throws JDOMException, IOException {
this.thg = new ThreadGroup(this + " thread group");
this.uiInit();
this.status = new JLabel();
this.setStatus("Inactif");
}
 
112,7 → 112,7
return null;
}
 
private void uiInit() throws JDOMException, IOException {
protected final void uiInit() throws JDOMException, IOException {
setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
c.ipadx = 40;
171,7 → 171,6
c.gridx = 0;
c.gridy++;
c.gridwidth = GridBagConstraints.REMAINDER;
this.status = new JLabel();
this.add(this.status, c);
 
c.gridy++;
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/cellFormat.ods
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/NumberStyle.java
18,7 → 18,6
import org.openconcerto.openoffice.ODValueType;
import org.openconcerto.openoffice.XMLVersion;
import org.openconcerto.openoffice.spreadsheet.CellStyle;
import org.openconcerto.openoffice.spreadsheet.MutableCell;
 
import java.util.Calendar;
import java.util.Date;
89,7 → 88,7
} else if (elem.getName().equals("fraction")) {
// TODO fractions
reportError("Fractions not supported", lenient);
sb.append(MutableCell.formatNumber(n, defaultStyle));
sb.append(getPackage().formatNumber(n, defaultStyle));
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/DataStyle.java
27,10 → 27,12
 
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
45,7 → 47,11
// from section 16.27 in v1.2-cs01-part1
public abstract class DataStyle extends Style {
private static final int DEFAULT_GROUPING_SIZE = new DecimalFormat().getGroupingSize();
public static final int DEFAULT_DECIMAL_PLACES = 10;
// 15 as of LibreOffice 6, was 10 earlier
/**
* 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"));
private static final Pattern QUOTE_PATRN = Pattern.compile("'", Pattern.LITERAL);
private static final Pattern EXP_PATTERN = Pattern.compile("E(\\d+)$");
 
85,8 → 91,7
super(clazz, version, elemName, baseName);
this.setElementNS(getVersion().getNS("number"));
// from 19.469 in v1.2-cs01-part1
this.getRefElementsMap().addAll(
"style:data-style-name",
this.getRefElementsMap().addAll("style:data-style-name",
Arrays.asList("presentation:date-time-decl", "style:style", "text:creation-date", "text:creation-time", "text:database-display", "text:date", "text:editing-duration",
"text:expression", "text:meta-field", "text:modification-date", "text:modification-time", "text:print-date", "text:print-time", "text:table-formula", "text:time",
"text:user-defined", "text:user-field-get", "text:user-field-input", "text:variable-get", "text:variable-input", "text:variable-set"));
176,6 → 181,15
throw new UnsupportedOperationException(msg);
}
 
public final Locale getLocale() {
return this.getLocale(this.getElement());
}
 
protected final Locale getLocale(final Element elem) {
final Locale res = DateStyle.getElementLocale(elem);
return res != null ? res : this.getPackage().getLocale();
}
 
protected final String formatNumberOrScientificNumber(final Element elem, final Number n, CellStyle defaultStyle) {
return this.formatNumberOrScientificNumber(elem, n, 1, defaultStyle);
}
243,7 → 257,9
numberSB.append('0');
}
 
final DecimalFormat decFormat = new DecimalFormat(numberSB.toString());
final DecimalFormatSymbols symbols = new DecimalFormatSymbols(this.getLocale());
 
final DecimalFormat decFormat = new DecimalFormat(numberSB.toString(), symbols);
// Java always use HALF_EVEN
decFormat.setRoundingMode(RoundingMode.HALF_UP);
decFormat.setGroupingUsed(grouping);
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/CurrencyStyle.java
63,7 → 63,7
if (elem.getTextTrim().length() > 0) {
sb.append(elem.getText());
} else {
sb.append(new DecimalFormatSymbols(DateStyle.getLocale(elem)).getCurrencySymbol());
sb.append(new DecimalFormatSymbols(this.getLocale(elem)).getCurrencySymbol());
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/DateStyle.java
54,7 → 54,7
return !"long".equals(elem.getAttributeValue("style", elem.getNamespace("number")));
}
 
public static final Locale getLocale(final Element elem) {
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());
61,7 → 61,7
if (lang != null) {
res = new Locale(lang, country == null ? "" : country);
} else {
res = Locale.getDefault();
res = null;
}
return res;
}
123,7 → 123,7
public String format(Object o, CellStyle defaultStyle, boolean lenient) {
final Date d = o instanceof Calendar ? ((Calendar) o).getTime() : (Date) o;
final Namespace numberNS = this.getElement().getNamespace();
final Locale styleLocale = getLocale(getElement());
final Locale styleLocale = this.getLocale();
final Calendar styleCalendar = Calendar.getInstance(styleLocale);
final StringBuilder res = new StringBuilder();
 
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/TimeStyle.java
69,7 → 69,7
final Namespace numberNS = this.getElement().getNamespace();
final StringBuilder sb = new StringBuilder();
 
final Locale styleLocale = DateStyle.getLocale(getElement());
final Locale styleLocale = this.getLocale();
final boolean truncate = StyleProperties.parseBoolean(getElement().getAttributeValue("truncate-on-overflow", numberNS), true);
@SuppressWarnings("unchecked")
final List<Element> children = this.getElement().getChildren();
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/BooleanStyle.java
66,7 → 66,7
public String format(Object o, CellStyle defaultStyle, boolean lenient) {
final Boolean b = (Boolean) o;
final Namespace numberNS = this.getElement().getNamespace();
final Locale styleLocale = DateStyle.getLocale(getElement());
final Locale styleLocale = this.getLocale();
final StringBuilder sb = new StringBuilder();
@SuppressWarnings("unchecked")
final List<Element> children = this.getElement().getChildren();
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/cellFormat.fods
New file
0,0 → 1,629
<?xml version="1.0" encoding="UTF-8"?>
 
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office: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:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
<office:meta><meta:creation-date>2011-08-18T14:24:40.28</meta:creation-date><dc:date>2019-03-18T16:35:20.347078479</dc:date><meta:editing-duration>PT12H49M11S</meta:editing-duration><meta:editing-cycles>46</meta:editing-cycles><meta:generator>LibreOffice/6.0.7.3$Linux_X86_64 LibreOffice_project/00m0$Build-3</meta:generator><dc:description>20120330: changed locale of A1 to german</dc:description><meta:document-statistic meta:table-count="1" meta:cell-count="38" meta:object-count="0"/></office:meta>
<office:settings>
<config:config-item-set config:name="ooo:view-settings">
<config:config-item config:name="VisibleAreaTop" config:type="int">0</config:config-item>
<config:config-item config:name="VisibleAreaLeft" config:type="int">0</config:config-item>
<config:config-item config:name="VisibleAreaWidth" config:type="int">12671</config:config-item>
<config:config-item config:name="VisibleAreaHeight" config:type="int">9203</config:config-item>
<config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view1</config:config-item>
<config:config-item-map-named config:name="Tables">
<config:config-item-map-entry config:name="Feuille1">
<config:config-item config:name="CursorPositionX" config:type="int">1</config:config-item>
<config:config-item config:name="CursorPositionY" config:type="int">22</config:config-item>
<config:config-item config:name="HorizontalSplitMode" config:type="short">0</config:config-item>
<config:config-item config:name="VerticalSplitMode" config:type="short">0</config:config-item>
<config:config-item config:name="HorizontalSplitPosition" config:type="int">0</config:config-item>
<config:config-item config:name="VerticalSplitPosition" config:type="int">0</config:config-item>
<config:config-item config:name="ActiveSplitRange" config:type="short">2</config:config-item>
<config:config-item config:name="PositionLeft" config:type="int">0</config:config-item>
<config:config-item config:name="PositionRight" config:type="int">0</config:config-item>
<config:config-item config:name="PositionTop" config:type="int">0</config:config-item>
<config:config-item config:name="PositionBottom" config:type="int">0</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ZoomValue" config:type="int">100</config:config-item>
<config:config-item config:name="PageViewZoomValue" config:type="int">60</config:config-item>
<config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item>
<config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item>
</config:config-item-map-entry>
</config:config-item-map-named>
<config:config-item config:name="ActiveTable" config:type="string">Feuille1</config:config-item>
<config:config-item config:name="HorizontalScrollbarWidth" config:type="int">1216</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ZoomValue" config:type="int">100</config:config-item>
<config:config-item config:name="PageViewZoomValue" config:type="int">60</config:config-item>
<config:config-item config:name="ShowPageBreakPreview" config:type="boolean">false</config:config-item>
<config:config-item config:name="ShowZeroValues" config:type="boolean">true</config:config-item>
<config:config-item config:name="ShowNotes" config:type="boolean">true</config:config-item>
<config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item>
<config:config-item config:name="GridColor" config:type="long">12632256</config:config-item>
<config:config-item config:name="ShowPageBreaks" config:type="boolean">true</config:config-item>
<config:config-item config:name="HasColumnRowHeaders" config:type="boolean">true</config:config-item>
<config:config-item config:name="HasSheetTabs" config:type="boolean">true</config:config-item>
<config:config-item config:name="IsOutlineSymbolsSet" config:type="boolean">true</config:config-item>
<config:config-item config:name="IsValueHighlightingEnabled" config:type="boolean">false</config:config-item>
<config:config-item config:name="IsSnapToRaster" config:type="boolean">false</config:config-item>
<config:config-item config:name="RasterIsVisible" config:type="boolean">false</config:config-item>
<config:config-item config:name="RasterResolutionX" config:type="int">1000</config:config-item>
<config:config-item config:name="RasterResolutionY" config:type="int">1000</config:config-item>
<config:config-item config:name="RasterSubdivisionX" config:type="int">1</config:config-item>
<config:config-item config:name="RasterSubdivisionY" config:type="int">1</config:config-item>
<config:config-item config:name="IsRasterAxisSynchronized" config:type="boolean">true</config:config-item>
<config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item>
</config:config-item-map-entry>
</config:config-item-map-indexed>
</config:config-item-set>
<config:config-item-set config:name="ooo:configuration-settings">
<config:config-item config:name="SyntaxStringRef" config:type="short">7</config:config-item>
<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
<config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item>
<config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item>
<config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterSetup" config:type="base64Binary">kQH+/0dlbmVyaWMgUHJpbnRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU0dFTlBSVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAMAsgAAAAAAAAAEAAhSAAAEdAAASm9iRGF0YSAxCnByaW50ZXI9R2VuZXJpYyBQcmludGVyCm9yaWVudGF0aW9uPVBvcnRyYWl0CmNvcGllcz0xCm1hcmdpbmRhanVzdG1lbnQ9MCwwLDAsMApjb2xvcmRlcHRoPTI0CnBzbGV2ZWw9MApwZGZkZXZpY2U9MApjb2xvcmRldmljZT0wClBQRENvbnRleERhdGEKUGFnZVNpemU6QTQARHVwbGV4Ok5vbmUAABIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmY=</config:config-item>
<config:config-item config:name="PrinterName" config:type="string">Generic Printer</config:config-item>
<config:config-item config:name="AutoCalculate" config:type="boolean">true</config:config-item>
<config:config-item config:name="LinkUpdateMode" config:type="short">3</config:config-item>
<config:config-item config:name="HasColumnRowHeaders" config:type="boolean">true</config:config-item>
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item>
<config:config-item config:name="ShowZeroValues" config:type="boolean">true</config:config-item>
<config:config-item config:name="GridColor" config:type="long">12632256</config:config-item>
<config:config-item config:name="ShowPageBreaks" config:type="boolean">true</config:config-item>
<config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item>
<config:config-item config:name="IsOutlineSymbolsSet" config:type="boolean">true</config:config-item>
<config:config-item config:name="IsDocumentShared" config:type="boolean">false</config:config-item>
<config:config-item config:name="ShowNotes" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="HasSheetTabs" config:type="boolean">true</config:config-item>
<config:config-item config:name="RasterSubdivisionY" config:type="int">1</config:config-item>
<config:config-item config:name="RasterIsVisible" config:type="boolean">false</config:config-item>
<config:config-item config:name="RasterResolutionX" config:type="int">1000</config:config-item>
<config:config-item config:name="RasterResolutionY" config:type="int">1000</config:config-item>
<config:config-item config:name="IsSnapToRaster" config:type="boolean">false</config:config-item>
<config:config-item config:name="RasterSubdivisionX" config:type="int">1</config:config-item>
<config:config-item config:name="IsRasterAxisSynchronized" config:type="boolean">true</config:config-item>
</config:config-item-set>
</office:settings>
<office:scripts>
<office:script script:language="ooo:Basic">
<ooo:libraries xmlns:ooo="http://openoffice.org/2004/office" xmlns:xlink="http://www.w3.org/1999/xlink"/>
</office:script>
</office:scripts>
<office:font-face-decls>
<style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Liberation Sans" svg:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="DejaVu Sans" svg:font-family="&apos;DejaVu Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Lucida Sans Unicode" svg:font-family="&apos;Lucida Sans Unicode&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Mangal" svg:font-family="Mangal" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system" style:font-pitch="variable"/>
</office:font-face-decls>
<office:styles>
<style:default-style style:family="table-cell">
<style:table-cell-properties style:decimal-places="7"/>
<style:paragraph-properties style:tab-stop-distance="12.5mm"/>
<style:text-properties style:font-name="Arial" fo:language="fr" fo:country="FR" style:font-name-asian="Lucida Sans Unicode" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Tahoma" style:language-complex="hi" style:country-complex="IN"/>
</style:default-style>
<number:number-style style:name="N0">
<number:number number:min-integer-digits="1"/>
</number:number-style>
<number:currency-style style:name="N108P0" style:volatile="true">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
<number:text> </number:text>
<number:currency-symbol number:language="fr" number:country="FR">€</number:currency-symbol>
</number:currency-style>
<number:currency-style style:name="N108">
<style:text-properties fo:color="#ff0000"/>
<number:text>-</number:text>
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
<number:text> </number:text>
<number:currency-symbol number:language="fr" number:country="FR">€</number:currency-symbol>
<style:map style:condition="value()&gt;=0" style:apply-style-name="N108P0"/>
</number:currency-style>
<number:number-style style:name="N109">
<number:number number:decimal-places="3" loext:min-decimal-places="3" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N110">
<number:number number:decimal-places="0" loext:min-decimal-places="0" number:min-integer-digits="2"/>
</number:number-style>
<number:percentage-style style:name="N111">
<number:text>%</number:text>
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1"/>
</number:percentage-style>
<number:number-style style:name="N112">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:display-factor="1000"/>
<number:text> is a number</number:text>
</number:number-style>
<number:number-style style:name="N113">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1"/>
<number:text> is a number</number:text>
</number:number-style>
<number:text-style style:name="N114">
<number:text>avant </number:text>
<number:text-content/>
<number:text> après</number:text>
</number:text-style>
<number:currency-style style:name="N115P0" style:volatile="true">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
<number:text> </number:text>
<number:currency-symbol number:language="fr" number:country="FR">€</number:currency-symbol>
</number:currency-style>
<number:currency-style style:name="N115">
<number:text>-</number:text>
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
<number:text> </number:text>
<number:currency-symbol number:language="fr" number:country="FR">€</number:currency-symbol>
<style:map style:condition="value()&gt;=0" style:apply-style-name="N115P0"/>
</number:currency-style>
<number:currency-style style:name="N117P0" style:volatile="true">
<number:currency-symbol number:language="en" number:country="GB">£</number:currency-symbol>
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
</number:currency-style>
<number:currency-style style:name="N117">
<style:text-properties fo:color="#ff0000"/>
<number:text>-</number:text>
<number:currency-symbol number:language="en" number:country="GB">£</number:currency-symbol>
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
<style:map style:condition="value()&gt;=0" style:apply-style-name="N117P0"/>
</number:currency-style>
<number:date-style style:name="N118">
<number:day number:style="long"/>
<number:text>/</number:text>
<number:month number:style="long"/>
<number:text>/</number:text>
<number:year number:style="long"/>
<number:text> </number:text>
<number:hours number:style="long"/>
<number:text>:</number:text>
<number:minutes number:style="long"/>
<number:text>:</number:text>
<number:seconds number:style="long" number:decimal-places="2"/>
</number:date-style>
<number:time-style style:name="N119" number:truncate-on-overflow="false">
<number:hours number:style="long"/>
<number:text>:</number:text>
<number:minutes/>
<number:text>:</number:text>
<number:seconds number:style="long" number:decimal-places="1"/>
</number:time-style>
<number:number-style style:name="N120P0" style:volatile="true">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N120P1" style:volatile="true">
<number:number number:decimal-places="0" loext:min-decimal-places="0" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N120">
<number:number number:min-integer-digits="1"/>
<number:text/>
<style:map style:condition="value()&lt;0" style:apply-style-name="N120P0"/>
<style:map style:condition="value()&gt;0" style:apply-style-name="N120P1"/>
</number:number-style>
<number:number-style style:name="N121P0" style:volatile="true">
<number:number number:decimal-places="0" loext:min-decimal-places="0" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N121P1" style:volatile="true">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N121">
<number:number number:min-integer-digits="1"/>
<number:text/>
<style:map style:condition="value()&lt;0" style:apply-style-name="N121P0"/>
<style:map style:condition="value()&gt;0" style:apply-style-name="N121P1"/>
</number:number-style>
<number:number-style style:name="N122P0" style:volatile="true">
<number:number number:decimal-places="0" loext:min-decimal-places="0" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N122P1" style:volatile="true">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N122">
<number:number number:min-integer-digits="1"/>
<number:text/>
<style:map style:condition="value()&lt;0" style:apply-style-name="N122P0"/>
<style:map style:condition="value()&gt;2" style:apply-style-name="N122P1"/>
</number:number-style>
<number:number-style style:name="N123P0" style:volatile="true">
<number:number number:decimal-places="0" loext:min-decimal-places="0" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N123P1" style:volatile="true">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1"/>
</number:number-style>
<number:number-style style:name="N123">
<number:number number:min-integer-digits="1"/>
<number:text/>
<style:map style:condition="value()&lt;0" style:apply-style-name="N123P0"/>
<style:map style:condition="value()&gt;=1" style:apply-style-name="N123P1"/>
</number:number-style>
<number:number-style style:name="N10107" number:language="de" number:country="DE">
<number:number number:decimal-places="0" loext:min-decimal-places="0" number:min-integer-digits="2"/>
</number:number-style>
<number:number-style style:name="N30111" number:language="en" number:country="GB">
<number:number number:decimal-places="3" loext:min-decimal-places="3" number:min-integer-digits="1"/>
</number:number-style>
<style:style style:name="Default" style:family="table-cell">
<style:text-properties style:font-name-complex="Mangal" style:font-family-complex="Mangal" style:font-family-generic-complex="system" style:font-pitch-complex="variable"/>
</style:style>
<style:style style:name="Heading_20__28_user_29_" style:display-name="Heading (user)" style:family="table-cell" style:parent-style-name="Default">
<style:text-properties fo:color="#000000" fo:font-size="24pt" fo:font-style="normal" fo:font-weight="bold"/>
</style:style>
<style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="table-cell" style:parent-style-name="Heading_20__28_user_29_">
<style:text-properties fo:color="#000000" fo:font-size="18pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Heading_20_2" style:display-name="Heading 2" style:family="table-cell" style:parent-style-name="Heading_20__28_user_29_">
<style:text-properties fo:color="#000000" fo:font-size="12pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Text" style:family="table-cell" style:parent-style-name="Default"/>
<style:style style:name="Note" style:family="table-cell" style:parent-style-name="Text">
<style:table-cell-properties fo:background-color="#ffffcc" style:diagonal-bl-tr="none" style:diagonal-tl-br="none" fo:border="0.74pt solid #808080"/>
<style:text-properties fo:color="#333333" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Footnote" style:family="table-cell" style:parent-style-name="Text">
<style:text-properties fo:color="#808080" fo:font-size="10pt" fo:font-style="italic" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Hyperlink" style:family="table-cell" style:parent-style-name="Text">
<style:text-properties fo:color="#0000ee" fo:font-size="10pt" fo:font-style="normal" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="#0000ee" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Status" style:family="table-cell" style:parent-style-name="Default"/>
<style:style style:name="Good" style:family="table-cell" style:parent-style-name="Status">
<style:table-cell-properties fo:background-color="#ccffcc"/>
<style:text-properties fo:color="#006600" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Neutral" style:family="table-cell" style:parent-style-name="Status">
<style:table-cell-properties fo:background-color="#ffffcc"/>
<style:text-properties fo:color="#996600" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Bad" style:family="table-cell" style:parent-style-name="Status">
<style:table-cell-properties fo:background-color="#ffcccc"/>
<style:text-properties fo:color="#cc0000" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Warning" style:family="table-cell" style:parent-style-name="Status">
<style:text-properties fo:color="#cc0000" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Error" style:family="table-cell" style:parent-style-name="Status">
<style:table-cell-properties fo:background-color="#cc0000"/>
<style:text-properties fo:color="#ffffff" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="bold"/>
</style:style>
<style:style style:name="Accent" style:family="table-cell" style:parent-style-name="Default">
<style:text-properties fo:color="#000000" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="bold"/>
</style:style>
<style:style style:name="Accent_20_1" style:display-name="Accent 1" style:family="table-cell" style:parent-style-name="Accent">
<style:table-cell-properties fo:background-color="#000000"/>
<style:text-properties fo:color="#ffffff" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Accent_20_2" style:display-name="Accent 2" style:family="table-cell" style:parent-style-name="Accent">
<style:table-cell-properties fo:background-color="#808080"/>
<style:text-properties fo:color="#ffffff" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal"/>
</style:style>
<style:style style:name="Accent_20_3" style:display-name="Accent 3" style:family="table-cell" style:parent-style-name="Accent">
<style:table-cell-properties fo:background-color="#dddddd"/>
</style:style>
<style:style style:name="Result" style:family="table-cell" style:parent-style-name="Default">
<style:text-properties fo:font-style="italic" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" fo:font-weight="bold"/>
</style:style>
<style:style style:name="Result2" style:family="table-cell" style:parent-style-name="Result" style:data-style-name="N108"/>
<style:style style:name="Heading" style:family="table-cell" style:parent-style-name="Default">
<style:table-cell-properties style:text-align-source="fix" style:repeat-content="false"/>
<style:paragraph-properties fo:text-align="center"/>
<style:text-properties fo:font-size="16pt" fo:font-style="italic" fo:font-weight="bold"/>
</style:style>
<style:style style:name="Heading1" style:family="table-cell" style:parent-style-name="Heading">
<style:table-cell-properties style:rotation-angle="90"/>
</style:style>
</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="69.37mm"/>
</style:style>
<style:style style:name="co2" style:family="table-column">
<style:table-column-properties fo:break-before="auto" style:column-width="34.68mm"/>
</style:style>
<style:style style:name="co3" style:family="table-column">
<style:table-column-properties fo:break-before="auto" style:column-width="22.67mm"/>
</style:style>
<style:style style:name="co4" style:family="table-column">
<style:table-column-properties fo:break-before="auto" style:column-width="22.58mm"/>
</style:style>
<style:style style:name="ro1" style:family="table-row">
<style:table-row-properties style:row-height="4.78mm" fo:break-before="auto" style:use-optimal-row-height="true"/>
</style:style>
<style:style style:name="ro2" style:family="table-row">
<style:table-row-properties style:row-height="4.52mm" fo:break-before="auto" style:use-optimal-row-height="true"/>
</style:style>
<style:style style:name="ro3" style:family="table-row">
<style:table-row-properties style:row-height="6.58mm" fo:break-before="auto" style:use-optimal-row-height="true"/>
</style:style>
<style:style style:name="ro4" style:family="table-row">
<style:table-row-properties style:row-height="4.73mm" 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>
<number:number-style style:name="N5">
<number:number number:decimal-places="2" loext:min-decimal-places="2" number:grouping="true"/>
</number:number-style>
<number:time-style style:name="N41">
<number:hours number:style="long"/>
<number:text>:</number:text>
<number:minutes number:style="long"/>
<number:text>:</number:text>
<number:seconds number:style="long"/>
</number:time-style>
<number:number-style style:name="N60">
<number:scientific-number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:min-exponent-digits="3" loext:exponent-interval="1" loext:forced-exponent-sign="true"/>
</number:number-style>
<number:number-style style:name="N61">
<number:scientific-number number:decimal-places="2" loext:min-decimal-places="2" number:min-integer-digits="1" number:min-exponent-digits="2" loext:exponent-interval="1" loext:forced-exponent-sign="true"/>
</number:number-style>
<number:date-style style:name="N20076" number:language="th" number:country="TH">
<number:day number:calendar="buddhist"/>
<number:text> </number:text>
<number:month number:calendar="buddhist" number:style="long" number:textual="true"/>
<number:text> </number:text>
<number:year number:calendar="buddhist" number:style="long"/>
</number:date-style>
<number:date-style style:name="N30079" number:language="en" number:country="GB" number:automatic-order="true">
<number:day-of-week number:style="long"/>
<number:text> </number:text>
<number:day/>
<number:text> </number:text>
<number:month number:style="long" number:textual="true"/>
<number:text> </number:text>
<number:year number:style="long"/>
</number:date-style>
<number:boolean-style style:name="N40099" number:language="pt" number:country="PT">
<number:boolean/>
</number:boolean-style>
<style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N10107"/>
<style:style style:name="ce2" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N109"/>
<style:style style:name="ce3" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N5"/>
<style:style style:name="ce4" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N60"/>
<style:style style:name="ce5" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N61"/>
<style:style style:name="ce6" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N113"/>
<style:style style:name="ce7" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N111"/>
<style:style style:name="ce8" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N114"/>
<style:style style:name="ce9" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N115"/>
<style:style style:name="ce10" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N117"/>
<style:style style:name="ce11" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N118"/>
<style:style style:name="ce12" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N20076"/>
<style:style style:name="ce13" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N30079"/>
<style:style style:name="ce14" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N119"/>
<style:style style:name="ce15" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N41"/>
<style:style style:name="ce16" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N123"/>
<style:style style:name="ce17" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N40099"/>
<style:style style:name="ce35" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N30111"/>
<style:page-layout style:name="pm1">
<style:page-layout-properties style:writing-mode="lr-tb"/>
<style:header-style>
<style:header-footer-properties fo:min-height="7.51mm" fo:margin-left="0mm" fo:margin-right="0mm" fo:margin-bottom="2.5mm"/>
</style:header-style>
<style:footer-style>
<style:header-footer-properties fo:min-height="7.51mm" fo:margin-left="0mm" fo:margin-right="0mm" fo:margin-top="2.5mm"/>
</style:footer-style>
</style:page-layout>
<style:page-layout style:name="pm2">
<style:page-layout-properties style:writing-mode="lr-tb"/>
<style:header-style>
<style:header-footer-properties fo:min-height="7.51mm" fo:margin-left="0mm" fo:margin-right="0mm" fo:margin-bottom="2.5mm" fo:border="2.49pt solid #000000" fo:padding="0.18mm" fo:background-color="#c0c0c0">
<style:background-image/>
</style:header-footer-properties>
</style:header-style>
<style:footer-style>
<style:header-footer-properties fo:min-height="7.51mm" fo:margin-left="0mm" fo:margin-right="0mm" fo:margin-top="2.5mm" fo:border="2.49pt solid #000000" fo:padding="0.18mm" fo:background-color="#c0c0c0">
<style:background-image/>
</style:header-footer-properties>
</style:footer-style>
</style:page-layout>
</office:automatic-styles>
<office:master-styles>
<style:master-page style:name="Default" style:page-layout-name="pm1">
<style:header>
<text:p><text:sheet-name>???</text:sheet-name></text:p>
</style:header>
<style:header-left style:display="false"/>
<style:footer>
<text:p>Page <text:page-number>1</text:page-number></text:p>
</style:footer>
<style:footer-left style:display="false"/>
</style:master-page>
<style:master-page style:name="Report" style:page-layout-name="pm2">
<style:header>
<style:region-left>
<text:p><text:sheet-name>???</text:sheet-name><text:s/>(<text:title>???</text:title>)</text:p>
</style:region-left>
<style:region-right>
<text:p><text:date style:data-style-name="N2" text:date-value="2019-03-18">00/00/0000</text:date>, <text:time style:data-style-name="N2" text:time-value="16:34:33.840313473">00:00:00</text:time></text:p>
</style:region-right>
</style:header>
<style:header-left style:display="false"/>
<style:footer>
<text:p>Page <text:page-number>1</text:page-number><text:s/>/ <text:page-count>99</text:page-count></text:p>
</style:footer>
<style:footer-left style:display="false"/>
</style:master-page>
</office:master-styles>
<office:body>
<office:spreadsheet>
<table:table table:name="Feuille1" table:style-name="ta1" table:print="false">
<table:table-column table:style-name="co1" table:default-cell-style-name="ce1"/>
<table:table-column table:style-name="co2" table:default-cell-style-name="Default"/>
<table:table-column table:style-name="co3" table:default-cell-style-name="Default"/>
<table:table-row table:style-name="ro1">
<table:table-cell office:value-type="float" office:value="0.5" calcext:value-type="float">
<text:p>01</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>round to int with at least 2 digits</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro2">
<table:table-cell table:style-name="ce2" office:value-type="float" office:value="0.5" calcext:value-type="float">
<text:p>0,500</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>3 decimals</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="Default" table:formula="of:=1/3" office:value-type="float" office:value="0.333333333333333" calcext:value-type="float">
<text:p>0,3333333</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>default</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce3" office:value-type="float" office:value="1234567" calcext:value-type="float">
<text:p>1 234 567,00</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>grouping</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce4" office:value-type="float" office:value="1234" calcext:value-type="float">
<text:p>1,23E+003</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>scientific number (3 digits)</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce5" office:value-type="float" office:value="0.0123" calcext:value-type="float">
<text:p>1,23E-02</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>scientific number (2 digits)</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce6" table:formula="of:=1234" office:value-type="float" office:value="1234" calcext:value-type="float">
<text:p>1234,00 is a number</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>number with text</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce7" office:value-type="percentage" office:value="0.123" calcext:value-type="percentage">
<text:p>%12,30</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>percent</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce8" office:value-type="string" office:string-value="O" calcext:value-type="string">
<text:p>avant O <text:s text:c="2"/>après</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>ATTN only works with 1 char</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce9" office:value-type="currency" office:currency="EUR" office:value="-100.01" calcext:value-type="currency">
<text:p>-100,01 €</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>currency default</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce10" office:value-type="currency" office:currency="GBP" office:value="-50.23" calcext:value-type="currency">
<text:p>-£50,23</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>current England</text:p>
</table:table-cell>
<table:table-cell table:style-name="ce10" office:value-type="currency" office:currency="GBP" office:value="12.35" calcext:value-type="currency">
<text:p>£12,35</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce11" table:formula="of:=NOW()" office:value-type="date" office:date-value="2019-03-18T16:35:19.075105" calcext:value-type="date">
<text:p>18/03/2019 16:35:19,08</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>date time</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro3">
<table:table-cell table:style-name="ce12" table:formula="of:=NOW()" office:value-type="date" office:date-value="2019-03-18T16:35:19.075117" calcext:value-type="date">
<text:p>18 มีนาคม 2562</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>Thai date</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce13" table:formula="of:=NOW()" office:value-type="date" office:date-value="2019-03-18T16:35:19.07512" calcext:value-type="date">
<text:p>Monday 18 March 2019</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>Gregorian calendar</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce14" office:value-type="time" office:time-value="PT56H05M02.47S" calcext:value-type="time">
<text:p>56:5:02,5</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>Time</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce15"/>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>Empty cell with a format</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro4">
<table:table-cell table:style-name="ce16" office:value-type="float" office:value="12.34321" calcext:value-type="float">
<text:p>12,34</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>default between 0 &amp; 1</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell table:style-name="ce17" table:formula="of:=1" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
<text:p>VERDADEIRO</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>boolean</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro2">
<table:table-cell table:style-name="ce35" office:value-type="float" office:value="0.5" calcext:value-type="float">
<text:p>0.500</text:p>
</table:table-cell>
<table:table-cell office:value-type="string" calcext:value-type="string">
<text:p>3 decimals in english</text:p>
</table:table-cell>
<table:table-cell/>
</table:table-row>
</table:table>
<table:named-expressions/>
</office:spreadsheet>
</office:body>
</office:document>
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODPackage.java
17,7 → 17,9
import static org.openconcerto.openoffice.ODPackage.RootElement.META;
import static org.openconcerto.openoffice.ODPackage.RootElement.STYLES;
 
import org.openconcerto.openoffice.spreadsheet.CellStyle;
import org.openconcerto.openoffice.spreadsheet.SpreadSheet;
import org.openconcerto.openoffice.style.data.DataStyle;
import org.openconcerto.openoffice.text.TextDocument;
import org.openconcerto.utils.CopyUtils;
import org.openconcerto.utils.ExceptionUtils;
48,6 → 50,7
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
57,6 → 60,7
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
69,6 → 73,7
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
 
377,6 → 382,7
private ODMeta meta;
private File file;
private ODDocument doc;
private Locale locale;
 
public ODPackage() {
this.files = new HashMap<String, ODPackageEntry>();
402,16 → 408,19
protected void processEntry(ZipEntry entry, InputStream in) throws IOException {
final String name = entry.getName();
final Object res;
out.reset();
StreamUtils.copy(in, out);
if (subdocNames.contains(name)) {
try {
res = OOUtils.getBuilder().build(in);
final SAXBuilder builder = OOUtils.getBuilder();
// bytes are read fully first in order to be compatible
// with SAXParser like Piccolo
res = builder.build(new ByteArrayInputStream(out.toByteArray()));
} catch (JDOMException e) {
// always correct
throw new IllegalStateException("parse error", e);
throw new IllegalStateException("parse error on " + name, e);
}
} else {
out.reset();
StreamUtils.copy(in, out);
res = out.toByteArray();
}
// we don't know yet the types
579,6 → 588,39
this.setContentType(newType);
}
 
public final void setLocale(Locale locale) {
this.locale = locale;
}
 
// http://help.libreoffice.org/Common/Selecting_the_Document_Language
// The document language is set by default-style/text-properties and is not used for formatting.
// The formatting used to fill cell content is set by the editor application not read from the
// document.
public final Locale getLocale() {
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 final String formatPercent(Number n, final CellStyle defaultStyle) {
return formatNumber(NumberFormat.getPercentInstance(getLocale()), n, defaultStyle);
}
 
public final String formatCurrency(Number n, final CellStyle defaultStyle) {
return formatNumber(NumberFormat.getCurrencyInstance(getLocale()), n, defaultStyle);
}
 
private final String formatNumber(NumberFormat format, Number n, final CellStyle defaultStyle) {
synchronized (format) {
final int decPlaces = DataStyle.getDecimalPlaces(defaultStyle);
format.setMinimumFractionDigits(0);
format.setMaximumFractionDigits(decPlaces);
return format.format(n);
}
}
 
/**
* Call {@link Validator#isValid()} on each XML subdocuments.
*
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/MutableCell.java
24,7 → 24,6
import org.openconcerto.openoffice.spreadsheet.CellStyle.StyleTableCellProperties;
import org.openconcerto.openoffice.style.data.BooleanStyle;
import org.openconcerto.openoffice.style.data.DataStyle;
import org.openconcerto.openoffice.style.data.DateStyle;
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.TimeUtils;
import org.openconcerto.utils.TimeUtils.DurationNullsChanger;
63,31 → 62,7
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 NumberFormat TextPFloatFormat = DecimalFormat.getNumberInstance();
static private final NumberFormat TextPPercentFormat = DecimalFormat.getPercentInstance();
static private final NumberFormat TextPCurrencyFormat = DecimalFormat.getCurrencyInstance();
 
static public String formatNumber(Number n, final CellStyle defaultStyle) {
return formatNumber(TextPFloatFormat, n, defaultStyle);
}
 
static public String formatPercent(Number n, final CellStyle defaultStyle) {
return formatNumber(TextPPercentFormat, n, defaultStyle);
}
 
static public String formatCurrency(Number n, final CellStyle defaultStyle) {
return formatNumber(TextPCurrencyFormat, n, defaultStyle);
}
 
static private String formatNumber(NumberFormat format, Number n, final CellStyle defaultStyle) {
synchronized (format) {
final int decPlaces = DataStyle.getDecimalPlaces(defaultStyle);
format.setMinimumFractionDigits(0);
format.setMaximumFractionDigits(decPlaces);
return format.format(n);
}
}
 
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();
241,11 → 216,11
} else {
// either there were no format or formatting failed
if (vt == ODValueType.FLOAT) {
text = formatNumber((Number) obj, getDefaultStyle());
text = getODDocument().getPackage().formatNumber((Number) obj, getDefaultStyle());
} else if (vt == ODValueType.PERCENTAGE) {
text = formatPercent((Number) obj, getDefaultStyle());
text = getODDocument().getPackage().formatPercent((Number) obj, getDefaultStyle());
} else if (vt == ODValueType.CURRENCY) {
text = formatCurrency((Number) obj, getDefaultStyle());
text = getODDocument().getPackage().formatCurrency((Number) obj, getDefaultStyle());
} else if (vt == ODValueType.DATE) {
final Date d;
if (obj instanceof Calendar) {
262,16 → 237,15
text = TextPTimeFormat.format(((Calendar) obj).getTime());
}
} else if (vt == ODValueType.BOOLEAN) {
// LO do not use the the document language but the system language
// http://help.libreoffice.org/Common/Selecting_the_Document_Language
Locale l = Locale.getDefault();
// except of course if there's a data style
Locale l = null;
final CellStyle s = getStyle();
if (s != null) {
final DataStyle ds = s.getDataStyle();
if (ds != null)
l = DateStyle.getLocale(ds.getElement());
l = ds.getLocale();
}
if (l == null)
l = getODDocument().getPackage().getLocale();
text = BooleanStyle.toString((Boolean) obj, l, lenient);
} else if (vt == ODValueType.STRING) {
text = obj.toString();
/trunk/OpenConcerto/src/org/openconcerto/ui/state/AbstractStateManager.java
13,6 → 13,8
package org.openconcerto.ui.state;
 
import org.openconcerto.utils.FileUtils;
 
import java.io.File;
import java.io.IOException;
import java.security.AccessController;
83,10 → 85,7
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws IOException {
if (file.getParentFile() != null && !file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
 
FileUtils.mkParentDirs(file);
writeState(file);
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/touch/ScrollableList.java
62,7 → 62,8
 
private boolean hasScrolled;
 
private List<ListSelectionListener> selectionListeners = new ArrayList<ListSelectionListener>();
private List<ListSelectionListener> selectionListeners = new ArrayList<>();
private List<ActionListener> actionListeners = new ArrayList<>();
 
public ScrollableList(ListModel model) {
a = new ScrollAnimator(this);
202,6 → 203,7
} else {
scrollToOffset(targetOffset);
}
fireActionPerformed();
}
 
public void setSelectedIndex(int index) {
376,6 → 378,18
}
}
 
public void addActionListener(ActionListener listener) {
this.actionListeners.add(listener);
}
 
private void fireActionPerformed() {
int size = this.actionListeners.size();
for (int i = 0; i < size; i++) {
this.actionListeners.get(i).actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "click"));
}
 
}
 
@Override
public void contentsChanged(ListDataEvent e) {
this.offsetY = 0;
/trunk/OpenConcerto/src/org/openconcerto/ui/table/CloseTableHeaderRenderer.java
82,7 → 82,7
header.setReorderingAllowed(false);
this.editedTable = table;
this.editedColumn = column;
this.label.setText(value.toString());
this.label.setText(String.valueOf(value));
this.header.removeMouseListener(this);
this.header.addMouseListener(this);
return this;
/trunk/OpenConcerto/src/org/openconcerto/ui/table/IconTableCellRenderer.java
98,7 → 98,7
 
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null) {
// Bug remonté sur Linux
// JTable$AccessibleJTable.getAccessibleChild()
value = Integer.valueOf(0);
}
int val = ((Integer) value).intValue();
/trunk/OpenConcerto/src/org/openconcerto/ui/grid/GridItem.java
New file
0,0 → 1,95
/*
* 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.grid;
 
import java.awt.Color;
 
public class GridItem {
private int x;
private int y;
private int w;
private int h;
private Color color = new Color(50, 200, 160, 150);
private Color borderColor = new Color(25, 100, 80, 150);
private Object cookie;
 
public GridItem(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
 
public final int getX() {
return this.x;
}
 
public final void setX(int x) {
this.x = x;
}
 
public final int getY() {
return this.y;
}
 
public final void setY(int y) {
this.y = y;
}
 
public final int getW() {
return this.w;
}
 
public final void setW(int w) {
this.w = w;
}
 
public final int getH() {
return this.h;
}
 
public final void setH(int h) {
this.h = h;
}
 
public final Color getColor() {
return this.color;
}
 
public final void setColor(Color color) {
this.color = color;
}
 
public final Color getBorderColor() {
return this.borderColor;
}
 
public final void setBorderColor(Color borderColor) {
this.borderColor = borderColor;
}
 
public Object getCookie() {
return this.cookie;
}
 
public void setCookie(Object cookie) {
this.cookie = cookie;
}
 
@Override
public String toString() {
return this.x + "," + this.y + " [" + this.w + "," + this.h + "]";
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/grid/GridPanel.java
New file
0,0 → 1,319
/*
* 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.grid;
 
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
 
public class GridPanel extends JPanel {
private static final Color SELECTION_BORDER_COLOR = new Color(200, 210, 220, 250);
private static final Color SELECTION_COLOR = new Color(230, 240, 250, 180);
private static final Color CREATION_COLOR = new Color(250, 254, 30, 100);
private static final Color CREATION_BORDER_COLOR = new Color(250, 254, 60, 180);
 
private int cellWidth = 40;
private final int cellHeight;
private int gridLineWidth = 1;
private Color gridVerticalColor = Color.LIGHT_GRAY;
private Color gridHorizontalColor = Color.DARK_GRAY;
private int columnCount;
private int rowCount;
private List<GridItem> items = new ArrayList<>();
private Map<Integer, List<GridItem>> itemsByRow = new HashMap<>();
 
protected GridItem onCreationItem;
protected int onCreationX;
protected boolean[] onCreationAllowedColumns;
private boolean editMode;
protected GridListener gridListener;
private Set<GridItem> selectedItems = new HashSet<>();
 
public GridPanel(int columnCount, int rowCount) {
this(columnCount, rowCount, 40);
}
 
public GridPanel(int columnCount, int rowCount, int rowHeight) {
this.setBackground(Color.WHITE);
this.rowCount = rowCount;
this.columnCount = columnCount;
this.cellHeight = rowHeight;
this.addMouseMotionListener(new MouseMotionListener() {
 
@Override
public void mouseMoved(MouseEvent e) {
// nothing
}
 
@Override
public void mouseDragged(MouseEvent e) {
if (GridPanel.this.onCreationItem != null) {
 
int x = getColumnFromMouseX(e.getX());
if (x >= 0 && x < columnCount && GridPanel.this.onCreationAllowedColumns[x]) {
if (x > GridPanel.this.onCreationX) {
GridPanel.this.onCreationItem.setW(x - GridPanel.this.onCreationX + 1);
} else {
GridPanel.this.onCreationItem.setX(x);
GridPanel.this.onCreationItem.setW(GridPanel.this.onCreationX - x + 1);
}
}
repaint();
 
}
 
}
});
this.addMouseListener(new MouseAdapter() {
 
@Override
public void mouseReleased(MouseEvent e) {
final GridItem selectedItem = getItemAtMouse(e.getX(), e.getY());
if (!e.isControlDown()) {
GridPanel.this.selectedItems.clear();
}
if (selectedItem != null) {
if (GridPanel.this.selectedItems.contains(selectedItem) && !e.isPopupTrigger()) {
GridPanel.this.selectedItems.remove(selectedItem);
} else {
GridPanel.this.selectedItems.add(selectedItem);
}
}
 
if (GridPanel.this.onCreationItem != null) {
// Add the item
GridItem newItem = new GridItem(GridPanel.this.onCreationItem.getX(), GridPanel.this.onCreationItem.getY(), GridPanel.this.onCreationItem.getW(),
GridPanel.this.onCreationItem.getH());
if (GridPanel.this.gridListener != null) {
boolean added = GridPanel.this.gridListener.add(GridPanel.this, newItem);
if (added) {
add(newItem);
}
}
//
GridPanel.this.onCreationItem = null;
 
}
repaint();
if (GridPanel.this.gridListener != null && e.isPopupTrigger()) {
GridPanel.this.gridListener.triggerPopup(GridPanel.this, e.getX(), e.getY());
}
}
 
@Override
public void mousePressed(MouseEvent e) {
final GridItem selectedItem = getItemAtMouse(e.getX(), e.getY());
if (GridPanel.this.editMode && selectedItem == null && getRowFromMouseY(e.getY()) < rowCount) {
GridPanel.this.onCreationX = getColumnFromMouseX(e.getX());
GridPanel.this.onCreationAllowedColumns = new boolean[columnCount];
GridPanel.this.onCreationAllowedColumns[GridPanel.this.onCreationX] = true;
final int onCreationY = getRowFromMouseY(e.getY());
for (int i = GridPanel.this.onCreationX + 1; i < columnCount; i++) {
if (getItem(onCreationY, i) == null) {
GridPanel.this.onCreationAllowedColumns[i] = true;
} else {
break;
}
}
for (int i = GridPanel.this.onCreationX - 1; i >= 0; i--) {
if (getItem(onCreationY, i) == null) {
GridPanel.this.onCreationAllowedColumns[i] = true;
} else {
break;
}
}
GridPanel.this.onCreationItem = new GridItem(getColumnFromMouseX(e.getX()), onCreationY, 1, 1);
GridPanel.this.onCreationItem.setColor(CREATION_COLOR);
GridPanel.this.onCreationItem.setBorderColor(CREATION_BORDER_COLOR);
 
}
repaint();
if (GridPanel.this.gridListener != null) {
GridPanel.this.gridListener.selectionChanged(GridPanel.this);
if (e.isPopupTrigger()) {
GridPanel.this.gridListener.triggerPopup(GridPanel.this, e.getX(), e.getY());
}
}
}
 
});
 
}
 
public void add(GridItem item) {
this.items.add(item);
for (int n = 0; n < item.getH(); n++) {
final int y = item.getY() + n;
List<GridItem> list = this.itemsByRow.get(y);
if (list == null) {
list = new ArrayList<>();
list.add(item);
this.itemsByRow.put(Integer.valueOf(y), list);
}
list.add(item);
}
}
 
public int getCellHeight() {
return this.cellHeight;
}
 
@Override
public Dimension getPreferredSize() {
return new Dimension(this.columnCount * this.cellWidth + (1 + this.columnCount) * this.gridLineWidth, this.rowCount * this.cellWidth + (1 + this.rowCount) * this.gridLineWidth);
}
 
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
 
@Override
public Dimension getMaximumSize() {
return getPreferredSize();
}
 
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
 
int x = 0;
final int h = this.getHeight();
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 4 }, 0));
// Vertical lines
g.setColor(this.gridVerticalColor);
for (int i = 0; i <= this.columnCount; i++) {
g.drawLine(x, 0, x, h);
x += this.gridLineWidth + this.cellWidth;
}
// Horizontal lines
g.setColor(this.gridHorizontalColor);
int w = this.getWidth();
int y = 0;
for (int i = 0; i <= this.rowCount; i++) {
g.drawLine(0, y, w, y);
y += this.gridLineWidth + this.cellHeight;
}
g2.setStroke(new BasicStroke(1));
for (GridItem item : this.items) {
drawItem(g, item);
}
if (this.onCreationItem != null) {
drawItem(g, this.onCreationItem);
}
 
}
 
private void drawItem(Graphics g, GridItem item) {
final boolean isSelected = this.selectedItems.contains(item);
if (isSelected) {
g.setColor(SELECTION_COLOR);
} else {
g.setColor(item.getColor());
}
int width = item.getW() * (this.gridLineWidth + this.cellWidth);
int height = item.getH() * (this.gridLineWidth + this.cellHeight);
final int itemX = item.getX() * (this.gridLineWidth + this.cellWidth);
final int itemY = item.getY() * (this.gridLineWidth + this.cellHeight);
g.fillRect(itemX + 1, itemY + 1, width - 2, height - 2);
if (isSelected) {
g.setColor(SELECTION_BORDER_COLOR);
} else {
g.setColor(item.getBorderColor());
}
g.drawRect(itemX + 1, itemY + 1, width - 2, height - 2);
g.drawRect(itemX, itemY, width, height);
}
 
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
 
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
//
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final GridPanel contentPane = new GridPanel(24, 4);
contentPane.add(new GridItem(0, 0, 1, 1));
contentPane.add(new GridItem(4, 0, 3, 1));
contentPane.add(new GridItem(1, 1, 2, 2));
f.setContentPane(contentPane);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
 
GridItem getItemAtMouse(int x, int y) {
int row = getRowFromMouseY(y);
int col = getColumnFromMouseX(x);
return getItem(row, col);
}
 
private GridItem getItem(int row, int col) {
List<GridItem> rItems = this.itemsByRow.get(row);
if (rItems == null) {
return null;
}
for (GridItem item : rItems) {
if (item.getX() <= col && (item.getX() + item.getW()) > col) {
return item;
}
}
return null;
}
 
private int getColumnFromMouseX(int x) {
return x / (this.gridLineWidth + this.cellWidth);
}
 
private int getRowFromMouseY(int y) {
return y / (this.gridLineWidth + this.cellHeight);
}
 
public void setEnableEditMode(boolean enable) {
this.editMode = enable;
}
 
public void setGridListener(GridListener gridListener) {
this.gridListener = gridListener;
}
 
public List<GridItem> getSelectedItems() {
return new ArrayList<>(this.selectedItems);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/grid/TwoYearsHeaderPanel.java
New file
0,0 → 1,82
/*
* 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.grid;
 
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
 
import javax.swing.JPanel;
 
public class TwoYearsHeaderPanel extends JPanel {
private int year;
private String[] months = new String[] { "Janv.", "Fév.", "Mars", "Avr.", "Mai", "Juin", "Juil.", "Août", "Sept.", "Oct.", "Nov.", "Déc." };
 
public TwoYearsHeaderPanel(int year) {
this.year = year;
this.setBackground(Color.white);
}
 
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(g.getFont().deriveFont(Font.BOLD));
 
int x1 = this.getWidth() / 4;
int x2 = (3 * this.getWidth()) / 4;
String str1 = String.valueOf(this.year);
int w1 = g.getFontMetrics().stringWidth(str1);
g.drawString(str1, x1 - w1 / 2, 16);
 
String str2 = String.valueOf(this.year + 1);
int w2 = g.getFontMetrics().stringWidth(str2);
g.drawString(str2, x2 - w2 / 2, 16);
int gw = (this.getWidth()) / 24;
g.setColor(Color.LIGHT_GRAY);
for (int x = 0; x < this.getWidth(); x += gw * 3) {
g.drawLine(x, 36, x, this.getHeight());
 
}
g.setColor(Color.GRAY);
for (int x = 0; x < this.getWidth(); x += gw * 6) {
g.drawLine(x, 24, x, this.getHeight());
 
}
 
g.setColor(Color.BLACK);
for (int x = 0; x < this.getWidth(); x += gw * 12) {
g.drawLine(x, 0, x, this.getHeight());
 
}
 
g.setFont(g.getFont().deriveFont(Font.PLAIN));
int delta = this.getWidth() / 2;
for (int i = 0; i < 12; i++) {
 
final String str = this.months[i];
int w = g.getFontMetrics().stringWidth(str2);
int x = i * gw + gw / 2 - w / 2;
g.drawString(str, x, 40);
x = x + delta;
g.drawString(str, x, 40);
}
}
 
@Override
public Dimension getMinimumSize() {
return new Dimension(getPreferredSize().width, 48);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/grid/GridListener.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.ui.grid;
 
public interface GridListener {
 
public void selectionChanged(GridPanel grid);
 
public void triggerPopup(GridPanel grid, int x, int y);
 
/**
* returns true if the newItem is must be added
*/
public boolean add(GridPanel gridPanel, GridItem newItem);
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/grid/DecoratedGridPanel.java
New file
0,0 → 1,140
/*
* 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.grid;
 
import org.openconcerto.ui.VFlowLayout;
 
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
 
public class DecoratedGridPanel extends JPanel {
 
private GridPanel grid;
 
public DecoratedGridPanel(JComponent header, int columnCount, int rowHeight, List<JComponent> rowHeader) {
this.setBackground(Color.WHITE);
this.setLayout(new GridBagLayout());
JPanel topLeft = new JPanel();
this.grid = new GridPanel(columnCount, rowHeader.size(), rowHeight);
header.setPreferredSize(new Dimension(this.grid.getPreferredSize().width, header.getMinimumSize().height));
header.setMaximumSize(new Dimension(this.grid.getPreferredSize().width, header.getMinimumSize().height));
header.setMinimumSize(new Dimension(this.grid.getPreferredSize().width, header.getMinimumSize().height));
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.weightx = 1;
c.gridwidth = 1;
c.fill = GridBagConstraints.BOTH;
this.add(topLeft, c);
c.gridx++;
c.weightx = 0;
this.add(header, c);
//
c.gridwidth = 2;
c.weightx = 1;
c.weighty = 1;
c.gridx = 0;
c.gridy++;
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
GridBagConstraints c2 = new GridBagConstraints();
c2.gridx = 0;
c2.gridy = 0;
c2.weightx = 1;
c2.anchor = GridBagConstraints.NORTH;
c2.fill = GridBagConstraints.BOTH;
panel.add(createLeft(rowHeader, this.grid.getCellHeight()), c2);
c2.gridx++;
c2.weightx = 0;
c2.weighty = 1;
panel.add(this.grid, c2);
 
final JScrollPane scroll = new JScrollPane(panel);
scroll.setBorder(null);
this.add(scroll, c);
 
}
 
private Component createLeft(List<JComponent> rowHeader, int h) {
JPanel p = new JPanel();
p.setLayout(new VFlowLayout(VFlowLayout.TOP, 1, 1, true));
 
for (JComponent c : rowHeader) {
c.setMinimumSize(new Dimension(c.getMinimumSize().width, h));
c.setPreferredSize(new Dimension(c.getPreferredSize().width, h));
p.add(c);
}
 
return p;
}
 
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
 
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
//
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
TwoYearsHeaderPanel b = new TwoYearsHeaderPanel(2018);
List<JComponent> panels = new ArrayList<>();
for (int i = 0; i < 5; i++) {
panels.add(new JButton("line " + i));
}
 
final DecoratedGridPanel contentPane = new DecoratedGridPanel(b, 24, 40, panels);
contentPane.add(new GridItem(0, 0, 1, 1));
contentPane.add(new GridItem(4, 0, 3, 1));
contentPane.add(new GridItem(1, 1, 2, 1));
f.setContentPane(contentPane);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
 
public void add(GridItem gridItem) {
this.grid.add(gridItem);
 
}
 
public void setEnableEditMode(boolean enable) {
this.grid.setEnableEditMode(enable);
}
 
public void setGridListener(GridListener gridListener) {
this.grid.setGridListener(gridListener);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/ColorField.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.ui;
 
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
 
import javax.swing.BorderFactory;
import javax.swing.JColorChooser;
import javax.swing.JPanel;
import javax.swing.JTextField;
 
public class ColorField extends JPanel {
private Color color = Color.WHITE;
private JPanel colorPanel = new JPanel();
 
public ColorField(String chooserTitle) {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
int h = new JTextField("O").getPreferredSize().height;
this.colorPanel.setPreferredSize(new Dimension(h * 2, h));
this.colorPanel.setMinimumSize(new Dimension(h, h));
this.colorPanel.setMaximumSize(new Dimension(h * 2, h));
this.colorPanel.setBackground(this.color);
this.colorPanel.setOpaque(true);
this.colorPanel.setBorder(BorderFactory.createLoweredBevelBorder());
this.colorPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
final Color c = JColorChooser.showDialog(ColorField.this.colorPanel, chooserTitle, getColor());
Color oldValue = getColor();
setColor(c);
firePropertyChange("value", oldValue, c);
 
}
});
this.add(this.colorPanel);
}
 
public void setColor(Color c) {
this.color = c;
this.colorPanel.setBackground(c);
}
 
public Color getColor() {
return this.color;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/SearchContent.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/ui/light/SearchSpec.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/ui/light/UserSearchItem.java
New file
0,0 → 1,95
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ui.light;
 
import org.openconcerto.utils.io.Transferable;
 
import net.minidev.json.JSONObject;
 
public class UserSearchItem implements Transferable {
// column id (or subject id of the search)
private String column;
// value as text typed by the user
private String text;
public static final String TYPE_IS = "is";
public static final String TYPE_CONTAINS = "contains";
public static final String TYPE_STARTS_WITH = "starts";
public static final String TYPE_ENDS_WITH = "ends";
public static final String TYPE_EQUALS = "equals";
public static final String TYPE_LESS_THAN = "lth";
public static final String TYPE_GREATER_THAN = "gth";
// type of search (contains,equals,...)
private String type;
// operator to apply (and / or)
private String operator;
 
public UserSearchItem(final JSONObject json) {
this.fromJSON(json);
}
 
public String getColumn() {
return this.column;
}
 
public String getText() {
return this.text;
}
 
public String getType() {
return this.type;
}
 
public String getOperator() {
return this.operator;
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = new JSONObject();
json.put("column", this.column);
json.put("text", this.text);
json.put("type", this.type);
json.put("operator", this.operator);
return json;
}
 
@Override
public void fromJSON(final JSONObject json) {
if (!json.containsKey("column") || !(json.get("column") instanceof String)) {
throw new IllegalArgumentException("value for 'column' not found or invalid");
}
if (!json.containsKey("text") || !(json.get("text") instanceof String)) {
throw new IllegalArgumentException("value for 'text' not found or invalid");
}
if (!json.containsKey("type") || !(json.get("type") instanceof String)) {
throw new IllegalArgumentException("value for 'type' not found or invalid");
}
if (json.containsKey("operator")) {
if (!(json.get("operator") instanceof String)) {
throw new IllegalArgumentException("value for 'operator' not found or invalid");
} else {
this.operator = (String) json.get("operator");
}
}
 
this.column = (String) json.get("column");
this.text = (String) json.get("text");
this.type = (String) json.get("type");
}
 
@Override
public String toString() {
return super.toString() + " column:" + this.column + " text:" + this.text + " type:" + this.type + " operator:" + this.operator;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIHTMLStrippedPanel.java
20,6 → 20,9
 
public class LightUIHTMLStrippedPanel extends LightUIPanel implements Transferable, HTMLable {
 
public LightUIHTMLStrippedPanel() {
}
 
public LightUIHTMLStrippedPanel(String id) {
super(id);
this.setType(LightUIElement.TYPE_RAW_HTML);
34,11 → 37,6
}
 
@Override
public LightUIElement clone() {
return new LightUIHTMLStrippedPanel(this);
}
 
@Override
public String getHTML() {
final StringBuilder b = new StringBuilder();
for (int i = 0; i < this.getChildrenCount(); i++) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/UserSearch.java
New file
0,0 → 1,83
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ui.light;
 
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
 
import java.util.ArrayList;
import java.util.List;
 
import net.minidev.json.JSONArray;
import net.minidev.json.JSONAware;
import net.minidev.json.JSONObject;
 
public class UserSearch implements Transferable, JSONAware {
private String tableId;
private List<UserSearchItem> content = new ArrayList<>();
 
public UserSearch() {
// Serialization
}
 
public UserSearch(final String tableId) {
this.tableId = tableId;
}
 
public UserSearch(final JSONObject json) {
this.fromJSON(json);
}
 
public final String getTableId() {
return this.tableId;
}
 
public final List<UserSearchItem> getContent() {
return this.content;
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = new JSONObject();
json.put("table-id", this.tableId);
json.put("content", JSONConverter.getJSON(this.content));
return json;
}
 
@Override
public void fromJSON(JSONObject json) {
this.tableId = JSONConverter.getParameterFromJSON(json, "table-id", String.class);
final JSONArray jsonContent = JSONConverter.getParameterFromJSON(json, "content", JSONArray.class);
if (jsonContent != null) {
this.content = new ArrayList<>();
for (final Object o : jsonContent) {
this.content.add(new UserSearchItem((JSONObject) JSONConverter.getObjectFromJSON(o, JSONObject.class)));
}
}
}
 
/*
* JSONAware pour que le JSONArray.toString() fonctionne quand cet objet est dans un JSONArray
*/
@Override
public String toJSONString() {
return toJSON().toJSONString();
}
 
@Override
public String toString() {
return "UserSearch on " + this.tableId + " " + this.content.size() + " items";
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TableSearchParameter.java
New file
0,0 → 1,100
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ui.light;
 
import org.openconcerto.utils.io.Transferable;
 
import java.util.ArrayList;
import java.util.List;
 
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
 
public class TableSearchParameter implements Transferable {
private String id;
private String label;
private List<TableSearchParameterType> types = new ArrayList<>();
 
public TableSearchParameter() {
// For serialization
}
 
public String getId() {
return this.id;
}
 
public String getLabel() {
return this.label;
}
 
public List<TableSearchParameterType> getTypes() {
return this.types;
}
 
public TableSearchParameter(String id, String label) {
this.id = id;
this.label = label;
}
 
public void add(TableSearchParameterType type) {
this.types.add(type);
}
 
public void remove(TableSearchParameterType type) {
this.types.remove(type);
}
 
@Override
public JSONObject toJSON() {
if (this.id == null) {
throw new IllegalStateException("null id");
}
if (this.label == null) {
throw new IllegalStateException("null label");
}
final JSONObject obj = new JSONObject();
obj.put("id", this.id);
obj.put("label", this.label);
if (!this.types.isEmpty()) {
final JSONArray array = new JSONArray();
for (TableSearchParameterType type : this.types) {
array.add(type.toJSON());
}
obj.put("types", array);
}
return obj;
}
 
@Override
public void fromJSON(JSONObject json) {
this.id = json.getAsString("id");
this.label = json.getAsString("label");
if (this.id == null) {
throw new IllegalStateException("null id");
}
if (this.label == null) {
throw new IllegalStateException("null label");
}
this.types.clear();
if (json.containsKey("types")) {
final JSONArray array = (JSONArray) json.get("types");
for (Object object : array) {
final TableSearchParameterType t = new TableSearchParameterType();
t.fromJSON(((JSONObject) object));
this.types.add(t);
}
}
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITable.java
18,10 → 18,6
 
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
 
33,7 → 29,7
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
 
public class LightUITable extends LightUserControlContainer implements Externalizable {
public class LightUITable extends LightUserControlContainer {
 
public static final int DEFAULT_LINE_HEIGHT = 40;
 
49,7 → 45,7
private Boolean autoSelectFirstLine = true;
private TableSpec tableSpec = null;
 
private transient List<ActionListener> selectionListeners = new ArrayList<ActionListener>();
private transient List<ActionListener> selectionListeners = new ArrayList<>();
 
// Nombre de ligne à afficher par Row
private int linePerRow = 1;
81,10 → 77,8
 
final RowSelectionSpec selection = new RowSelectionSpec(this.getId());
final ColumnsSpec columnsSpec = new ColumnsSpec(this.getId(), new ArrayList<ColumnSpec>(), new ArrayList<String>(), new ArrayList<String>());
final TableSpec tableSpec = new TableSpec(this.getId(), selection, columnsSpec);
tableSpec.setContent(new TableContent(this.getId()));
 
this.setTableSpec(tableSpec);
this.tableSpec = new TableSpec(this.getId(), selection, columnsSpec);
this.tableSpec.setContent(new TableContent(this.getId()));
}
 
@Override
243,7 → 237,7
}
 
public final List<Row> getSelectedRows() {
final List<Row> selectedRows = new ArrayList<Row>();
final List<Row> selectedRows = new ArrayList<>();
 
if (this.getTableSpec().getSelection() != null) {
final List<Number> selectedIds = this.getSelectedIds();
374,7 → 368,7
}
 
public <T extends LightUIElement> List<T> findChildren(final Class<T> expectedClass, final boolean recursively) {
final List<T> result = new ArrayList<T>();
final List<T> result = new ArrayList<>();
 
if (this.hasRow()) {
final int size = this.getRowsCount();
382,16 → 376,18
final Row row = this.getRow(i);
final List<Object> rowValues = row.getValues();
for (final Object value : rowValues) {
if (recursively) {
if (value instanceof LightUIContainer) {
result.addAll(((LightUIContainer) value).findChildren(expectedClass, recursively));
} else if (value instanceof LightUITable) {
result.addAll(((LightUITable) value).findChildren(expectedClass, recursively));
if (value != null) {
if (recursively) {
if (value instanceof LightUIContainer) {
result.addAll(((LightUIContainer) value).findChildren(expectedClass, recursively));
} else if (value instanceof LightUITable) {
result.addAll(((LightUITable) value).findChildren(expectedClass, recursively));
}
}
if (expectedClass.isAssignableFrom(value.getClass())) {
result.add(expectedClass.cast(value));
}
}
if (expectedClass.isAssignableFrom(value.getClass())) {
result.add(expectedClass.cast(value));
}
}
}
} else {
427,7 → 423,7
final Document xmlConf = new Document();
 
final int columnSpecCount = columnsSpec.getColumnCount();
final List<String> visibleIds = new ArrayList<String>();
final List<String> visibleIds = new ArrayList<>();
for (int i = 0; i < columnSpecCount; i++) {
final ColumnSpec columnSpec = columnsSpec.getColumn(i);
final Element xmlColumn = this.createXmlColumn(columnSpec.getId(), columnSpec.getMaxWidth(), columnSpec.getMinWidth(), columnSpec.getWidth());
494,7 → 490,7
final Row row = this.getRow(i);
final List<Object> values = row.getValues();
for (final Object value : values) {
if (value != null && value instanceof LightUIElement) {
if (value instanceof LightUIElement) {
((LightUIElement) value).setReadOnly(readOnly);
}
}
526,9 → 522,9
 
for (int i = 0; i < size; i++) {
final Row row = this.getRow(i);
final JSONObject jsonLineContext = (JSONObject) JSONConverter.getObjectFromJSON(jsonContext.get(i), JSONObject.class);
final JSONObject jsonLineContext = JSONConverter.getObjectFromJSON(jsonContext.get(i), JSONObject.class);
final Number rowId = JSONConverter.getParameterFromJSON(jsonLineContext, "row.id", Number.class);
final String rowExtendId = (String) JSONConverter.getParameterFromJSON(jsonLineContext, "row.extend.id", String.class);
final String rowExtendId = JSONConverter.getParameterFromJSON(jsonLineContext, "row.extend.id", String.class);
if (NumberUtils.areNumericallyEqual(rowId, row.getId()) && (row.getExtendId() == null || (row.getExtendId() != null && rowExtendId.equals(row.getExtendId())))) {
if (row.isFillWidth()) {
if (!row.getValues().isEmpty() && row.getValues().get(0) instanceof LightUserControl) {
559,7 → 555,7
}
}
} else {
final List<Number> ids = new ArrayList<Number>(size);
final List<Number> ids = new ArrayList<>(size);
for (int j = 0; j < size; j++) {
ids.add(this.getRow(j).getId());
}
611,29 → 607,6
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
 
out.writeBoolean(dynamicLoad);
out.writeBoolean(allowSelection);
out.writeBoolean(allowMultiSelection);
out.writeBoolean(autoSelectFirstLine);
tableSpec.writeExternal(out);
 
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
this.dynamicLoad = in.readBoolean();
this.allowSelection = in.readBoolean();
this.allowMultiSelection = in.readBoolean();
this.autoSelectFirstLine = in.readBoolean();
tableSpec = new TableSpec();
tableSpec.readExternal(in);
}
 
@Override
public void destroy() {
super.destroy();
this.selectionListeners.clear();
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TableSearchParameterType.java
New file
0,0 → 1,89
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ui.light;
 
import org.openconcerto.utils.io.Transferable;
 
import java.util.Locale;
 
import net.minidev.json.JSONObject;
 
public class TableSearchParameterType implements Transferable {
 
// type from UserSearchItem type
private String type;
private String label;
private String valueType;
 
TableSearchParameterType() {
// For serialization
}
 
public TableSearchParameterType(String type) {
this.type = type;
}
 
public TableSearchParameterType(String type, String label, String valueType) {
this.type = type;
this.label = label;
this.valueType = valueType;
}
 
public String getType() {
return this.type;
}
 
public String getLabel() {
return this.label;
}
 
public String getValueType() {
return this.valueType;
}
 
@Override
public JSONObject toJSON() {
final JSONObject obj = new JSONObject();
obj.put("type", this.type);
obj.put("label", this.label);
obj.put("value-type", this.valueType);
return obj;
}
 
@Override
public void fromJSON(JSONObject json) {
this.type = json.getAsString("type");
this.label = json.getAsString("label");
this.valueType = json.getAsString("value-type");
}
 
public static TableSearchParameterType getContainsStringInstance(Locale locale) {
if (locale.equals(Locale.FRENCH)) {
return new TableSearchParameterType(UserSearchItem.TYPE_CONTAINS, "Contient", "string");
}
return new TableSearchParameterType(UserSearchItem.TYPE_CONTAINS, "Contains", "string");
}
 
public static TableSearchParameterType getIsStringInstance(Locale locale) {
if (locale.equals(Locale.FRENCH)) {
return new TableSearchParameterType(UserSearchItem.TYPE_IS, "Est", "string");
}
return new TableSearchParameterType(UserSearchItem.TYPE_IS, "Is", "string");
}
 
@Override
public String toString() {
return super.toString() + "type:" + this.type + " label:" + this.label + " value-type:" + this.valueType;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TableContent.java
16,10 → 16,6
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
 
26,7 → 22,7
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
 
public class TableContent implements Transferable, Externalizable {
public class TableContent implements Transferable {
private static final long serialVersionUID = 3648381615123520834L;
private String tableId;
private List<Row> rows;
100,7 → 96,7
* @return a copy of the list
*/
public final synchronized List<Row> getRows() {
return new ArrayList<Row>(this.rows);
return new ArrayList<>(this.rows);
}
 
@Override
122,7 → 118,7
this.tableId = JSONConverter.getParameterFromJSON(json, "table-id", String.class);
final JSONArray jsonRows = JSONConverter.getParameterFromJSON(json, "rows", JSONArray.class);
if (jsonRows != null) {
final List<Row> listRows = new ArrayList<Row>();
final List<Row> listRows = new ArrayList<>();
for (final Object o : jsonRows) {
listRows.add(new Row(JSONConverter.getObjectFromJSON(o, JSONObject.class)));
}
130,27 → 126,4
}
}
 
@Override
public synchronized void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(tableId);
out.writeInt(rows.size());
for (Row row : this.rows) {
row.writeExternal(out);
}
 
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
tableId = in.readUTF();
int size = in.readInt();
this.rows = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
final Row row = new Row();
row.readExternal(in);
this.rows.add(row);
}
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIStrippedImageLine.java
42,11 → 42,6
}
 
@Override
public LightUIElement clone() {
return new LightUIStrippedImageLine(this);
}
 
@Override
protected void copy(LightUIElement element) {
super.copy(element);
 
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITab.java
54,11 → 54,6
}
 
@Override
public LightUIElement clone() {
return new LightUITab(this);
}
 
@Override
public void copy(final LightUIElement element) {
if (!(element instanceof LightUITab)) {
throw new InvalidClassException(LightUITab.class.getName(), element.getClassName(), element.getId());
/trunk/OpenConcerto/src/org/openconcerto/ui/light/RowsBulk.java
13,6 → 13,9
package org.openconcerto.ui.light;
 
import org.openconcerto.utils.io.JSONAble;
import org.openconcerto.utils.io.JSONConverter;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
21,8 → 24,6
import java.util.Collections;
import java.util.List;
 
import org.openconcerto.utils.io.JSONAble;
import org.openconcerto.utils.io.JSONConverter;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
 
143,7 → 144,7
this.total = JSONConverter.getParameterFromJSON(json, "total", Integer.class);
 
final JSONArray jsonRows = JSONConverter.getParameterFromJSON(json, "rows", JSONArray.class);
this.rows = new ArrayList<Row>();
this.rows = new ArrayList<>();
if (jsonRows != null) {
for (final Object o : jsonRows) {
this.rows.add(new Row(JSONConverter.getObjectFromJSON(o, JSONObject.class)));
153,6 → 154,6
 
@Override
public String toString() {
return this.rows.size() + " rows at offset " + offset + " (total:" + total + ") remove:" + this.remove;
return this.rows.size() + " rows at offset " + this.offset + " (total:" + this.total + ") remove:" + this.remove;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFileUploadWithSelection.java
38,11 → 38,6
}
 
@Override
public LightUIElement clone() {
return new LightUIFileUploadWithSelection(this);
}
 
@Override
protected void copy(LightUIElement element) {
super.copy(element);
if (!(element instanceof LightUIFileUploadWithSelection)) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIElement.java
200,7 → 200,7
}
 
private static long count = 0;
private static Integer counterLock = new Integer(123456);
private static Object counterLock = new Object();
 
private String getNextUUID() {
String result;
536,7 → 536,11
}
 
public void setId(final String id) {
if (id == null) {
throw new IllegalArgumentException("id cannot be null");
}
this.id = id;
 
}
 
public String getUUID() {
809,6 → 813,9
if (element == null) {
throw new IllegalArgumentException("Try to copy attributes of null element in " + this.getId());
}
System.err.println("LightUIElement.copy() " + element);
this.UUID = getNextUUID();
this.id = element.getId();
this.fontSize = element.fontSize;
this.gridHeight = element.gridHeight;
this.gridWidth = element.gridWidth;
866,7 → 873,7
 
@Override
public String toString() {
if (!destroyed) {
if (!this.destroyed) {
return super.toString() + " " + this.id;
} else {
return super.toString() + " " + this.id + " DESTROYED";
1012,6 → 1019,9
if (this.toolTip != null) {
result.put("tool-tip", this.toolTip);
}
if (this.UUID == null) {
throw new IllegalStateException("null UUID, id: " + this.id);
}
result.put("uuid", this.UUID);
if (this.value != null) {
result.put("value", this.value);
1045,6 → 1055,9
public void fromJSON(final JSONObject json) {
this.id = JSONConverter.getParameterFromJSON(json, "id", String.class);
this.UUID = JSONConverter.getParameterFromJSON(json, "uuid", String.class);
if (this.UUID == null) {
throw new IllegalArgumentException("null UUID, id : " + this.id);
}
this.displayPrecision = JSONConverter.getParameterFromJSON(json, "display-precision", String.class);
this.icon = JSONConverter.getParameterFromJSON(json, "icon", String.class);
this.label = JSONConverter.getParameterFromJSON(json, "label", String.class);
1109,7 → 1122,7
}
 
public boolean isDestroyed() {
return destroyed;
return this.destroyed;
}
 
@Override
1120,7 → 1133,7
}
out.writeUTF(this.id);
if (this.UUID == null) {
throw new IllegalStateException("UUID");
throw new IllegalStateException("null UUID, id : " + this.id);
}
out.writeUTF(this.UUID);
 
1223,6 → 1236,9
this.type = in.readInt();
this.id = in.readUTF();
this.UUID = in.readUTF();
if (this.UUID == null) {
throw new IllegalStateException("null UUID, id : " + this.id);
}
if (in.readBoolean()) {
this.label = in.readUTF();
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFrame.java
62,10 → 62,16
super.destroy();
if (this.titlePanel != null) {
this.titlePanel.destroy();
this.titlePanel = null;
}
if (this.footerPanel != null) {
this.footerPanel.destroy();
this.footerPanel = null;
}
if (this.contentPanel != null) {
this.contentPanel.destroy();
this.contentPanel = null;
}
if (this.childrenFrame != null) {
for (LightUIFrame frame : childrenFrame) {
frame.destroy();
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TableSpec.java
16,19 → 16,19
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
 
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
 
public class TableSpec implements Transferable, Externalizable {
public class TableSpec implements Transferable {
private String id;
private ColumnsSpec columns;
private TableContent content;
private RowSelectionSpec selection;
private SearchSpec search;
private List<TableSearchParameter> searchParameters = new ArrayList<>();
private UserSearch search;
private Boolean variableColumnsCount = false;
 
public TableSpec() {
84,11 → 84,11
this.selection = selection;
}
 
public SearchSpec getSearch() {
public UserSearch getSearch() {
return this.search;
}
 
public void setSearch(final SearchSpec search) {
public void setSearch(final UserSearch search) {
this.search = search;
}
 
100,6 → 100,14
this.variableColumnsCount = variableColumnsCount;
}
 
public void addSearchParameter(TableSearchParameter p) {
this.searchParameters.add(p);
}
 
public void removeSearchParameter(TableSearchParameter p) {
this.searchParameters.remove(p);
}
 
@Override
public JSONObject toJSON() {
final JSONObject result = new JSONObject();
114,6 → 122,7
if (this.selection != null) {
result.put("selection", JSONConverter.getJSON(this.selection));
}
 
if (this.search != null) {
result.put("search", JSONConverter.getJSON(this.search));
}
121,23 → 130,30
result.put("variable-columns-count", JSONConverter.getJSON(true));
}
 
if (!this.searchParameters.isEmpty()) {
JSONArray a = new JSONArray();
for (TableSearchParameter p : this.searchParameters) {
a.add(p.toJSON());
}
result.put("search-params", a);
}
return result;
}
 
@Override
public void fromJSON(final JSONObject json) {
this.id = (String) JSONConverter.getParameterFromJSON(json, "id", String.class);
this.id = json.getAsString("id");
 
final JSONObject jsonColumns = (JSONObject) JSONConverter.getParameterFromJSON(json, "columns", JSONObject.class);
final JSONObject jsonColumns = JSONConverter.getParameterFromJSON(json, "columns", JSONObject.class);
if (jsonColumns != null) {
this.columns = new ColumnsSpec(jsonColumns);
}
 
final JSONObject jsonContent = (JSONObject) JSONConverter.getParameterFromJSON(json, "content", JSONObject.class);
final JSONObject jsonContent = JSONConverter.getParameterFromJSON(json, "content", JSONObject.class);
if (jsonContent != null) {
this.content = new TableContent(jsonContent);
}
final JSONObject jsonSelection = (JSONObject) JSONConverter.getParameterFromJSON(json, "selection", JSONObject.class);
final JSONObject jsonSelection = JSONConverter.getParameterFromJSON(json, "selection", JSONObject.class);
if (jsonSelection != null) {
this.selection = new RowSelectionSpec(jsonSelection);
} else {
144,39 → 160,22
throw new IllegalArgumentException("null selection");
}
 
final JSONObject jsonSearch = (JSONObject) JSONConverter.getParameterFromJSON(json, "search", JSONObject.class);
final JSONObject jsonSearch = JSONConverter.getParameterFromJSON(json, "search", JSONObject.class);
if (jsonSearch != null) {
this.search = new SearchSpec(jsonSearch);
this.search = new UserSearch(jsonSearch);
}
 
this.variableColumnsCount = (Boolean) JSONConverter.getParameterFromJSON(json, "variable-columns-count", Boolean.class);
}
this.variableColumnsCount = JSONConverter.getParameterFromJSON(json, "variable-columns-count", Boolean.class);
this.searchParameters.clear();
if (json.containsKey("search-params")) {
final JSONArray array = (JSONArray) json.get("search-params");
for (Object o : array) {
final TableSearchParameter p = new TableSearchParameter();
p.fromJSON((JSONObject) o);
this.searchParameters.add(p);
}
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(id);
this.columns.writeExternal(out);
this.content.writeExternal(out);
 
this.selection.writeExternal(out);
this.search.writeExternal(out);
 
out.writeBoolean(this.variableColumnsCount);
 
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readUTF();
this.columns = new ColumnsSpec();
this.columns.readExternal(in);
this.content = new TableContent();
this.content.readExternal(in);
this.selection = new RowSelectionSpec();
this.selection.readExternal(in);
this.search = new SearchSpec();
this.search.readExternal(in);
this.variableColumnsCount = in.readBoolean();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_en.xml
12,7 → 12,8
<FIELD name="ID_USER_RIGHT_COMMON" label="User rights" />
<FIELD name="MAIL" label="E-Mail" />
<FIELD name="DISABLED" label="Account disabled" />
<FIELD name="TEL" label="Phone" titlelabel="Phone" />
<FIELD name="TEL" label="Phone" />
<FIELD name="COLOR" label="Color" />
</element>
<element refid="sql.right">
<name base="right" />
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/SavableCustomEditorProvider.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/TableSearchColumnMatcher.java
New file
0,0 → 1,76
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearchItem;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
 
public class TableSearchColumnMatcher implements TableSearchMatcher {
private final SQLTableModelColumn col;
 
public TableSearchColumnMatcher(SQLTableModelColumn col) {
this.col = col;
}
 
@Override
public boolean useMatch() {
return false;
}
 
@Override
public boolean match(SQLRowValues r, TableSearchParameterType type, String txt) {
return true;
}
 
@Override
public Where getWhere(SQLSelect sel, TableSearchParameterType type, String txt) {
final Set<FieldPath> fields = this.col.getPaths();
final List<Where> wFields = new ArrayList<>(fields.size());
for (final FieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final FieldRef fieldRef = sel.followFieldPath(fpath);
if (type.getType().equals(UserSearchItem.TYPE_CONTAINS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", "%" + txt.toLowerCase() + "%");
wFields.add(w);
} else if (type.getType().equals(UserSearchItem.TYPE_STARTS_WITH)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase() + "%");
wFields.add(w);
} else if (type.getType().equals(UserSearchItem.TYPE_IS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase());
wFields.add(w);
}
}
}
return Where.or(wFields);
}
 
@Override
public List<FieldPath> getAdditionnalFieldsToFetch() {
return Collections.emptyList();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/SearchInfo.java
17,8 → 17,8
import org.openconcerto.sql.view.search.SearchList;
import org.openconcerto.sql.view.search.TextSearchSpec;
import org.openconcerto.sql.view.search.TextSearchSpec.Mode;
import org.openconcerto.ui.light.SearchContent;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.ui.light.UserSearch;
 
import java.util.ArrayList;
import java.util.List;
28,10 → 28,10
private final SearchList list = new SearchList();
private final List<String> texts = new ArrayList<String>();
 
public SearchInfo(final SearchSpec params) {
public SearchInfo(final UserSearch params) {
int stop = params.getContent().size();
for (int i = 0; i < stop; i++) {
final SearchContent param = params.getContent().get(i);
final UserSearchItem param = params.getContent().get(i);
final String col = param.getColumn();
final String type = param.getType();
final String[] tTexts = param.getText().split(" ");
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/TableSearchMatcher.java
New file
0,0 → 1,51
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.ui.light.TableSearchParameterType;
 
import java.util.List;
 
public interface TableSearchMatcher {
 
/**
* Where to add to prefilter the result
*/
public Where getWhere(SQLSelect sel, TableSearchParameterType type, String txt);
 
/**
* Fields to fetch for this matcher. The fields will be accessed in the match method, from the
* SQLRowValues
*
* @return the fields paths
* @return null or emtpy List is nothing to fetch
*/
public List<FieldPath> getAdditionnalFieldsToFetch();
 
/**
* @return true is the match method must be used
*/
public boolean useMatch();
 
/**
* Match the SQLRowValues retrieve from the database (filtered by the Where from getWhere) using
* the type and the user text
*/
public boolean match(SQLRowValues r, TableSearchParameterType type, String txt);
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightUIPanelFiller.java
15,6 → 15,7
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.Constraint;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowAccessor;
31,6 → 32,9
 
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
/**
58,11 → 62,17
}
}
 
public void fillFromRow(final PropsConfiguration configuration, final SQLRowAccessor row) {
this.fillFromRow(this.panel, configuration, row);
public void fillFromRow(final PropsConfiguration configuration, SQLElement element, final SQLRowAccessor row, String sessionSecurityToken) {
this.fillFromRow(this.panel, configuration, element, row, sessionSecurityToken);
}
 
private void fillFromRow(final LightUIPanel panel, final PropsConfiguration configuration, SQLRowAccessor sqlRow) {
private void fillFromRow(final LightUIPanel panel, final PropsConfiguration configuration, SQLElement sqlElement, SQLRowAccessor sqlRow, String sessionSecurityToken) {
List<CustomRowEditor> editors = sqlElement.getCustomRowEditors(configuration, sessionSecurityToken);
Map<String, CustomRowEditor> mapEditor = new HashMap<>(editors.size());
for (CustomRowEditor e : editors) {
mapEditor.put(e.getItemId(), e);
}
 
final int panelChildCount = panel.getChildrenCount();
// Convert as sqlrow if possible to get all values from db
if (sqlRow.hasID()) {
73,54 → 83,59
final int lineChildCount = panelChild.getChildrenCount();
for (int j = 0; j < lineChildCount; j++) {
final LightUIElement element = panelChild.getChild(j);
final SQLField sqlField = configuration.getFieldMapper().getSQLFieldForItem(element.getId());
if (mapEditor.containsKey(element.getId())) {
mapEditor.get(element.getId()).fillFrom(element, sqlRow);
} else {
 
SQLRowAccessor sqlRowTmp = this.getSQLRowForField(sqlRow, sqlField);
if (sqlRowTmp == null) {
throw new IllegalArgumentException("Impossible to reach the field: " + sqlField.getName() + " from table " + sqlRow.getTable().getName());
}
final SQLField sqlField = configuration.getFieldMapper().getSQLFieldForItem(element.getId());
 
int type = element.getType();
if (type == LightUIElement.TYPE_TEXT_FIELD || type == LightUIElement.TYPE_TEXT_AREA) {
SQLRowAccessor sqlRowTmp = this.getSQLRowForField(sqlRow, sqlField);
if (sqlRowTmp == null) {
throw new IllegalArgumentException("Impossible to reach the field: " + sqlField.getName() + " from table " + sqlRow.getTable().getName());
}
 
if (sqlField == null) {
Log.get().severe("No field found for text field : " + element.getId());
continue;
}
element.setValue(sqlRowTmp.getString(sqlField.getName()));
} else if (sqlField != null && sqlField.isKey() && (type == LightUIElement.TYPE_COMBOBOX || type == LightUIElement.TYPE_AUTOCOMPLETE_COMBOBOX)) {
// send: id,value
final LightUIComboBox combo = (LightUIComboBox) element;
LightUIComboBoxElement value = null;
final Number foreignID = sqlRowTmp.getForeignIDNumber(sqlField.getName());
if (foreignID != null) {
final SQLTable foreignTable = sqlField.getForeignTable();
final ComboSQLRequest req = configuration.getDirectory().getElement(foreignTable).getComboRequest();
final IComboSelectionItem comboItem = req.getComboItem(foreignID.intValue());
if (comboItem != null) {
value = new LightUIComboBoxElement(comboItem.getId());
value.setValue1(comboItem.getLabel());
int type = element.getType();
if (type == LightUIElement.TYPE_TEXT_FIELD || type == LightUIElement.TYPE_TEXT_AREA) {
 
if (sqlField == null) {
Log.get().severe("No field found for text field : " + element.getId());
continue;
}
element.setValue(sqlRowTmp.getString(sqlField.getName()));
} else if (sqlField != null && sqlField.isKey() && (type == LightUIElement.TYPE_COMBOBOX || type == LightUIElement.TYPE_AUTOCOMPLETE_COMBOBOX)) {
// send: id,value
final LightUIComboBox combo = (LightUIComboBox) element;
LightUIComboBoxElement value = null;
final Number foreignID = sqlRowTmp.getForeignIDNumber(sqlField.getName());
if (foreignID != null) {
final SQLTable foreignTable = sqlField.getForeignTable();
final ComboSQLRequest req = configuration.getDirectory().getElement(foreignTable).getComboRequest();
final IComboSelectionItem comboItem = req.getComboItem(foreignID.intValue());
if (comboItem != null) {
value = new LightUIComboBoxElement(comboItem.getId());
value.setValue1(comboItem.getLabel());
}
}
combo.setSelectedValue(value);
} else if (type == LightUIElement.TYPE_CHECKBOX) {
if (sqlRowTmp.getObject(sqlField.getName()) != null && sqlRowTmp.getBoolean(sqlField.getName())) {
element.setValue("true");
} else {
element.setValue("false");
}
} else if (type == LightUIElement.TYPE_DATE) {
Calendar date = sqlRowTmp.getDate(sqlField.getName());
if (date != null) {
element.setValue(JSONConverter.getJSON(date).toString());
}
} else if (type == LightUIElement.TYPE_PANEL) {
this.fillFromRow((LightUIPanel) element, configuration, sqlElement, sqlRowTmp, sessionSecurityToken);
} else if (type == LightUIElement.TYPE_SLIDER) {
final Integer value = sqlRowTmp.getInt(sqlField.getName());
if (value != null) {
element.setValue(value.toString());
}
}
combo.setSelectedValue(value);
} else if (type == LightUIElement.TYPE_CHECKBOX) {
if (sqlRowTmp.getObject(sqlField.getName()) != null && sqlRowTmp.getBoolean(sqlField.getName())) {
element.setValue("true");
} else {
element.setValue("false");
}
} else if (type == LightUIElement.TYPE_DATE) {
Calendar date = sqlRowTmp.getDate(sqlField.getName());
if (date != null) {
element.setValue(JSONConverter.getJSON(date).toString());
}
} else if (type == LightUIElement.TYPE_PANEL) {
this.fillFromRow((LightUIPanel) element, configuration, sqlRowTmp);
} else if (type == LightUIElement.TYPE_SLIDER) {
final Integer value = sqlRowTmp.getInt(sqlField.getName());
if (value != null) {
element.setValue(value.toString());
}
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightForeignRowValuesTableOffline.java
16,11 → 16,12
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.SQLTableModelLinesSourceOffline;
import org.openconcerto.ui.light.LightUIElement;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableContent;
import org.openconcerto.ui.light.UserSearch;
 
import java.util.concurrent.Future;
 
31,14 → 32,19
private SQLField foreignField;
private Number parentRowId;
 
public LightForeignRowValuesTableOffline(final Configuration configuration, final Number userId, final String id, final ITableModel model, final SQLField foreignField, final Number parentRowId) {
public LightForeignRowValuesTableOffline(final Configuration configuration, final Number userId, final String id, final ITableModel model, final SQLField foreignField) {
super(configuration, userId, id, model);
 
this.foreignField = foreignField;
this.parentRowId = parentRowId;
this.init();
}
 
public void setParentRowId(Number parentRowId) {
this.parentRowId = parentRowId;
// FIXME : d'apres Sylvain, on pourrait ne pas a utiliser le ITableMobel car on veut du
// synchrone
this.getModel().getReq().getReq().setWhere(new Where(this.foreignField, "=", parentRowId));
}
 
public LightForeignRowValuesTableOffline(final LightForeignRowValuesTableOffline table) {
super(table);
 
70,7 → 76,7
}
 
@Override
public void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset) {
public void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset) {
// TODO: Implement search in offline table
this.getModel().fireTableRowsInserted(0, Integer.MAX_VALUE);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/GroupToLightUIConvertor.java
23,7 → 23,6
import org.openconcerto.ui.group.Group;
import org.openconcerto.ui.group.Item;
import org.openconcerto.ui.group.LayoutHints;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.LightUIAutoCompleteComboBox;
import org.openconcerto.ui.light.LightUICheckBox;
import org.openconcerto.ui.light.LightUIDate;
43,6 → 42,7
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class GroupToLightUIConvertor {
49,7 → 49,7
private final int maxColumnCount;
private PropsConfiguration configuration;
private FieldMapper mapper;
private Map<String, CustomEditorProvider> customEditorProviders = new HashMap<String, CustomEditorProvider>();
private Map<String, CustomRowEditor> customRowEditors = new HashMap<>();
 
public GroupToLightUIConvertor(PropsConfiguration conf) {
this(conf, 4);
73,6 → 73,15
}
 
final SQLElement sqlElement = this.configuration.getDirectory().getElement(defaultRow.getTable());
if (sqlElement == null) {
throw new IllegalArgumentException("not SQLElement found for default row table : " + defaultRow.getTable().getName());
}
if (sqlElement.getGroupForCreation() == null) {
throw new IllegalArgumentException("no group for creation defined in " + sqlElement.getClass().getName());
}
if (sqlElement.getGroupForModification() == null) {
throw new IllegalArgumentException("no group for creation defined in " + sqlElement.getClass().getName());
}
if (!sqlElement.getGroupForCreation().equals(group) && sqlElement.getGroupForModification().equals(group)) {
throw new IllegalArgumentException("This group isn't attached to this SQLElement, group ID: " + group.getId() + " element code: " + sqlElement.getCode());
}
313,11 → 322,14
}
 
private LightUIElement getCustomEditor(final String id) {
final CustomEditorProvider customEditorProvider = this.customEditorProviders.get(id);
if (id == null) {
throw new IllegalArgumentException("null id");
}
final CustomRowEditor customEditorProvider = this.customRowEditors.get(id);
if (customEditorProvider != null) {
final LightUIElement element = customEditorProvider.createUIElement(id);
final LightUIElement element = customEditorProvider.createUIElement();
if (element.getId() == null) {
throw new IllegalStateException("Null id for custom editor for id: " + id);
throw new IllegalStateException("Null id for custom editor for id: " + id + " element : " + element);
}
return element;
}
324,11 → 336,12
return null;
}
 
public void putCustomEditorProvider(final String id, final CustomEditorProvider provider) {
this.customEditorProviders.put(id, provider);
public void putCustomEditorProvider(final CustomRowEditor e) {
this.customRowEditors.put(e.getItemId(), e);
}
 
public void putAllCustomEditorProvider(final Map<String, CustomEditorProvider> map) {
this.customEditorProviders.putAll(map);
public void putAllCustomEditorProvider(final List<CustomRowEditor> editors) {
for (CustomRowEditor e : editors)
this.customRowEditors.put(e.getItemId(), e);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTable.java
14,8 → 14,14
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.ListSQLLine;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
26,12 → 32,21
import org.openconcerto.ui.light.LightUIElement;
import org.openconcerto.ui.light.LightUITable;
import org.openconcerto.ui.light.Row;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableSearchParameter;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearch;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
 
import javax.swing.SwingUtilities;
55,8 → 70,10
 
private transient ITransformer<SQLSelect, SQLSelect> orginTransformer;
 
private transient List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>();
private transient List<TableModelListener> tableModelListeners = new ArrayList<>();
 
private Map<TableSearchParameter, TableSearchMatcher> searchMap = new HashMap<>();
 
public LightRowValuesTable() {
// Serialization
}
72,6 → 89,74
if (model.getReq() instanceof SQLTableModelSourceOnline) {
final SQLTableModelSourceOnline source = (SQLTableModelSourceOnline) model.getReq();
this.orginTransformer = source.getReq().getSelectTransf();
 
List<SQLTableModelColumn> columns = model.getReq().getColumns();
// all
// TODO : traduire
TableSearchParameter tableSearchParameterAll = new TableSearchParameter("all", "Tous");
 
TableSearchMatcher m = new TableSearchMatcher() {
 
@Override
public boolean useMatch() {
return false;
}
 
@Override
public boolean match(SQLRowValues r, TableSearchParameterType type, String txt) {
return true;
}
 
@Override
public Where getWhere(SQLSelect sel, TableSearchParameterType type, String txt) {
final Set<FieldPath> fields = new HashSet<>();
for (SQLTableModelColumn col : columns) {
fields.addAll(col.getPaths());
}
final List<Where> wFields = new ArrayList<>(fields.size());
for (final FieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final FieldRef fieldRef = sel.followFieldPath(fpath);
if (type.getType().equals(UserSearchItem.TYPE_CONTAINS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", "%" + txt.toLowerCase() + "%");
wFields.add(w);
}
if (type.getType().equals(UserSearchItem.TYPE_STARTS_WITH)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase() + "%");
wFields.add(w);
}
if (type.getType().equals(UserSearchItem.TYPE_IS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase());
wFields.add(w);
}
}
}
return Where.or(wFields);
}
 
@Override
public List<FieldPath> getAdditionnalFieldsToFetch() {
return Collections.emptyList();
}
};
tableSearchParameterAll.add(TableSearchParameterType.getContainsStringInstance(Locale.FRENCH));
tableSearchParameterAll.add(TableSearchParameterType.getIsStringInstance(Locale.FRENCH));
 
this.addSearchParameter(tableSearchParameterAll, m);
 
//
for (int i = 0; i < columns.size(); i++) {
SQLTableModelColumn col = columns.get(i);
TableSearchParameter tableSearchParameter = new TableSearchParameter("col" + i, col.getName());
// FIXME : locale à recuperer depuis le user
// TODO : mettre d'autres TableSearchParameterType en fonction du type de la colonne
tableSearchParameter.add(TableSearchParameterType.getContainsStringInstance(Locale.FRENCH));
tableSearchParameter.add(TableSearchParameterType.getIsStringInstance(Locale.FRENCH));
 
TableSearchMatcher tableSearchMatcher = new TableSearchColumnMatcher(col);
this.addSearchParameter(tableSearchParameter, tableSearchMatcher);
}
 
} else {
this.orginTransformer = null;
}
108,7 → 193,13
 
public final void addTableModelListener(final TableModelListener tableModelListener) {
this.tableModelListeners.add(tableModelListener);
this.model.addTableModelListener(tableModelListener);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
LightRowValuesTable.this.model.addTableModelListener(tableModelListener);
}
});
 
}
 
public final void removeTableModelListener(final TableModelListener tableModelListener) {
270,8 → 361,26
}
 
// TODO: merge with OpenConcerto List search system
public abstract void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset);
public abstract void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset);
 
public void addSearchParameter(TableSearchParameter tableSearchParameter, TableSearchMatcher tableSearchMatcher) {
this.searchMap.put(tableSearchParameter, tableSearchMatcher);
this.getTableSpec().addSearchParameter(tableSearchParameter);
}
 
protected TableSearchMatcher getSearchMatcher(String colId, String searchType) {
for (TableSearchParameter p : this.searchMap.keySet()) {
if (p.getId().equals(colId)) {
for (TableSearchParameterType t : p.getTypes()) {
if (t.getType().equals(searchType)) {
return this.searchMap.get(p);
}
}
}
}
return null;
}
 
@Override
public Row getRowById(Number rowId) {
for (int i = 0; i < this.model.getRowCount(); i++) {
314,9 → 423,10
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
final List<TableModelListener> tableModelListeners = LightRowValuesTable.this.tableModelListeners;
for (int i = tableModelListeners.size() - 1; i > -1; i--) {
LightRowValuesTable.this.removeTableModelListener(tableModelListeners.get(i));
 
final List<TableModelListener> listeners = LightRowValuesTable.this.tableModelListeners;
for (int i = listeners.size() - 1; i > -1; i--) {
LightRowValuesTable.this.removeTableModelListener(listeners.get(i));
}
}
});
325,5 → 435,6
}
 
this.clearRows();
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightEditFrame.java
41,6 → 41,8
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
 
145,19 → 147,18
 
final SQLElement sqlElement = configuration.getDirectory().getElement(this.sqlRow.getTable());
 
final Map<String, CustomEditorProvider> customEditors;
if (this.editMode.equals(EditMode.CREATION)) {
customEditors = sqlElement.getCustomEditorProviderForCreation(configuration, sessionSecurityToken);
} else {
customEditors = sqlElement.getCustomEditorProviderForModification(configuration, this.sqlRow, sessionSecurityToken);
final List<CustomRowEditor> customRowEditors = sqlElement.getCustomRowEditors(configuration, sessionSecurityToken);
 
final Map<String, CustomRowEditor> customEditors = new HashMap<>(customRowEditors.size());
for (CustomRowEditor e : customRowEditors) {
customEditors.put(e.getItemId(), e);
}
 
this.createRowValues(configuration, sqlElement, fieldMapper, this.group, customEditors);
this.setMetaData(userId);
}
 
final protected void createRowValues(final Configuration configuration, final SQLElement sqlElement, final FieldMapper fieldMapper, final Group group,
final Map<String, CustomEditorProvider> customEditors) {
protected final void createRowValues(final Configuration configuration, final SQLElement sqlElement, final FieldMapper fieldMapper, final Group group,
final Map<String, CustomRowEditor> customEditors) {
final int itemCount = group.getSize();
for (int i = 0; i < itemCount; i++) {
final Item item = group.getItem(i);
176,7 → 177,16
this.putValueFromUserControl(configuration, sqlElement, field, uiElement, customEditors);
}
} else {
Log.get().warning("No field attached to " + item.getId());
final LightUIElement uiElement = this.findChildByID(item.getId(), LightUIElement.class);
if (uiElement == null) {
throw new IllegalArgumentException("Impossible to find UI Element with id: " + item.getId());
}
if (customEditors.containsKey(uiElement.getId())) {
final CustomRowEditor customEditor = customEditors.get(uiElement.getId());
customEditor.store(uiElement, this.sqlRow);
} else {
Log.get().warning("No field attached to " + item.getId());
}
}
}
}
183,19 → 193,13
}
 
protected final void putValueFromUserControl(final Configuration configuration, final SQLElement sqlElement, final SQLField sqlField, final LightUIElement uiElement,
final Map<String, CustomEditorProvider> customEditors) {
final Map<String, CustomRowEditor> customEditors) {
if (!uiElement.isNotSaved()) {
boolean useElementValue = true;
final Class<?> fieldType = sqlField.getType().getJavaType();
if (customEditors.containsKey(uiElement.getId())) {
final CustomEditorProvider customEditor = customEditors.get(uiElement.getId());
if (customEditor instanceof SavableCustomEditorProvider) {
((SavableCustomEditorProvider) customEditor).save(this.sqlRow, sqlField, uiElement);
useElementValue = false;
}
}
 
if (useElementValue) {
final CustomRowEditor customEditor = customEditors.get(uiElement.getId());
customEditor.store(uiElement, this.sqlRow);
} else {
final String fieldName = sqlField.getFieldName();
if (sqlField.isKey()) {
if (!(uiElement instanceof LightUIComboBox)) {
268,11 → 272,13
* @param row Element saved row
* @param customEditors List of custom editors used in element edit frame
*/
final public void saveReferentRows(final Configuration configuration, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors, final String sessionSecurityToken) {
@Deprecated
public final void saveReferentRows(final Configuration configuration, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors, final String sessionSecurityToken) {
this.saveReferentRows(configuration, this.group, parentSqlRow, customEditors, sessionSecurityToken);
}
 
final private void saveReferentRows(final Configuration configuration, final Group group, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors,
@Deprecated
private final void saveReferentRows(final Configuration configuration, final Group group, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors,
final String sessionSecurityToken) {
for (int i = 0; i < group.getSize(); i++) {
final Item item = group.getItem(i);
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/CustomRowEditor.java
New file
0,0 → 1,49
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.ui.light.LightUIElement;
 
public abstract class CustomRowEditor {
private final String itemId;
 
public CustomRowEditor(String itemId) {
this.itemId = itemId;
}
 
public String getItemId() {
return this.itemId;
}
 
/**
* Create the UI element filled with the row
*
*/
public abstract LightUIElement createUIElement();
 
public abstract void fillFrom(final LightUIElement uiElement, final SQLRowAccessor row);
 
/**
* Store the values in the row from the UI element
*/
public abstract void store(final LightUIElement uiElement, final SQLRowValues row);
 
public void afterCommit(LightUIElement uiElement, SQLRow insertedRow) {
// nothing
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTableOnline.java
14,29 → 14,23
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.IFieldPath;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.Log;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelSource;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearch;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
 
import javax.swing.SwingUtilities;
 
import net.minidev.json.JSONObject;
 
public class LightRowValuesTableOnline extends LightRowValuesTable {
48,7 → 42,6
 
public LightRowValuesTableOnline(final Configuration configuration, final Number userId, final String id, final ITableModel model) {
super(configuration, userId, id, model);
 
this.orginTransformer = ((SQLTableModelSourceOnline) model.getReq()).getReq().getSelectTransf();
}
 
55,7 → 48,6
// Clone constructor
public LightRowValuesTableOnline(final LightRowValuesTableOnline tableElement) {
super(tableElement);
 
this.orginTransformer = tableElement.orginTransformer;
}
 
66,85 → 58,73
}
 
@Override
public void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset) {
public void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset) {
 
this.getTableSpec().setSearch(searchSpec);
 
this.setOffset(offset);
 
final SQLTableModelSource tableSource = this.getModel().getReq();
final SearchInfo sInfo = (searchSpec != null) ? new SearchInfo(searchSpec) : null;
final ListSQLRequest req = tableSource.getReq();
final List<UserSearchItem> content = new ArrayList<>();
if (searchSpec != null) {
content.addAll(searchSpec.getContent());
 
final FutureTask<ListSQLRequest> f = new FutureTask<ListSQLRequest>(new Callable<ListSQLRequest>() {
@Override
public ListSQLRequest call() throws Exception {
final ListSQLRequest req = tableSource.getReq();
final List<SQLTableModelColumn> columns = tableSource.getColumns();
req.setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(final SQLSelect sel) {
if (LightRowValuesTableOnline.this.orginTransformer != null) {
LightRowValuesTableOnline.this.orginTransformer.transformChecked(sel);
}
setWhere(sel, sInfo, columns);
return sel;
for (UserSearchItem item : content) {
// ex "col0"
String colId = item.getColumn();
// ex "contains"
String searchType = item.getType();
TableSearchMatcher m = LightRowValuesTableOnline.this.getSearchMatcher(colId, searchType);
if (m != null && m.getAdditionnalFieldsToFetch() != null) {
for (FieldPath p : m.getAdditionnalFieldsToFetch()) {
req.addToGraphToFetch(p.getPath(), Arrays.asList(p.getField().getFieldName()));
}
});
return req;
}
}
});
 
// TODO: clean swing
SwingUtilities.invokeLater(f);
 
try {
final ListSQLRequest req = f.get();
 
// get values
long t4 = System.currentTimeMillis();
final List<SQLRowValues> rowValues = req.getValues();
final int size = rowValues.size();
long t5 = System.currentTimeMillis();
 
System.err.println("DefaultTableContentHandler.handle() getValues() :" + size + " : " + (t5 - t4) + " ms");
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}
req.setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(final SQLSelect sel) {
if (LightRowValuesTableOnline.this.orginTransformer != null) {
LightRowValuesTableOnline.this.orginTransformer.transformChecked(sel);
}
if (searchSpec != null) {
//
final List<Where> wheres = new ArrayList<>();
for (UserSearchItem item : content) {
// ex "col0"
String colId = item.getColumn();
// ex "hello"
String userText = item.getText();
// ex "contains"
String searchType = item.getType();
TableSearchMatcher m = LightRowValuesTableOnline.this.getSearchMatcher(colId, searchType);
if (m != null) {
final Where where = m.getWhere(sel, new TableSearchParameterType(searchType), userText);
if (where != null) {
wheres.add(where);
}
} else {
Log.get().warning("no TableSearchMatcher for " + item);
}
 
/**
* Apply filter on ListSQLRequest
*
* @param sel - The ListSQLRequest select
* @param sInfo - Search parameters
*/
private final void setWhere(final SQLSelect sel, final SearchInfo sInfo, final List<SQLTableModelColumn> cols) {
if (sInfo != null) {
final Set<IFieldPath> fields = new HashSet<>(cols.size() * 2);
for (final SQLTableModelColumn sqlTableModelColumn : cols) {
fields.addAll(sqlTableModelColumn.getPaths());
}
final List<Where> wheres = new ArrayList<>();
final List<Where> wFields = new ArrayList<>();
}
 
final List<String> texts = sInfo.getTexts();
for (String string : texts) {
wFields.clear();
for (final IFieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, sel.followFieldPath(fpath)), "LIKE", "%" + string.toLowerCase() + "%");
wFields.add(w);
final Where w;
if (!wheres.isEmpty()) {
if (sel.getWhere() != null) {
w = Where.and(sel.getWhere(), Where.and(wheres));
} else {
w = Where.and(wheres);
}
sel.setWhere(w);
}
}
wheres.add(Where.or(wFields));
return sel;
}
});
 
final Where w;
if (sel.getWhere() != null) {
w = Where.and(sel.getWhere(), Where.and(wheres));
} else {
w = Where.and(wheres);
}
sel.setWhere(w);
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/IColorChooser.java
New file
0,0 → 1,85
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.ui;
 
import org.openconcerto.ui.ColorField;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Color;
import java.beans.PropertyChangeListener;
 
import javax.swing.JComponent;
 
public class IColorChooser extends ColorField implements ValueWrapper<Integer> {
 
public IColorChooser(String title) {
super(title);
}
 
@Override
public JComponent getComp() {
return this;
}
 
@Override
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
@Override
public void setValue(Integer val) {
if (val == null) {
val = Color.WHITE.getRGB();
}
setColor(new Color(val));
}
 
@Override
public Integer getValue() {
if (getColor() == null) {
return null;
} else {
return getColor().getRGB();
}
}
 
@Override
public void addValidListener(ValidListener l) {
// TODO Auto-generated method stub
 
}
 
@Override
public void removeValidListener(ValidListener l) {
// TODO Auto-generated method stub
 
}
 
@Override
public void resetValue() {
this.setColor(null);
}
 
@Override
public final void addValueListener(final PropertyChangeListener l) {
this.addPropertyChangeListener("value", l);
}
 
@Override
public void rmValueListener(final PropertyChangeListener l) {
this.removePropertyChangeListener("value", l);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_fr.xml
2,21 → 2,23
<translations>
<element refid="sql.user">
<name base="utilisateur" nounClass="masculine" />
<FIELD name="NOM" label="Nom" titlelabel="Nom" />
<FIELD name="PRENOM" label="Prénom" titlelabel="Prénom" />
<FIELD name="PASSWORD" label="Mot de passe" titlelabel="Mot de passe" />
<FIELD name="NOM" label="Nom" />
<FIELD name="PRENOM" label="Prénom" />
<FIELD name="PASSWORD" label="Mot de passe" />
<FIELD name="PASSWORD_CONFIRM" label="Confirmation" />
<FIELD name="LOGIN" label="Identifiant" titlelabel="Identifiant" />
<FIELD name="SURNOM" label="Surnom" titlelabel="Surnom" />
<FIELD name="LOGIN" label="Identifiant" />
<FIELD name="SURNOM" label="Surnom" />
<FIELD name="ADMIN" label="Administrateur" titlelabel="Admin." />
<FIELD name="ID_USER_RIGHT_COMMON" label="Droits utilisateur" titlelabel="Droits utilisateur" />
<FIELD name="ID_USER_RIGHT_COMMON" label="Droits utilisateur" />
<FIELD name="MAIL" label="E-Mail" titlelabel="E-Mail" />
<FIELD name="COMPTE_NUMERO" label="N° compte comptable" />
<FIELD name="DISABLED" label="Compte désactivé" />
<FIELD name="TEL" label="Téléphone" titlelabel="Téléphone" />
<FIELD name="TEL" label="Téléphone" />
<FIELD name="COLOR" label="Couleur" />
</element>
<element refid="sql.right">
<name base="droit" nounClass="masculine" />
<FIELD name="CODE" label="Code" titlelabel="Code" />
<FIELD name="CODE" label="Code" />
<FIELD name="NOM" label="Nom" titlelabel="Nom du droit" />
<FIELD name="DESCRIPTION" label="Description" titlelabel="Desc." />
</element>
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
57,10 → 57,10
import org.openconcerto.sql.request.SQLCache;
import org.openconcerto.sql.request.SQLFieldTranslator;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.ui.light.CustomRowEditor;
import org.openconcerto.sql.ui.light.GroupToLightUIConvertor;
import org.openconcerto.sql.ui.light.LightEditFrame;
import org.openconcerto.sql.ui.light.LightUIPanelFiller;
import org.openconcerto.sql.ui.light.SavableCustomEditorProvider;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
74,7 → 74,6
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.group.Group;
import org.openconcerto.ui.light.ComboValueConvertor;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.IntValueConvertor;
import org.openconcerto.ui.light.LightUIComboBox;
import org.openconcerto.ui.light.LightUIElement;
337,10 → 336,10
editFrame.createTitlePanel(this.getCreationFrameTitle());
} else if (editMode.equals(EditMode.MODIFICATION)) {
editFrame.createTitlePanel(this.getModificationFrameTitle(sqlRow));
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, sqlRow);
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, this, sqlRow, sessionSecurityToken);
} else if (editMode.equals(EditMode.READONLY)) {
editFrame.createTitlePanel(this.getReadOnlyFrameTitle(sqlRow));
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, sqlRow);
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, this, sqlRow, sessionSecurityToken);
}
 
this.setEditFrameModifiers(editFrame, sessionSecurityToken);
389,11 → 388,12
*/
public GroupToLightUIConvertor getGroupToLightUIConvertor(final PropsConfiguration configuration, final EditMode editMode, final SQLRowAccessor sqlRow, final String token) {
final GroupToLightUIConvertor convertor = new GroupToLightUIConvertor(configuration);
if (editMode.equals(EditMode.CREATION)) {
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForCreation(configuration, token));
} else {
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForModification(configuration, sqlRow, token));
}
// if (editMode.equals(EditMode.CREATION)) {
convertor.putAllCustomEditorProvider(this.getCustomRowEditors(configuration, token));
// } else {
// convertor.putAllCustomEditorProvider(this.getCustomRowEditors(configuration, sqlRow,
// token));
// }
return convertor;
}
 
418,76 → 418,55
public void setEditFrameModifiers(final LightEditFrame frame, final String sessionToken) {
}
 
public final Map<String, CustomEditorProvider> getCustomEditorProviderForCreation(final Configuration configuration, final String sessionToken) {
final Map<String, CustomEditorProvider> map = this.getDefaultCustomEditorProvider(configuration, null, sessionToken);
map.putAll(this._getCustomEditorProviderForCreation(configuration, sessionToken));
return map;
}
 
public final Map<String, CustomEditorProvider> getCustomEditorProviderForModification(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
final Map<String, CustomEditorProvider> map = this.getDefaultCustomEditorProvider(configuration, sqlRow, sessionToken);
map.putAll(this._getCustomEditorProviderForModification(configuration, sqlRow, sessionToken));
return map;
}
 
protected Map<String, CustomEditorProvider> _getCustomEditorProviderForCreation(final Configuration configuration, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
protected Map<String, CustomEditorProvider> _getCustomEditorProviderForModification(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
protected Map<String, CustomEditorProvider> _getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
private final Map<String, CustomEditorProvider> getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
public List<CustomRowEditor> getCustomRowEditors(final Configuration configuration, final String sessionToken) {
final Map<String, ComboValueConvertor<?>> comboConvertors = this.getComboConvertors();
final Map<String, CustomEditorProvider> result = new HashMap<String, CustomEditorProvider>();
final List<CustomRowEditor> result = new ArrayList<>();
for (final Entry<String, ComboValueConvertor<?>> entry : comboConvertors.entrySet()) {
result.put(entry.getKey(), new SavableCustomEditorProvider() {
 
final String itemId = entry.getKey();
result.add(new CustomRowEditor(itemId) {
final ComboValueConvertor<?> convertor = entry.getValue();
 
@Override
public LightUIElement createUIElement(final String elementId) {
final LightUIComboBox uiCombo = new LightUIComboBox(elementId);
public LightUIElement createUIElement() {
final LightUIComboBox uiCombo = new LightUIComboBox(getItemId());
this.convertor.fillCombo(uiCombo, null);
return uiCombo;
}
 
if (sqlRow == null) {
this.convertor.fillCombo(uiCombo, null);
} else {
final SQLField field = configuration.getFieldMapper().getSQLFieldForItem(elementId);
if (this.convertor instanceof StringValueConvertor) {
((StringValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getString(field.getFieldName()));
} else if (this.convertor instanceof IntValueConvertor) {
if (sqlRow.getObject(field.getFieldName()) == null) {
this.convertor.fillCombo(uiCombo, null);
} else {
((IntValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getInt(field.getFieldName()));
}
@Override
public void fillFrom(LightUIElement uiElement, SQLRowAccessor sqlRow) {
final LightUIComboBox uiCombo = (LightUIComboBox) uiElement;
final SQLField field = configuration.getFieldMapper().getSQLFieldForItem(getItemId());
if (this.convertor instanceof StringValueConvertor) {
((StringValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getString(field.getFieldName()));
} else if (this.convertor instanceof IntValueConvertor) {
if (sqlRow.getObject(field.getFieldName()) != null) {
((IntValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getInt(field.getFieldName()));
}
}
return uiCombo;
 
}
 
@Override
protected void _save(final SQLRowValues sqlRow, final SQLField sqlField, final LightUIElement uiElement) {
final LightUIComboBox combo = (LightUIComboBox) uiElement;
if (combo.hasSelectedValue()) {
public void store(LightUIElement uiElement, SQLRowValues sqlRow) {
final LightUIComboBox combobox = (LightUIComboBox) uiElement;
final String fieldName = configuration.getFieldMapper().getSQLFieldForItem(getItemId()).getName();
if (combobox.hasSelectedValue()) {
if (this.convertor instanceof StringValueConvertor) {
sqlRow.put(sqlField.getName(), ((StringValueConvertor) this.convertor).getIdFromIndex(combo.getSelectedValue().getId()));
sqlRow.put(fieldName, ((StringValueConvertor) this.convertor).getIdFromIndex(combobox.getSelectedValue().getId()));
} else if (this.convertor instanceof IntValueConvertor) {
sqlRow.put(sqlField.getName(), combo.getSelectedValue().getId());
sqlRow.put(fieldName, combobox.getSelectedValue().getId());
} else {
throw new IllegalArgumentException("the save is not implemented for the class: " + this.convertor.getClass().getName() + " - ui element id: " + uiElement.getId());
throw new IllegalArgumentException("the save is not implemented for the class: " + this.convertor.getClass().getName() + " - ui id: " + getItemId());
}
} else {
sqlRow.put(sqlField.getName(), null);
sqlRow.put(fieldName, null);
}
 
}
});
}
result.putAll(this._getDefaultCustomEditorProvider(configuration, sqlRow, sessionToken));
return result;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java
434,7 → 434,13
if (!(this instanceof GroupSQLComponent)) {
 
for (final Entry<String, JComponent> e : this.getElement().getAdditionalFields().entrySet()) {
final SpecParser spec = new SpecParser(null, true);
final SpecParser spec;
// FIXME Required à spécifier directement depuis le module
if (this.requiredNames != null && this.requiredNames.contains(e.getKey())) {
spec = new SpecParser(REQ, true);
} else {
spec = new SpecParser(null, true);
}
final JComponent comp = e.getValue();
if (comp == null)
// infer component
726,7 → 732,6
return this.getRequest().setLastKnownDBVals(current, this.getRequest().fetchRow(current.getID(), ls));
}
 
 
@Override
public final void select(int id) {
// TODO in an executor outside of the EDT
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java
202,10 → 202,55
* @return the corresponding SQLElement, or <code>null</code> if none can be found.
* @throws IllegalArgumentException if there's more than one match.
*/
public synchronized final <S extends SQLElement> S getElement(Class<S> clazz) {
return clazz.cast(this.getElement(getSoleTable(this.byClass, clazz)));
public final <S extends SQLElement> S getElement(Class<S> clazz) {
return this.getElementOfClass(clazz, false);
}
 
public final <S extends SQLElement> S getElementOfClass(Class<S> clazz, final boolean allowSubclass) {
final List<S> res = getElementsOfClass(clazz, allowSubclass);
if (res.size() > 1)
throw new IllegalArgumentException(clazz + " is not unique: " + res);
return res.isEmpty() ? null : res.get(0);
}
 
/**
* Search for SQLElement whose class is <code>clazz</code>.
*
* @param clazz the class.
* @param allowSubclass <code>true</code> to include {@link Class#isInstance(Object)
* subclasses}, <code>false</code> to only return exact match.
* @return the corresponding elements.
*/
public final <S extends SQLElement> List<S> getElementsOfClass(final Class<S> clazz, final boolean allowSubclass) {
final List<S> res;
synchronized (this) {
if (allowSubclass) {
res = new ArrayList<>();
for (final SQLElement elem : this.elements.values()) {
if (clazz.isInstance(elem))
res.add(clazz.cast(elem));
}
} else {
final Set<SQLTable> tables = this.byClass.get(clazz);
if (tables != null) {
res = new ArrayList<>(tables.size());
for (final SQLTable t : tables) {
res.add(clazz.cast(this.getElement(t)));
}
} else {
res = Collections.emptyList();
}
}
}
if (res.isEmpty()) {
return Collections.emptyList();
} else if (res.size() == 1) {
return Collections.singletonList(res.get(0));
} else {
return Collections.unmodifiableList(res);
}
}
 
public synchronized final SQLElement getElementForCode(String code) {
return this.getElement(getSoleTable(this.byCode, code));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GroupSQLComponent.java
64,8 → 64,8
 
private final Group group;
private final int columns = 2;
private final Map<String, JComponent> labels = new HashMap<String, JComponent>();
private final Map<String, JComponent> editors = new HashMap<String, JComponent>();
private final Map<String, JComponent> labels = new HashMap<>();
private final Map<String, JComponent> editors = new HashMap<>();
private String startTabAfter = null;
private boolean tabGroup;
private int tabDepth;
80,6 → 80,12
 
public GroupSQLComponent(final SQLElement element, final Group group) {
super(element);
if (element == null) {
throw new IllegalArgumentException("null SQLElement");
}
if (group == null) {
throw new IllegalArgumentException("null group (SQLElement : " + element + ")");
}
this.group = group;
this.hasAdditionnalFields = this.getElement().getAdditionalFields().size() > 0;
this.additionnalFieldsGroup = getAdditionalFieldsGroup(group.getDescendantGroups());
99,7 → 105,7
}
 
public void startTabGroupAfter(String id) {
startTabAfter = id;
this.startTabAfter = id;
}
 
@Override
155,7 → 161,8
c.gridx = 0;
c.weightx = 1;
c.gridwidth = 4;
panel.add(getLabel(id), c);
JComponent comp = getLabel(id);
panel.add(comp, c);
c.gridy++;
}
}
276,13 → 283,13
}
 
}
if (id.equals(startTabAfter)) {
if (tabGroup) {
if (id.equals(this.startTabAfter)) {
if (this.tabGroup) {
throw new IllegalArgumentException("ID " + id + " already set as tab");
}
tabGroup = true;
tabDepth = level;
pane = new JTabbedPane();
this.tabGroup = true;
this.tabDepth = level;
this.pane = new JTabbedPane();
c.gridx = 0;
c.gridy++;
c.weightx = 1;
289,7 → 296,7
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 4;
panel.add(pane, c);
panel.add(this.pane, c);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java
122,7 → 122,7
};
 
@SuppressWarnings("unchecked")
private static final Map<String, Number> getUndefIDs(final SQLSchema schema) {
public static final Map<String, Number> getUndefIDs(final SQLSchema schema) {
if (!UNDEFINED_IDs.containsKey(schema)) {
final Map<String, Number> r;
if (schema.contains(undefTable)) {
556,7 → 556,10
return undef.intValue();
}
} else if ("inDB".equals(policy)) {
throw new IllegalStateException("Not in " + new SQLName(this.getDBRoot().getName(), undefTable) + " : " + this.getName());
return SQLRow.NONEXISTANT_ID;
// FIXME : BUG A INVESTIGUER DANS LA CREATION DE MODULE throw new
// throw new IllegalStateException("Not in " + new SQLName(this.getDBRoot().getName(),
// undefTable) + " : " + this.getName());
} else if (policy != null && !"nonexistant".equals(policy)) {
final int res = Integer.parseInt(policy);
if (res < SQLRow.MIN_VALID_ID)
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLInjector.java
166,18 → 166,28
rowVals.put(field.getName(), value);
}
 
protected void transfertReference(SQLRowAccessor srcRow, SQLRowValues rowVals, String from, String to) {
protected void transfertReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField, String from, String to) {
 
String label = rowVals.getString(to);
if (label != null && label.trim().length() > 0) {
rowVals.put(to, label + ", " + srcRow.getString(from));
} else {
rowVals.put(to, srcRow.getString(from));
SQLPreferences prefs = SQLPreferences.getMemCached(srcRow.getTable().getDBRoot());
 
if (prefs.getBoolean("TransfertRef", true) || !to.equals("NOM")) {
if (label != null && label.trim().length() > 0) {
rowVals.put(to, label + ", " + srcRow.getString(from));
} else {
rowVals.put(to, srcRow.getString(from));
}
} else if (prefs.getBoolean("TransfertMultiRef", false)) {
SQLRowValues rowValsHeader = new SQLRowValues(UndefinedRowValuesCache.getInstance().getDefaultRowValues(tableElementDestination));
// TODO taxe may be undefined set it to default
rowValsHeader.put("NOM", srcRow.getString(from));
rowValsHeader.put(refField, rowVals);
}
 
}
 
protected void transfertNumberReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField) {
SQLPreferences prefs = new SQLPreferences(srcRow.getTable().getDBRoot());
SQLPreferences prefs = SQLPreferences.getMemCached(srcRow.getTable().getDBRoot());
 
if (prefs.getBoolean("TransfertRef", true)) {
String label = rowVals.getString("NOM");
412,7 → 422,7
* register manually a transfer, use with caution
*
* @throws SQLException
* */
*/
public void addTransfert(int idFrom, int idTo) throws SQLException {
final SQLTable tableTransfert = getSource().getTable(getTableTranferName());
final SQLRowValues rowTransfer = new SQLRowValues(tableTransfert);
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLUpdate.java
New file
0,0 → 1,115
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.model;
 
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
public class SQLUpdate {
private List<SQLField> fields = new ArrayList<>();
private List<Object> values = new ArrayList<>();
private SQLTable table;
private Where where;
 
public SQLUpdate(Where where) {
this.where = where;
}
 
public void add(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
this.fields.add(field);
this.values.add(value);
}
 
public void set(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
this.values.set(index, value);
}
 
public boolean contains(SQLField field) {
return this.fields.indexOf(field) >= 0;
}
 
public Object getValue(SQLField field) {
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
return this.values.get(index);
}
 
public String asString() {
if (this.fields.isEmpty()) {
throw new IllegalStateException("not fields added");
}
final StringBuilder builder = new StringBuilder();
builder.append("UPDATE ");
builder.append(this.table.getSQLName());
builder.append(" SET ");
//
int stop = this.fields.size();
for (int i = 0; i < stop; i++) {
final SQLField field = this.fields.get(i);
builder.append(field.getQuotedName());
builder.append("=");
 
Object value = this.values.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
builder.append(field.getType().toString(str));
if (i < stop - 1) {
builder.append(',');
}
}
builder.append(" WHERE ");
builder.append(this.where.getClause());
return builder.toString();
}
 
/**
* Update multiple rows with a batch. Rows can be from different tables.
*
* Speed : 5000 /s
*/
public static long executeMultipleWithBatch(final DBSystemRoot sysRoot, final List<SQLUpdate> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no updates");
}
final List<String> l = new ArrayList<>(queries.size());
for (final SQLUpdate i : queries)
l.add(i.asString());
return sysRoot.getDataSource().executeBatch(l, true).get0();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLDataSource.java
16,11 → 16,13
import org.openconcerto.sql.Log;
import org.openconcerto.sql.State;
import org.openconcerto.sql.request.SQLCache;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.ExceptionUtils;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.ThreadFactory;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cache.ICacheSupport;
 
48,6 → 50,8
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
 
import org.apache.commons.dbcp.AbandonedConfig;
993,7 → 997,66
return res;
}
 
private static final Tuple2<Long, int[]> NO_QUERIES_RES = Tuple2.create(0l, new int[0]);
 
/**
* Execute multiple queries in batch.
*
* @param queries what to execute.
* @param atomic <code>true</code> if all queries should be executed in a transaction.
* @return the total update count (&lt; 0 if unknown), followed by the individual update counts.
* @throws SQLException if an error occurs.
* @see Statement#executeBatch()
*/
public final Tuple2<Long, int[]> executeBatch(final List<String> queries, final boolean atomic) throws SQLException {
if (queries.isEmpty())
return NO_QUERIES_RES;
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
final AtomicLong afterQueryInfo = new AtomicLong();
final AtomicLong afterExecute = new AtomicLong();
final AtomicReference<Connection> conn = new AtomicReference<>();
final ConnectionHandlerNoSetup<int[], SQLException> handler = new ConnectionHandlerNoSetup<int[], SQLException>() {
@Override
public int[] handle(SQLDataSource ds) throws SQLException {
afterQueryInfo.set(System.nanoTime());
conn.set(ds.getConnection());
final int[] res;
try (final Statement stmt = conn.get().createStatement()) {
for (final String s : queries) {
stmt.addBatch(s);
}
if (Thread.currentThread().isInterrupted())
throw new RTInterruptedException("Interrupted before executing : " + queries);
res = stmt.executeBatch();
}
afterExecute.set(System.nanoTime());
return res;
}
};
final int[] res = atomic ? SQLUtils.executeAtomic(this, handler) : this.useConnection(handler);
long totalCount = 0;
int i = 0;
for (final int count : res) {
if (count == Statement.SUCCESS_NO_INFO) {
totalCount = -1;
break;
} else {
if (count < 0)
throw new SQLException("Invalid count (" + count + ") for query " + i + " : " + queries.get(i));
totalCount += count;
}
i++;
}
if (SQLRequestLog.isEnabled()) {
final long afterHandle = System.nanoTime();
SQLRequestLog.log(queries.toString(), "executeBatch", conn.get(), timeMs, time, afterCache, afterQueryInfo.get(), afterExecute.get(), afterHandle, afterHandle, (int) totalCount);
}
return Tuple2.create(totalCount, res);
}
 
/**
* Try to execute a {@link #getValidationQuery() simple query} on the database server. This
* method even works when the pool is exhausted.
*
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowListRSH.java
19,10 → 19,12
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
 
import org.apache.commons.dbutils.ResultSetHandler;
 
37,16 → 39,18
// ATTN doesn't check that the types of columns are coherent with the types of the fields
public RSH(final SQLTable t, final List<String> names) {
this(Tuple2.create(t, names));
if (!t.getFieldsName().containsAll(names))
throw new IllegalArgumentException("Not all names are fields of " + t + " : " + names);
// null are OK (they're ignored)
final List<String> unknown = names.stream().filter(n -> n != null && !t.getFieldsName().contains(n)).collect(Collectors.toList());
if (!unknown.isEmpty())
throw new IllegalArgumentException("Not all names are fields of " + t + " : " + unknown);
}
 
private RSH(Tuple2<SQLTable, List<String>> names) {
private RSH(final Tuple2<SQLTable, List<String>> names) {
this.names = names;
}
 
@Override
public List<SQLRow> handle(ResultSet rs) throws SQLException {
public List<SQLRow> handle(final ResultSet rs) throws SQLException {
// since the result will be cached, disallow its modification (e.g.avoid
// ConcurrentModificationException)
return Collections.unmodifiableList(SQLRow.createListFromRS(this.names.get0(), rs, this.names.get1()));
58,7 → 62,7
}
 
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
78,7 → 82,7
return t;
}
 
static Tuple2<SQLTable, List<String>> getIndexes(SQLSelect sel, final TableRef passedTable, final boolean findTable) {
static Tuple2<SQLTable, List<String>> getIndexes(final SQLSelect sel, final TableRef passedTable, final boolean findTable) {
final List<FieldRef> selectFields = sel.getSelectFields();
final int size = selectFields.size();
if (size == 0)
119,11 → 123,12
 
/**
* Create a handler that don't need metadata.
*
*
* @param sel the select that will produce the result set, must only have one table.
* @return a handler creating a list of {@link SQLRow}.
* @deprecated use {@link SQLSelectHandlerBuilder}
*/
@Deprecated
static public ResultSetHandler createFromSelect(final SQLSelect sel) {
return create(getIndexes(sel, null, true));
}
131,12 → 136,13
/**
* Create a handler that don't need metadata. Useful since some JDBC drivers perform queries for
* each metadata.
*
*
* @param sel the select that will produce the result set.
* @param t the table for which to create rows.
* @return a handler creating a list of {@link SQLRow}.
* @deprecated use {@link SQLSelectHandlerBuilder}
*/
@Deprecated
static public ResultSetHandler createFromSelect(final SQLSelect sel, final TableRef t) {
return create(getIndexes(sel, t, false));
}
145,10 → 151,24
return new RSH(names);
}
 
static public List<SQLRow> fetch(final SQLTable t, final Collection<? extends Number> ids) throws IllegalArgumentException {
return fetch(t, ids, null);
}
 
static public List<SQLRow> fetch(final SQLTable t, final Collection<? extends Number> ids, final Collection<String> fields) throws IllegalArgumentException {
final SQLSelect sel = new SQLSelect();
if (fields == null)
sel.addSelectStar(t);
else
sel.addAllSelect(t, fields);
sel.setWhere(new Where(t.getKey(), ids));
return execute(sel);
}
 
/**
* Execute the passed select and return rows. NOTE if there's more than one table in the query
* {@link #execute(SQLSelect, TableRef)} must be used.
*
*
* @param sel the query to execute.
* @return rows.
* @throws IllegalArgumentException if there's more than one table in the query.
164,7 → 184,7
/**
* Execute the passed select and return rows of <code>t</code>. NOTE if there's only one table
* in the query {@link #execute(SQLSelect)} should be used.
*
*
* @param sel the query to execute.
* @param t the table to use.
* @return rows of <code>t</code>.
195,17 → 215,18
private final SQLTable t;
private final boolean tableOnly;
 
public SQLRowListRSH(SQLTable t) {
public SQLRowListRSH(final SQLTable t) {
this(t, false);
}
 
public SQLRowListRSH(SQLTable t, final boolean tableOnly) {
public SQLRowListRSH(final SQLTable t, final boolean tableOnly) {
super();
this.t = t;
this.tableOnly = tableOnly;
}
 
public Object handle(ResultSet rs) throws SQLException {
@Override
public List<SQLRow> handle(final ResultSet rs) throws SQLException {
return SQLRow.createListFromRS(this.t, rs, this.tableOnly);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRequestLog.java
25,6 → 25,7
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.text.DateFormat;
60,7 → 61,23
private static final String ACTIVER_LA_CAPTURE = "Enable monitoring";
private static final String DESACTIVER_LA_CAPTURE = "Disable monitoring";
private static Vector<SQLRequestLog> list = new Vector<SQLRequestLog>(500);
@GuardedBy("this")
private static boolean enabled;
 
public static synchronized void setEnabled(boolean enable) {
enabled = enable;
}
 
public static synchronized boolean toggleEnabled() {
final boolean newVal = !isEnabled();
setEnabled(newVal);
return newVal;
}
 
public static synchronized boolean isEnabled() {
return enabled;
}
 
private String query;
private String comment;
private long startAsMs;
85,10 → 102,6
return l == 0 ? "" : dformat.format(l / 1000000D) + " ms";
}
 
public static void setEnabled(boolean enable) {
enabled = enable;
}
 
public SQLRequestLog(String query, String comment, int connectionId, long starAtMs, String ex, boolean inSwing, long startTime, long afterCache, long afterQueryInfo, long afterExecute,
long afterHandle, long endTime, int count) {
this.query = query;
116,7 → 129,7
public static void log(String query, String comment, int connectionId, long starAtMs, long startTime, long afterCache, long afterQueryInfo, long afterExecute, long afterHandle, long endTime,
int count) {
 
if (enabled) {
if (isEnabled()) {
if (list.size() < 50000) {
final String ex = ExceptionUtils.getStackTrace(new Exception());
 
135,7 → 148,7
 
public static void log(PreparedStatement pStmt, String comment, long timeMs, long startTime, long afterCache, long afterQueryInfo, long afterExecute, long afterHandle, long endTime) {
// only call potentially expensive and/or exceptions throwing methods if necessary
if (enabled) {
if (isEnabled()) {
try {
log(pStmt.toString(), comment, pStmt.getConnection(), timeMs, startTime, afterCache, afterQueryInfo, afterExecute, afterHandle, endTime, 0);
} catch (Exception e) {
433,7 → 446,7
JPanel bar = new JPanel(new FlowLayout());
 
final JButton b0 = new JButton();
if (enabled) {
if (isEnabled()) {
b0.setText(DESACTIVER_LA_CAPTURE);
} else {
b0.setText(ACTIVER_LA_CAPTURE);
440,12 → 453,10
}
b0.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (enabled) {
enabled = false;
public void actionPerformed(ActionEvent e) {
if (!toggleEnabled()) {
b0.setText(ACTIVER_LA_CAPTURE);
} else {
enabled = true;
b0.setText(DESACTIVER_LA_CAPTURE);
}
 
620,4 → 631,15
model.fireTableRowsUpdated(0, model.getRowCount() - 1);
}
}
 
public static void dump(PrintStream out) {
final DecimalFormat dformat = new DecimalFormat("##0.00");
for (SQLRequestLog log : list) {
out.print(dformat.format(log.getDurationTotalNano() / 1000000D) + " ms ");
out.print("\t");
out.print(log.getQuery());
out.println();
}
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBackgroundTableCacheItem.java
28,6 → 28,11
public SQLBackgroundTableCacheItem(final SQLTable t, final int second) {
this.table = t;
this.timeout = second;
 
if (second == -1) {
reloadFromDB();
}
 
this.table.addTableModifiedListener(new SQLTableModifiedListener() {
 
@Override
44,17 → 49,21
this.enableReloadIfTableModified = enableReloadIfTableModified;
}
 
@SuppressWarnings("unchecked")
public synchronized void reloadFromDbIfNeeded() {
final long delta = System.currentTimeMillis() - this.lastReload;
if (delta / 1000 > this.timeout) {
final SQLSelect sel = new SQLSelect();
sel.addSelectStar(this.table);
this.rows = Collections.unmodifiableList((List<SQLRow>) this.table.getBase().getDataSource().execute(sel.asString(), SQLRowListRSH.createFromSelect(sel, this.table)));
this.lastReload = System.currentTimeMillis();
if (this.timeout >= 0 && delta / 1000 > this.timeout) {
reloadFromDB();
}
}
 
@SuppressWarnings("unchecked")
private void reloadFromDB() {
final SQLSelect sel = new SQLSelect();
sel.addSelectStar(this.table);
this.rows = Collections.unmodifiableList((List<SQLRow>) this.table.getBase().getDataSource().execute(sel.asString(), SQLRowListRSH.createFromSelect(sel, this.table)));
this.lastReload = System.currentTimeMillis();
}
 
public synchronized SQLRow getFirstRowContains(final int value, final SQLField field) {
for (SQLRow r : this.rows) {
if (r.getInt(field.getName()) == value && !r.isArchived()) {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLInsert.java
New file
0,0 → 1,314
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.model;
 
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
 
import org.postgresql.copy.CopyManager;
import org.postgresql.core.BaseConnection;
import org.postgresql.jdbc.PgConnection;
 
public class SQLInsert {
private List<SQLField> fields = new ArrayList<>();
private List<Object> values = new ArrayList<>();
private SQLTable table;
 
public void add(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
this.fields.add(field);
this.values.add(value);
}
 
public void set(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
this.values.set(index, value);
}
 
public boolean contains(SQLField field) {
return this.fields.indexOf(field) >= 0;
}
 
public Object getValue(SQLField field) {
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
return this.values.get(index);
}
 
public String asString() {
if (this.fields.isEmpty()) {
throw new IllegalStateException("not fields added");
}
final StringBuilder builder = new StringBuilder();
builder.append("INSERT INTO ");
builder.append(this.table.getSQLName());
builder.append(" (");
//
int stop = this.fields.size();
for (int i = 0; i < stop; i++) {
builder.append(this.fields.get(i).getQuotedName());
if (i < stop - 1) {
builder.append(',');
}
}
 
builder.append(") VALUES (");
 
for (int i = 0; i < stop; i++) {
Object value = this.values.get(i);
final SQLField field = this.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (value != null && !javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
builder.append(field.getType().toString(str));
 
if (i < stop - 1) {
builder.append(',');
}
}
 
builder.append(")");
return builder.toString();
}
 
/**
* Insert multiple rows. Rows can be from different tables.
*
* Speed : 19 000 inserts /s on PostgreSQL
*/
public static void executeMultiple(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
final Map<SQLTable, List<SQLInsert>> map = new HashMap<>();
for (final SQLInsert q : queries) {
List<SQLInsert> list = map.get(q.table);
if (list == null) {
list = new ArrayList<>();
map.put(q.table, list);
}
list.add(q);
}
for (Entry<SQLTable, List<SQLInsert>> entry : map.entrySet()) {
executeSimilarInserts(sysRoot, entry.getValue(), false);
}
}
 
/**
* Insert multiple rows with a batch. Rows can be from different tables.
*
* Speed : 8 000 inserts /s on PostgreSQL
*/
public static long executeMultipleWithBatch(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
final List<String> l = new ArrayList<>(queries.size());
for (final SQLInsert i : queries)
l.add(i.asString());
return sysRoot.getDataSource().executeBatch(l, true).get0();
}
 
/**
* Insert multiple rows in the same table, using COPY on PostgreSQL for the maximum speed
*
* Speed : 26 000 inserts /s on PostgreSQL
*/
public static long executeSimilarWithCopy(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
SQLDataSource dataSource = sysRoot.getDataSource();
if (dataSource.getSystem() != SQLSystem.POSTGRESQL) {
return executeSimilarInserts(sysRoot, queries, true).size();
}
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
SQLInsert insert0 = queries.get(0);
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
 
final String query = insert0 + "..." + queries.size() + " queries";
 
return dataSource.useConnection(new ConnectionHandlerNoSetup<Long, SQLException>() {
@Override
public Long handle(SQLDataSource ds) throws SQLException {
final Connection conn = ds.getConnection().unwrap(PgConnection.class);
final CopyManager copyManager = new CopyManager((BaseConnection) conn);
final StringBuilder allValues = new StringBuilder(insert0.fields.size() * 10 * queries.size());
final List<String> fi = new ArrayList<>();
for (SQLField f : insert0.fields) {
fi.add(f.getQuotedName());
}
for (final SQLInsert q : queries) {
if (!q.table.equals(insert0.table)) {
throw new IllegalArgumentException("table " + q.table.getName() + " is not " + insert0.table.getTable());
}
if (!q.fields.equals(insert0.fields)) {
throw new IllegalArgumentException("fields" + q.fields + " not equals to " + insert0.fields);
}
int stop = q.values.size();
for (int i = 0; i < stop; i++) {
Object value = q.values.get(i);
final SQLField field = q.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
// FIXME null, escapes (see SQLSyntaxPG)
allValues.append(field.getType().toString(str));
if (i < stop - 1) {
allValues.append('\t');
}
}
allValues.append('\n');
}
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute;
final long afterHandle;
final long count;
try {
count = copyManager.copyIn("COPY " + insert0.table.getSQLName() + "(" + String.join(",", fi) + ") FROM STDIN WITH (ENCODING 'UTF-8') ", new StringReader(allValues.toString()));
} catch (IOException e) {
throw new SQLException(e);
}
afterExecute = System.nanoTime();
afterHandle = afterExecute;
SQLRequestLog.log(query, "multiple similar with copy", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), queries.size());
 
return count;
}
});
}
 
/**
* Insert multiple rows in the same table
*
* Speed : 20 000 inserts /s on PostgreSQL
*/
public static List<Number> executeSimilarInserts(final DBSystemRoot sysRoot, final List<SQLInsert> queries, boolean returnIds) throws SQLException {
SQLDataSource dataSource = sysRoot.getDataSource();
 
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
SQLInsert insert0 = queries.get(0);
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
 
final String query = insert0 + "..." + queries.size() + " queries";
if (sysRoot.getServer().getSQLSystem() != SQLSystem.POSTGRESQL) {
List<Number> res = new ArrayList<>();
for (SQLInsert sqlInsert : queries) {
res.add((Number) sysRoot.getDataSource().executeScalar(sqlInsert.asString()));
}
return res;
} else {
return dataSource.useConnection(new ConnectionHandlerNoSetup<List<Number>, SQLException>() {
@Override
public List<Number> handle(SQLDataSource ds) throws SQLException {
final Connection conn = ds.getConnection();
final List<String> fi = new ArrayList<>();
for (SQLField f : insert0.fields) {
fi.add(f.getQuotedName());
}
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute;
final long afterHandle;
final StringBuilder sql = new StringBuilder(insert0.fields.size() * 10 * (queries.size() + 1));
sql.append("(" + String.join(",", fi) + ")");
sql.append(" VALUES ");
int size = queries.size();
for (int j = 0; j < size; j++) {
final SQLInsert q = queries.get(j);
if (!q.table.equals(insert0.table)) {
throw new IllegalArgumentException("table " + q.table.getName() + " is not " + insert0.table.getTable());
}
if (!q.fields.equals(insert0.fields)) {
throw new IllegalArgumentException("fields" + q.fields + " not equals to " + insert0.fields);
}
sql.append("(");
int stop = q.values.size();
for (int i = 0; i < stop; i++) {
Object value = q.values.get(i);
final SQLField field = q.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!field.isNullable() && value == null) {
throw new IllegalStateException("null value for " + field);
}
if (value != null && !javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
// FIXME : escape ' (quote)
sql.append(field.getType().toString(str));
 
if (i < stop - 1) {
sql.append(',');
}
}
sql.append(")");
if (j < size - 1) {
sql.append(',');
}
}
List<Number> res;
if (!returnIds) {
// TODO return count
SQLRowValues.insertCount(insert0.table, sql.toString());
res = null;
} else {
res = SQLRowValues.insertIDs(insert0.table, sql.toString());
}
afterExecute = System.nanoTime();
afterHandle = afterExecute;
SQLRequestLog.log(query, "multiple similar insert", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), queries.size());
 
return res;
}
});
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBackgroundTableCache.java
19,7 → 19,7
 
public class SQLBackgroundTableCache {
private static SQLBackgroundTableCache instance;
private Map<SQLTable, SQLBackgroundTableCacheItem> list = new HashMap<SQLTable, SQLBackgroundTableCacheItem>();
private Map<SQLTable, SQLBackgroundTableCacheItem> list = new HashMap<>();
 
/**
* @param args
90,7 → 90,8
item.reloadFromDbIfNeeded();
} else {
System.err.println("SQLBackgroundTableCache.getCacheForTable() WARNING " + t.getName() + " is not registered (use add to register)");
this.add(t, 0);
// Start cache without autorefresh for Caisse offline
this.add(t, -1);
item = this.list.get(t);
item.reloadFromDbIfNeeded();
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java
1006,7 → 1006,7
}
 
// TODO support java.time.LocalDateTime in Java 8
static private <T, U> U convert(final Class<T> source, final Object value, final Class<U> dest) {
public static <T, U> U convert(final Class<T> source, final Object value, final Class<U> dest) {
final ValueConvertor<T, U> conv = ValueConvertorFactory.find(source, dest);
if (conv == null)
throw new IllegalArgumentException("No convertor to " + dest + " from " + source);
2447,7 → 2447,6
return insert(t, sql, ReturnMode.NO_FIELDS).getCount();
}
 
// if scalar is null primary keys aren't fetched
private static final Insertion<?> insert(final SQLTable t, final String sql, final ReturnMode mode) throws SQLException {
return new Inserter(t).insert(sql, mode, true);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/SQLUtils.java
372,9 → 372,8
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute, afterHandle;
final Statement stmt = conn.createStatement();
int count = 0;
try {
try (final Statement stmt = conn.createStatement()){
if (Thread.currentThread().isInterrupted())
throw new RTInterruptedException("Interrupted before executing : " + query);
stmt.execute(query);
392,8 → 391,6
stmt.getMoreResults();
}
afterHandle = System.nanoTime();
} finally {
stmt.close();
}
SQLRequestLog.log(query, "executeMultiple", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), count);
return null;
/trunk/OpenConcerto/src/org/openconcerto/sql/users/UserCommonSQLElement.java
28,6 → 28,7
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.itemview.SimpleRowItemView;
import org.openconcerto.sql.ui.IColorChooser;
import org.openconcerto.sql.ui.Login;
import org.openconcerto.sql.view.QuickAssignPanel;
import org.openconcerto.sql.view.list.ITableModel;
220,8 → 221,7
// Login
c.gridx = 0;
c.insets = new Insets(2, 2, 1, 2);
final JLabel labelLogin = new JLabel(getLabelFor("LOGIN"));
labelLogin.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelLogin = new JLabel(getLabelFor("LOGIN"), SwingConstants.RIGHT);
this.add(labelLogin, c);
final JTextField textLogin = new JTextField();
c.gridx++;
242,8 → 242,7
c.gridx = 0;
c.weightx = 0;
c.insets = new Insets(2, 2, 1, 2);
final JLabel labelPass = new JLabel(getLabelFor("PASSWORD"));
labelPass.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelPass = new JLabel(getLabelFor("PASSWORD"), SwingConstants.RIGHT);
this.add(labelPass, c);
this.passField = new JPasswordField(15);
c.gridx++;
254,8 → 253,7
// Confirmation password
c.gridx++;
c.weightx = 0;
final JLabel labelConfirmationPass = new JLabel(getLabelFor("PASSWORD_CONFIRM"));
labelConfirmationPass.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelConfirmationPass = new JLabel(getLabelFor("PASSWORD_CONFIRM"), SwingConstants.RIGHT);
this.add(labelConfirmationPass, c);
this.passFieldConfirm = new JPasswordField(15);
c.gridx++;
267,8 → 265,7
c.gridx = 0;
c.gridy++;
c.weightx = 0;
final JLabel labelNom = new JLabel(getLabelFor("NOM"));
labelNom.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelNom = new JLabel(getLabelFor("NOM"), SwingConstants.RIGHT);
this.add(labelNom, c);
final JTextField textNom = new JTextField();
c.gridx++;
278,8 → 275,7
// Prenom
c.gridx++;
c.weightx = 0;
final JLabel labelPrenom = new JLabel(getLabelFor("PRENOM"));
labelPrenom.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelPrenom = new JLabel(getLabelFor("PRENOM"), SwingConstants.RIGHT);
this.add(labelPrenom, c);
final JTextField textPrenom = new JTextField();
c.gridx++;
290,8 → 286,7
c.gridx = 0;
c.gridy++;
c.weightx = 0;
final JLabel labelSurnom = new JLabel(getLabelFor("SURNOM"));
labelSurnom.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelSurnom = new JLabel(getLabelFor("SURNOM"), SwingConstants.RIGHT);
this.add(labelSurnom, c);
final JTextField textSurnom = new JTextField();
c.gridx++;
313,8 → 308,7
c.weightx = 0;
 
if (getTable().contains("MAIL")) {
final JLabel labelMail = new JLabel(getLabelFor("MAIL"));
labelMail.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelMail = new JLabel(getLabelFor("MAIL"), SwingConstants.RIGHT);
c.anchor = GridBagConstraints.NORTHWEST;
this.add(labelMail, c);
c.gridx++;
325,6 → 319,7
this.add(textMail, c);
this.addView(textMail, "MAIL");
}
 
if (getTable().contains("OUT")) {
c.gridx++;
final JCheckBox boxOut = new JCheckBox(getLabelFor("OUT"));
345,9 → 340,24
}
}
c.gridy++;
 
if (getTable().contains("COMPTE_NUMERO")) {
final JLabel labelMail = new JLabel(getLabelFor("COMPTE_NUMERO"));
labelMail.setHorizontalAlignment(SwingConstants.RIGHT);
c.anchor = GridBagConstraints.NORTHWEST;
this.add(labelMail, c);
c.gridx++;
final JTextField textMail = new JTextField();
c.gridwidth = 1;
c.weightx = 1;
c.gridy++;
this.add(textMail, c);
this.addView(textMail, "COMPTE_NUMERO");
}
 
if (getTable().contains("TEL")) {
c.gridx = 0;
final JLabel labelTel = new JLabel(getLabelFor("TEL"));
final JLabel labelTel = new JLabel(getLabelFor("TEL"), SwingConstants.RIGHT);
c.gridwidth = 1;
c.weightx = 0;
this.add(labelTel, c);
365,6 → 375,20
this.add(boxCalUser, c);
this.addView(boxCalUser, "CALENDAR_USER");
}
if (getTable().contains("COLOR")) {
c.gridy++;
c.gridx = 0;
final JLabel labelTel = new JLabel(getLabelFor("COLOR"), SwingConstants.RIGHT);
c.gridwidth = 1;
c.weightx = 0;
this.add(labelTel, c);
final IColorChooser colorChooser = new IColorChooser(getLabelFor("COLOR"));
c.gridx++;
c.weightx = 1;
c.fill = GridBagConstraints.HORIZONTAL;
this.add(colorChooser, c);
this.addView(colorChooser, "COLOR");
}
 
final boolean gestionHoraire = false;
if (Configuration.getInstance().getAppName().startsWith("OpenConcerto") && gestionHoraire) {
/trunk/OpenConcerto/src/org/openconcerto/sql/users/User.java
15,6 → 15,8
 
import org.openconcerto.sql.model.SQLRowAccessor;
 
import java.awt.Color;
 
import net.jcip.annotations.Immutable;
 
@Immutable
22,6 → 24,7
private final int id;
private final String name, firstName, nickName;
private final Boolean active;
private final Color color;
 
public User(final SQLRowAccessor r) {
this.id = r.getID();
33,6 → 36,11
} else {
this.active = null;
}
if (r.contains("COLOR")) {
this.color = new Color(r.getInt("COLOR"));
} else {
this.color = null;
}
}
 
public String getName() {
63,4 → 71,8
public boolean isActive() {
return this.active;
}
 
public Color getColor() {
return this.color;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/SQLTableRightEditor.java
13,6 → 13,7
package org.openconcerto.sql.users.rights;
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
27,7 → 28,6
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
 
import javax.swing.JComponent;
import javax.swing.JTextField;
41,15 → 41,12
 
@Override
public JComponent getRightEditor(final String right, final DBRoot root, final SQLElementDirectory directory, final JTextField fieldObject) {
final ISearchableCombo<SQLTableComboItem> comboMenu = new ISearchableCombo<SQLTableComboItem>();
DefaultIMutableListModel<SQLTableComboItem> comboItems = new DefaultIMutableListModel<SQLTableComboItem>();
Set<SQLTable> set = root.getTables();
 
List<SQLTableComboItem> result = new ArrayList<SQLTableComboItem>(set.size());
final ISearchableCombo<SQLTableComboItem> comboMenu = new ISearchableCombo<>();
final DefaultIMutableListModel<SQLTableComboItem> comboItems = new DefaultIMutableListModel<>();
final List<SQLTableComboItem> result = new ArrayList<>();
result.add(SQLTableComboItem.createFromTable(null));
for (SQLTable table : set) {
final SQLElement elt = directory.getElement(table);
result.add(SQLTableComboItem.create(table, elt));
for (SQLElement elt : directory.getElements()) {
result.add(SQLTableComboItem.create(elt.getTable(), elt));
}
comboItems.addAll(result);
comboMenu.initCache(comboItems);
57,7 → 54,7
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
final SQLTableComboItem selectedItem = (SQLTableComboItem) comboMenu.getSelectedItem();
final SQLTableComboItem selectedItem = comboMenu.getSelectedItem();
if (selectedItem != null) {
fieldObject.setText(selectedItem.getValue());
}
72,22 → 69,28
RightEditorManager.getInstance().register(code, editor);
}
 
static public class SQLTableComboItem {
public static class SQLTableComboItem {
 
static public SQLTableComboItem create(final SQLTable t, final SQLElement elt) {
public static SQLTableComboItem create(final SQLTable t, final SQLElement elt) {
assert elt == null || elt.getTable() == t;
return elt != null ? createFromElement(elt) : createFromTable(t);
}
 
static public SQLTableComboItem createFromElement(final SQLElement elt) {
return new SQLTableComboItem(elt.getTable(), elt.getName().getVariant(Grammar.SINGULAR));
public static SQLTableComboItem createFromElement(final SQLElement elt) {
String variant = elt.getName().getVariant(Grammar.SINGULAR);
if (variant.contains("_")) {
// quick patch for not translated tables
Log.get().warning(elt.getName() + " not translated");
variant = variant.replace('_', ' ').toLowerCase();
}
return new SQLTableComboItem(elt.getTable(), variant);
}
 
static public SQLTableComboItem createFromTable(final SQLTable t) {
return new SQLTableComboItem(t, t == null ? TM.tr("rights.allTables") : t.getName());
public static SQLTableComboItem createFromTable(final SQLTable t) {
return new SQLTableComboItem(t, t == null ? TM.tr("rights.allTables") : t.getName().toLowerCase().replace('_', ' '));
}
 
static public SQLTableComboItem createFromString(final String s, final DBRoot r, final SQLElementDirectory dir) {
public static SQLTableComboItem createFromString(final String s, final DBRoot r, final SQLElementDirectory dir) {
if (s == null)
return createFromTable(null);
final SQLName n = SQLName.parse(s);
96,7 → 99,7
final SQLTable t = r.findTable(n.getName());
if (t == null)
// allow to use unknown table (e.g. not yet created)
return new SQLTableComboItem(s, n.getName());
return new SQLTableComboItem(s, n.getName().toLowerCase().replace('_', ' '));
else
return create(t, dir.getElement(t));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/TableAllRights.java
31,9 → 31,11
public static final String ADD_ROW_TABLE = "INSERT_ROW";
public static final String VIEW_ROW_TABLE = "SELECT_ROW";
public static final String SAVE_ROW_TABLE = "SAVE_ROW";
public static final String USER_UI_LOCK_ROW = "LIST_UI_LOCK_ROWS";
public static final String USER_UI_UNLOCK_ROW = "LIST_UI_UNLOCK_ROWS";
 
public static final List<String> getCodes() {
return Arrays.asList(CODE, CODE_MODIF, DELETE_ROW_TABLE, MODIFY_ROW_TABLE, ADD_ROW_TABLE, VIEW_ROW_TABLE, SAVE_ROW_TABLE);
return Arrays.asList(CODE, CODE_MODIF, DELETE_ROW_TABLE, MODIFY_ROW_TABLE, ADD_ROW_TABLE, VIEW_ROW_TABLE, SAVE_ROW_TABLE, USER_UI_UNLOCK_ROW, USER_UI_LOCK_ROW);
}
 
public static RightTuple createRight(final SQLTable t, final boolean b) {
119,6 → 121,8
res.add(new RightTuple(DELETE_ROW_TABLE, object, haveRight));
res.add(new RightTuple(MODIFY_ROW_TABLE, object, haveRight));
res.add(new RightTuple(ADD_ROW_TABLE, object, haveRight));
res.add(new RightTuple(USER_UI_LOCK_ROW, object, haveRight));
res.add(new RightTuple(USER_UI_UNLOCK_ROW, object, haveRight));
if (getCode() == CODE)
res.add(new RightTuple(VIEW_ROW_TABLE, object, haveRight));
return res;
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/KeyTableCellRenderer.java
20,6 → 20,7
import org.openconcerto.sql.model.SQLTableEvent;
import org.openconcerto.sql.model.SQLTableEvent.Mode;
import org.openconcerto.sql.model.SQLTableModifiedListener;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.IComboSelectionItem;
 
import java.awt.Component;
37,13 → 38,18
private Object toSelect;
private boolean isLoading = false;
private final SQLElement el;
private final List<String> fields;
private JTable t;
static private final Map<SQLElement, Map<Integer, IComboSelectionItem>> cacheMap = new HashMap<SQLElement, Map<Integer, IComboSelectionItem>>();
 
public KeyTableCellRenderer(final SQLElement el) {
this(el, null);
}
 
public KeyTableCellRenderer(final SQLElement el, final List<String> fields) {
super();
this.el = el;
 
this.fields = fields;
if (cacheMap.get(this.el) == null) {
loadCacheAsynchronous();
}
107,7 → 113,9
Configuration.getInstance().getNonInteractiveSQLExecutor().execute(new Runnable() {
public void run() {
 
List<IComboSelectionItem> items = KeyTableCellRenderer.this.el.getComboRequest().getComboItems();
final ComboSQLRequest comboRequest = KeyTableCellRenderer.this.fields == null || KeyTableCellRenderer.this.fields.isEmpty() ? KeyTableCellRenderer.this.el.getComboRequest()
: KeyTableCellRenderer.this.el.createComboRequest(KeyTableCellRenderer.this.fields, null);
List<IComboSelectionItem> items = comboRequest.getComboItems();
final Map<Integer, IComboSelectionItem> m = new HashMap<Integer, IComboSelectionItem>();
for (IComboSelectionItem comboSelectionItem : items) {
m.put(comboSelectionItem.getId(), comboSelectionItem);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java
30,6 → 30,7
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.users.User;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.sql.users.rights.TableAllRights;
import org.openconcerto.sql.view.FileTransfertHandler;
import org.openconcerto.sql.view.IListener;
import org.openconcerto.sql.view.list.IListeAction.ButtonsBuilder;
146,6 → 147,8
public final class IListe extends JPanel {
 
static private final class LockAction extends RowAction {
private final boolean lock;
 
public LockAction(final boolean lock) {
super(new AbstractAction(TM.tr(lock ? "ilist.lockRows" : "ilist.unlockRows")) {
@Override
167,12 → 170,13
t.fireTableModified(fireID.intValue(), update.getFieldsNames());
}
}, false, true);
this.lock = lock;
}
 
@Override
public boolean enabledFor(IListeEvent evt) {
// TODO use right
return evt.getSelectedRows().size() > 0;
boolean hasRight = TableAllRights.currentUserHasRight(this.lock ? TableAllRights.USER_UI_LOCK_ROW : TableAllRights.USER_UI_UNLOCK_ROW, evt.getTable());
return !evt.getSelectedRows().isEmpty() && hasRight;
}
}
 
1204,9 → 1208,8
try {
res.add(getRow(i, clazz));
} catch (IndexOutOfBoundsException e) {
throw new IllegalStateException(
"The selected row at " + i
+ " is not in the model : it has been changed before Swing could update the selection. E.g. the DB was changed on mousePressed and Swing updated the selection on mouseReleased.",
throw new IllegalStateException("The selected row at " + i
+ " is not in the model : it has been changed before Swing could update the selection. E.g. the DB was changed on mousePressed and Swing updated the selection on mouseReleased.",
e);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTextComboTableCellEditor.java
34,6 → 34,7
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventObject;
import java.util.List;
 
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
56,7 → 57,7
private IListFrame listFrame = null;
 
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined) {
this(elt, addUndefined, false);
this(elt, addUndefined, false,null);
}
 
/**
66,8 → 67,18
* @param chooseInListe possibilité de choisir via une IListe
*/
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined, boolean chooseInListe) {
super();
this(elt, addUndefined, chooseInListe, null);
}
 
/**
*
* @param elt Element à afficher dans la combo
* @param addUndefined ajout de l'indéfini
* @param chooseInListe possibilité de choisir via une IListe
*/
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined, boolean chooseInListe, List<String> fieldsInCombo) {
super();
 
this.addUndefined = addUndefined;
 
this.comboBox = new SQLRequestComboBox(addUndefined);
77,7 → 88,7
this.comboBox.setBorder(new LineBorder(Color.black));
this.comboBox.getPulseComponents().iterator().next().setBorder(null);
 
ComboSQLRequest c = elt.getComboRequest(true);
ComboSQLRequest c = fieldsInCombo == null || fieldsInCombo.isEmpty() ? elt.getComboRequest(true) : elt.createComboRequest(fieldsInCombo, null);
this.comboBox.uiInit(c);
 
if (chooseInListe) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTableModel.java
20,6 → 20,7
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesCluster.StoreMode;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSyntax.ConstraintType;
import org.openconcerto.sql.model.SQLTable;
300,7 → 301,7
for (int i = 0; i < size; i++) {
final SQLRowValues r = rowsToCommmit.get(i);
r.put(r.getTable().getOrderField().getFieldName(), o.add(new BigDecimal(i + 1)));
final SQLRow row = r.commit();
final SQLRow row = r.getGraph().store(StoreMode.COMMIT).getStoredRow(r);
r.setID(row.getIDNumber());
}
} catch (SQLException e) {
/trunk/OpenConcerto/src/org/openconcerto/utils/ooxml/XLSXDocument.java
New file
0,0 → 1,273
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.ooxml;
 
import org.openconcerto.utils.StringInputStream;
 
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
 
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
 
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
 
public class XLSXDocument {
 
private File file;
private final List<XLSXSheet> sheets = new ArrayList<>();
private final Map<String, String> relationships = new HashMap<>();
private final List<String> sharedString = new ArrayList<>();
private final Map<Integer, XLSXFormat> mapFormats = new HashMap<>();
private final List<XLSXFormat> customFormats = new ArrayList<>();
private final List<XLSXStyle> styles = new ArrayList<>();
private final DocumentBuilderFactory dbFactory;
 
public static XLSXDocument createFromFile(File f) throws IOException {
XLSXDocument doc = new XLSXDocument();
doc.load(f);
return doc;
}
 
public XLSXDocument() {
this.mapFormats.put(0, new XLSXFormat(0, "General", false));
this.mapFormats.put(1, new XLSXFormat(1, "0", false));
this.mapFormats.put(2, new XLSXFormat(2, "0.00", false));
this.mapFormats.put(3, new XLSXFormat(3, "#,##0", false));
this.mapFormats.put(4, new XLSXFormat(4, "#,##0.00", false));
this.mapFormats.put(9, new XLSXFormat(9, "0%", false));
this.mapFormats.put(10, new XLSXFormat(10, "0.00%", false));
this.mapFormats.put(11, new XLSXFormat(11, "0.00E+00", false));
this.mapFormats.put(12, new XLSXFormat(12, "# ?/?", false));
this.mapFormats.put(13, new XLSXFormat(13, "# ??/??", false));
this.mapFormats.put(14, new XLSXFormat(14, "mm-dd-yy", true));
this.mapFormats.put(15, new XLSXFormat(15, "d-mmm-yy", true));
this.mapFormats.put(16, new XLSXFormat(16, "d-mmm", true));
this.mapFormats.put(17, new XLSXFormat(17, "mmm-yy", true));
this.mapFormats.put(18, new XLSXFormat(18, "h:mm AM/PM", false));
this.mapFormats.put(19, new XLSXFormat(19, "h:mm:ss AM/PM", false));
this.mapFormats.put(20, new XLSXFormat(20, "h:mm", false));
this.mapFormats.put(21, new XLSXFormat(21, "h:mm:ss", false));
this.mapFormats.put(22, new XLSXFormat(22, "m/d/yy h:mm", true));
this.mapFormats.put(27, new XLSXFormat(27, "[$-404]e/m/d", true));
this.mapFormats.put(30, new XLSXFormat(30, "m/d/yy", true));
this.mapFormats.put(36, new XLSXFormat(36, "[$-404]e/m/d", true));
this.mapFormats.put(37, new XLSXFormat(37, "#,##0 ;(#,##0)", false));
this.mapFormats.put(38, new XLSXFormat(38, "#,##0 ;[Red](#,##0)", false));
this.mapFormats.put(39, new XLSXFormat(39, "#,##0.00;(#,##0.00)", false));
this.mapFormats.put(40, new XLSXFormat(40, "#,##0.00;[Red](#,##0.00)", false));
this.mapFormats.put(44, new XLSXFormat(44, "_(\"$\"* #,##0.00_);_(\"$\"* (#,##0.00);_(\"$\"* \"-\"??_);_(@_)", false));
this.mapFormats.put(45, new XLSXFormat(45, "mm:ss", false));
this.mapFormats.put(46, new XLSXFormat(46, "[h]:mm:ss", false));
this.mapFormats.put(47, new XLSXFormat(47, "mmss.0", false));
this.mapFormats.put(48, new XLSXFormat(48, "##0.0E+0", false));
this.mapFormats.put(49, new XLSXFormat(49, "@", false));
this.mapFormats.put(50, new XLSXFormat(50, "[$-404]e/m/d", true));
this.mapFormats.put(57, new XLSXFormat(57, "[$-404]e/m/d", true));
this.mapFormats.put(59, new XLSXFormat(59, "t0", false));
this.mapFormats.put(60, new XLSXFormat(60, "t0.00", false));
this.mapFormats.put(61, new XLSXFormat(61, "t#,##0", false));
this.mapFormats.put(62, new XLSXFormat(62, "t#,##0.00", false));
this.mapFormats.put(67, new XLSXFormat(67, "t0%", false));
this.mapFormats.put(68, new XLSXFormat(68, "t0.00%", false));
this.mapFormats.put(69, new XLSXFormat(69, "t# ?/?", false));
this.mapFormats.put(70, new XLSXFormat(70, "t# ??/??", false));
 
this.dbFactory = DocumentBuilderFactory.newInstance();
try {
this.dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
} catch (ParserConfigurationException e) {
throw new IllegalStateException(e);
}
try {
this.dbFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
this.dbFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
} catch (Exception e) {
// ignore
}
this.dbFactory.setNamespaceAware(true);
 
}
 
public File getFile() {
return this.file;
}
 
private void load(File f) throws IOException {
this.file = f;
try (ZipFile zipFile = new ZipFile(f)) {
try {
parseSharedStrings(zipFile);
parseStyles(zipFile);
parseWorkBook(zipFile);
} catch (ParserConfigurationException | SAXException e) {
throw new IOException(e);
}
 
}
}
 
private void parseWorkBook(ZipFile zipFile) throws ParserConfigurationException, SAXException, IOException {
final String relationxXML = getContent(zipFile, "xl/_rels/workbook.xml.rels");
final DocumentBuilder dBuilder1 = this.dbFactory.newDocumentBuilder();
final Document doc1 = dBuilder1.parse(new StringInputStream(relationxXML, StandardCharsets.UTF_8.name()));
doc1.getDocumentElement().normalize();
final NodeList nList = doc1.getElementsByTagName("Relationship");
for (int i = 0; i < nList.getLength(); i++) {
final NamedNodeMap attributes = nList.item(i).getAttributes();
final String rId = attributes.getNamedItem("Id").getNodeValue();
final String target = attributes.getNamedItem("Target").getNodeValue();
this.relationships.put(rId, target);
}
 
final String workbookXML = getContent(zipFile, "xl/workbook.xml");
final DocumentBuilder dBuilder2 = this.dbFactory.newDocumentBuilder();
final Document doc2 = dBuilder2.parse(new StringInputStream(workbookXML, StandardCharsets.UTF_8.name()));
doc2.getDocumentElement().normalize();
doc2.getElementsByTagName("sheets");
final NodeList nListSheet = doc2.getElementsByTagName("sheet");
for (int i = 0; i < nListSheet.getLength(); i++) {
final NamedNodeMap attributes = nListSheet.item(i).getAttributes();
final String sheetId = attributes.getNamedItem("sheetId").getNodeValue();
final String name = attributes.getNamedItem("name").getNodeValue();
final String rId = attributes.getNamedItemNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id").getNodeValue();
final String target = "xl/" + this.relationships.get(rId);
final String xml = getContent(zipFile, target);
this.sheets.add(new XLSXSheet(this, sheetId, rId, name, xml));
}
 
}
 
private void parseSharedStrings(ZipFile zipFile) throws ParserConfigurationException, SAXException, IOException {
final String relationxXML = getContent(zipFile, "xl/sharedStrings.xml");
final DocumentBuilder dBuilder1 = this.dbFactory.newDocumentBuilder();
final Document doc1 = dBuilder1.parse(new StringInputStream(relationxXML, StandardCharsets.UTF_8.name()));
doc1.getDocumentElement().normalize();
final NodeList nList = doc1.getElementsByTagName("si");
for (int i = 0; i < nList.getLength(); i++) {
final Node siNode = nList.item(i);
StringBuilder b = new StringBuilder();
NodeList list = siNode.getChildNodes();
for (int j = 0; j < list.getLength(); j++) {
Node n = list.item(j);
if (n.getLocalName().equals("t")) {
b.append(n.getTextContent());
} else {
NodeList subList = n.getChildNodes();
for (int k = 0; k < subList.getLength(); k++) {
Node nn = subList.item(k);
if (nn.getLocalName().equals("t")) {
b.append(nn.getTextContent());
}
 
}
 
}
}
this.sharedString.add(b.toString());
}
 
}
 
private void parseStyles(ZipFile zipFile) throws ParserConfigurationException, SAXException, IOException {
final String relationxXML = getContent(zipFile, "xl/styles.xml");
final DocumentBuilder dBuilder1 = this.dbFactory.newDocumentBuilder();
final Document doc1 = dBuilder1.parse(new StringInputStream(relationxXML, StandardCharsets.UTF_8.name()));
doc1.getDocumentElement().normalize();
final NodeList nListFormats = doc1.getElementsByTagName("numFmts");
for (int i = 0; i < nListFormats.getLength(); i++) {
final Node siNode = nListFormats.item(i);
NodeList list = siNode.getChildNodes();
for (int j = 0; j < list.getLength(); j++) {
Node n = list.item(j);
NamedNodeMap m = n.getAttributes();
int id = Integer.parseInt(m.getNamedItem("numFmtId").getNodeValue());
String format = m.getNamedItem("formatCode").getNodeValue();
final XLSXFormat f = new XLSXFormat(id, format);
this.mapFormats.put(id, f);
this.customFormats.add(f);
}
 
}
 
final NodeList nListCellXfs = doc1.getElementsByTagName("cellXfs");
for (int i = 0; i < nListCellXfs.getLength(); i++) {
final Node siNode = nListCellXfs.item(i);
NodeList list = siNode.getChildNodes();
for (int j = 0; j < list.getLength(); j++) {
// xf
Node n = list.item(j);
NamedNodeMap m = n.getAttributes();
int id = Integer.parseInt(m.getNamedItem("numFmtId").getNodeValue());
this.styles.add(new XLSXStyle(id));
}
 
}
 
}
 
private String getContent(ZipFile zipFile, String string) throws IOException {
final ZipEntry entry = zipFile.getEntry(string);
if (entry == null) {
throw new IOException("no entry : " + string);
}
final InputStream in = zipFile.getInputStream(entry);
final ByteArrayOutputStream b = new ByteArrayOutputStream();
final byte[] bytes = new byte[8192];
while (in.available() > 0) {
final int length = in.read(bytes);
b.write(bytes, 0, length);
}
return b.toString(StandardCharsets.UTF_8.name());
}
 
public XLSXSheet getSheet(int sheetNumber) {
return this.sheets.get(sheetNumber);
}
 
public int getSheetCount() {
return this.sheets.size();
}
 
public String getSharedString(int index) {
return this.sharedString.get(index);
}
 
public XLSXFormat getFormatFromStyle(int styleIndex) {
final XLSXStyle style = this.styles.get(styleIndex);
if (style == null) {
return null;
}
return this.mapFormats.get(style.getFormatId());
}
 
public DocumentBuilderFactory getDbFactory() {
return this.dbFactory;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ooxml/XLSXStyle.java
New file
0,0 → 1,26
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.ooxml;
 
public class XLSXStyle {
private final int formatId;
 
public XLSXStyle(int formatId) {
this.formatId = formatId;
}
 
public int getFormatId() {
return this.formatId;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ooxml/XLSXFormat.java
New file
0,0 → 1,71
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.ooxml;
 
import java.text.DecimalFormat;
import java.text.Format;
import java.text.SimpleDateFormat;
 
public class XLSXFormat {
private final int id;
private final String format;
private boolean isDateFormat = false;
private Format jformat;
 
public XLSXFormat(int id, String format) {
this.id = id;
this.format = format;
final String f = format.toLowerCase();
if (f.contains("mm") || f.contains("dd") || f.contains("yy")) {
this.isDateFormat = true;
}
}
 
public XLSXFormat(int id, String format, boolean date) {
this.id = id;
this.format = format;
this.isDateFormat = date;
}
 
public int getId() {
return this.id;
}
 
public String getFormat() {
return this.format;
}
 
public boolean isDateFormat() {
return this.isDateFormat;
}
 
public String format(String txt) {
if (this.format.equalsIgnoreCase("general")) {
return txt;
}
if (this.jformat == null) {
String javaFormat = this.format.replace("YYYY", "yyyy");
javaFormat = javaFormat.replace("YY", "yy");
javaFormat = javaFormat.replace("mm", "MM");
javaFormat = javaFormat.replace("dd", "DD");
if (this.isDateFormat) {
this.jformat = new SimpleDateFormat(javaFormat);
} else {
this.jformat = new DecimalFormat(javaFormat);
}
}
return this.jformat.format(txt);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ooxml/XLSXSheet.java
New file
0,0 → 1,261
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.ooxml;
 
import org.openconcerto.utils.StringInputStream;
import org.openconcerto.utils.StringUtils;
 
import java.awt.Point;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
 
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
 
import com.ibm.icu.math.BigDecimal;
 
public class XLSXSheet {
private int columnCount;
private int startX;
private int startY;
private int endX;
private int endY;
private static final String MINCELL = "\\$?([A-Z]+)\\$?([0-9]+)";
private static final Pattern minCellPattern = Pattern.compile(MINCELL);
private final List<List<Object>> rows;
private String id;
private String rId;
private String name;
 
public XLSXSheet(XLSXDocument document, String id, String rId, String name, String xml) throws IOException, ParserConfigurationException, SAXException {
this.id = id;
this.rId = rId;
this.name = name;
 
final DocumentBuilder dBuilder = document.getDbFactory().newDocumentBuilder();
final Document doc = dBuilder.parse(new StringInputStream(xml, StandardCharsets.UTF_8.name()));
doc.getDocumentElement().normalize();
 
final NodeList nList = doc.getElementsByTagName("dimension");
final String dimension = nList.item(0).getAttributes().getNamedItem("ref").getNodeValue();
final List<String> parts = StringUtils.fastSplit(dimension, ':');
 
final Point start = resolve(parts.get(0));
this.startX = start.x;
this.startY = start.y;
 
final Point end = resolve(parts.get(1));
this.endX = end.x;
this.endY = end.y;
this.rows = new ArrayList<>(end.y - start.y);
this.columnCount = this.endX - this.startX + 1;
 
for (int i = start.y; i <= end.y; i++) {
List<Object> row = new ArrayList<>();
for (int j = 0; j < this.columnCount; j++) {
row.add(null);
}
this.rows.add(row);
}
Calendar calendar = Calendar.getInstance();
NodeList nListRows = doc.getElementsByTagName("row");
int l1 = nListRows.getLength();
for (int i = 0; i < l1; i++) {
Node r = nListRows.item(i);
NodeList nListCells = r.getChildNodes();
int l2 = nListCells.getLength();
for (int j = 0; j < l2; j++) {
Node c = nListCells.item(j);
final String location = c.getAttributes().getNamedItem("r").getNodeValue();
final Point p = resolve(location);
if (p == null) {
throw new IllegalStateException("unable to parse location : " + location);
}
// The index of this cell's style. Style records are stored in the Styles Part.
// The possible values for this attribute are defined by the W3C XML Schema
// unsignedInt datatype.
int style = 0;
if (c.getAttributes().getNamedItem("s") != null) {
style = Integer.parseInt(c.getAttributes().getNamedItem("s").getNodeValue());
}
// An enumeration representing the cell's data type.
// The possible values for this attribute are defined by the ST_CellType simple type
// (§18.18.11):
// "b" boolean
// "d" ISO 8601 date
// "n" number
// "e" error
// "s" strin
// "str" formula
// "inlineStr" the cell value is in the is element rather than the v
// element in the cell
String type = "n";
if (c.getAttributes().getNamedItem("t") != null) {
type = c.getAttributes().getNamedItem("t").getNodeValue();
}
NodeList nListCellParts = c.getChildNodes();
int l3 = nListCellParts.getLength();
for (int k = 0; k < l3; k++) {
Node part = nListCellParts.item(k);
if (part.getNodeName().equals("v")) {
String value = part.getTextContent();
Object cellValue = null;
if (type.equals("n")) {
final XLSXFormat format = document.getFormatFromStyle(style);
if (format != null) {
if (format.isDateFormat()) {
cellValue = stringToDate(calendar, value);
} else {
cellValue = new BigDecimal(value);
}
} else {
cellValue = new BigDecimal(value);
}
} else if (type.equals("s")) {
cellValue = document.getSharedString(Integer.parseInt(value));
}
this.rows.get(p.y - this.startY).set(p.x - this.startX, cellValue);
}
}
 
}
}
}
 
public Object getValueAt(int col, int row) {
return this.rows.get(row).get(col);
}
 
public int getColumnCount() {
return this.columnCount;
}
 
public int getRowCount() {
return this.rows.size();
}
 
/**
* Convert string coordinates into numeric ones.
*
* @param ref the string address, eg "$AA$34" or "AA34".
* @return the numeric coordinates or <code>null</code> if <code>ref</code> is not valid, eg
* {26, 33}.
*/
static final Point resolve(String ref) {
final Matcher matcher = minCellPattern.matcher(ref);
if (!matcher.matches())
return null;
return resolve(matcher.group(1), matcher.group(2));
}
 
/**
* Convert string coordinates into numeric ones. ATTN this method does no checks.
*
* @param letters the column, eg "AA".
* @param digits the row, eg "34".
* @return the numeric coordinates, eg {26, 33}.
*/
static final Point resolve(final String letters, final String digits) {
return new Point(toInt(letters), Integer.parseInt(digits) - 1);
}
 
// "AA" => 26
static final int toInt(String col) {
if (col.length() < 1)
throw new IllegalArgumentException("x cannot be empty");
col = col.toUpperCase();
 
int x = 0;
for (int i = 0; i < col.length(); i++) {
x = x * 26 + (col.charAt(i) - 'A' + 1);
}
 
// zero based
return x - 1;
}
 
public static final String toStr(int col) {
if (col < 0)
throw new IllegalArgumentException("negative column : " + col);
// one based (i.e. 0 is A)
col++;
 
final int radix = 26;
final StringBuilder chars = new StringBuilder(4);
while (col > 0) {
chars.append((char) ('A' + ((col - 1) % radix)));
col = (col - 1) / radix;
}
 
return chars.reverse().toString();
}
 
/**
* Convert numeric coordinates into string ones.
*
* @param p the numeric coordinates, e.g. {26, 33}.
* @return the string address, e.g. "AA34".
*/
static final String getAddress(Point p) {
if (p.x < 0 || p.y < 0)
throw new IllegalArgumentException("negative coordinates : " + p);
return toStr(p.x) + (p.y + 1);
}
 
public String getId() {
return this.id;
}
 
public static Date stringToDate(Calendar c, String d) {
c.clear();
c.set(1900, 0, 0);
c.add(Calendar.DAY_OF_YEAR, Integer.parseInt(d) - 1);
return c.getTime();
}
 
public int getStartX() {
return this.startX;
}
 
public int getStartY() {
return this.startY;
}
 
public int getEndX() {
return this.endX;
}
 
public int getEndY() {
return this.endY;
}
 
public String getName() {
return this.name;
}
 
public String getRId() {
return this.rId;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/TableSorter.java
348,7 → 348,11
* @return the corresponding index in the model.
*/
public int modelIndex(int viewIndex) {
return getViewToModel()[viewIndex].modelIndex;
try {
return getViewToModel()[viewIndex].modelIndex;
} catch (Exception e) {
throw new IllegalStateException(this + " couldn't get model index for view index " + viewIndex + " with " + this.getTableModel().getRowCount() + " row(s) in our model", e);
}
}
 
private int[] getModelToView() {
430,6 → 434,11
this.supp.removePropertyChangeListener(l);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " on " + this.getTableModel();
}
 
// Helper classes
 
private class Row implements Comparable<Row> {
/trunk/OpenConcerto/src/org/openconcerto/utils/FileUtils.java
695,6 → 695,7
* @see StreamUtils#createXMLWriter(java.io.OutputStream)
*/
public static BufferedWriter createXMLWriter(final File f) throws IOException {
FileUtils.mkParentDirs(f);
final FileOutputStream outs = new FileOutputStream(f);
try {
return StreamUtils.createXMLWriter(outs);
/trunk/OpenConcerto/src/org/openconcerto/utils/text/CSVReader.java
29,7 → 29,6
 
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
248,11 → 247,4
br.close();
}
 
public static void main(String[] args) throws IOException {
CSVReader reader = new CSVReader(new FileReader("n:\\Sans nom 1.csv"));
String[] s = reader.readNext();
for (int i = 0; i < s.length; i++) {
System.err.println("CSVReader.main() :" + i + " : " + s[i]);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/NetUtils.java
22,11 → 22,17
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
 
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
 
public class NetUtils {
 
125,6 → 131,10
}
};
 
public static final String getHTTPContent(String address) {
return getHTTPContent(address, false);
}
 
public static final String getHTTPContent(String address, final boolean dontVerify) {
String content = "";
OutputStream out = null;
167,4 → 177,23
 
return content;
}
 
// Create a trust manager that does not validate certificate chains
static private final TrustManager[] TRUSTALL_MANAGERS = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
 
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
 
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
 
static public final SSLContext createTrustAllContext() throws KeyManagementException, NoSuchAlgorithmException {
final SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, TRUSTALL_MANAGERS, new java.security.SecureRandom());
return sc;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ProductInfo.java
14,6 → 14,9
package org.openconcerto.utils;
 
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Properties;
 
157,6 → 160,12
return this.getProperty(VERSION);
}
 
public final void store(final Path p) throws IOException {
try (final OutputStream out = Files.newOutputStream(p)) {
this.getProps().store(out, this.getClass().getName());
}
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " for " + getName() + " " + getVersion();
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/CustomEquals.java
19,7 → 19,10
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
import java.util.Set;
import java.util.function.BiPredicate;
 
/**
* Allow to create a proxy object which uses a {@link HashingStrategy}.
103,6 → 106,28
return CompareUtils.equals(sA, sB);
}
 
static public final <S, T1 extends S> int indexOf(final List<T1> s1, final S o, final HashingStrategy<S> s) {
return indexOf(s1, o, s::equals);
}
 
static public final <S, T1 extends S> int indexOf(final List<T1> s1, final S o, final BiPredicate<S, S> s) {
if (s1 instanceof RandomAccess) {
final int stop = s1.size();
for (int i = 0; i < stop; i++) {
if (s.test(s1.get(i), o))
return i;
}
} else {
final ListIterator<T1> listIter = s1.listIterator();
while (listIter.hasNext()) {
final T1 item = listIter.next();
if (s.test(item, o))
return listIter.previousIndex();
}
}
return -1;
}
 
static public class ProxyFull<S, E extends S> implements ProxyItf<E> {
 
static public final <S, E extends S> Set<ProxyFull<S, E>> createSet(final HashingStrategy<S> strategy, final Collection<E> coll) {
192,6 → 217,11
else
return this.strategy.equals(this.getDelegate(), delegate2);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " using strategy " + this.getStrategy() + " for " + this.getDelegate();
}
}
 
/**
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/IExnFactory.java
New file
0,0 → 1,20
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.cc;
 
public interface IExnFactory<E, X extends Exception> {
 
public abstract E createChecked() throws X;
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/Cookies.java
New file
0,0 → 1,216
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.cc;
 
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
 
import com.google.gson.reflect.TypeToken;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
/**
* Type-safer map (e.g. can store multiple types and collections).
*
* @author Sylvain
*/
@ThreadSafe
public class Cookies {
 
@GuardedBy("this")
private final Map<Object, Object> map;
@GuardedBy("this")
private Map<Object, Object> collectionTypes;
 
public Cookies() {
this(8);
}
 
public Cookies(final int initialCapacity) {
this.map = new HashMap<>(initialCapacity);
this.collectionTypes = null;
}
 
public Cookies(final Cookies source) {
synchronized (source) {
this.map = new HashMap<>(source.map);
this.collectionTypes = source.collectionTypes == null ? null : new HashMap<>(source.collectionTypes);
}
}
 
public final void putAll(final Cookies other) {
if (this == other)
return;
final Map<Object, Object> map;
final Map<Object, Object> collectionTypes;
synchronized (other) {
map = new HashMap<>(other.map);
collectionTypes = other.collectionTypes == null ? null : new HashMap<>(other.collectionTypes);
}
synchronized (this) {
// don't just use putAll() since it won't remove entries from collectionTypes for
// replaced items
for (final Entry<Object, Object> e : map.entrySet()) {
this.put(e.getKey(), e.getValue(), collectionTypes == null ? null : collectionTypes.get(e.getKey()));
}
}
}
 
public final Object put(Object k, Object v) {
return this.put(k, v, null);
}
 
private final Object putCollectionType(Object k, Object v, Object type) {
if (type == null)
throw new IllegalArgumentException("Null type");
return this.put(k, v, type);
}
 
private final synchronized Object put(Object k, Object v, Object type) {
if (type != null) {
if (this.collectionTypes == null)
this.collectionTypes = new HashMap<>(4);
this.collectionTypes.put(k, type);
} else if (this.collectionTypes != null) {
this.collectionTypes.remove(k);
}
return this.map.put(k, v);
}
 
public final <T> Object putCollection(Object k, Collection<T> v, Class<T> clazz) {
return this.putCollectionType(k, v, clazz);
}
 
public final <K, V> Object putMap(Object k, Map<K, V> v, Class<K> keyClass, Class<V> valueClass) {
Objects.requireNonNull(keyClass, "Key class");
Objects.requireNonNull(valueClass, "value class");
return this.putCollectionType(k, v, Arrays.asList(keyClass, valueClass));
}
 
public final <T> Object putGeneric(Object k, T v, TypeToken<T> clazz) {
return this.putCollectionType(k, v, clazz);
}
 
public final synchronized boolean containsKey(Object k) {
return this.map.containsKey(k);
}
 
public final synchronized Object getObject(Object k) {
return this.map.get(k);
}
 
public final int getInt(Object k) {
return getObjectAs(k, Number.class).intValue();
}
 
public final long getLong(Object k) {
return getObjectAs(k, Number.class).longValue();
}
 
public final Boolean getBoolean(Object k) {
return getObjectAs(k, Boolean.class);
}
 
public final boolean getBoolean(Object k, final boolean def) {
final Boolean res = getBoolean(k);
return res == null ? def : res.booleanValue();
}
 
public final String getString(Object k) {
return getObjectAs(k, String.class);
}
 
public synchronized final <T> T getContainedObjectAs(Object key, Class<T> clazz) {
if (!this.containsKey(key))
throw new IllegalArgumentException(key + " not present in this : " + this.map.keySet());
return this.getObjectAs(key, clazz);
}
 
public final <T> T getObjectAs(Object k, Class<T> clazz) {
return this.getObjectAs(k, clazz, null);
}
 
public final <T> T getObjectAs(Object k, Class<T> clazz, final T defaultVal) {
return this.getObjectAs(k, clazz, defaultVal, true);
}
 
public synchronized final <T> T getObjectAs(Object k, Class<T> clazz, final T defaultVal, final boolean useDefaultIfNullValue) {
final Object res = this.getObject(k);
if (res == null && (useDefaultIfNullValue || !this.containsKey(k)))
return defaultVal;
try {
return clazz.cast(res);
} catch (ClassCastException e) {
throw new IllegalArgumentException("Couldn't access " + k + " in " + this + " as " + clazz.getSimpleName(), e);
}
}
 
public final <T> Object checkType(Object k, Object wantedType, final String needMethodName) {
final Object object;
final Object type;
synchronized (this) {
object = this.getObject(k);
type = this.collectionTypes == null ? null : this.collectionTypes.get(k);
}
// as getObject() : don't fail on null
if (object == null)
return null;
if (type == null)
throw new IllegalStateException("Wasn't stored with " + needMethodName + " : " + k);
if (!type.equals(wantedType))
throw new IllegalArgumentException("Wasn't stored with the passed type : " + wantedType + " != " + type);
return object;
}
 
public final <T> Collection<T> getCollection(Object k, Class<T> clazz) {
final Object object = checkType(k, clazz, "putCollection()");
@SuppressWarnings("unchecked")
final Collection<T> res = (Collection<T>) object;
return res;
}
 
public final <T> List<T> getList(Object k, Class<T> clazz) {
return (List<T>) this.getCollection(k, clazz);
}
 
public final <T> Set<T> getSet(Object k, Class<T> clazz) {
return (Set<T>) this.getCollection(k, clazz);
}
 
public final <K, V> Map<K, V> getMap(Object k, Class<K> keyClass, Class<V> valueClass) {
final Object object = checkType(k, Arrays.asList(keyClass, valueClass), "putMap()");
@SuppressWarnings("unchecked")
final Map<K, V> res = (Map<K, V>) object;
return res;
}
 
public final <T> T getGeneric(Object k, TypeToken<T> clazz) {
final Object object = checkType(k, clazz, "putGeneric()");
@SuppressWarnings("unchecked")
final T res = (T) object;
return res;
}
 
@Override
public synchronized String toString() {
return this.getClass().getSimpleName() + " of " + this.map.keySet();
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/IFactory.java
13,8 → 13,9
package org.openconcerto.utils.cc;
 
public interface IFactory<E> {
public interface IFactory<E> extends IExnFactory<E, RuntimeException> {
 
@Override
public abstract E createChecked();
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/CollectionMap2.java
122,6 → 122,9
 
// ** copy constructors
 
// ATTN getDelegate() is not in CollectionMap2Itf, so if one copies an unmodifiableMap() this
// constructor won't be used and the delegate will be the default HashMap (even if the source
// used a LinkedHashMap).
public CollectionMap2(final CollectionMap2<K, C, ? extends V> m) {
this(CopyUtils.copy(m.getDelegate()), m);
}
/trunk/OpenConcerto/src/org/openconcerto/utils/CollectionUtils.java
18,6 → 18,7
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.cc.IdentityHashSet;
import org.openconcerto.utils.cc.IdentitySet;
import org.openconcerto.utils.cc.LinkedIdentitySet;
import org.openconcerto.utils.cc.Transformer;
 
import java.io.Serializable;
643,14 → 644,16
return collector;
}
 
@SuppressWarnings("unchecked")
public static <T> Collection<T> subtract(final Collection<T> a, final Collection<? extends T> b) {
return org.apache.commons.collections.CollectionUtils.subtract(a, b);
final Collection<T> res = a instanceof IdentitySet ? new LinkedIdentitySet<>(a) : new ArrayList<>(a);
for (Iterator<? extends T> it = b.iterator(); it.hasNext();) {
res.remove(it.next());
}
return res;
}
 
@SuppressWarnings("unchecked")
public static <T> Collection<T> substract(final Collection<T> a, final Collection<? extends T> b) {
return org.apache.commons.collections.CollectionUtils.subtract(a, b);
return subtract(a, b);
}
 
public static final <T> T coalesce(T o1, T o2) {
935,10 → 938,11
* @param <K> type of key.
* @param <V> type of value.
* @param keys the keys of the map.
* @return a new map, if <code>keys</code> is a {@link List} it will be ordered.
* @return a new ordered map.
*/
public static <K, V> Map<K, V> createMap(Collection<? extends K> keys) {
return fillMap(keys instanceof List ? new LinkedHashMap<K, V>(keys.size()) : new HashMap<K, V>(keys.size()), keys);
// there's no way to tell if a Collection is ordered, so always use ordered map.
return fillMap(new LinkedHashMap<K, V>(keys.size()), keys);
}
 
/**
/trunk/OpenConcerto/src/org/openconcerto/utils/StringUtils.java
28,6 → 28,7
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/**
820,4 → 821,13
}
return b.toString();
}
 
public static final Matcher findFirstContaining(final String s, final Pattern... patterns) {
for (final Pattern p : patterns) {
final Matcher matcher = p.matcher(s);
if (matcher.find())
return matcher;
}
return null;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/sync/HashWriter.java
13,6 → 13,8
package org.openconcerto.utils.sync;
 
import org.openconcerto.utils.MessageDigestUtils;
 
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
38,8 → 40,8
}
final DataOutputStream bOut = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
bOut.writeInt((int) this.in.length());
final MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
final MessageDigest md5 = MessageDigest.getInstance("MD5");
final MessageDigest hashSum = MessageDigestUtils.getSHA256();
final MessageDigest md5 = MessageDigestUtils.getMD5();
fb = new BufferedInputStream(new FileInputStream(in));
final RollingChecksum32 r32 = new RollingChecksum32();
final byte[] buffer = new byte[BLOCK_SIZE];
74,8 → 76,8
}
}
 
public static byte[] getHash(File f) throws Exception {
final MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
public static byte[] getHash(File f) throws IOException {
final MessageDigest hashSum = MessageDigestUtils.getSHA256();
FileInputStream fIn = null;
try {
fIn = new FileInputStream(f);
123,4 → 125,15
return true;
}
 
private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
 
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/sync/SimpleSyncClient.java
New file
0,0 → 1,413
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.sync;
 
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.MessageDigestUtils;
import org.openconcerto.utils.StreamUtils;
 
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.FileTime;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
 
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
 
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import net.minidev.json.parser.JSONParser;
 
public final class SimpleSyncClient {
 
private static final int MIN_GZIP_SIZE = 64;
 
static protected final long getLong(final Object o) {
return ((Number) o).longValue();
}
 
static protected final Instant getInstant(final Object o) {
return Instant.ofEpochMilli(getLong(o));
}
 
static public class ServerException extends RuntimeException {
private final int responseCode;
private final boolean authenticateError;
 
protected ServerException(int responseCode, boolean authenticateError) {
super("Response code was " + responseCode);
this.responseCode = responseCode;
this.authenticateError = authenticateError;
}
 
public final int getResponseCode() {
return this.responseCode;
}
 
public final boolean isAuthenticateError() {
return this.authenticateError;
}
}
 
static public final class Response {
 
protected final static Response create(HttpsURLConnection con, final Set<Integer> okCodes) throws IOException {
final boolean success = okCodes == null ? con.getResponseCode() == 200 : okCodes.contains(con.getResponseCode());
return new Response(success, con.getResponseCode(), con.getResponseMessage(), con.getContentEncoding(), con.getContentType());
}
 
private final boolean success;
private final int code;
private final String message;
private final String contentEncoding, contentType;
 
protected Response(boolean success, int code, String message, String contentEncoding, String contentType) {
super();
this.success = success;
this.code = code;
this.message = message;
this.contentEncoding = contentEncoding;
this.contentType = contentType;
}
 
public final int getCode() {
return this.code;
}
 
public final boolean isSuccess() {
return this.success;
}
 
public final String getMessage() {
return this.message;
}
 
public final String getContentEncoding() {
return this.contentEncoding;
}
 
public final String getContentType() {
return this.contentType;
}
}
 
static protected abstract class BaseAttrs {
private final String path;
private final String name;
private final Instant lastModified;
 
protected BaseAttrs(final String path, final String name, final Instant lastModified) {
super();
this.path = path;
this.name = name;
this.lastModified = lastModified;
}
 
public final String getPath() {
return this.path;
}
 
public final String getName() {
return this.name;
}
 
public final Instant getLastModified() {
return this.lastModified;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " '" + this.getName() + "'";
}
}
 
static public final class DirAttrs extends BaseAttrs {
static protected DirAttrs fromJSON(final String path, final JSONArray array) {
return new DirAttrs(path, (String) array.get(0), getInstant(array.get(1)));
}
 
protected DirAttrs(final String path, String name, Instant lastModified) {
super(path, name, lastModified);
}
}
 
static public final class FileAttrs extends BaseAttrs {
 
static protected FileAttrs fromJSON(final String path, final JSONArray array) {
return new FileAttrs(path, (String) array.get(0), getInstant(array.get(2)), getLong(array.get(1)), (String) array.get(3));
}
 
private final long size;
private final String sha256;
 
protected FileAttrs(final String path, String name, Instant lastModified, long size, String sha256) {
super(path, name, lastModified);
this.size = size;
this.sha256 = sha256;
}
 
public final long getSize() {
return this.size;
}
 
public final String getSHA256() {
return this.sha256;
}
 
public final void saveFile(final InputStream in, final Path localFile) throws IOException {
// Save to temporary file to avoid overwriting old file with a new invalid one. In
// same folder for the move.
final Path tmpFile = Files.createTempFile(localFile.getParent(), "partial", null);
try {
final MessageDigest md = this.getSHA256() == null ? null : MessageDigestUtils.getSHA256();
try (final BufferedOutputStream fileStream = new BufferedOutputStream(Files.newOutputStream(tmpFile));
//
final OutputStream out = md == null ? fileStream : new DigestOutputStream(fileStream, md)) {
StreamUtils.copy(in, out);
}
if (this.getSize() >= 0) {
final long savedSize = Files.size(tmpFile);
if (savedSize != this.getSize())
throw new IOException("Expected " + this.getSize() + " bytes but saved " + savedSize);
}
if (md != null) {
final String savedHash = MessageDigestUtils.getHashString(md);
if (!savedHash.equalsIgnoreCase(this.getSHA256()))
throw new IOException("Expected hash was " + this.getSHA256() + " but saved " + savedHash);
}
Files.move(tmpFile, localFile, StandardCopyOption.REPLACE_EXISTING);
} finally {
Files.deleteIfExists(tmpFile);
}
if (this.getLastModified().compareTo(Instant.EPOCH) > 0)
Files.setLastModifiedTime(localFile, FileTime.from(this.getLastModified()));
}
 
@Override
public String toString() {
return super.toString() + " of size " + getSize();
}
}
 
static public final class DirContent {
private final String path;
private final JSONObject json;
 
protected DirContent(final String path, JSONObject json) {
super();
this.path = path;
this.json = json;
}
 
public final List<FileAttrs> getFiles() {
return this.getFiles(null);
}
 
public final List<FileAttrs> getFiles(final Predicate<String> namePredicate) {
return this.getContent("files", namePredicate, FileAttrs::fromJSON);
}
 
public final List<DirAttrs> getDirs() {
return this.getDirs(null);
}
 
public final List<DirAttrs> getDirs(final Predicate<String> namePredicate) {
return this.getContent("dirs", namePredicate, DirAttrs::fromJSON);
}
 
protected final <T extends BaseAttrs> List<T> getContent(final String key, final Predicate<String> namePredicate, final BiFunction<String, JSONArray, T> create) {
final JSONArray files = (JSONArray) this.json.get(key);
if (files == null)
return Collections.emptyList();
final List<T> res = new ArrayList<>();
for (final Object f : files) {
final JSONArray array = (JSONArray) f;
if (namePredicate == null || namePredicate.test((String) array.get(0))) {
res.add(create.apply(this.path, array));
}
}
return res;
}
}
 
private final String url;
private SSLSocketFactory socketFactory;
private String token;
private boolean throwException = true;
 
public SimpleSyncClient(final String url) {
this.url = url;
}
 
public final SSLSocketFactory getSocketFactory() {
return this.socketFactory;
}
 
public final void setSocketFactory(SSLSocketFactory socketFactory) {
this.socketFactory = socketFactory;
}
 
public final void setToken(String token) {
this.token = token;
}
 
public final boolean hasToken() {
return this.getToken() != null;
}
 
protected final String getToken() {
return this.token;
}
 
public final void setThrowException(boolean throwException) {
this.throwException = throwException;
}
 
public final boolean throwsException() {
return this.throwException;
}
 
protected Response checkResponseCode(final HttpsURLConnection con) throws IOException {
return checkResponseCode(con, null);
}
 
protected Response checkResponseCode(final HttpsURLConnection con, final Set<Integer> okCodes) throws IOException {
final Response res = Response.create(con, okCodes);
if (this.throwsException() && !res.isSuccess())
throw new ServerException(res.getCode(), con.getHeaderField("WWW-Authenticate") != null);
return res;
}
 
private final HttpsURLConnection openConnection(final String path) throws IOException {
final HttpsURLConnection con = (HttpsURLConnection) new URL(this.url + path).openConnection();
con.setRequestProperty("Accept-Encoding", "gzip");
if (this.getSocketFactory() != null)
con.setSSLSocketFactory(this.getSocketFactory());
if (getToken() != null)
con.setRequestProperty("Authorization", "Bearer " + Base64.getEncoder().encodeToString(getToken().getBytes(StandardCharsets.UTF_8)));
return con;
}
 
private final InputStream getInputStream(final HttpsURLConnection con) throws IOException {
return "gzip".equals(con.getContentEncoding()) ? new GZIPInputStream(con.getInputStream()) : con.getInputStream();
}
 
private final HttpsURLConnection send(final HttpsURLConnection con, final String params) throws IOException {
return this.send(con, params.getBytes(StandardCharsets.UTF_8), false);
}
 
private final HttpsURLConnection send(final HttpsURLConnection con, final byte[] toSend, final boolean allowGzip) throws IOException {
final boolean useGzip = allowGzip && toSend.length >= MIN_GZIP_SIZE;
if (useGzip)
con.setRequestProperty("Content-Encoding", "gzip");
con.setRequestMethod("POST");
con.setDoOutput(true);
try (final OutputStream o = useGzip ? new GZIPOutputStream(con.getOutputStream()) : con.getOutputStream()) {
o.write(toSend);
}
return con;
}
 
public DirContent getDir(final String path) throws Exception {
final HttpsURLConnection con = openConnection("/getDir");
final Response res = checkResponseCode(send(con, "rp=" + path + "&type=json"));
if (!res.isSuccess())
return null;
final JSONParser p = new JSONParser(JSONParser.MODE_STRICTEST);
try (final InputStream in = getInputStream(con)) {
return new DirContent(path, (JSONObject) p.parse(in));
}
}
 
@FunctionalInterface
static public interface FileConsumer {
public void accept(FileAttrs attrs, InputStream fileStream) throws IOException;
}
 
static private final Set<Integer> GETFILE_OK_CODES = CollectionUtils.createSet(200, 404);
 
public Response getFile(final String path, final String fileName, final FileConsumer fileConsumer) throws IOException {
final HttpsURLConnection con = openConnection("/get");
send(con, "rn=" + fileName + "&rp=" + path);
final Response res = checkResponseCode(con, GETFILE_OK_CODES);
if (res.getCode() == 404) {
fileConsumer.accept(null, null);
} else if (res.getCode() == 200) {
final FileAttrs fileAttrs = new FileAttrs(path, fileName, Instant.ofEpochMilli(con.getLastModified()), -1, con.getHeaderField("X-SHA256"));
try (final InputStream in = getInputStream(con)) {
fileConsumer.accept(fileAttrs, in);
}
}
return res;
}
 
// ATTN contrary to other methods, the result isn't if the request was OK : it ignores
// throwsException() and always throws. The return value is true if the file existed and was
// saved.
public boolean saveFile(final String path, final String fileName, final Path localFile) throws IOException {
final AtomicBoolean missing = new AtomicBoolean(true);
final Response res = this.getFile(path, fileName, (fileAttrs, in) -> {
missing.set(fileAttrs == null);
if (!missing.get()) {
fileAttrs.saveFile(in, localFile);
}
});
if (!res.isSuccess())
throw new IOException("Couldn't retrieve file " + fileName);
return !missing.get();
}
 
public Response deleteFile(final String path, final String fileName) throws MalformedURLException, IOException, ProtocolException, UnsupportedEncodingException {
final HttpsURLConnection con = openConnection("/delete");
return checkResponseCode(send(con, "rn=" + fileName + "&rp=" + path));
}
 
public Response sendFile(String path, File localFile) throws Exception, MalformedURLException, IOException, ProtocolException {
byte[] newsha256 = HashWriter.getHash(localFile);
long size = localFile.length();
 
final HttpsURLConnection con = openConnection("/put");
// We use Base64 because headers are not supporting UTF8
con.setRequestProperty("X_FILENAME_B64", Base64.getEncoder().encodeToString(localFile.getName().getBytes(StandardCharsets.UTF_8)));
con.setRequestProperty("X_PATH_B64", Base64.getEncoder().encodeToString(path.getBytes(StandardCharsets.UTF_8)));
con.setRequestProperty("X_FILESIZE", String.valueOf(size));
con.setRequestProperty("X_SHA256", HashWriter.bytesToHex(newsha256));
con.setRequestProperty("X-Last-Modified-ms", String.valueOf(localFile.lastModified()));
 
return checkResponseCode(send(con, Files.readAllBytes(localFile.toPath()), true));
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/TranslationManager.java
25,16 → 25,17
import java.util.Map;
import java.util.ResourceBundle.Control;
 
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
@ThreadSafe
public class TranslationManager {
private static final Locale FALLBACK_LOCALE = Locale.ENGLISH;
64,7 → 65,7
@GuardedBy("classes")
private Locale locale;
 
private final Object trMutex = new String("translations mutex");
private final Object trMutex = new Object();
@GuardedBy("trMutex")
private Map<String, String> menuTranslation;
@GuardedBy("trMutex")
73,7 → 74,7
private Map<String, String> actionTranslation;
 
private TranslationManager() {
this.classes = new ArrayList<Class<?>>();
this.classes = new ArrayList<>();
}
 
public void addTranslationStreamFromClass(Class<?> c) {
164,10 → 165,10
 
private void loadAllTranslation() {
synchronized (this.trMutex) {
this.menuTranslation = new HashMap<String, String>();
this.itemTranslation = new HashMap<String, String>();
this.actionTranslation = new HashMap<String, String>();
if (this.classes.size() == 0) {
this.menuTranslation = new HashMap<>();
this.itemTranslation = new HashMap<>();
this.actionTranslation = new HashMap<>();
if (this.classes.isEmpty()) {
Log.get().warning("TranslationManager has no resources to load (" + this.getLocale() + ")");
}
for (Class<?> c : this.classes) {
182,7 → 183,7
// return all existing (e.g fr_CA only specify differences with fr)
private List<InputStream> findStream(final Locale locale, final Class<?> c, final boolean rootLast) {
final Control cntrl = CONTROL;
final List<InputStream> res = new ArrayList<InputStream>();
final List<InputStream> res = new ArrayList<>();
final String baseName = c.getPackage().getName() + "." + BASENAME;
 
// test emptiness to not mix languages
203,7 → 204,7
// we want more specific translations to replace general ones, i.e. root Locale first
for (final InputStream input : findStream(l, c, false)) {
// create new instances to check if there's no duplicates in each resource
final Map<String, String> menuTranslation = new HashMap<String, String>(), itemTranslation = new HashMap<String, String>(), actionTranslation = new HashMap<String, String>();
final Map<String, String> menuTranslation = new HashMap<>(), itemTranslation = new HashMap<>(), actionTranslation = new HashMap<>();
loadTranslation(input, menuTranslation, itemTranslation, actionTranslation);
// on the other hand, it's OK for one resource to override another
this.menuTranslation.putAll(menuTranslation);
214,10 → 215,14
return translationLoaded;
}
 
static private void loadTranslation(final InputStream input, final Map<String, String> menuTranslation, final Map<String, String> itemTranslation, final Map<String, String> actionTranslation) {
private static void loadTranslation(final InputStream input, final Map<String, String> menuTranslation, final Map<String, String> itemTranslation, final Map<String, String> actionTranslation) {
// FIXME : l'implementation de Java est lente
// com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl : 60 ms!
// On pourrait passer à 1ms avec Piccolo...
final DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
 
try {
dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
final DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
final Document doc = dBuilder.parse(input);
// Menus
239,7 → 244,7
}
}
 
static private void loadTranslation(final Document doc, final String tagName, final Map<String, String> m) {
private static void loadTranslation(final Document doc, final String tagName, final Map<String, String> m) {
final NodeList menuChildren = doc.getElementsByTagName(tagName);
final int size = menuChildren.getLength();
for (int i = 0; i < size; i++) {
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLDecoderJDOM.java
New file
0,0 → 1,74
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.xml;
 
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.util.Iterator;
 
import org.jdom2.Element;
 
/**
* To encode and decode using {@link XMLEncoder} and {@link XMLDecoder}.
*
* @author Sylvain CUAZ
*/
public final class XMLDecoderJDOM extends AbstractXMLDecoder<Element, RuntimeException> {
 
@Override
protected String getAttributeValue(Element elem, String attrName) {
return elem.getAttributeValue(attrName);
}
 
@Override
protected String getLocalName(Element elem) {
return elem.getName();
}
 
@Override
protected String getElementText(Element elem) {
return elem.getText();
}
 
@Override
protected Element getFirstChild(Element elem) {
return elem.getChildren().get(0);
}
 
@Override
protected String toString(Element elem) {
return JDOM2Utils.output(elem);
}
 
@Override
protected Children<Element> createChildren(final Element elem) {
return new Children<Element>() {
 
private final Iterator<Element> iter = elem.getChildren().iterator();
 
@Override
public Element getNextChild() {
if (!this.iter.hasNext())
return null;
 
final Element res = this.iter.next();
assert res != null;
return res;
}
};
}
 
protected XMLDecoderJDOM() {
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/AbstractXMLDecoder.java
New file
0,0 → 1,381
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.xml;
 
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cache.ICache;
import org.openconcerto.utils.cc.ExnTransformer;
 
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
 
/**
* To decode XML in {@link XMLEncoder} format.
*
* @author Sylvain CUAZ
* @param <S> type of source
* @param <E> type of exception
*/
public abstract class AbstractXMLDecoder<S, E extends Exception> {
 
protected static interface Children<C> {
C getNextChild();
}
 
private static final ICache<Object, Method, Object> cache = new ICache<Object, Method, Object>(60, -1, "methods for " + XMLCodecUtils.class);
private static final ICache<Object, Constructor<?>, Object> cacheCtor = new ICache<Object, Constructor<?>, Object>(60, -1, "constructors for " + XMLCodecUtils.class);
 
protected abstract String getLocalName(S elem);
 
protected abstract String getAttributeValue(S elem, final String attrName);
 
protected abstract String getElementText(S elem) throws E;
 
protected abstract S getFirstChild(S elem);
 
protected abstract String toString(S elem);
 
protected abstract Children<S> createChildren(S elem) throws E;
 
public final <K, V> Map<K, V> decodeFromArray(final S elem, final Class<K> keyClass, final Class<V> valueClass) {
return XMLCodecUtils.decodeFromArray((Object[]) this.decode1(elem), keyClass, valueClass);
}
 
/**
* Tries to decode an xml element parsed from a string obtained from XMLEncoder. This doesn't
* use {@link XMLDecoder} as it requires outputting it first to string which is inefficient.
* NOTE: this decoder supports only a subset of XMLDecoder.
*
* @param javaElem a "java" element.
* @return the decoded object.
*/
public final Object decode1(S javaElem) {
final S elem = getFirstChild(javaElem);
try {
return eval(elem, new Stack<Object>(), new HashMap<String, Object>());
} catch (Exception e) {
throw new IllegalStateException("error decoding " + toString(javaElem), e);
}
}
 
private final Object eval(S elem, Stack<Object> context, final Map<String, Object> ids)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, E {
preEval(elem);
final Object res = this._eval(elem, context, ids);
postEval(elem, res);
return res;
}
 
protected void preEval(S elem) throws E {
}
 
protected void nullDecoded(S elem) throws E {
}
 
protected void idRefDecoded(S elem) throws E {
}
 
protected void postEval(S elem, final Object res) throws E {
}
 
private final Object _eval(S elem, Stack<Object> context, final Map<String, Object> ids)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, E {
final String n = getLocalName(elem);
// Ordered from real world scenario
// string : 80k
// void : 53k
// int : 18k
// object : 9k
// null : 6k
switch (n) {
case "string":
return getElementText(elem);
case "void":
case "object":
final String idref = getAttributeValue(elem, "idref");
if (idref != null) {
if (!ids.containsKey(idref))
throw new IllegalStateException("id '" + idref + "' wasn't defined");
idRefDecoded(elem);
return ids.get(idref);
}
final String id = getAttributeValue(elem, "id");
final String targetClass = getAttributeValue(elem, "class");
final Object target = targetClass == null ? context.peek() : Class.forName(targetClass);
final String propAttr = getAttributeValue(elem, "property");
final String indexAttr = getAttributeValue(elem, "index");
final String methodAttr = getAttributeValue(elem, "method");
 
// statement or expression
final Object res = evalContainer(elem, context, ids, new ExnTransformer<List<Object>, Object, Exception>() {
@Override
public Object transformChecked(List<Object> args) throws Exception {
// call the statement
final Object res;
 
if (propAttr != null) {
final String methodName = (args.size() == 0 ? "get" : "set") + StringUtils.firstUp(propAttr);
res = invoke(target, methodName, args);
} else if (indexAttr != null) {
final String methodName;
if (target instanceof List) {
methodName = args.size() == 0 ? "get" : "set";
// get(index) or set(index, value)
args.add(0, Integer.valueOf(indexAttr));
res = invoke(target, methodName, args);
} else if (target.getClass().isArray()) {
final Class<?> componentType = target.getClass().getComponentType();
// in Array there's set(array, int index, Object value) or
// setPrimitive(array, int index, primitive value)
methodName = (args.size() == 0 ? "get" : "set") + (componentType.isPrimitive() ? StringUtils.firstUp(componentType.getSimpleName()) : "");
args.add(0, target);
args.add(1, Integer.valueOf(indexAttr));
res = invoke(Array.class, methodName, args);
} else
throw new IllegalStateException("use index with neither List nor array: " + target);
} else if (methodAttr != null) {
res = invoke(target, methodAttr, args);
} else
res = getCtor((Class<?>) target, args).newInstance(args.toArray());
return res;
}
});
// not very functional but it works
if (id != null)
ids.put(id, res);
return res;
case "int":
return Integer.valueOf(getElementText(elem));
case "null":
nullDecoded(elem);
return null;
case "boolean":
return Boolean.valueOf(getElementText(elem));
case "byte":
return Byte.valueOf(getElementText(elem));
case "char":
return Character.valueOf(getElementText(elem).charAt(0));
case "short":
return Short.valueOf(getElementText(elem));
case "long":
return Long.valueOf(getElementText(elem));
case "float":
return Float.valueOf(getElementText(elem));
case "double":
return Double.valueOf(getElementText(elem));
case "array":
final String classAttr = getAttributeValue(elem, "class");
final String lengthAttr = getAttributeValue(elem, "length");
 
final Class<?> componentClass = parseClassName(classAttr);
if (lengthAttr != null) {
context.push(Array.newInstance(componentClass, Integer.parseInt(lengthAttr)));
final Children<S> children = createChildren(elem);
S child;
while ((child = children.getNextChild()) != null) {
eval(child, context, ids);
}
return context.pop();
} else {
final List<Object> items = new LinkedList<>();
final Children<S> children = createChildren(elem);
S child;
while ((child = children.getNextChild()) != null) {
items.add(eval(child, context, ids));
}
final Object resArray = Array.newInstance(componentClass, items.size());
int i = 0;
for (final Object item : items)
Array.set(resArray, i++, item);
return resArray;
}
case "class":
return Class.forName(getElementText(elem));
default:
throw new UnsupportedOperationException("doesn't yet support " + n);
}
}
 
private final Object evalContainer(final S parent, Stack<Object> context, final Map<String, Object> ids, final ExnTransformer<List<Object>, Object, ? extends Exception> transf)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, E {
final List<Object> args = new ArrayList<Object>();
final Children<S> children = createChildren(parent);
boolean noVoid = true;
S child = null;
while (noVoid && (child = children.getNextChild()) != null) {
if (getLocalName(child).equals("void"))
noVoid = false;
else {
args.add(eval(child, context, ids));
}
}
 
// call the statement
final Object res = transf.transformCheckedWithExn(args, false, InvocationTargetException.class, InstantiationException.class, IllegalAccessException.class);
 
context.push(res);
 
// now call the voids
if (child != null) {
do {
eval(child, context, ids);
} while ((child = children.getNextChild()) != null);
}
return context.pop();
}
 
private static final Object invoke(final Object target, String methodName, final List<Object> args) throws IllegalAccessException, InvocationTargetException {
// <object class="Cell" method="createEmpty" >
// for static methods the target is already a class
final Class clazz = target instanceof Class ? (Class) target : target.getClass();
final Method m = getMethod(clazz, methodName, args);
return m.invoke(target, args.toArray());
}
 
private static final Method getMethod(Class<?> clazz, String name, List<Object> actualArgs) {
final List<Class<?>> actualClasses = objectsToClasses(actualArgs);
final List<Object> key = new ArrayList<Object>(3);
key.add(clazz);
key.add(name);
key.add(actualClasses);
 
final CacheResult<Method> cacheRes = cache.check(key);
if (cacheRes.getState() == CacheResult.State.VALID)
return cacheRes.getRes();
 
final Method res = findMethod(clazz, name, actualClasses);
if (res == null)
throw new IllegalStateException("No matching method " + name + " found in " + clazz);
cache.put(key, res);
return res;
}
 
private static final Constructor getCtor(Class<?> clazz, List<Object> actualArgs) {
final List<Class<?>> actualClasses = objectsToClasses(actualArgs);
final List<Object> key = new ArrayList<Object>(3);
key.add(clazz);
key.add(actualClasses);
 
final CacheResult<Constructor<?>> cacheRes = cacheCtor.check(key);
if (cacheRes.getState() == CacheResult.State.VALID)
return cacheRes.getRes();
 
final Constructor res = findCtor(clazz, actualClasses);
cacheCtor.put(key, res);
return res;
}
 
private static final List<Class<?>> objectsToClasses(List<Object> actualArgs) {
final List<Class<?>> actualClasses = new ArrayList<Class<?>>(actualArgs.size());
for (final Object actualArg : actualArgs)
actualClasses.add(actualArg == null ? null : actualArg.getClass());
return actualClasses;
}
 
// TODO return the most specific matching method instead of the first one
// (handle both Sub/Superclass and primitive/object type)
private static final Method findMethod(Class<?> clazz, String name, List<Class<?>> actualArgs) {
for (final Method m : clazz.getMethods()) {
if (m.getName().equals(name) && callableWith(m.getParameterTypes(), actualArgs)) {
return m;
}
}
return null;
}
 
// TODO see findMethod()
private static final Constructor findCtor(Class<?> clazz, List<Class<?>> actualArgs) {
for (final Constructor m : clazz.getConstructors()) {
if (callableWith(m.getParameterTypes(), actualArgs)) {
return m;
}
}
return null;
}
 
private static final boolean callableWith(Class<?>[] formalArgs, List<Class<?>> actualArgs) {
if (formalArgs.length != actualArgs.size())
return false;
int i = 0;
for (final Class<?> argClass : formalArgs) {
final Class<?> actualArg = actualArgs.get(i);
// null match everything
if (actualArg != null && !argClass.isAssignableFrom(actualArg) && argClass != getPrimitive(actualArg))
return false;
i++;
}
 
return true;
}
 
private static Class<?> getPrimitive(Class<?> argClass) {
if (argClass == Boolean.class)
return Boolean.TYPE;
else if (argClass == Character.class)
return Character.TYPE;
else if (argClass == Byte.class)
return Byte.TYPE;
else if (argClass == Short.class)
return Short.TYPE;
else if (argClass == Integer.class)
return Integer.TYPE;
else if (argClass == Long.class)
return Long.TYPE;
else if (argClass == Float.class)
return Float.TYPE;
else if (argClass == Double.class)
return Double.TYPE;
else
return null;
}
 
private static final Map<String, Class> primitiveNames = new HashMap<String, Class>();
 
static {
primitiveNames.put("boolean", boolean.class);
primitiveNames.put("byte", byte.class);
primitiveNames.put("char", char.class);
primitiveNames.put("short", short.class);
primitiveNames.put("int", int.class);
primitiveNames.put("long", long.class);
primitiveNames.put("float", float.class);
primitiveNames.put("double", double.class);
}
 
/**
* Parse class names (including primitive).
*
* @param className a class name, eg "java.lang.String" or "int".
* @return the matching class, eg java.lang.String.class or Integer.TYPE.
* @throws ClassNotFoundException if the passed name doesn't exist.
*/
private static Class<?> parseClassName(String className) throws ClassNotFoundException {
final Class<?> primitive = primitiveNames.get(className);
if (primitive != null)
return primitive;
else
return Class.forName(className);
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLCodecUtils.java
13,11 → 13,6
package org.openconcerto.xml;
 
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cache.ICache;
import org.openconcerto.utils.cc.ExnTransformer;
 
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
35,11 → 30,8
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
47,7 → 39,6
import java.util.Map.Entry;
import java.util.RandomAccess;
import java.util.Set;
import java.util.Stack;
 
import org.jdom2.Element;
import org.jdom2.JDOMException;
62,9 → 53,6
 
private static final String END_DECL = "?>";
 
private static final ICache<Object, Method, Object> cache = new ICache<Object, Method, Object>(60, -1, "methods for " + XMLCodecUtils.class);
private static final ICache<Object, Constructor<?>, Object> cacheCtor = new ICache<Object, Constructor<?>, Object>(60, -1, "constructors for " + XMLCodecUtils.class);
 
// the same as XMLEncoder
private static final Charset CS = Charset.forName("UTF-8");
 
85,6 → 73,9
}
};
 
public static final XMLDecoderJDOM XML_DECODER_JDOM = new XMLDecoderJDOM();
public static final XMLDecoderStAX XML_DECODER_STAX = new XMLDecoderStAX();
 
/**
* Register a {@link PersistenceDelegate} for the passed class. This method tries to set
* <code>del</code> as the default for any subsequent {@link Encoder}, but with the current JRE
130,7 → 121,46
return res;
}
 
public static final String encodeAsArray(final Map<?, ?> m) {
return encodeAsArray(m, new StringBuilder(1024)).toString();
}
 
/**
* Encode a map as an array. Useful since parsing an array is faster than parsing a map.
*
* @param m the map to encode.
* @param sb where to encode.
* @return <code>sb</code>.
* @see AbstractXMLDecoder#decodeFromArray(Object, Class, Class)
*/
public static final StringBuilder encodeAsArray(final Map<?, ?> m, final StringBuilder sb) {
final Object[] array = new Object[m.size() * 2];
int i = 0;
for (final Entry<?, ?> e : m.entrySet()) {
array[i++] = e.getKey();
array[i++] = e.getValue();
}
assert i == array.length;
return encodeSimple(array, sb);
}
 
public static final <K, V> Map<K, V> decodeFromArray(final Object[] array, final Class<K> keyClass, final Class<V> valueClass) {
return decodeFromArray(array, keyClass, valueClass, null);
}
 
public static final <K, V> Map<K, V> decodeFromArray(final Object[] array, final Class<K> keyClass, final Class<V> valueClass, Map<K, V> m) {
final int l = array.length;
if (m == null)
m = new HashMap<K, V>((int) (l / 2 / 0.8f) + 1, 0.8f);
for (int i = 0; i < l; i += 2) {
final K key = keyClass.cast(array[i]);
final V value = valueClass.cast(array[i + 1]);
m.put(key, value);
}
return m;
}
 
/**
* Encodes an object using {@link XMLEncoder}, stripping the XML declaration.
*
* @param o the object to encode.
153,10 → 183,14
*/
public static final String encodeSimple(Object o) {
final StringBuilder sb = new StringBuilder(256);
return encodeSimple(o, sb).toString();
}
 
public static final StringBuilder encodeSimple(final Object o, final StringBuilder sb) {
sb.append("<java version=\"1.6.0\" class=\"java.beans.XMLDecoder\">");
encodeSimpleRec(o, sb);
sb.append("</java>");
return sb.toString();
return sb;
}
 
private static final void createElemEscaped(final String elemName, final Object o, final StringBuilder sb) {
361,287 → 395,9
* @return the decoded object.
*/
public static final Object decode1(Element javaElem) {
final Element elem = (Element) javaElem.getChildren().get(0);
try {
return eval(elem, new Stack<Object>(), new HashMap<String, Object>());
} catch (Exception e) {
throw new IllegalStateException("error decoding " + JDOM2Utils.output(javaElem), e);
}
return XML_DECODER_JDOM.decode1(javaElem);
}
 
private static final Object eval(Element elem, Stack<Object> context, final Map<String, Object> ids)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
final String n = elem.getName();
// Ordered from real world scenario
// string : 80k
// void : 53k
// int : 18k
// object : 9k
// null : 6k
if (n.equals("string")) {
return elem.getText();
} else if (n.equals("void") || n.equals("object")) {
final String idref = elem.getAttributeValue("idref");
if (idref != null) {
if (!ids.containsKey(idref))
throw new IllegalStateException("id '" + idref + "' wasn't defined");
return ids.get(idref);
}
final String id = elem.getAttributeValue("id");
final String targetClass = elem.getAttributeValue("class");
final Object target = targetClass == null ? context.peek() : Class.forName(targetClass);
final String propAttr = elem.getAttributeValue("property");
final String indexAttr = elem.getAttributeValue("index");
final String methodAttr = elem.getAttributeValue("method");
 
// statement or expression
final Object res = evalContainer(elem, context, ids, new ExnTransformer<List<Object>, Object, Exception>() {
@Override
public Object transformChecked(List<Object> args) throws Exception {
// call the statement
final Object res;
 
if (propAttr != null) {
final String methodName = (args.size() == 0 ? "get" : "set") + StringUtils.firstUp(propAttr);
res = invoke(target, methodName, args);
} else if (indexAttr != null) {
final String methodName;
if (target instanceof List) {
methodName = args.size() == 0 ? "get" : "set";
// get(index) or set(index, value)
args.add(0, Integer.valueOf(indexAttr));
res = invoke(target, methodName, args);
} else if (target.getClass().isArray()) {
final Class<?> componentType = target.getClass().getComponentType();
// in Array there's set(array, int index, Object value) or
// setPrimitive(array, int index, primitive value)
methodName = (args.size() == 0 ? "get" : "set") + (componentType.isPrimitive() ? StringUtils.firstUp(componentType.getSimpleName()) : "");
args.add(0, target);
args.add(1, Integer.valueOf(indexAttr));
res = invoke(Array.class, methodName, args);
} else
throw new IllegalStateException("use index with neither List nor array: " + target);
} else if (methodAttr != null) {
res = invoke(target, methodAttr, args);
} else
res = getCtor((Class<?>) target, args).newInstance(args.toArray());
return res;
}
});
// not very functional but it works
if (id != null)
ids.put(id, res);
return res;
} else if (n.equals("int")) {
return Integer.valueOf(elem.getText());
} else if (n.equals("null")) {
return null;
} else if (n.equals("boolean")) {
return Boolean.valueOf(elem.getText());
} else if (n.equals("byte")) {
return Byte.valueOf(elem.getText());
} else if (n.equals("char")) {
return Character.valueOf(elem.getText().charAt(0));
} else if (n.equals("short")) {
return Short.valueOf(elem.getText());
} else if (n.equals("long")) {
return Long.valueOf(elem.getText());
} else if (n.equals("float")) {
return Float.valueOf(elem.getText());
} else if (n.equals("double")) {
return Double.valueOf(elem.getText());
} else if (n.equals("array")) {
final String classAttr = elem.getAttributeValue("class");
final String lengthAttr = elem.getAttributeValue("length");
 
final Class<?> componentClass = parseClassName(classAttr);
if (lengthAttr != null) {
context.push(Array.newInstance(componentClass, Integer.parseInt(lengthAttr)));
for (final Object child : elem.getChildren()) {
eval((Element) child, context, ids);
}
return context.pop();
} else {
return evalContainer(elem, context, ids, new ExnTransformer<List<Object>, Object, RuntimeException>() {
@Override
public Object transformChecked(List<Object> args) {
final Object res = Array.newInstance(componentClass, args.size());
for (int j = 0; j < args.size(); j++) {
Array.set(res, j, args.get(j));
}
return res;
}
});
}
} else if (n.equals("class")) {
return Class.forName(elem.getText());
} else
throw new UnsupportedOperationException("doesn't yet support " + n);
}
 
private static final Object evalContainer(final Element parent, Stack<Object> context, final Map<String, Object> ids, final ExnTransformer<List<Object>, Object, ? extends Exception> transf)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
final List<Object> args = new ArrayList<Object>();
final List<?> children = parent.getChildren();
int i = 0;
boolean noVoid = true;
final int size = children.size();
while (i < size && noVoid) {
final Element child = (Element) children.get(i);
if (child.getName().equals("void"))
noVoid = false;
else {
args.add(eval(child, context, ids));
i++;
}
}
 
// call the statement
final Object res = transf.transformCheckedWithExn(args, false, InvocationTargetException.class, InstantiationException.class, IllegalAccessException.class);
 
context.push(res);
 
// now call the voids
while (i < children.size()) {
final Element child = (Element) children.get(i);
eval(child, context, ids);
i++;
}
return context.pop();
}
 
private static final Object invoke(final Object target, String methodName, final List<Object> args) throws IllegalAccessException, InvocationTargetException {
// <object class="Cell" method="createEmpty" >
// for static methods the target is already a class
final Class clazz = target instanceof Class ? (Class) target : target.getClass();
final Method m = getMethod(clazz, methodName, args);
return m.invoke(target, args.toArray());
}
 
private static final Method getMethod(Class<?> clazz, String name, List<Object> actualArgs) {
final List<Class<?>> actualClasses = objectsToClasses(actualArgs);
final List<Object> key = new ArrayList<Object>(3);
key.add(clazz);
key.add(name);
key.add(actualClasses);
 
final CacheResult<Method> cacheRes = cache.check(key);
if (cacheRes.getState() == CacheResult.State.VALID)
return cacheRes.getRes();
 
final Method res = findMethod(clazz, name, actualClasses);
cache.put(key, res);
return res;
}
 
private static final Constructor getCtor(Class<?> clazz, List<Object> actualArgs) {
final List<Class<?>> actualClasses = objectsToClasses(actualArgs);
final List<Object> key = new ArrayList<Object>(3);
key.add(clazz);
key.add(actualClasses);
 
final CacheResult<Constructor<?>> cacheRes = cacheCtor.check(key);
if (cacheRes.getState() == CacheResult.State.VALID)
return cacheRes.getRes();
 
final Constructor res = findCtor(clazz, actualClasses);
cacheCtor.put(key, res);
return res;
}
 
private static final List<Class<?>> objectsToClasses(List<Object> actualArgs) {
final List<Class<?>> actualClasses = new ArrayList<Class<?>>(actualArgs.size());
for (final Object actualArg : actualArgs)
actualClasses.add(actualArg == null ? null : actualArg.getClass());
return actualClasses;
}
 
// TODO return the most specific matching method instead of the first one
// (handle both Sub/Superclass and primitive/object type)
private static final Method findMethod(Class<?> clazz, String name, List<Class<?>> actualArgs) {
for (final Method m : clazz.getMethods()) {
if (m.getName().equals(name) && callableWith(m.getParameterTypes(), actualArgs)) {
return m;
}
}
return null;
}
 
// TODO see findMethod()
private static final Constructor findCtor(Class<?> clazz, List<Class<?>> actualArgs) {
for (final Constructor m : clazz.getConstructors()) {
if (callableWith(m.getParameterTypes(), actualArgs)) {
return m;
}
}
return null;
}
 
private static final boolean callableWith(Class<?>[] formalArgs, List<Class<?>> actualArgs) {
if (formalArgs.length != actualArgs.size())
return false;
int i = 0;
for (final Class<?> argClass : formalArgs) {
final Class<?> actualArg = actualArgs.get(i);
// null match everything
if (actualArg != null && !argClass.isAssignableFrom(actualArg) && argClass != getPrimitive(actualArg))
return false;
i++;
}
 
return true;
}
 
private static Class<?> getPrimitive(Class<?> argClass) {
if (argClass == Boolean.class)
return Boolean.TYPE;
else if (argClass == Character.class)
return Character.TYPE;
else if (argClass == Byte.class)
return Byte.TYPE;
else if (argClass == Short.class)
return Short.TYPE;
else if (argClass == Integer.class)
return Integer.TYPE;
else if (argClass == Long.class)
return Long.TYPE;
else if (argClass == Float.class)
return Float.TYPE;
else if (argClass == Double.class)
return Double.TYPE;
else
return null;
}
 
private static final Map<String, Class> primitiveNames = new HashMap<String, Class>();
 
static {
primitiveNames.put("boolean", boolean.class);
primitiveNames.put("byte", byte.class);
primitiveNames.put("char", char.class);
primitiveNames.put("short", short.class);
primitiveNames.put("int", int.class);
primitiveNames.put("long", long.class);
primitiveNames.put("float", float.class);
primitiveNames.put("double", double.class);
}
 
/**
* Parse class names (including primitive).
*
* @param className a class name, eg "java.lang.String" or "int".
* @return the matching class, eg java.lang.String.class or Integer.TYPE.
* @throws ClassNotFoundException if the passed name doesn't exist.
*/
private static Class<?> parseClassName(String className) throws ClassNotFoundException {
final Class<?> primitive = primitiveNames.get(className);
if (primitive != null)
return primitive;
else
return Class.forName(className);
}
 
private XMLCodecUtils() {
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLUtils.java
New file
0,0 → 1,133
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.xml;
 
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
 
public class XMLUtils {
 
public static final String escapeAttribute(final String value) {
final int len = value.length();
int idx = 0;
 
checkloop: while (idx < len) {
final char ch = value.charAt(idx);
if (ch == '<' || ch == '>' || ch == '&' || ch == '\r' || ch == '\n' || ch == '"' || ch == '\t') {
break checkloop;
}
idx++;
}
 
if (idx == len) {
return value;
}
 
final StringBuilder sb = new StringBuilder(len + 5);
sb.append(value, 0, idx);
while (idx < len) {
final char ch = value.charAt(idx++);
switch (ch) {
case '<':
sb.append("&lt;");
break;
case '>':
sb.append("&gt;");
break;
case '&':
sb.append("&amp;");
break;
case '\r':
sb.append("&#xD;");
break;
case '"':
sb.append("&quot;");
break;
case '\t':
sb.append("&#x9;");
break;
case '\n':
sb.append("&#xA;");
break;
default:
sb.append(ch);
break;
}
}
 
return sb.toString();
}
 
public static final String escapeText(final String value) {
final int right = value.length();
int idx = 0;
checkloop: while (idx < right) {
final char ch = value.charAt(idx);
if (ch == '<' || ch == '>' || ch == '&' || ch == '\r' || ch == '\n') {
break checkloop;
}
idx++;
}
 
if (idx == right) {
// no escape needed.
return value;
}
 
final StringBuilder sb = new StringBuilder();
if (idx > 0) {
sb.append(value, 0, idx);
}
 
while (idx < right) {
final char ch = value.charAt(idx++);
switch (ch) {
case '<':
sb.append("&lt;");
break;
case '>':
sb.append("&gt;");
break;
case '&':
sb.append("&amp;");
break;
case '\r':
sb.append("&#xD;");
break;
case '\n':
sb.append('\n');
break;
default:
sb.append(ch);
break;
}
}
return sb.toString();
}
 
public static final void skipToEndElement(final XMLStreamReader reader) throws XMLStreamException {
if (!reader.isStartElement())
throw new IllegalStateException("Not at a start of an element : " + reader.getEventType() + ", " + reader.getLocation());
final String name = reader.getLocalName();
int depth = 1;
while (!(depth == 0 && reader.isEndElement() && reader.getLocalName().equals(name))) {
final int eventType = reader.next();
if (eventType == XMLStreamConstants.START_ELEMENT)
depth++;
else if (eventType == XMLStreamConstants.END_ELEMENT)
depth--;
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLDecoderStAX.java
New file
0,0 → 1,99
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.xml;
 
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
 
/**
* To decode using {@link XMLStreamReader}.
*
* @author Sylvain CUAZ
*/
public final class XMLDecoderStAX extends AbstractXMLDecoder<XMLStreamReader, XMLStreamException> {
 
@Override
protected String getAttributeValue(XMLStreamReader elem, String attrName) {
return elem.getAttributeValue(null, attrName);
}
 
@Override
protected String getLocalName(XMLStreamReader elem) {
return elem.getLocalName();
}
 
@Override
protected String getElementText(XMLStreamReader elem) throws XMLStreamException {
return elem.getElementText();
}
 
@Override
protected XMLStreamReader getFirstChild(XMLStreamReader reader) {
try {
reader.nextTag();
} catch (XMLStreamException e) {
throw new IllegalStateException("Couldn't advance to first child", e);
}
return reader;
}
 
@Override
protected void preEval(XMLStreamReader reader) throws XMLStreamException {
assert reader.isStartElement();
}
 
@Override
protected void nullDecoded(XMLStreamReader reader) throws XMLStreamException {
reader.nextTag();
}
 
@Override
protected void idRefDecoded(XMLStreamReader reader) throws XMLStreamException {
reader.nextTag();
}
 
@Override
protected void postEval(XMLStreamReader reader, final Object res) throws XMLStreamException {
assert reader.isEndElement();
reader.nextTag();
}
 
@Override
protected String toString(XMLStreamReader elem) {
return elem.getLocation().toString();
}
 
@Override
protected Children<XMLStreamReader> createChildren(final XMLStreamReader reader) throws XMLStreamException {
if (!reader.isStartElement())
throw new IllegalStateException("Not at a start of an element : " + reader.getLocation());
final String localName = reader.getLocalName();
// move from START parent to either :
// 1. END parent if no children, or
// 2. START child
reader.nextTag();
return new Children<XMLStreamReader>() {
@Override
public XMLStreamReader getNextChild() {
if (reader.isEndElement() && reader.getLocalName().equals(localName)) {
return null;
}
return reader;
}
};
}
 
protected XMLDecoderStAX() {
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/FastXMLProperties.java
New file
0,0 → 1,71
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.xml;
 
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Properties;
 
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.input.sax.XMLReaderSAX2Factory;
 
public class FastXMLProperties {
 
public static void load(Properties props, InputStream in) throws IOException {
final SAXBuilder builder = new SAXBuilder(new XMLReaderSAX2Factory(false, "com.bluecast.xml.Piccolo"), null, null);
try {
final Document document = builder.build(new BufferedInputStream(in));
for (Element element : document.getRootElement().getChildren()) {
if (element.getName().equals("entry")) {
props.setProperty(element.getAttributeValue("key"), element.getText());
}
}
} catch (Exception e) {
throw new IOException(e);
}
 
}
 
/**
* Fast alternative (<1ms) for Properties.storeToXML (30ms)
*
*/
public static void store(Properties props, OutputStream out, String comment) throws IOException {
PrintStream prt = new PrintStream(out, false, "UTF-8");
prt.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n");
prt.append("<properties>\\r\n");
if (comment != null) {
prt.append("<comment>");
prt.append(comment);
prt.append("</comment>\\r\n");
}
synchronized (props) {
for (String k : props.stringPropertyNames()) {
prt.append("<entry key=\"");
prt.append(XMLUtils.escapeAttribute(k));
prt.append("\">");
prt.append(XMLUtils.escapeText(props.getProperty(k)));
prt.append("</entry>\\r\n");
}
}
prt.append("</properties>");
prt.close();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/compta/ExportFEC.java
42,10 → 42,10
 
public class ExportFEC extends AbstractExport {
 
private static final char ZONE_SEPARATOR = '\t';
private static final char RECORD_SEPARATOR = '\n';
public static final char ZONE_SEPARATOR = '\t';
public static final char RECORD_SEPARATOR = '\n';
private static final char REPLACEMENT = ' ';
static private final List<String> COLS = Arrays.asList("JournalCode", "JournalLib", "EcritureNum", "EcritureDate", "CompteNum", "CompteLib", "CompAuxNum", "CompAuxLib", "PieceRef", "PieceDate",
public static final List<String> COLS = Arrays.asList("JournalCode", "JournalLib", "EcritureNum", "EcritureDate", "CompteNum", "CompteLib", "CompAuxNum", "CompAuxLib", "PieceRef", "PieceDate",
"EcritureLib", "Debit", "Credit", "EcritureLet", "DateLet", "ValidDate", "Montantdevise", "Idevise");
 
private final DecimalFormat format = new DecimalFormat("##0.00", DecimalFormatSymbols.getInstance(Locale.FRANCE));
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/compta/ExportPanel.java
87,6 → 87,12
return new ExportSageXimport(root);
}
},
SAGE_ETENDU("Sage Etendu") {
@Override
public AbstractExport createExport(DBRoot root) {
return new ExportSageEtendu(root);
}
},
CCMX("Cegid CCMX") {
@Override
public AbstractExport createExport(DBRoot root) {
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/compta/ExportSageEtendu.java
New file
0,0 → 1,359
/*
* 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.panel.compta;
 
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.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.GestionDevise;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.io.IOException;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Row;
 
public class ExportSageEtendu extends AbstractExport {
 
private List<SQLRowValues> data;
private Map<Integer, SQLRowValues> mapFacture = new HashMap<>();
private Map<Integer, SQLRowValues> mapAvoir = new HashMap<>();
 
public ExportSageEtendu(DBRoot rootSociete) {
super(rootSociete, "Sage Etendu", ".xls");
}
 
@Override
protected int fetchData(Date from, Date to, SQLRow selectedJournal, boolean onlyNew) {
 
final SQLTable tableEcriture = getEcritureT();
 
// Fetch facture
final SQLTable tableVF = tableEcriture.getTable("SAISIE_VENTE_FACTURE");
SQLRowValues rowValsVF = new SQLRowValues(tableVF);
rowValsVF.put("ID", null);
rowValsVF.put("DATE", null);
rowValsVF.put("NOM", null);
rowValsVF.put("NUMERO", null);
 
SQLRowValues rowValsMdr = rowValsVF.putRowValues("ID_MODE_REGLEMENT");
 
rowValsMdr.putNulls(rowValsMdr.getTable().getFieldsName());
rowValsMdr.putRowValues("ID_TYPE_REGLEMENT").putNulls("NOM");
 
if (tableVF.contains("ID_ABONNEMENT")) {
rowValsVF.putRowValues("ID_ABONNEMENT").putNulls("DATE_DEBUT_FACTURE", "DATE_FIN_FACTURE");
}
SQLRowValuesListFetcher fetcherVF = SQLRowValuesListFetcher.create(rowValsVF);
List<SQLRowValues> resultVF = fetcherVF.fetch(new Where(tableVF.getField("DATE"), from, to));
 
for (SQLRowValues sqlRowValues : resultVF) {
this.mapFacture.put(sqlRowValues.getID(), sqlRowValues);
}
 
// Fetch avoirs
final SQLTable tableAvoir = tableEcriture.getTable("AVOIR_CLIENT");
SQLRowValues rowValsAvoir = new SQLRowValues(tableAvoir);
rowValsAvoir.put("ID", null);
rowValsAvoir.put("DATE", null);
rowValsAvoir.put("NOM", null);
rowValsAvoir.put("NUMERO", null);
SQLRowValues rowValsMdrAvoir = rowValsAvoir.putRowValues("ID_MODE_REGLEMENT");
 
rowValsMdrAvoir.putNulls(rowValsMdrAvoir.getTable().getFieldsName());
rowValsMdrAvoir.putRowValues("ID_TYPE_REGLEMENT").putNulls("NOM");
 
SQLRowValuesListFetcher fetcherAvoir = SQLRowValuesListFetcher.create(rowValsAvoir);
List<SQLRowValues> resultAvoir = fetcherAvoir.fetch(new Where(tableAvoir.getField("DATE"), from, to));
 
for (SQLRowValues sqlRowValues : resultAvoir) {
this.mapAvoir.put(sqlRowValues.getID(), sqlRowValues);
}
 
final SQLTable tableCompte = tableEcriture.getForeignTable("ID_COMPTE_PCE");
 
SQLRowValues rowValsFetch = new SQLRowValues(tableEcriture);
rowValsFetch.putNulls("NOM", "DATE", "DEBIT", "CREDIT");
if (tableEcriture.contains("CODE_CLIENT")) {
rowValsFetch.put("CODE_CLIENT", null);
}
 
rowValsFetch.putRowValues("ID_MOUVEMENT").putNulls("NUMERO", "SOURCE", "IDSOURCE").putRowValues("ID_PIECE").put("NOM", null);
 
rowValsFetch.putRowValues("ID_COMPTE_PCE").putNulls("NUMERO", "NOM");
rowValsFetch.putRowValues("ID_JOURNAL").putNulls("CODE", "NOM");
 
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsFetch);
fetcher.addSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
 
@Override
public SQLSelect transformChecked(SQLSelect input) {
input.setWhere(getWhere(from, to, selectedJournal, onlyNew));
input.addFieldOrder(input.getAlias(tableEcriture).getField("ID_MOUVEMENT"));
input.addFieldOrder(input.getAlias(tableCompte).getField("NUMERO"));
return input;
}
}, 0);
 
final List<SQLRowValues> l = fetcher.fetch();
this.data = l;
return l == null ? 0 : l.size();
}
 
@Override
protected void export(OutputStream bufOut) throws IOException {
final List<SQLRowValues> l = this.data;
final boolean containsCodeClient = getEcritureT().contains("CODE_CLIENT");
final int size = l.size();
 
HSSFWorkbook workBook = new HSSFWorkbook();
HSSFSheet sheet = workBook.createSheet("Ecritures");
Row rowEntete = sheet.createRow(0);
List<String> colName = Arrays.asList("Date d'écriture", "Code Journal", "Numéro de facture", "Référence", "Compte Général", "Compte Client", "Libellé de l'écriture", "Date d'échéance",
"Mode de règlement", "Montant débiteur", "Montant Créditeur", "Date de début d'abonnement", "Date de fin d'abonnement");
int colIndex = 0;
for (String string : colName) {
Cell cell = rowEntete.createCell(colIndex, CellType.STRING);
cell.setCellValue(string);
colIndex++;
}
 
CellStyle cellStyle = workBook.createCellStyle();
CreationHelper createHelper = workBook.getCreationHelper();
cellStyle.setDataFormat(createHelper.createDataFormat().getFormat("m/d/yy"));
 
for (int i = 0; i < size; i++) {
 
Row row = sheet.createRow(i + 1);
 
final SQLRowValues rowLine = l.get(i);
 
// Date
final Date d = rowLine.getDate("DATE").getTime();
Cell cellDate = row.createCell(0);
cellDate.setCellStyle(cellStyle);
cellDate.setCellValue(d);
// Jrnl
SQLRowAccessor rowJrnl = rowLine.getForeign("ID_JOURNAL");
Cell cellJrnl = row.createCell(1);
cellJrnl.setCellValue(StringUtils.toAsciiString(rowJrnl.getString("CODE").trim()));
 
SQLRowAccessor rowValsSource = null;
SQLRowAccessor rowMvt = rowLine.getForeign("ID_MOUVEMENT");
if (rowMvt.getString("SOURCE").equals("AVOIR_CLIENT")) {
rowValsSource = this.mapAvoir.get(rowMvt.getInt("IDSOURCE"));
} else if (rowMvt.getString("SOURCE").equals("SAISIE_VENTE_FACTURE")) {
rowValsSource = this.mapFacture.get(rowMvt.getInt("IDSOURCE"));
}
 
// Numero Piece
Cell cellPiece = row.createCell(2);
if (rowValsSource != null) {
cellPiece.setCellValue(StringUtils.toAsciiString(rowValsSource.getString("NUMERO")));
}
 
// Ref vide
Cell cellRef = row.createCell(3);
cellRef.setCellValue("");
 
// N° Compte
final String cpt = rowLine.getForeign("ID_COMPTE_PCE").getString("NUMERO").trim();
Cell cellCpt = row.createCell(4, CellType.STRING);
cellCpt.setCellValue(getFormattedCompte(cpt));
 
Cell cellCodeClient = row.createCell(5);
if (containsCodeClient) {
// Code Client
String codeClient = "";
if (cpt.startsWith("41")) {
codeClient = rowLine.getString("CODE_CLIENT");
}
cellCodeClient.setCellValue(StringUtils.toAsciiString(codeClient));
}
 
// Libellé
Cell cellLib = row.createCell(6);
cellLib.setCellValue(StringUtils.toAsciiString(rowLine.getString("NOM").trim()));
 
Cell cellDateEch = row.createCell(7);
Cell cellTypeRegl = row.createCell(8);
if (rowValsSource != null && cpt.startsWith("41")) {
final SQLRowAccessor foreignMdr = rowValsSource.getForeign("ID_MODE_REGLEMENT");
Date ech = ModeDeReglementSQLElement.calculDate(foreignMdr, rowValsSource.getDate("DATE").getTime());
cellDateEch.setCellValue(ech);
cellDateEch.setCellStyle(cellStyle);
cellTypeRegl.setCellValue(foreignMdr.getForeign("ID_TYPE_REGLEMENT").getString("NOM"));
}
 
// Debit
Cell cellDebit = row.createCell(9);
final Long debit = rowLine.getLong("DEBIT");
cellDebit.setCellValue(debit / 100.0D);
// Credit
final Long credit = rowLine.getLong("CREDIT");
Cell cellCredit = row.createCell(10);
cellCredit.setCellValue(credit / 100.0D);
 
Cell cellDebAbo = row.createCell(11);
Cell cellFinAbo = row.createCell(12);
 
if (rowValsSource != null && rowValsSource.contains("ID_ABONNEMENT") && rowValsSource.getTable().getName().equals("ID_SAISIE_VENTE_FACTURE") && cpt.startsWith("41")) {
SQLRowAccessor rowValsAbo = rowValsSource.getForeign("ID_ABONNEMENT");
if (rowValsAbo != null && !rowValsAbo.isUndefined()) {
final Calendar calDeb = rowValsAbo.getDate("DATE_DEBUT_FACTURE");
if (calDeb != null) {
cellDebAbo.setCellValue(calDeb.getTime());
cellDebAbo.setCellStyle(cellStyle);
}
 
final Calendar calFin = rowValsAbo.getDate("DATE_FIN_FACTURE");
if (calFin != null) {
cellFinAbo.setCellValue(calFin.getTime());
cellFinAbo.setCellStyle(cellStyle);
}
}
}
 
}
workBook.write(bufOut);
workBook.close();
}
 
private void exportTAB(OutputStream bufOut) throws IOException {
final List<SQLRowValues> l = this.data;
final boolean containsCodeClient = getEcritureT().contains("CODE_CLIENT");
final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
final int size = l.size();
for (int i = 0; i < size; i++) {
 
// Ligne à insérer dans le fichier
final StringBuilder line = new StringBuilder();
 
final SQLRowValues rowLine = l.get(i);
 
// Date
final Date d = rowLine.getDate("DATE").getTime();
line.append(dateFormat.format(d));
line.append('\t');
// Jrnl
SQLRowAccessor rowJrnl = rowLine.getForeign("ID_JOURNAL");
line.append(StringUtils.toAsciiString(rowJrnl.getString("CODE").trim()));
line.append('\t');
 
SQLRowAccessor rowValsSource = null;
SQLRowAccessor rowMvt = rowLine.getForeign("ID_MOUVEMENT");
if (rowMvt.getString("SOURCE").equals("AVOIR_CLIENT")) {
rowValsSource = this.mapAvoir.get(rowMvt.getInt("IDSOURCE"));
} else if (rowMvt.getString("SOURCE").equals("SAISIE_VENTE_FACTURE")) {
rowValsSource = this.mapFacture.get(rowMvt.getInt("IDSOURCE"));
}
 
// Numero Piece
if (rowValsSource != null) {
line.append(StringUtils.toAsciiString(rowValsSource.getString("NUMERO")));
}
line.append('\t');
 
// Référence
// if (rowValsSource != null) {
// line.append(StringUtils.toAsciiString(rowValsSource.getString("NOM")));
// }
line.append('\t');
 
// N° Compte
final String cpt = rowLine.getForeign("ID_COMPTE_PCE").getString("NUMERO").trim();
line.append(getFormattedCompte(cpt));
line.append('\t');
 
if (containsCodeClient) {
// Code Client
String codeClient = "";
if (cpt.startsWith("41")) {
codeClient = rowLine.getString("CODE_CLIENT");
}
line.append(StringUtils.toAsciiString(codeClient));
line.append('\t');
}
 
// Libellé
line.append(StringUtils.toAsciiString(rowLine.getString("NOM").trim()));
line.append('\t');
 
if (rowValsSource != null && cpt.startsWith("41")) {
final SQLRowAccessor foreignMdr = rowValsSource.getForeign("ID_MODE_REGLEMENT");
Date ech = ModeDeReglementSQLElement.calculDate(foreignMdr, rowValsSource.getDate("DATE").getTime());
line.append(dateFormat.format(ech));
line.append('\t');
line.append(foreignMdr.getForeign("ID_TYPE_REGLEMENT").getString("NOM"));
line.append('\t');
} else {
line.append('\t');
line.append('\t');
}
 
// Debit
final Long debit = rowLine.getLong("DEBIT");
line.append(GestionDevise.currencyToString(debit.longValue(), false));
line.append('\t');
// Credit
final Long credit = rowLine.getLong("CREDIT");
line.append(GestionDevise.currencyToString(credit.longValue(), false));
line.append('\t');
 
if (rowValsSource != null && rowValsSource.contains("ID_ABONNEMENT") && rowValsSource.getTable().getName().equals("ID_SAISIE_VENTE_FACTURE") && cpt.startsWith("41")) {
SQLRowAccessor rowValsAbo = rowValsSource.getForeign("ID_ABONNEMENT");
if (rowValsAbo != null && !rowValsAbo.isUndefined()) {
final Calendar calDeb = rowValsAbo.getDate("DATE_DEBUT_FACTURE");
if (calDeb != null) {
line.append(dateFormat.format(calDeb.getTime()));
}
line.append('\t');
final Calendar calFin = rowValsAbo.getDate("DATE_FIN_FACTURE");
if (calFin != null) {
line.append(dateFormat.format(calFin.getTime()));
}
line.append('\t');
}
} else {
line.append('\t');
line.append('\t');
}
 
line.append('\r');
line.append('\n');
bufOut.write(line.toString().getBytes(StringUtils.Cp1252));
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/compta/ImportRImport.java
New file
0,0 → 1,190
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.panel.compta;
 
import org.openconcerto.erp.generationEcritures.Ecriture;
import org.openconcerto.erp.generationEcritures.Exercice;
import org.openconcerto.erp.generationEcritures.Mouvement;
import org.openconcerto.erp.generationEcritures.Piece;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.users.User;
import org.openconcerto.utils.StringUtils;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.sql.SQLException;
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 ImportRImport {
private String error = null;
private final Map<String, Piece> mapPiece = new HashMap<>();
private final Map<String, String> mapJournal = new HashMap<>();
 
/**
* Import format Ciel.
*
* Une pièce par journal
*
*/
public ImportRImport() {
//
}
 
public void loadFrom(File file) throws IOException {
this.mapPiece.clear();
this.mapJournal.clear();
this.error = null;
parseJournaux(file);
try (BufferedReader bReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("Cp1252")))) {
String line = bReader.readLine();
while (!(line.startsWith("##Section") && line.contains("Mvt"))) {
line = bReader.readLine();
}
line = bReader.readLine();
while (line != null && !line.contains("#Section")) {
final List<String> parts = StringUtils.fastSplit(line, '\t');
final String journalCode = unquote(parts.get(1).trim());
final Date ecritureDate = parseDate(unquote(parts.get(2).trim()));
final String compteNum = unquote(parts.get(3).trim());
final String compteLib = unquote(parts.get(4).trim());
final BigDecimal m = new BigDecimal(cleanMontant(parts.get(5)));
BigDecimal debit = BigDecimal.ZERO;
BigDecimal credit = BigDecimal.ZERO;
if (parts.get(6).equalsIgnoreCase("D")) {
debit = m;
} else {
credit = m;
}
final String valid = parts.get(7);
Date validDate = null;
if (valid.equalsIgnoreCase("V")) {
validDate = ecritureDate;
}
final String ecritureLib = unquote(parts.get(8).trim());
final String pieceRef = "Import " + journalCode;
Piece p = this.mapPiece.get(pieceRef);
Mouvement mouvement;
if (p == null) {
p = new Piece(pieceRef);
mouvement = new Mouvement();
p.add(mouvement);
 
} else {
mouvement = p.getMouvements().get(0);
}
final Ecriture ecriture = new Ecriture(ecritureDate, debit, credit);
ecriture.setNom(ecritureLib);
ecriture.setCompte(compteNum, compteLib);
final String journal = getJournal(journalCode);
if (journal == null) {
this.error = "Pas de journal trouvé pour le code journal : " + journalCode;
return;
}
ecriture.setJournal(journalCode, journal);
ecriture.setDateValidation(validDate);
if ("AN".equals(journalCode)) {
ecriture.setaNouveau(true);
}
mouvement.add(ecriture);
 
// Next
line = bReader.readLine();
}
 
}
}
 
private String unquote(String str) {
if (str.length() < 3) {
return str;
}
return str.substring(1, str.length() - 1);
}
 
private void parseJournaux(File file) throws IOException {
try (BufferedReader bReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("Cp1252")))) {
String line = bReader.readLine();
while (!(line.startsWith("##Section") && line.contains("Jnl"))) {
line = bReader.readLine();
}
line = bReader.readLine();
while (line != null && !line.contains("#Section")) {
final List<String> parts = StringUtils.fastSplit(line, '\t');
this.mapJournal.put(unquote(parts.get(0)), unquote(parts.get(1)));
// Next
line = bReader.readLine();
}
}
 
}
 
private String getJournal(String journalCode) {
return this.mapJournal.get(journalCode);
}
 
private String cleanMontant(String str) {
final int l = str.length();
final StringBuilder b = new StringBuilder(l);
for (int i = 0; i < l; i++) {
final char c = str.charAt(i);
if (Character.isDigit(c)) {
b.append(c);
} else if (c == ',') {
b.append('.');
}
}
return b.toString();
}
 
private Date parseDate(String str) {
if (str.length() != 10) {
return null;
}
final Calendar c = Calendar.getInstance();
 
final int day = Integer.parseInt(str.substring(0, 2));
final int month = Integer.parseInt(str.substring(3, 5));
final int year = Integer.parseInt(str.substring(6, 10));
c.set(year, month - 1, day, 0, 0, 0);
return c.getTime();
}
 
// return null is no error
public String getError() {
return this.error;
}
 
public void importTo(SQLElementDirectory directory, DBRoot rootSociete, User user) throws SQLException {
Exercice e = new Exercice();
e.insert(directory, rootSociete, user, new ArrayList<Piece>(this.mapPiece.values()));
}
 
public static void main(String[] args) throws IOException {
ImportRImport i = new ImportRImport();
i.loadFrom(new File("Y:\\Projets\\OpenConcerto\\ExportCiel\\RImport.txt"));
System.err.println("ImportRImport.main()" + i.getError());
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/compta/ImportFEC.java
New file
0,0 → 1,164
/*
* 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.panel.compta;
 
import org.openconcerto.erp.generationEcritures.Ecriture;
import org.openconcerto.erp.generationEcritures.Exercice;
import org.openconcerto.erp.generationEcritures.Mouvement;
import org.openconcerto.erp.generationEcritures.Piece;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.users.User;
import org.openconcerto.utils.StringUtils;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.sql.SQLException;
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 ImportFEC {
private String error = null;
private Map<String, Piece> mapPiece = new HashMap<>();
 
public ImportFEC() {
//
}
 
public void loadFrom(File file) throws IOException {
this.error = null;
this.mapPiece = null;
 
try (BufferedReader bReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("Cp1252")))) {
String line = bReader.readLine();
final List<String> headers = StringUtils.fastSplit(line, ExportFEC.ZONE_SEPARATOR);
for (int i = 0; i < headers.size(); i++) {
String c1 = headers.get(i);
String c2 = ExportFEC.COLS.get(i);
// Typo chez les stars de Ciel : MontantDevise au lieu de Montantdevise
if (!c1.equalsIgnoreCase(c2)) {
this.error = "L'entête de la colonne " + (i + 1) + " : " + c1 + " n'est pas " + c2;
return;
}
}
line = bReader.readLine();
while (line != null) {
final List<String> parts = fastSplit(line, ExportFEC.ZONE_SEPARATOR);
final String journalCode = parts.get(0).trim();
final String journalLib = parts.get(1).trim();
// final String ecritureNum = parts.get(2).trim();
final Date ecritureDate = parseDate(parts.get(3).trim());
final String compteNum = parts.get(4).trim();
final String compteLib = parts.get(5).trim();
// final String compAuxNum = parts.get(6).trim();
// final String compAuxLib = parts.get(7).trim();
String pieceRef = parts.get(8).trim();
// final String pieceDate = parts.get(9).trim();
final String ecritureLib = parts.get(10).trim();
final BigDecimal debit = new BigDecimal(parts.get(11).replace(',', '.'));
final BigDecimal credit = new BigDecimal(parts.get(12).replace(',', '.'));
final String ecritureLet = parts.get(13).trim();
final Date dateLet = parseDate(parts.get(14).trim());
final Date validDate = parseDate(parts.get(15).trim());
// final String montantdevise = parts.get(16).trim();
// final String idevise = parts.get(17).trim();
 
if (pieceRef.isEmpty()) {
pieceRef = "Import";
}
Piece p = this.mapPiece.get(pieceRef);
Mouvement mouvement;
if (p == null) {
p = new Piece(pieceRef);
mouvement = new Mouvement();
p.add(mouvement);
 
} else {
mouvement = p.getMouvements().get(0);
}
final Ecriture ecriture = new Ecriture(ecritureDate, debit, credit);
ecriture.setNom(ecritureLib);
ecriture.setCompte(compteNum, compteLib);
ecriture.setJournal(journalCode, journalLib);
ecriture.setDateValidation(validDate);
ecriture.setDateLettrage(dateLet);
ecriture.setLettrage(ecritureLet);
if ("AN".equals(journalCode)) {
ecriture.setaNouveau(true);
}
mouvement.add(ecriture);
 
// Next
line = bReader.readLine();
}
 
}
}
 
private Date parseDate(String str) {
if (str.length() != 8) {
return null;
}
final Calendar c = Calendar.getInstance();
final int year = Integer.parseInt(str.substring(0, 4));
final int month = Integer.parseInt(str.substring(4, 6));
final int day = Integer.parseInt(str.substring(6, 8));
c.set(year, month - 1, day, 0, 0, 0);
return c.getTime();
}
 
// return null is no error
public String getError() {
return this.error;
}
 
public void importTo(SQLElementDirectory directory, DBRoot rootSociete, User user) throws SQLException {
final Exercice e = new Exercice();
e.insert(directory, rootSociete, user, new ArrayList<Piece>(this.mapPiece.values()));
}
 
public static void main(String[] args) throws IOException {
final ImportFEC i = new ImportFEC();
i.loadFrom(new File("Y:\\Projets\\OpenConcerto\\ExportCiel\\FEC20171231.txt"));
System.err.println("ImportFEC.main()" + i.getError());
}
 
public static final List<String> fastSplit(final String string, final char sep) {
final List<String> l = new ArrayList<>();
final int length = string.length();
final char[] cars = string.toCharArray();
int rfirst = 0;
 
for (int i = 0; i < length; i++) {
if (cars[i] == sep) {
l.add(new String(cars, rfirst, i - rfirst));
rfirst = i + 1;
}
}
if (rfirst <= length) {
// <= au lieu de < pour Ciel....
l.add(new String(cars, rfirst, length - rfirst));
}
return l;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/model/MouseSheetXmlListeListener.java
14,6 → 14,8
package org.openconcerto.erp.model;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.customerrelationship.mail.EmailTemplate;
import org.openconcerto.erp.core.customerrelationship.mail.ValueListener;
import org.openconcerto.erp.generationDoc.AbstractSheetXml;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLBase;
27,6 → 29,7
import org.openconcerto.ui.EmailComposer;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.awt.event.ActionEvent;
import java.io.File;
112,13 → 115,13
this.showHeader = showHeader;
}
 
protected void sendMail(final AbstractSheetXml sheet, final boolean readOnly) {
protected void sendMail(EmailTemplate template, final AbstractSheetXml sheet, final boolean readOnly) {
List<AbstractSheetXml> l = new ArrayList<>(1);
l.add(sheet);
sendMail(l, readOnly);
sendMail(template, l, readOnly);
}
 
protected void sendMail(final List<AbstractSheetXml> sheets, final boolean readOnly) {
protected void sendMail(EmailTemplate template, final List<AbstractSheetXml> sheets, final boolean readOnly) {
final Thread t = new Thread() {
@Override
public void run() {
231,6 → 234,10
public void run() {
try {
String subject = sheets.get(0).getReference();
if (template != null) {
subject = template.getTitle() + " " + sheets.get(0).getReference().trim();
}
subject = subject.trim();
if (subject.isEmpty()) {
final StringJoiner joiner = new StringJoiner(", ");
for (File f : files) {
238,7 → 245,14
}
subject = joiner.toString();
}
final String message = getMailObject(sheets.get(0).getSQLRow());
String message = getMailObject(sheets.get(0).getSQLRow());
if (template != null) {
if (template.getText().contains("{message}")) {
message = template.getText().replace("{message}", message);
} else {
message += template.getText();
}
}
EmailComposer.getInstance().compose(mailDest, subject, message, files.toArray(new File[files.size()]));
} catch (Exception e) {
ExceptionHandler.handle("Impossible d'envoyer le courriel!", e);
286,11 → 300,27
 
}
} else {
// ODS Viewer
if (this.previewIsVisible) {
l.add(new RowAction(new AbstractAction() {
public void actionPerformed(ActionEvent ev) {
try {
createAbstractSheet(IListe.get(ev).fetchSelectedRow()).showPreviewDocument();
final AbstractSheetXml sheet = createAbstractSheet(IListe.get(ev).fetchSelectedRow());
final SQLTable table = IListe.get(ev).getSource().getPrimaryTable();
sheet.showPreviewDocument(TranslationManager.getInstance().getTranslationForAction("email"), new Runnable() {
 
@Override
public void run() {
EmailTemplate.askTemplate(IListe.get(ev), table.getDBRoot(), new ValueListener() {
 
@Override
public void valueSelected(Object value) {
sendMail((EmailTemplate) value, sheet, true);
}
});
 
}
});
} catch (Exception e) {
ExceptionHandler.handle("Impossible d'ouvrir le fichier", e);
}
388,13 → 418,7
public RowAction getSendMail() {
return new RowAction(new AbstractAction() {
public void actionPerformed(ActionEvent ev) {
final List<SQLRowValues> selectedRows = IListe.get(ev).getSelectedRows();
final SQLTable table = IListe.get(ev).getSource().getPrimaryTable();
final List<SQLRow> rows = new ArrayList<SQLRow>();
for (SQLRowValues r : selectedRows) {
rows.add(table.getRow(r.getID()));
}
sendMail(createAbstractSheets(rows), false);
sendMail(ev, false);
}
}, false, "document.send.email") {
 
411,17 → 435,7
public RowAction getSendMailPDF() {
return new RowAction(new AbstractAction() {
public void actionPerformed(ActionEvent ev) {
try {
final List<SQLRowValues> selectedRows = IListe.get(ev).getSelectedRows();
final SQLTable table = IListe.get(ev).getSource().getPrimaryTable();
final List<SQLRow> rows = new ArrayList<SQLRow>();
for (SQLRowValues r : selectedRows) {
rows.add(table.getRow(r.getID()));
}
sendMail(createAbstractSheets(rows), true);
} catch (Exception e) {
ExceptionHandler.handle("Impossible d'envoyer le(s) fichier(s)", e);
}
sendMail(ev, true);
}
}, false, "document.pdf.send.email") {
 
496,4 → 510,21
}
};
}
 
private void sendMail(ActionEvent ev, boolean pdf) {
final List<SQLRowValues> selectedRows = IListe.get(ev).getSelectedRows();
final SQLTable table = IListe.get(ev).getSource().getPrimaryTable();
final List<SQLRow> rows = new ArrayList<>();
for (SQLRowValues r : selectedRows) {
rows.add(table.getRow(r.getID()));
}
 
EmailTemplate.askTemplate(IListe.get(ev), table.getDBRoot(), new ValueListener() {
 
@Override
public void valueSelected(Object value) {
sendMail((EmailTemplate) value, createAbstractSheets(rows), pdf);
}
});
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/importer/DataImporter.java
13,17 → 13,15
package org.openconcerto.erp.importer;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.openoffice.spreadsheet.Sheet;
import org.openconcerto.openoffice.spreadsheet.SpreadSheet;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesCluster.StoreMode;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.utils.ooxml.XLSXDocument;
import org.openconcerto.utils.ooxml.XLSXSheet;
import org.openconcerto.utils.text.CSVReader;
import org.openconcerto.utils.text.CSVWriter;
import org.openconcerto.utils.text.CharsetHelper;
51,6 → 49,7
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
59,13 → 58,13
public class DataImporter {
private boolean skipFirstLine = true;
private SQLTable table;
private final Map<Integer, ValueConverter> map = new HashMap<Integer, ValueConverter>();
private final Map<SQLField, List<Integer>> fieldMap = new HashMap<SQLField, List<Integer>>();
private final Map<Integer, Constraint> constraints = new HashMap<Integer, Constraint>();
private List<SQLField> uniqueField = new ArrayList<SQLField>();
private List<SQLRowValues> valuesToUpdate = new ArrayList<SQLRowValues>();
private List<SQLRowValues> valuesToInsert = new ArrayList<SQLRowValues>();
private Map<ValueConverter, SQLField> foreignMap = new HashMap<ValueConverter, SQLField>();
private final Map<Integer, ValueConverter> map = new HashMap<>();
private final Map<SQLField, List<Integer>> fieldMap = new HashMap<>();
private final Map<Integer, Constraint> constraints = new HashMap<>();
private List<SQLField> uniqueField = new ArrayList<>();
private List<SQLRowValues> valuesToUpdate = new ArrayList<>();
private List<SQLRowValues> valuesToInsert = new ArrayList<>();
private Map<ValueConverter, SQLField> foreignMap = new HashMap<>();
 
public DataImporter() {
}
78,43 → 77,6
this.table = table;
}
 
public static void main(String[] args) throws Exception {
System.setProperty(SQLBase.STRUCTURE_USE_XML, "true");
final ComptaPropsConfiguration conf = ComptaPropsConfiguration.create();
Configuration.setInstance(conf);
try {
conf.getBase();
} catch (Exception e) {
e.printStackTrace();
}
 
final ComptaPropsConfiguration comptaPropsConfiguration = ((ComptaPropsConfiguration) Configuration.getInstance());
comptaPropsConfiguration.setUpSocieteDataBaseConnexion(39);
UserManager.getInstance().setCurrentUser(2);
 
SQLTable table = Configuration.getInstance().getRoot().findTable("ARTICLE");
DataImporter importer = new DataImporter(table);
importer.skipFirstLine = false;
importer.map(0, table.getField("CODE"));
importer.map(8, table.getField("ID_FOURNISSEUR"));
importer.map(4, table.getField("NOM"));
importer.addContraint(0, new NotEmptyConstraint());
importer.addUniqueField(table.getField("CODE"));
// ArrayTableModel m = importer.createModelFromODS(new File("c:/products-en.ods"));
// ArrayTableModel m = importer.createModelFromCSV(new File("c:/products-en.csv"));
// ArrayTableModel m = importer.createModelFromCSV(new File("c:/products-en.scsv.csv"));
ArrayTableModel m = importer.createModelFromXLS(new File("c:/products-en.xls"), 0);
m.dump(0, 4);
m = importer.createConvertedModel(m);
System.out.println("Dump");
m.dump(0, 4);
importer.importFromModel(m);
System.out.println(importer.getValuesToInsert().size() + " rows to insert");
System.out.println(importer.getValuesToUpdate().size() + " rows to update");
// importer.commit();
 
}
 
public void commit() throws SQLException {
for (SQLRowValues row : this.valuesToInsert) {
row.getGraph().store(StoreMode.INSERT, false);
126,11 → 88,11
}
 
public List<SQLRowValues> getValuesToInsert() {
return valuesToInsert;
return this.valuesToInsert;
}
 
public List<SQLRowValues> getValuesToUpdate() {
return valuesToUpdate;
return this.valuesToUpdate;
}
 
public void addUniqueField(SQLField field) {
142,7 → 104,7
}
 
public void addContraint(int columnIndex, Constraint c) {
constraints.put(Integer.valueOf(columnIndex), c);
this.constraints.put(Integer.valueOf(columnIndex), c);
}
 
public void map(int columnIndex, SQLField field) {
156,17 → 118,17
public void map(int columnIndex, SQLField field, SQLField foreignField) {
final ValueConverter converter = new ValueConverter(foreignField);
map(columnIndex, foreignField, converter);
foreignMap.put(converter, field);
this.foreignMap.put(converter, field);
 
}
 
public void map(int columnIndex, SQLField field, ValueConverter converter) {
final Integer value = Integer.valueOf(columnIndex);
map.put(value, converter);
List<Integer> l = fieldMap.get(field);
this.map.put(value, converter);
List<Integer> l = this.fieldMap.get(field);
if (l == null) {
l = new ArrayList<Integer>();
fieldMap.put(field, l);
l = new ArrayList<>();
this.fieldMap.put(field, l);
} else if (!field.getType().getJavaType().equals(String.class)) {
throw new IllegalArgumentException("Mapping multiple column is only supoprted for String values");
}
195,12 → 157,12
}
}
int start = 0;
if (skipFirstLine) {
if (this.skipFirstLine) {
start = 1;
}
final List<List<Object>> rows = new ArrayList<List<Object>>(rowCount - start);
final List<List<Object>> rows = new ArrayList<>(rowCount - start);
for (int i = start; i < rowCount; i++) {
List<Object> row = new ArrayList<Object>();
List<Object> row = new ArrayList<>();
for (int j = 0; j < columnCount; j++) {
row.add(sheet.getValueAt(j, i));
}
210,16 → 172,45
return new ArrayTableModel(rows);
}
 
public ArrayTableModel createModelFromXLSXGM(File xlsFile, int sheetNumber) throws IOException {
XLSXDocument doc = XLSXDocument.createFromFile(xlsFile);
XLSXSheet sheet = doc.getSheet(sheetNumber);
final int rowCount = sheet.getRowCount();
final int columnCount = sheet.getColumnCount();
 
int start = 0;
if (this.skipFirstLine) {
start = 1;
}
final List<List<Object>> selectedRows = new ArrayList<>(rowCount - start);
for (int i = start; i < rowCount; i++) {
List<Object> row = new ArrayList<>();
for (int j = 0; j < columnCount; j++) {
row.add(sheet.getValueAt(j, i));
}
selectedRows.add(row);
}
 
return new ArrayTableModel(selectedRows);
 
}
 
public ArrayTableModel createModelFromXLS(File xlsFile, int sheetNumber) throws IOException {
final InputStream inputStream = new FileInputStream(xlsFile);
final POIFSFileSystem fileSystem = new POIFSFileSystem(new BufferedInputStream(inputStream));
final HSSFWorkbook workBook = new HSSFWorkbook(fileSystem);
final HSSFSheet sheet = workBook.getSheetAt(sheetNumber);
Iterator<Row> rowsIterator = sheet.rowIterator();
final List<List<Object>> rows = createFromExcel(workBook.getCreationHelper().createFormulaEvaluator(), sheet.rowIterator(), sheet.rowIterator());
workBook.close();
return new ArrayTableModel(rows);
 
}
 
private List<List<Object>> createFromExcel(FormulaEvaluator evaluator, Iterator<Row> rowsIterator1, Iterator<Row> rowsIterator2) {
int columnCount = 0;
int rowCount = 0;
while (rowsIterator.hasNext()) {
Row row = rowsIterator.next();
while (rowsIterator1.hasNext()) {
Row row = rowsIterator1.next();
int i = row.getPhysicalNumberOfCells();
if (i > columnCount) {
columnCount = i;
227,18 → 218,16
rowCount++;
}
// Extract data
rowsIterator = sheet.rowIterator();
int start = 0;
if (skipFirstLine) {
if (this.skipFirstLine) {
start = 1;
rowsIterator.next();
rowsIterator2.next();
}
final List<List<Object>> rows = new ArrayList<List<Object>>(rowCount - start);
FormulaEvaluator evaluator = workBook.getCreationHelper().createFormulaEvaluator();
final List<List<Object>> rows = new ArrayList<>(rowCount - start);
 
while (rowsIterator.hasNext()) {
final Row row = rowsIterator.next();
final List<Object> rowData = new ArrayList<Object>();
while (rowsIterator2.hasNext()) {
final Row row = rowsIterator2.next();
final List<Object> rowData = new ArrayList<>();
for (int i = 0; i < columnCount; i++) {
final Cell cell = row.getCell(i);
 
245,30 → 234,33
if (cell == null) {
rowData.add("");
} else {
CellValue cellValue = evaluator.evaluate(cell);
CellValue cellValue = null;
try {
cellValue = evaluator.evaluate(cell);
} catch (NotImplementedException exception) {
exception.printStackTrace();
}
if (cellValue == null) {
rowData.add("");
} else {
switch (cellValue.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
switch (cellValue.getCellTypeEnum()) {
case BOOLEAN:
rowData.add(Boolean.valueOf(cellValue.getBooleanValue()));
break;
case Cell.CELL_TYPE_NUMERIC:
 
case NUMERIC:
if (HSSFDateUtil.isCellDateFormatted(cell)) {
System.out.println("Row No.: " + row.getRowNum() + " " + cell.getDateCellValue());
rowData.add(cell.getDateCellValue());
} else {
rowData.add(Double.valueOf(cellValue.getNumberValue()));
}
break;
case Cell.CELL_TYPE_STRING:
case STRING:
rowData.add(cellValue.getStringValue());
break;
case Cell.CELL_TYPE_FORMULA:
case FORMULA:
rowData.add(cell.getCellFormula());
break;
case Cell.CELL_TYPE_BLANK:
case BLANK:
rowData.add("");
break;
default:
283,9 → 275,7
rows.add(rowData);
 
}
inputStream.close();
return new ArrayTableModel(rows);
 
return rows;
}
 
public ArrayTableModel createModelFromCSV(File csvFile) throws IOException {
319,12 → 309,12
final int columnCount = lines.get(0).length;
 
int start = 0;
if (skipFirstLine) {
if (this.skipFirstLine) {
start = 1;
}
final List<List<Object>> rows = new ArrayList<List<Object>>(rowCount - start);
final List<List<Object>> rows = new ArrayList<>(rowCount - start);
for (int i = start; i < rowCount; i++) {
List<Object> row = new ArrayList<Object>();
List<Object> row = new ArrayList<>();
String[] values = lines.get(i);
for (int j = 0; j < columnCount; j++) {
row.add(values[j]);
347,23 → 337,23
 
public ArrayTableModel createConvertedModel(ArrayTableModel model) {
final int rowCount = model.getRowCount();
final ArrayList<Integer> colsUsed = new ArrayList<Integer>(map.keySet());
colsUsed.addAll(constraints.keySet());
final ArrayList<Integer> colsUsed = new ArrayList<>(this.map.keySet());
colsUsed.addAll(this.constraints.keySet());
 
final int columnCount = 1 + Collections.max(colsUsed);
 
final List<List<Object>> rows = new ArrayList<List<Object>>(rowCount);
final List<List<Object>> rows = new ArrayList<>(rowCount);
 
for (int i = 0; i < rowCount; i++) {
boolean validRow = true;
final List<Object> row = new ArrayList<Object>();
final List<Object> row = new ArrayList<>();
for (int j = 0; j < columnCount; j++) {
Object value = model.getValueAt(i, j);
ValueConverter converter = map.get(j);
ValueConverter converter = this.map.get(j);
if (converter != null) {
value = converter.convertFrom(value);
}
final Constraint constraint = constraints.get(j);
final Constraint constraint = this.constraints.get(j);
// Verification de la validité de la valeur à importer
if (constraint != null && !constraint.isValid(value)) {
validRow = false;
380,19 → 370,19
}
 
protected void customizeRowValuesToFetch(SQLRowValues vals) {
 
// Nothing
}
 
public void importFromModel(ArrayTableModel model) throws IOException {
final int rowCount = model.getRowCount();
// Load existing data for duplication check
final SQLRowValues vals = new SQLRowValues(table);
final SQLRowValues vals = new SQLRowValues(this.table);
 
for (SQLField field : this.fieldMap.keySet()) {
if (field.getTable().equals(table)) {
if (field.getTable().equals(this.table)) {
vals.put(field.getName(), null);
} else {
final Set<SQLField> foreignKeys = table.getForeignKeys(field.getTable());
final Set<SQLField> foreignKeys = this.table.getForeignKeys(field.getTable());
for (SQLField sqlField : foreignKeys) {
vals.put(sqlField.getName(), null);
}
399,17 → 389,15
}
}
customizeRowValuesToFetch(vals);
System.out.println("Fetching values");
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(vals);
List<SQLRowValues> existingRows = fetcher.fetch();
System.out.println("Computing cache");
final int existingRowsCount = existingRows.size();
final ValueConverter[] converters = map.values().toArray(new ValueConverter[map.size()]);
final ValueConverter[] converters = this.map.values().toArray(new ValueConverter[this.map.size()]);
 
// Une map <Object(valeur),SQLRowValues> pour chaque champs unique
Map<SQLField, Map<Object, SQLRowValues>> cache = new HashMap<SQLField, Map<Object, SQLRowValues>>();
Map<SQLField, Map<Object, SQLRowValues>> cache = new HashMap<>();
for (SQLField field : this.uniqueField) {
Map<Object, SQLRowValues> m = new HashMap<Object, SQLRowValues>();
Map<Object, SQLRowValues> m = new HashMap<>();
cache.put(field, m);
final String fieldName = field.getName();
for (int j = 0; j < existingRowsCount; j++) {
424,7 → 412,7
// Recherche d'existant
SQLRowValues existingRow = null;
for (SQLField field : this.uniqueField) {
List<Integer> cols = fieldMap.get(field);
List<Integer> cols = this.fieldMap.get(field);
Object objectToInsert = null;
for (Integer col : cols) {
Object v = model.getValueAt(i, col);
449,7 → 437,7
 
private void updateOrInsert(ArrayTableModel model, final ValueConverter[] converters, int i, SQLRowValues existingRow) {
 
final Map<String, Object> newValues = new HashMap<String, Object>();
final Map<String, Object> newValues = new HashMap<>();
if (existingRow != null) {
// Préremplissage de la map avec la row existante
newValues.putAll(existingRow.getAbsolutelyAll());
457,7 → 445,7
for (int j = 0; j < converters.length; j++) {
ValueConverter valueConverter = converters[j];
 
List<Integer> cols = fieldMap.get(valueConverter.getField());
List<Integer> cols = this.fieldMap.get(valueConverter.getField());
Object objectToInsert = null;
for (Integer col : cols) {
Object v = model.getValueAt(i, col);
471,11 → 459,11
 
final String fieldName = valueConverter.getFieldName();
if (objectToInsert != null || !valueConverter.isIgnoringEmptyValue()) {
if (valueConverter.getField().getTable().equals(table)) {
if (valueConverter.getField().getTable().equals(this.table)) {
newValues.put(fieldName, objectToInsert);
} else {
 
final SQLField sqlField = foreignMap.get(valueConverter);
final SQLField sqlField = this.foreignMap.get(valueConverter);
 
final Object value = newValues.get(sqlField.getName());
if (value == null || value instanceof SQLRowValues) {
490,26 → 478,21
}
}
}
final SQLRowValues rowVals = new SQLRowValues(table, newValues);
final SQLRowValues rowVals = new SQLRowValues(this.table, newValues);
patchRowValues(rowVals, model.getLineValuesAt(i), existingRow);
if (existingRow == null) {
this.valuesToInsert.add(rowVals);
}
// else if (!newValues.equals(existingRow.getAbsolutelyAll())) {
else {
} else {
this.valuesToUpdate.add(rowVals);
// for (SQLRowValues ref : rowVals.getReferentRows()) {
// this.valuesToUpdate.add(ref);
// }
}
}
 
public void doAfterImport() throws SQLException {
 
// Nothing
}
 
protected void patchRowValues(SQLRowValues rowVals, List<Object> lineValues, SQLRowValues existingRow) {
 
// Nothing
}
 
public void setSkipFirstLine(boolean skipFirstLine) {
531,8 → 514,10
return createModelFromCSV(file);
} else if (name.endsWith(".xls")) {
return createModelFromXLS(file, sheetNumber);
} else if (name.endsWith(".xlsx") || name.endsWith(".xlsm")) {
return createModelFromXLSXGM(file, sheetNumber);
}
throw new IllegalArgumentException("File format not supported. Please provide an ods, csv or xls file.");
throw new IllegalArgumentException("File format not supported. Please provide an ods, csv, xls or xlsx file.");
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/MailRelancePreferencePanel.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/TemplateNXProps.java
17,7 → 17,6
import org.openconcerto.erp.core.customerrelationship.customer.report.FicheClientXmlSheet;
import org.openconcerto.erp.core.edm.AttachmentSQLElement;
import org.openconcerto.erp.core.finance.accounting.report.BalanceSheet;
import org.openconcerto.erp.core.finance.accounting.report.GrandLivreSheet;
import org.openconcerto.erp.core.finance.accounting.report.GrandLivreSheetXML;
import org.openconcerto.erp.core.finance.accounting.report.JournauxSheetXML;
import org.openconcerto.erp.core.humanresources.payroll.report.EtatChargesPayeSheet;
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/GestionCommercialeGlobalPreferencePanel.java
29,11 → 29,13
 
public class GestionCommercialeGlobalPreferencePanel extends JavaPrefPreferencePanel {
public static String TRANSFERT_REF = "TransfertRef";
public static String COMMANDE_FOURNISSEUR_EN_COURS = "CommandeFournisseurEncours";
public static String TRANSFERT_MULTI_REF = "TransfertMultiRef";
public static String TRANSFERT_NO_REF = "TransfertNoRef";
public static String ACOMPTE_DEVIS = "AcompteDevis";
public static String ORDER_PACKAGING_MANAGEMENT = "OrderPackagingManagement";
public static String ADDRESS_SPEC = "AddressSpec";
public static String CATEGORIE_COMPTABLE_SPEC = "CategorieComptableSpec";
public static String GESTION_TIMBRE_FISCAL = "GestionTimbreFiscal";
public static String TAUX_TIMBRE_FISCAL = "TauxTimbreFiscal";
public static String BARCODE_INSERTION = "BarcodeInsertion";
69,6 → 71,10
orderQuoting.setDefaultValue(Boolean.FALSE);
this.addView(orderQuoting);
 
PrefView<Boolean> cmdEnCours = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Activer la gestion des commandes fournisseurs en cours", COMMANDE_FOURNISSEUR_EN_COURS);
cmdEnCours.setDefaultValue(Boolean.FALSE);
this.addView(cmdEnCours);
 
PrefView<Boolean> viewAcompteDevis = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Gérer les acomptes sur devis", ACOMPTE_DEVIS);
viewAcompteDevis.setDefaultValue(Boolean.FALSE);
this.addView(viewAcompteDevis);
76,6 → 82,10
PrefView<Boolean> addressSpec = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Afficher les sélecteurs d'adresse spécifique", ADDRESS_SPEC);
addressSpec.setDefaultValue(Boolean.TRUE);
this.addView(addressSpec);
PrefView<Boolean> catComptableSpec = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Afficher les sélecteurs de catégorie comptable spécifique", CATEGORIE_COMPTABLE_SPEC);
catComptableSpec.setDefaultValue(Boolean.FALSE);
this.addView(catComptableSpec);
 
PrefView<Boolean> gestTimbreFisc = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Activer la gestion du timbre fiscal", GESTION_TIMBRE_FISCAL);
gestTimbreFisc.setDefaultValue(Boolean.FALSE);
/trunk/OpenConcerto/src/org/openconcerto/erp/config/InstallationPanel.java
49,6 → 49,7
import org.openconcerto.sql.request.Inserter.Insertion;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.users.rights.TableAllRights;
import org.openconcerto.sql.utils.AlterTable;
import org.openconcerto.sql.utils.ChangeTable;
import org.openconcerto.sql.utils.ChangeTable.ClauseType;
63,6 → 64,7
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.ProductInfo;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.GridBagConstraints;
2387,18 → 2389,24
}
root.getTable("ARTICLE").getSchema().updateVersion();
// Valeur par défaut des numérotations
SQLRowValues rNumerotation = root.getTable("NUMEROTATION_AUTO").getRow(2).asRowValues();
boolean numerotationFixed = false;
if (rNumerotation.getString("AVOIR_F_FORMAT").trim().isEmpty()) {
rNumerotation.put("AVOIR_F_FORMAT", "'AVOIR'yyMM-000");
if (root.contains("NUMEROTATION_AUTO")) {
SQLRow rowNumerotation = root.getTable("NUMEROTATION_AUTO").getRow(2);
if (rowNumerotation != null) {
SQLRowValues rNumerotation = rowNumerotation.asRowValues();
boolean numerotationFixed = false;
if (StringUtils.isEmpty(rNumerotation.getString("AVOIR_F_FORMAT"), true)) {
rNumerotation.put("AVOIR_F_FORMAT", "'AVOIR'yyMM-000");
numerotationFixed = true;
}
if (StringUtils.isEmpty(rNumerotation.getString("CLIENT_FORMAT"), true)) {
rNumerotation.put("CLIENT_FORMAT", "'CLI'00000");
numerotationFixed = true;
}
if (numerotationFixed) {
rNumerotation.commit();
}
}
}
if (rNumerotation.getString("CLIENT_FORMAT").trim().isEmpty()) {
rNumerotation.put("CLIENT_FORMAT", "'CLI'00000");
}
if (numerotationFixed) {
rNumerotation.commit();
}
 
//
 
final SQLTable tableCalendarItem = root.getTable("CALENDAR_ITEM");
3835,6 → 3843,32
rowValsUserRight.commit();
}
 
if (!codes.contains(TableAllRights.USER_UI_LOCK_ROW)) {
SQLRowValues rowVals = new SQLRowValues(table);
rowVals.put("CODE", TableAllRights.USER_UI_LOCK_ROW);
rowVals.put("NOM", "Autoriser à verrouiller une ligne dans une liste.");
String desc = "Autorise un utilisateur à verrouiller une ou plusieurs dans les listes où cette fonctionnalité est active.";
rowVals.put("DESCRIPTION", desc);
SQLRow row = rowVals.commit();
SQLRowValues rowValsUserRight = new SQLRowValues(table.getTable("USER_RIGHT"));
rowValsUserRight.put("ID_RIGHT", row.getID());
rowValsUserRight.put("HAVE_RIGHT", Boolean.TRUE);
rowValsUserRight.commit();
}
 
if (!codes.contains(TableAllRights.USER_UI_UNLOCK_ROW)) {
SQLRowValues rowVals = new SQLRowValues(table);
rowVals.put("CODE", TableAllRights.USER_UI_UNLOCK_ROW);
rowVals.put("NOM", "Autoriser à déverrouiller une ligne dans une liste.");
String desc = "Autorise un utilisateur à déverrouiller une ou plusieurs dans les listes où cette fonctionnalité est active.";
rowVals.put("DESCRIPTION", desc);
SQLRow row = rowVals.commit();
SQLRowValues rowValsUserRight = new SQLRowValues(table.getTable("USER_RIGHT"));
rowValsUserRight.put("ID_RIGHT", row.getID());
rowValsUserRight.put("HAVE_RIGHT", Boolean.TRUE);
rowValsUserRight.commit();
}
 
}
 
private void findBadForeignKey(DBRoot root) {
3975,6 → 4009,15
 
// FK
new AddFK(root.getDBSystemRoot()).changeAll(root);
 
// Couleur
final SQLTable tableUser = root.getTable("USER_COMMON");
if (!tableUser.contains("COLOR")) {
final AlterTable alter = new AlterTable(tableUser);
alter.addIntegerColumn("COLOR", 0, false);
Updater_1_5.exec(alter);
}
 
}
 
protected void fixCompletion(DBRoot root) throws SQLException {
4027,6 → 4070,11
alter = true;
}
 
if (!table.getFieldsName().contains("ID_JOURNAL_VALEUR_ENCAISSEMENT")) {
t.addForeignColumn("ID_JOURNAL_VALEUR_ENCAISSEMENT", root.getTable("JOURNAL"));
alter = true;
}
 
if (!table.getFieldsName().contains("ID_COMPTE_PCE_PORT_NON_SOUMIS")) {
t.addForeignColumn("ID_COMPTE_PCE_PORT_NON_SOUMIS", root.getTable("COMPTE_PCE"));
alter = true;
4625,7 → 4673,6
 
// at the end to let Updater_1_5 change field types from varchar to text
fixUnboundedVarchar(root);
 
return null;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/config/translation_fr.xml
178,8 → 178,9
<action id="sales.quote.clone" label="Créer à partir de" />
<action id="sales.quote.create.customer.order" label="Transfert vers commande client" />
<action id="sales.quote.create.customer.delivery" label="Transfert vers bon de livraison" />
<action id="sales.quote.accept.create.customer.order" label="Marquer comme accepté et Transfert en commande client" />
 
<action id="sales.quote.accept.create.customer.order"
label="Marquer comme accepté et Transfert en commande client" />
<!-- Customer -->
<action id="customerrelationship.customer.label.print" label="Imprimer l'étiquette client" />
<action id="customerrelationship.customer.info.create" label="Créer la fiche client" />
220,6 → 221,7
<action id="supplychain.order.create.purchase" label="Transfert vers saisie achat" />
<action id="supplychain.order.valid" label="Marquer comme validée" />
<action id="supplychain.order.create.receipt" label="Transfert vers bon de réception" />
<action id="supplychain.invoice.clone" label="Créer à partir de" />
 
<!-- Customer order -->
<action id="sales.order.create.deliverynote" label="Transfert vers bon de livraison" />
247,9 → 249,9
<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" />
 
 
 
<!-- Currency -->
<item id="currency.USD" label="Dollar américain" />
<item id="currency.EUR" label="Euro" />
290,7 → 292,7
<item id="autres.contributions.ligne" label="Autres contributions dues par l'employeur" />
<item id="csg.nonimp.ligne" label="CSG non imposable à l'impôt sur le revenu" />
<item id="csg.imp.ligne" label="CSG/CRDS imposable à l'impôt sur le revenu" />
<item id="allegement.cotisations.ligne" label="Exonération de cotisations employeur" />
<item id="allegement.cotisations.ligne" label="Allégement de cotisation" />
<item id="paye.simplifie.ignore" label="Ligne ignorée" />
 
<!-- Groupe Paye Simplifiée -->
305,6 → 307,6
<item id="cotisations.convention" label="COTISATIONS DE CONVENTION COLLECTIVE OU STATUAIRES" />
<item id="csg.nonimp" label="CSG/CRDS déductible de l'impôt sur le revenu" />
<item id="csg.imp" label="CSG/CRDS non déductible à l'impôt sur le revenu" />
<item id="allegement" label="Exonération de cotisations employeur" />
 
<item id="allegement" label="Allégement de cotisation" />
<action id="email" label="Email" />
</translation>
/trunk/OpenConcerto/src/org/openconcerto/erp/config/mappingCompta_fr.xml
1,5 → 1,11
<?xml version="1.0" encoding="UTF-8" ?>
<ROOT>
<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="humanresources.payroll.advance" nameClass="masculine" name="acompte">
<FIELD name="ID_SALARIE" label="Salarié" />
<FIELD name="MONTANT" label="Montant" />
241,6 → 247,7
<element refid="sales.credit.note" nameClass="feminine" name="facture d'avoir" namePlural="factures d'avoir">
<FIELD name="ID_ADRESSE" label="Adresse fact. spéc." />
<FIELD name="ID_ADRESSE_LIVRAISON" label="Adresse livr. spéc." />
<FIELD name="ID_CATEGORIE_COMPTABLE" label="Cat. comptable spéc." />
<FIELD name="ID_CLIENT_DEPARTEMENT" label="Service" />
<FIELD name="ID_SECRETAIRE" label="Secrétaire" />
<FIELD name="ID_ECHEANCIER_CCI" label="Echeancier CCI" />
386,7 → 393,7
<FIELD name="DATE_NAISSANCE" label="Date de naissance" />
</element>
<element refid="bank" nameClass="feminine" name="banque">
<FIELD name="NOM" label="Nom" />
<FIELD name="NOM" label="Banque" />
<FIELD name="NUMERO_RUE" label="Numéro de rue" />
<FIELD name="VOIE" label="Voie" />
<FIELD name="RUE" label="Rue" />
473,6 → 480,7
<FIELD name="FRAIS_DOCUMENT_HT" label="Frais de document HT" />
<FIELD name="ID_ADRESSE" label="Adresse fact. spéc." />
<FIELD name="ID_ADRESSE_LIVRAISON" label="Adresse livr. spéc." />
<FIELD name="ID_CATEGORIE_COMPTABLE" label="Cat. comptable spéc." />
<FIELD name="ID_CLIENT_DEPARTEMENT" label="Service" />
<FIELD name="ID_CONTACT" label="Contact" />
<FIELD name="ID_TARIF" label="Tarif à appliquer" />
834,6 → 842,25
<FIELD name="FONCTION" label="Fonction" />
<FIELD name="N4DS" label="Contact pour la N4DS" />
</element>
<element refid="CONTACT_SALARIE" nameClass="masculine" name="contact salarié">
<FIELD name="PRENOM" label="Prénom du contact" />
<FIELD name="NOM" label="Nom du contact" />
<FIELD name="ID_TITRE_PERSONNEL" label="Titre" />
<FIELD name="TEL_DIRECT" label="Téléphone" />
<FIELD name="TEL_PERSONEL" label="Téléphone Personnel" />
<FIELD name="TEL_STANDARD" label="Téléphone du standard" />
<FIELD name="TEL_MOBILE" label="Portable" />
<FIELD name="EMAIL" label="Mail" />
<FIELD name="FAX" label="Fax" />
<FIELD name="FONCTION" label="Lien de parenté" />
<FIELD name="ID_SALARIE" label="Salarié" />
<FIELD name="NO_MAILING" label="Pas de mailing" />
<FIELD name="TYPE" label="Type" />
<FIELD name="SERVICE" label="Service" />
<FIELD name="PAYS" label="Pays" />
<FIELD name="ID_ADRESSE" label="Adresse" />
<FIELD name="DATE_NAISSANCE" label="Date de naissance" />
</element>
<element refid="humanresources.payroll.anticipation.contract" nameClass="masculine"
name="contrat de prévoyance, mutuelle, formation" namePlural="contrats de prévoyance, mutuelle, formation">
<FIELD name="REFERENCE" label="Référence du contrat de Prévoyance (S21.G00.15.001)" />
880,6 → 907,7
<element refid="humanresources.payroll.contract.employe" nameClass="masculine" name="contrat salarié"
namePlural="contrats salariés">
<FIELD name="NATURE" label="Nature de l'emploi (*)" titlelabel="Nature de l'emploi" />
<FIELD name="COMPLEMENT_PCS" label="Code complément PCS-ESE" />
<FIELD name="ID_CODE_EMPLOI" label="Catégorie socioprofessionnelle "
titlelabel="Code Catégorie socioprofessionnelle" />
<FIELD name="ID_CODE_CONTRAT_TRAVAIL" label="Contrat de travail" titlelabel="Code contrat" />
989,6 → 1017,7
<FIELD name="DATE_LIVRAISON_PREV" label="Livraison prévue le" />
<FIELD name="ID_ADRESSE" label="Adresse fact. spéc." />
<FIELD name="ID_ADRESSE_LIVRAISON" label="Adresse livr. spéc." />
<FIELD name="ID_CATEGORIE_COMPTABLE" label="Cat. comptable spéc." />
<FIELD name="ID_CLIENT_DEPARTEMENT" label="Service" />
<FIELD name="ACOMPTE_COMMANDE" label="Acompte" />
<FIELD name="ID_CONTACT" label="Contact" />
1276,6 → 1305,7
<FIELD name="ID_CLIENT_DEPARTEMENT" label="Service" />
<FIELD name="ID_ADRESSE" label="Adresse fact. spéc." />
<FIELD name="ID_ADRESSE_LIVRAISON" label="Adresse livr. spéc." />
<FIELD name="ID_CATEGORIE_COMPTABLE" label="Cat. comptable spéc." />
<FIELD name="CONTACT_MAIL_RAPPORT" label="Email dest. suppl." />
<FIELD name="SITE_DIFF" label="Site d'intervention différent du donneur d'ordre" />
<FIELD name="DESIGNATION_SITE" label="Désignation du site" />
1578,6 → 1608,7
</element>
<element refid="supplychain.order.invoice.purchase" nameClass="feminine" name="facture fournisseur"
namePlural="factures fournisseur">
<FIELD name="TVA_ADJUSTMENT" label="Ajustement de TVA" />
<FIELD name="ID_AVOIR_FOURNISSEUR" label="Avoir" />
<FIELD name="NET_A_PAYER" label="Net à payer" />
<FIELD name="ID_TAXE_PORT" label="Taxe sur port" />
1607,6 → 1638,7
</element>
<element refid="supplychain.orderinvoice.purchase.item" nameClass="masculine" name="élément de facture"
namePlural="éléments de facture">
<FIELD name="ID_COMPTE_PCE" label="Compte charge spécifique" />
<FIELD name="ID_DEPOT_STOCK" label="Dépôt Stock" />
<FIELD name="ID_ECO_CONTRIBUTION" label="Code Eco-Contrib." />
<FIELD name="ECO_CONTRIBUTION" label="Dont Eco-Contrib." />
1814,6 → 1846,7
<FIELD name="DATE_SORTIE" label="Date de sortie" />
<FIELD name="CODE_AT" label="Code AT" />
<FIELD name="CODE_SECTION_AT" label="Code section AT" />
<FIELD name="DUREE_FORFAIT" label="Durée du forfait" />
</element>
<element refid="finance.accounting.book" nameClass="masculine" name="journal">
<FIELD name="NOM" label="Journal" />
2217,6 → 2250,7
<FIELD name="TOTAL_TIMBRE_FISCAL" label="Total timbre" />
<FIELD name="ID_CLIENT_DEPARTEMENT" label="Service" />
<FIELD name="ID_ADRESSE_LIVRAISON" label="Adresse livr. spéc." />
<FIELD name="ID_CATEGORIE_COMPTABLE" label="Cat. comptable spéc." />
<FIELD name="ID_COMPTE_PCE_VENTE" label="Compte vente" />
<FIELD name="ID_ADRESSE" label="Adresse spécifique" />
<FIELD name="T_HA" label="Total achat" />
2269,6 → 2303,7
</element>
<element refid="sales.invoice.item" nameClass="masculine" name="article facturé" namePlural="articles facturés">
<FIELD name="ID_DEPOT_STOCK" label="Dépôt Stock" />
<FIELD name="ID_COMPTE_PCE" label="Compte vente spécifique" />
<FIELD name="ID_ECO_CONTRIBUTION" label="Code Eco-Contrib." />
<FIELD name="ECO_CONTRIBUTION" label="Dont Eco-Contrib." />
<FIELD name="T_ECO_CONTRIBUTION" label="Total Eco-Contrib." />
2352,6 → 2387,7
<FIELD name="NOM" label="Nom (*)" titlelabel="Nom" />
<FIELD name="PRENOM" label="Prénom (*)" titlelabel="Prénom" />
<FIELD name="ID_TITRE_PERSONNEL" label="Titre (*)" titlelabel="Titre" />
<FIELD name="ID_USER_COMMON" label="Utilisateur associé" titlelabel="Utilisateur associé" />
<FIELD name="CODE" label="Code (*)" titlelabel="Code" />
<FIELD name="NOM_JEUNE_FILLE" label="Nom de jeune fille" titlelabel="Nom jeune fille" />
<FIELD name="ID_ETAT_CIVIL" label="Etat civil" />
2496,4 → 2532,12
<FIELD name="ControlSum" label="Total des prélèvements" />
<FIELD name="XML" label="Message XML" />
</element>
<element refid="customerrelationship.mail.email.template" nameClass="masculine" name="modèle d'email"
namePlural="modèles d'email">
<FIELD name="NOM" label="Nom du modèle" />
<FIELD name="TITRE" label="Titre" />
<FIELD name="TEXTE" label="Texte" />
<FIELD name="FORMAT_DATE" label="Format de date" />
<FIELD name="PAR_DEFAUT" label="Par défaut" />
</element>
</ROOT>
/trunk/OpenConcerto/src/org/openconcerto/erp/config/Gestion.java
51,6 → 51,7
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.ThrowableHandler;
import org.openconcerto.utils.protocol.Helper;
import org.openconcerto.xml.FastXMLProperties;
 
import java.awt.AWTEvent;
import java.awt.Component;
204,6 → 205,9
}
 
public static void main(String[] args) {
System.setProperty("org.xml.sax.driver", "com.bluecast.xml.Piccolo");
System.setProperty("org.xml.sax.parser", "com.bluecast.xml.Piccolo");
System.setProperty("javax.xml.parsers.SAXParserFactory", "com.bluecast.xml.JAXPSAXParserFactory");
ComptaPropsConfiguration.checkJava();
// Check MacOS Sandbox
String cwd = new File(getProperty("user.dir")).toURI().toString();
410,7 → 414,7
 
if (fTOS.exists()) {
try {
pTOS.loadFromXML(new FileInputStream(fTOS));
FastXMLProperties.load(pTOS, new FileInputStream(fTOS));
} catch (Exception e1) {
e1.printStackTrace();
}
578,7 → 582,7
private static void saveProperties(File fTOS, Properties pTOS) {
try {
final FileOutputStream outputStream = new FileOutputStream(fTOS);
pTOS.storeToXML(outputStream, "tos", "UTF-8");
FastXMLProperties.store(pTOS, outputStream, "tos");
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
593,7 → 597,7
public boolean handle(String message, Throwable throwable) {
if (throwable == null)
return false;
 
throwable.printStackTrace();
final ByteArrayOutputStream out = new ByteArrayOutputStream();
throwable.printStackTrace(new PrintStream(out));
String s = new String(out.toByteArray());
634,7 → 638,7
return true;
}
 
else if (s.contains("No application is associated with the specified file for this operation")) {
else if (s.contains("No application is associated with the specified file for this operation") || s.contains("Error message: Package could not be registered")) {
JOptionPane.showMessageDialog(null, "Merci d'installer LibreOffice ou tout autre application succeptible d'ouvrir ce fichier");
return true;
} else if (s.contains("java.net.SocketTimeoutException: connect timed out")) {
/trunk/OpenConcerto/src/org/openconcerto/erp/config/translation_pl.xml
193,6 → 193,7
<!-- Supplier order -->
<action id="supplychain.order.create.purchase" label="Transfer do zakupów" />
<action id="supplychain.order.create.receipt" label="Transfer do zamówienia" />
<action id="supplychain.invoice.clone" label="Kopiuj z" />
 
<!-- Customer order -->
<action id="sales.order.create.deliverynote" label="Transfer WZ" />
/trunk/OpenConcerto/src/org/openconcerto/erp/config/ComptaPropsConfiguration.java
27,10 → 27,11
import org.openconcerto.erp.core.common.element.StyleSQLElement;
import org.openconcerto.erp.core.common.element.TitrePersonnelSQLElement;
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;
import org.openconcerto.erp.core.customerrelationship.customer.element.ComptaContactSQLElement.ContactSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.ComptaContactSQLElement.ContactSalarieSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.CompteClientTransactionSQLELement;
import org.openconcerto.erp.core.customerrelationship.customer.element.ContactSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.ContactSQLElement.ContactAdministratifSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.ContactSQLElement.ContactFournisseurSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.CourrierClientSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.CustomerCategorySQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.CustomerSQLElement;
38,6 → 39,7
import org.openconcerto.erp.core.customerrelationship.customer.element.ReferenceClientSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.RelanceSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.TypeLettreRelanceSQLElement;
import org.openconcerto.erp.core.customerrelationship.mail.EmailTemplateSQLElement;
import org.openconcerto.erp.core.edm.AttachmentSQLElement;
import org.openconcerto.erp.core.finance.accounting.element.AssociationAnalytiqueSQLElement;
import org.openconcerto.erp.core.finance.accounting.element.AssociationCompteAnalytiqueSQLElement;
172,6 → 174,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.CustomerProductQtyPriceSQLElement;
import org.openconcerto.erp.core.sales.product.element.EcoContributionSQLElement;
import org.openconcerto.erp.core.sales.product.element.FamilleArticleSQLElement;
import org.openconcerto.erp.core.sales.product.element.FamilleEcoContributionSQLElement;
227,6 → 230,7
import org.openconcerto.erp.generationDoc.provider.AdresseVilleClientValueProvider;
import org.openconcerto.erp.generationDoc.provider.AdresseVilleNomClientValueProvider;
import org.openconcerto.erp.generationDoc.provider.ArticleCodeClientProvider;
import org.openconcerto.erp.generationDoc.provider.ArticleCodeFournisseurProvider;
import org.openconcerto.erp.generationDoc.provider.ConditionsReglementDetailsProvider;
import org.openconcerto.erp.generationDoc.provider.DateBLProvider;
import org.openconcerto.erp.generationDoc.provider.DateProvider;
240,6 → 244,7
import org.openconcerto.erp.generationDoc.provider.PrixUVProvider;
import org.openconcerto.erp.generationDoc.provider.PrixUnitaireProvider;
import org.openconcerto.erp.generationDoc.provider.PrixUnitaireRemiseProvider;
import org.openconcerto.erp.generationDoc.provider.QteTotalDocProvider;
import org.openconcerto.erp.generationDoc.provider.QteTotalProvider;
import org.openconcerto.erp.generationDoc.provider.RecapFactureProvider;
import org.openconcerto.erp.generationDoc.provider.RefClientValueProvider;
269,6 → 274,8
import org.openconcerto.erp.injector.CommandeCliCommandeSQLInjector;
import org.openconcerto.erp.injector.CommandeFactureAchatSQLInjector;
import org.openconcerto.erp.injector.CommandeFactureClientSQLInjector;
import org.openconcerto.erp.injector.CommandeFactureEltSQLInjector;
import org.openconcerto.erp.injector.CommandeFactureFournisseurSQLInjector;
import org.openconcerto.erp.injector.DevisBlEltSQLInjector;
import org.openconcerto.erp.injector.DevisBlSQLInjector;
import org.openconcerto.erp.injector.DevisCommandeFournisseurSQLInjector;
298,7 → 305,6
import org.openconcerto.sql.model.DBStructureItemNotFound;
import org.openconcerto.sql.model.DBSystemRoot;
import org.openconcerto.sql.model.FieldMapper;
import org.openconcerto.sql.model.LoadingListener;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLServer;
338,14 → 344,8
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
 
import javax.imageio.ImageIO;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
605,6 → 605,7
AdresseVilleNomClientValueProvider.register();
AdresseFullClientValueProvider.register();
QteTotalProvider.register();
QteTotalDocProvider.register();
StockLocationProvider.register();
RefClientValueProvider.register();
ModeDeReglementDetailsProvider.register();
618,62 → 619,10
RecapFactureProvider.register();
RestantAReglerProvider.register();
SaledTotalNotDiscountedProvider.register();
ArticleCodeFournisseurProvider.register();
}
 
@Override
protected void initSystemRoot(DBSystemRoot input) {
super.initSystemRoot(input);
if (!GraphicsEnvironment.isHeadless()) {
final JDialog f = new JOptionPane("Mise à jour des caches en cours...\nCette opération prend généralement moins d'une minute.", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION,
null, new Object[] {}).createDialog("Veuillez patienter");
input.addLoadingListener(new LoadingListener() {
 
private int loadingCount = 0;
private final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
final Thread thread = new Thread(r, "Loading listener thread");
thread.setDaemon(true);
return thread;
}
});
private ScheduledFuture<?> future = null;
 
@Override
public synchronized void loading(LoadingEvent evt) {
this.loadingCount += evt.isStarting() ? 1 : -1;
if (this.loadingCount < 0) {
throw new IllegalStateException();
} else if (this.loadingCount == 0) {
this.future.cancel(false);
this.future = null;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
f.setVisible(false);
f.dispose();
}
});
} else if (this.future == null) {
this.future = this.exec.schedule(new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
f.setVisible(true);
}
});
}
}, 1, TimeUnit.SECONDS);
}
}
 
});
}
}
 
@Override
protected void initDS(SQLDataSource ds) {
super.initDS(ds);
ds.setInitialSize(3);
862,7 → 811,7
 
dir.addSQLElement(AttachmentSQLElement.class);
 
 
dir.addSQLElement(CustomerProductQtyPriceSQLElement.class);
dir.addSQLElement(EtatStockSQLElement.class);
dir.addSQLElement(EtatStockItemSQLElement.class);
dir.addSQLElement(ArticleTarifSQLElement.class);
882,6 → 831,7
dir.addSQLElement(CoefficientPrimeSQLElement.class);
dir.addSQLElement(ContactFournisseurSQLElement.class);
dir.addSQLElement(ContactAdministratifSQLElement.class);
dir.addSQLElement(ContactSalarieSQLElement.class);
dir.addSQLElement(new TitrePersonnelSQLElement());
dir.addSQLElement(new ContactSQLElement());
dir.addSQLElement(new SaisieKmItemSQLElement());
1065,6 → 1015,7
dir.addSQLElement(CalendarItemSQLElement.class);
dir.addSQLElement(CalendarItemGroupSQLElement.class);
dir.addSQLElement(DeviseHistoriqueSQLElement.class);
dir.addSQLElement(EmailTemplateSQLElement.class);
 
if (getRootSociete().contains("FWK_LIST_PREFS")) {
dir.addSQLElement(new FWKListPrefs(getRootSociete()));
1122,6 → 1073,7
 
public static void setSocieteSQLInjector(final DBRoot rootSociete) {
new AchatAvoirSQLInjector(rootSociete);
new CommandeFactureEltSQLInjector(rootSociete);
new ArticleCommandeEltSQLInjector(rootSociete);
new CommandeCliCommandeSQLInjector(rootSociete);
new FactureAvoirSQLInjector(rootSociete);
1141,6 → 1093,7
new CommandeBrSQLInjector(rootSociete);
new BonReceptionFactureFournisseurSQLInjector(rootSociete);
new CommandeFactureAchatSQLInjector(rootSociete);
new CommandeFactureFournisseurSQLInjector(rootSociete);
new EcheanceEncaisseSQLInjector(rootSociete);
new EcheanceRegleSQLInjector(rootSociete);
new BrFactureAchatSQLInjector(rootSociete);
1181,7 → 1134,7
if (getRootSociete().getTable("CLIENT").getFieldsName().contains("LOCALISATION")) {
showAs.show("CLIENT", "NOM", "LOCALISATION");
} else {
SQLPreferences prefs = new SQLPreferences(root);
SQLPreferences prefs = SQLPreferences.getMemCached(root);
if (prefs.getBoolean(GestionClientPreferencePanel.DISPLAY_CLIENT_PCE, false)) {
showAs.show("CLIENT", "ID_PAYS", "GROUPE", "NOM", "ID_COMPTE_PCE");
} else {
1227,12 → 1180,14
final List<String> lEchFact = new ArrayList<String>();
lEchFact.add("NUMERO");
lEchFact.add("DATE");
lEchFact.add("ID_MODE_REGLEMENT");
lEchFact.add("ID_COMMERCIAL");
SQLTable tableEch = root.getTable("ECHEANCE_CLIENT");
showAs.show(tableEch.getField("ID_SAISIE_VENTE_FACTURE"), lEchFact);
 
showAs.show("ECHEANCE_FOURNISSEUR", SQLRow.toList("ID_FOURNISSEUR,ID_MOUVEMENT"));
showAs.show("FICHE_PAYE", SQLRow.toList("ID_MOIS,ANNEE"));
showAs.show("FICHE_PAYE", SQLRow.toList("ID_MOIS,ANNEE,ID_PROFIL_PAYE"));
 
showAs.show("FOURNISSEUR", "NOM");
 
showAs.show("IDCC", "NOM");
1305,6 → 1260,16
public void setUpSocieteDataBaseConnexion(int base) {
final String customerName = setUpSocieteStructure(base);
final DBRoot rootSociete = this.getRootSociete();
 
try {
// create table if necessary
SQLPreferences.getPrefTable(rootSociete);
SQLPreferences.startMemCached(rootSociete);
} catch (Exception e) {
// don't die now, we might not need them
ExceptionHandler.handle("Impossible d'accéder aux préférences", e);
}
 
closeSocieteConnexion();
setSocieteDirectory();
NumerotationAutoSQLElement.addListeners();
1318,15 → 1283,6
// Prefetch undefined
rootSociete.getTables().iterator().next().getUndefinedID();
 
try {
// create table if necessary
SQLPreferences.getPrefTable(rootSociete);
SQLPreferences.startMemCached(rootSociete);
} catch (Exception e) {
// don't die now, we might not need them
ExceptionHandler.handle("Impossible d'accéder aux préférences", e);
}
 
this.getModuleManager().addFactories(Gestion.MODULES_DIR);
this.getModuleManager().setup(this.getRootSociete(), this);
}
1337,9 → 1293,7
 
public void setupBarCodeIfNeeded() {
final DBRoot rootSociete = this.getRootSociete();
 
// TODO check is the SQLPreferences returned by startMemCached() can be used
SQLPreferences pref = new SQLPreferences(rootSociete);
SQLPreferences pref = SQLPreferences.getMemCached(rootSociete);
if (pref.getBoolean(GestionCommercialeGlobalPreferencePanel.BARCODE_INSERTION, false)) {
this.barcodeReader = new BarcodeReader(80);
this.barcodeReader.start();
/trunk/OpenConcerto/src/org/openconcerto/erp/config/translation_en.xml
196,7 → 196,8
<!-- Supplier order -->
<action id="supplychain.order.create.purchase" label="Transfer to purchase" />
<action id="supplychain.order.create.receipt" label="Transfer to supplier receipt" />
 
<action id="supplychain.invoice.clone" label="Copy from" />
<!-- Customer order -->
<action id="sales.order.create.deliverynote" label="Transfer to delivey note" />
<action id="sales.order.create.invoice" label="Transfer to invoice" />
397,5 → 398,5
<item id="product.bom.expose" label="Expose BOM" />
<item id="product.bom.flat" label="Flat BOM" />
 
 
<action id="email" label="Email" />
</translation>
/trunk/OpenConcerto/src/org/openconcerto/erp/config/DefaultMenuConfiguration.java
28,6 → 28,7
import org.openconcerto.erp.core.customerrelationship.customer.action.ListeDesDepartementsClientsAction;
import org.openconcerto.erp.core.customerrelationship.customer.action.NouvelHistoriqueListeClientAction;
import org.openconcerto.erp.core.customerrelationship.mail.action.ListeDesCourriersClientsAction;
import org.openconcerto.erp.core.customerrelationship.mail.action.ListeDesModelesEmailAction;
import org.openconcerto.erp.core.finance.accounting.action.BalanceAgeeAction;
import org.openconcerto.erp.core.finance.accounting.action.CompteResultatBilanAction;
import org.openconcerto.erp.core.finance.accounting.action.EtatBalanceAction;
68,6 → 69,7
import org.openconcerto.erp.core.finance.payment.action.NouveauDecaissementChequeAvoirAction;
import org.openconcerto.erp.core.finance.payment.action.NouveauListeDesChequesADecaisserAction;
import org.openconcerto.erp.core.finance.payment.action.NouveauListeDesChequesAEncaisserAction;
import org.openconcerto.erp.core.finance.payment.element.EncaisserMontantSQLElement;
import org.openconcerto.erp.core.finance.tax.action.ReportingEcoContributionPanel;
import org.openconcerto.erp.core.finance.tax.action.ReportingTaxeComplementairePanel;
import org.openconcerto.erp.core.humanresources.ListeDesContactsAdministratif;
92,6 → 94,7
import org.openconcerto.erp.core.reports.stat.action.EvolutionCmdAction;
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.VenteArticleFamilleGraphAction;
import org.openconcerto.erp.core.reports.stat.action.VenteArticleGraphAction;
import org.openconcerto.erp.core.reports.stat.action.VenteArticleMargeGraphAction;
101,6 → 104,7
import org.openconcerto.erp.core.sales.invoice.action.GenEtatStockAction;
import org.openconcerto.erp.core.sales.invoice.action.GenListeVenteAction;
import org.openconcerto.erp.core.sales.invoice.action.GenReportingVenteAction;
import org.openconcerto.erp.core.sales.invoice.action.ImportReglementSageAction;
import org.openconcerto.erp.core.sales.invoice.action.ListeDebiteursAction;
import org.openconcerto.erp.core.sales.invoice.action.ListeDesElementsFactureAction;
import org.openconcerto.erp.core.sales.invoice.action.ListeDesFactureItemsAction;
121,6 → 125,7
import org.openconcerto.erp.core.sales.product.action.ListeDesArticlesAction;
import org.openconcerto.erp.core.sales.product.action.ListeEcoContributionAction;
import org.openconcerto.erp.core.sales.product.action.ListeHistoCodeClientArticleAction;
import org.openconcerto.erp.core.sales.product.action.TransfertStockAction;
import org.openconcerto.erp.core.sales.quote.action.ListeDesDevisAction;
import org.openconcerto.erp.core.sales.quote.action.ListeDesDevisActionTCP;
import org.openconcerto.erp.core.sales.quote.action.ListeDesElementsDevisAction;
294,6 → 299,7
supplierGroup.addItem("supplier.credit.create");
group.addItem("stock.io.create");
}
group.addItem("product.stock.transfert");
 
return group;
}
328,7 → 334,7
gUser.addItem("user.task.right");
group.add(gUser);
}
 
group.addItem("email.template.list");
group.addItem("product.ecotax");
group.addItem("office.contact.list");
group.addItem("salesman.list");
414,6 → 420,7
group.addItem("sales.list.reporting");
group.addItem("order.list.reporting");
group.addItem("sales.list.report");
group.addItem("sales.list.salesman.report");
group.addItem("sales.product.graph");
group.addItem("sales.product.margin.graph");
group.addItem("sales.product.family.graph");
599,6 → 606,7
mManager.putAction(new NouveauSaisieVenteFactureAction(conf), "customer.invoice.create");
 
mManager.putAction(new NouveauAvoirClientAction(conf), "customer.credit.create");
mManager.putAction(new TransfertStockAction(conf), "product.stock.transfert");
 
if (rights.haveRight(NXRights.LOCK_MENU_ACHAT.getCode())) {
mManager.putAction(new NouvelleDemandePrixAction(conf), "supplier.order.ask.create");
710,8 → 718,8
}
 
public void registerStatsMenuActions(final MenuAndActions mManager) {
final ComptaPropsConfiguration conf = getConfiguration();
 
 
mManager.putAction(new EvolutionCAAction(), "sales.graph");
mManager.putAction(new EvolutionCACumulAction(), "sales.graph.cumulate");
 
718,6 → 726,8
mManager.putAction(new EvolutionCmdAction(), "sales.graph.cmd");
mManager.putAction(new EvolutionCmdCumulAction(), "sales.graph.cmd.cumulate");
 
mManager.putAction(new ReportingCommercialAction(conf.getRootSociete()), "sales.list.salesman.report");
 
mManager.putAction(new EvolutionMargeAction(), "sales.margin.graph");
mManager.putAction(new GenReportingVenteAction(false), "sales.list.reporting");
mManager.putAction(new GenReportingVenteAction(true), "order.list.reporting");
763,6 → 773,7
 
if (rights.haveRight(NXRights.GESTION_ENCAISSEMENT.getCode())) {
mManager.putAction(new ListesFacturesClientsImpayeesAction(), "customer.invoice.unpaid.list");
mManager.putAction(new ImportReglementSageAction(conf.getDirectory().getElement(EncaisserMontantSQLElement.class)), "customer.invoice.payment.xml.sage.import");
mManager.putAction(new ListeDebiteursAction(), "customer.dept.list");
mManager.putAction(new AbstractAction("Relevé client") {
@Override
839,7 → 850,7
mManager.putAction(new GestionDroitsAction(), "user.right.list");
mManager.putAction(new TaskAdminAction(), "user.task.right");
}
 
mManager.putAction(new ListeDesModelesEmailAction(), "email.template.list");
mManager.putAction(new ListeDesContactsAdministratif(), "office.contact.list");
mManager.putAction(new ListeDesCommerciauxAction(), "salesman.list");
mManager.putAction(new ListeDesCaissesTicketAction(), "pos.list");
/trunk/OpenConcerto/src/org/openconcerto/erp/config/mapping_fr.xml
1,5 → 1,15
<?xml version="1.0" encoding="UTF-8" ?>
<ROOT>
 
<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="common.address" nameClass="feminine" name="adresse">
<FIELD name="RAISON_SOCIALE" label="Raison sociale" />
<FIELD name="RUE" label="Rue" />
266,4 → 276,6
<FIELD name="FORMULE" label="Formule" />
<FIELD name="INFOS" label="Description" />
</element>
 
</ROOT>
/trunk/OpenConcerto/src/org/openconcerto/erp/config/update/Updater_1_5.java
15,6 → 15,7
 
import org.openconcerto.erp.config.InstallationPanel;
import org.openconcerto.erp.core.common.ui.AbstractVenteArticleItemTable;
import org.openconcerto.erp.core.customerrelationship.mail.EmailTemplateSQLElement;
import org.openconcerto.erp.core.finance.payment.element.SDDMessageSQLElement;
import org.openconcerto.erp.core.finance.payment.element.SEPAMandateSQLElement;
import org.openconcerto.erp.core.finance.payment.element.TypeReglementSQLElement;
23,6 → 24,7
import org.openconcerto.erp.core.sales.pos.element.TicketCaisseSQLElement;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.erp.core.sales.quote.element.DevisLogMailSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.ComposedItemStockUpdater;
import org.openconcerto.erp.core.supplychain.stock.element.DepotStockSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.StockItem;
import org.openconcerto.sql.changer.convert.AddMDFields;
37,6 → 39,7
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLSystem;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTable.Index;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.request.UpdateBuilder;
58,6 → 61,7
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.prefs.BackingStoreException;
 
import org.apache.commons.dbutils.handlers.ArrayListHandler;
1790,6 → 1794,14
root.refetchTable("VARIABLE_SALARIE");
root.getSchema().updateVersion();
}
SQLTable tableBL = root.getTable("BON_DE_LIVRAISON");
if (!tableBL.contains("ID_COMMERCIAL")) {
final AlterTable alterB = new AlterTable(tableBL);
alterB.addForeignColumn("ID_COMMERCIAL", root.getTable("COMMERCIAL"));
root.getBase().getDataSource().execute(alterB.asString());
root.refetchTable("BON_DE_LIVRAISON");
root.getSchema().updateVersion();
}
 
// fix stock
{
1857,17 → 1869,151
}
}
 
// Tarification client par quantite
if (root.getTable("TARIF_ARTICLE_CLIENT") == null) {
final SQLCreateTable createTableQtyTarif = new SQLCreateTable(root, "TARIF_ARTICLE_CLIENT");
createTableQtyTarif.addForeignColumn("ID_ARTICLE", root.getTable("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_ARTICLE_CLIENT");
root.getSchema().updateVersion();
} catch (SQLException ex) {
throw new IllegalStateException("Erreur lors de la création de la table " + "TARIF_QUANTITE", ex);
}
}
 
SQLTable tableTrCmd = root.getTable("TR_COMMANDE");
if (!tableTrCmd.contains("ID_FACTURE_FOURNISSEUR")) {
AlterTable t = new AlterTable(tableTrCmd);
t.addForeignColumn("ID_FACTURE_FOURNISSEUR", root.getTable("FACTURE_FOURNISSEUR"));
tableTrCmd.getBase().getDataSource().execute(t.asString());
root.refetchTable(tableTrCmd.getName());
root.getSchema().updateVersion();
}
 
SQLTable tableContrat = root.getTable("CONTRAT_SALARIE");
if (!tableContrat.contains("COMPLEMENT_PCS")) {
AlterTable t = new AlterTable(tableContrat);
t.addVarCharColumn("COMPLEMENT_PCS", 54);
tableContrat.getBase().getDataSource().execute(t.asString());
root.refetchTable(tableContrat.getName());
root.getSchema().updateVersion();
}
 
List<String> tablesCatComptable = Arrays.asList("DEVIS", "COMMANDE_CLIENT", "BON_DE_LIVRAISON", "SAISIE_VENTE_FACTURE", "AVOIR_CLIENT");
for (String tableToUp : tablesCatComptable) {
final SQLTable tableCatComptToAdd = root.getTable(tableToUp);
if (!tableCatComptToAdd.contains("ID_CATEGORIE_COMPTABLE")) {
final AlterTable alter = new AlterTable(tableCatComptToAdd);
alter.addForeignColumn("ID_CATEGORIE_COMPTABLE", root.getTable("CATEGORIE_COMPTABLE"));
exec(alter);
root.refetchTable(tableToUp);
root.getSchema().updateVersion();
}
}
 
 
// Modèles pour les emails
if (!root.contains(EmailTemplateSQLElement.TABLE_NAME)) {
final SQLCreateTable createTable = new SQLCreateTable(root, EmailTemplateSQLElement.TABLE_NAME);
createTable.addVarCharColumn("NOM", 80);
createTable.addVarCharColumn("TITRE", 80);
createTable.addVarCharColumn("TEXTE", 4096);
createTable.addVarCharColumn("FORMAT_DATE", 20);
createTable.addBooleanColumn("PAR_DEFAUT", Boolean.FALSE, false);
try {
root.getBase().getDataSource().execute(createTable.asString());
InstallationPanel.insertUndef(createTable);
root.refetchTable(EmailTemplateSQLElement.TABLE_NAME);
root.getSchema().updateVersion();
} catch (SQLException ex) {
throw new IllegalStateException("Erreur lors de la création de la table " + EmailTemplateSQLElement.TABLE_NAME, ex);
}
}
// Force undefined policy to inDb
root.setMetadata(SQLTable.UNDEFINED_ID_POLICY, "inDB");
final Map<String, Number> mapTableNameUndefined = SQLTable.getUndefIDs(root.getSchema());
final Set<String> tables = root.getSchema().getTableNames();
for (String tName : tables) {
if (!mapTableNameUndefined.containsKey(tName)) {
System.err.println("Updater_1_5.update() adding undefined in db for " + tName);
SQLTable.setUndefID(root.getSchema(), tName, null);
}
}
 
// Création de la table Modéle
if (!root.contains("CONTACT_SALARIE")) {
 
SQLCreateTable createModele = new SQLCreateTable(root, "CONTACT_SALARIE");
createModele.addVarCharColumn("NOM", 256);
createModele.addVarCharColumn("PRENOM", 256);
createModele.addVarCharColumn("TEL_DIRECT", 256);
createModele.addVarCharColumn("TEL_MOBILE", 256);
createModele.addVarCharColumn("EMAIL", 256);
createModele.addVarCharColumn("FAX", 256);
createModele.addVarCharColumn("FONCTION", 256);
createModele.addVarCharColumn("TEL_PERSONEL", 256);
createModele.addVarCharColumn("TEL_STANDARD", 256);
createModele.addForeignColumn("ID_TITRE_PERSONNEL", root.findTable("TITRE_PERSONNEL"));
createModele.addForeignColumn("ID_SALARIE", root.findTable("SALARIE"));
 
try {
root.getBase().getDataSource().execute(createModele.asString());
root.refetchTable("CONTACT_SALARIE");
SQLRowValues rowVals = new SQLRowValues(root.getTable("CONTACT_SALARIE"));
SQLRow rowInserted = rowVals.commit();
SQLTable.setUndefID(root.getSchema(), "CONTACT_SALARIE", rowInserted.getID());
tableDevis.getSchema().updateVersion();
} catch (SQLException ex) {
throw new IllegalStateException("Erreur lors de la création de la table MODELE", ex);
}
}
 
final SQLTable tableRgltPaye = root.getTable("REGLEMENT_PAYE");
if (!tableRgltPaye.contains("IBAN")) {
final AlterTable alter = new AlterTable(tableRgltPaye);
alter.addVarCharColumn("IBAN", 128);
exec(alter);
root.refetchTable(tableRgltPaye.getName());
root.getSchema().updateVersion();
}
if (!tableRgltPaye.contains("BIC")) {
final AlterTable alter = new AlterTable(tableRgltPaye);
alter.addVarCharColumn("BIC", 40);
exec(alter);
root.refetchTable(tableRgltPaye.getName());
root.getSchema().updateVersion();
}
final SQLTable tableSalarie = root.getTable("SALARIE");
if (!tableSalarie.contains("ID_USER_COMMON")) {
final AlterTable alter = new AlterTable(tableSalarie);
alter.addForeignColumn("ID_USER_COMMON", root.findTable("USER_COMMON"));
exec(alter);
root.refetchTable(tableSalarie.getName());
root.getSchema().updateVersion();
}
 
final SQLTable tableInfosSalarie = root.getTable("INFOS_SALARIE_PAYE");
if (!tableInfosSalarie.contains("DUREE_FORFAIT")) {
final AlterTable alter = new AlterTable(tableInfosSalarie);
alter.addColumn("DUREE_FORFAIT", "real");
exec(alter);
root.refetchTable(tableSalarie.getName());
root.getSchema().updateVersion();
}
 
}
 
public static void initStock(SQLRow row) {
SQLSelect sel = new SQLSelect();
sel.addSelectStar(row.getTable().getTable("DEPOT_STOCK"));
List<SQLRow> rowsDepot = SQLRowListRSH.execute(sel);
public static void initStock(SQLRow rowArticle, int idDepot) {
 
SQLSelect selStock = new SQLSelect();
selStock.addSelectStar(row.getTable().getTable("STOCK"));
selStock.setWhere(new Where(row.getTable().getTable("STOCK").getField("ID_ARTICLE"), "=", row.getID()));
selStock.addSelectStar(rowArticle.getTable().getTable("STOCK"));
selStock.setWhere(new Where(rowArticle.getTable().getTable("STOCK").getField("ID_ARTICLE"), "=", rowArticle.getID()));
List<SQLRow> rowsStock = SQLRowListRSH.execute(selStock);
Map<Integer, SQLRow> initedDepot = new HashMap<>();
for (SQLRow sqlRow : rowsStock) {
1875,47 → 2021,51
}
 
List<StockItem> stockItems = new ArrayList<StockItem>();
for (SQLRow sqlRow : rowsDepot) {
try {
if (!initedDepot.keySet().contains(sqlRow.getID())) {
SQLRowValues rowVals = new SQLRowValues(row.getTable().getTable("STOCK"));
rowVals.put("ID_ARTICLE", row.getID());
rowVals.put("ID_DEPOT_STOCK", sqlRow.getID());
try {
if (!initedDepot.keySet().contains(idDepot)) {
SQLRowValues rowVals = new SQLRowValues(rowArticle.getTable().getTable("STOCK"));
rowVals.put("ID_ARTICLE", rowArticle.getID());
rowVals.put("ID_DEPOT_STOCK", idDepot);
 
SQLRow rowStock = rowVals.commit();
if ((row.getObject("ID_DEPOT_STOCK") == null || row.isForeignEmpty("ID_DEPOT_STOCK")) && sqlRow.getID() == DepotStockSQLElement.DEFAULT_ID) {
row.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID).commit();
} else if (sqlRow.getID() == row.getForeignID("ID_DEPOT_STOCK")) {
row.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).commit();
}
stockItems.add(new StockItem(row, rowStock));
SQLRow rowStock = rowVals.commit();
if ((rowArticle.getObject("ID_DEPOT_STOCK") == null || rowArticle.isForeignEmpty("ID_DEPOT_STOCK")) && idDepot == DepotStockSQLElement.DEFAULT_ID) {
rowArticle.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID).commit();
} else if (idDepot == rowArticle.getForeignID("ID_DEPOT_STOCK")) {
rowArticle.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).commit();
}
stockItems.add(new StockItem(rowArticle, rowStock));
 
} else {
SQLRow rowExisting = initedDepot.get(sqlRow.getID());
if ((row.getObject("ID_DEPOT_STOCK") == null || row.isForeignEmpty("ID_DEPOT_STOCK")) && sqlRow.getID() == DepotStockSQLElement.DEFAULT_ID) {
row.createEmptyUpdateRow().put("ID_STOCK", rowExisting.getID()).put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID).commit();
} else if (sqlRow.getID() == row.getForeignID("ID_DEPOT_STOCK")) {
row.createEmptyUpdateRow().put("ID_STOCK", rowExisting.getID()).commit();
}
stockItems.add(new StockItem(row, rowExisting));
} else {
SQLRow rowExisting = initedDepot.get(idDepot);
if ((rowArticle.getObject("ID_DEPOT_STOCK") == null || rowArticle.isForeignEmpty("ID_DEPOT_STOCK")) && idDepot == DepotStockSQLElement.DEFAULT_ID) {
rowArticle.createEmptyUpdateRow().put("ID_STOCK", rowExisting.getID()).put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID).commit();
} else if (idDepot == rowArticle.getForeignID("ID_DEPOT_STOCK")) {
rowArticle.createEmptyUpdateRow().put("ID_STOCK", rowExisting.getID()).commit();
}
stockItems.add(new StockItem(rowArticle, rowExisting));
}
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors de l'initialisation du stock de l'article", e);
}
 
if (rowArticle.getReferentRows(rowArticle.getTable().getTable("ARTICLE_ELEMENT").getField("ID_ARTICLE_PARENT")).size() > 0) {
ComposedItemStockUpdater up = new ComposedItemStockUpdater(rowArticle.getTable().getDBRoot(), stockItems);
try {
up.updateNomenclature(stockItems);
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors de l'initialisation du stock de l'article", e);
ExceptionHandler.handle("Erreur lors de l'actualisation du stock!", e);
}
}
// if
// (row.getReferentRows(row.getTable().getTable("ARTICLE_ELEMENT").getField("ID_ARTICLE_PARENT")).size()
// > 0) {
// ComposedItemStockUpdater up = new ComposedItemStockUpdater(row.getTable().getDBRoot(),
// stockItems);
// try {
// up.updateNomenclature(stockItems);
// } catch (SQLException e) {
// ExceptionHandler.handle("Erreur lors de l'actualisation du stock!", e);
// }
// }
}
 
public static void initStock(SQLRow row) {
int foreignID = DepotStockSQLElement.DEFAULT_ID;
if (row.getObject("ID_DEPOT_STOCK") != null && !row.isForeignEmpty("ID_DEPOT_STOCK")) {
foreignID = row.getForeignID("ID_DEPOT_STOCK");
}
initStock(row, foreignID);
}
 
public static void exec(final AlterTable alter) throws SQLException {
alter.getTable().getDBSystemRoot().getDataSource().execute(alter.asString());
alter.getTable().getSchema().updateVersion();
/trunk/OpenConcerto/src/org/openconcerto/erp/config/translation_es.xml
200,6 → 200,7
<action id="supplychain.order.create.purchase" label="Transferencia hacia introducción de compra" />
<action id="supplychain.order.valid" label="Marcar como validada" />
<action id="supplychain.order.create.receipt" label="Transferencia hacia álbaran de entrada" />
<action id="supplychain.invoice.clone" label="Crear a partir de" />
 
<!-- Customer order -->
<action id="sales.order.create.deliverynote" label="Transferencia hacia álabaran de salida" />
/trunk/OpenConcerto/src/org/openconcerto/erp/action/CreateIListFrameAbstractAction.java
27,6 → 27,10
super(conf, clazz);
}
 
protected CreateIListFrameAbstractAction(final ComptaPropsConfiguration conf, final E elem) {
super(conf, elem);
}
 
protected SQLTableModelSource createTableSource() {
return this.getElem().createTableSource();
}
/trunk/OpenConcerto/src/org/openconcerto/erp/action/CreateEditFrameAbstractAction.java
29,7 → 29,11
private static final String[] TRANSLATION_KEY_ARRAY = new String[] { TRANSLATION_KEY };
 
protected CreateEditFrameAbstractAction(final PropsConfiguration conf, final Class<? extends E> clazz) {
super(conf.getDirectory().getElement(clazz));
this(conf, conf.getDirectory().getElementOfClass(clazz, true));
}
 
protected CreateEditFrameAbstractAction(final PropsConfiguration conf, final E elem) {
super(elem);
// TODO use conf to find TM
final NounClass nounClass = this.getElem().getName().getNounClass();
final String[] translationKeys = nounClass == null ? TRANSLATION_KEY_ARRAY : new String[] { TRANSLATION_KEY + '.' + nounClass.getName(), TRANSLATION_KEY };
/trunk/OpenConcerto/src/org/openconcerto/erp/action/NouvelleConnexionAction.java
293,6 → 293,11
}
 
static public void initCache(final ComptaPropsConfiguration comptaConf) {
initCache(comptaConf, 600);
}
 
static public void initCache(final ComptaPropsConfiguration comptaConf, final int timeout) {
 
final SQLBase baseSociete = comptaConf.getSQLBaseSociete();
Thread t = new Thread() {
@Override
299,7 → 304,7
public void run() {
// laisse le temps au logiciel de demarrer
try {
Thread.sleep(1000);
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
310,19 → 315,19
 
Ville.init(new NXDatabaseAccessor(comptaConf), prefs.getBoolean(GestionClientPreferencePanel.LOAD_CITIES, true));
 
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("TAXE"), 600);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("ETAT_DEVIS"), 600);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("PREFS_COMPTE"), 600);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("COMPTE_PCE"), 600);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("JOURNAL"), 600);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("TAXE"), timeout);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("ETAT_DEVIS"), timeout);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("PREFS_COMPTE"), timeout);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("COMPTE_PCE"), timeout);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("JOURNAL"), timeout);
 
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("COMMERCIAL"), 600);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("PERIODE_VALIDITE"), 1000);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("COMMERCIAL"), timeout);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("PERIODE_VALIDITE"), timeout);
 
if (comptaConf.getRootSociete().contains("DEPOT_STOCK")) {
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("DEPOT_STOCK"), 600);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("DEPOT_STOCK"), timeout);
}
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("TYPE_REGLEMENT"), 1000);
SQLBackgroundTableCache.getInstance().add(baseSociete.getTable("TYPE_REGLEMENT"), timeout);
SQLBackgroundTableCache.getInstance().startCacheWatcher();
 
TaxeCache.getCache();
/trunk/OpenConcerto/src/org/openconcerto/erp/action/CreateListFrameAbstractAction.java
61,7 → 61,11
private final ComptaPropsConfiguration conf;
 
protected CreateListFrameAbstractAction(final ComptaPropsConfiguration conf, final Class<? extends E> clazz) {
super(conf.getDirectory().getElement(clazz));
this(conf, conf.getDirectory().getElementOfClass(clazz, true));
}
 
protected CreateListFrameAbstractAction(final ComptaPropsConfiguration conf, final E elem) {
super(elem);
this.conf = conf;
// TODO use conf to find TM
final NounClass nounClass = this.getElem().getName().getNounClass();
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/DevisCommandeSQLInjector.java
68,6 → 68,9
map(tableDevis.getField("MONTANT_REMISE"), getDestination().getField("MONTANT_REMISE"));
map(tableDevis.getField("POURCENT_REMISE"), getDestination().getField("POURCENT_REMISE"));
}
if (getSource().getTable().contains("ID_CATEGORIE_COMPTABLE") && getDestination().getTable().contains("ID_CATEGORIE_COMPTABLE")) {
map(getSource().getField("ID_CATEGORIE_COMPTABLE"), getDestination().getField("ID_CATEGORIE_COMPTABLE"));
}
}
 
@Override
78,9 → 81,9
final SQLTable tableElementSource = getSource().getTable("DEVIS_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("COMMANDE_CLIENT_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "OBJET", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_COMMANDE_CLIENT");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_COMMANDE_CLIENT", "OBJET", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_COMMANDE_CLIENT", "INFOS", "INFOS");
 
if (myListItem.size() != 0) {
final SQLInjector injector = SQLInjector.getInjector(tableElementSource, tableElementDestination);
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/DevisFactureSQLInjector.java
67,6 → 67,9
map(tableDevis.getField("MONTANT_REMISE"), tableFacture.getField("MONTANT_REMISE"));
map(tableDevis.getField("POURCENT_REMISE"), tableFacture.getField("POURCENT_REMISE"));
}
if (getSource().getTable().contains("ID_CATEGORIE_COMPTABLE") && getDestination().getTable().contains("ID_CATEGORIE_COMPTABLE")) {
map(getSource().getField("ID_CATEGORIE_COMPTABLE"), getDestination().getField("ID_CATEGORIE_COMPTABLE"));
}
}
 
@Override
78,9 → 81,9
final SQLTable tableElementSource = getSource().getTable("DEVIS_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("SAISIE_VENTE_FACTURE_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "OBJET", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE", "OBJET", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE", "INFOS", "INFOS");
 
if (getDestination().contains("ID_TAXE_FRAIS_DOCUMENT")) {
final SQLRowAccessor rowClient = srcRow.getForeign("ID_CLIENT");
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/BonFactureSQLInjector.java
46,6 → 46,9
if (getSource().getTable().contains("ID_ADRESSE_LIVRAISON")) {
map(getSource().getField("ID_ADRESSE_LIVRAISON"), getDestination().getField("ID_ADRESSE_LIVRAISON"));
}
if (getSource().getTable().contains("ID_CATEGORIE_COMPTABLE") && getDestination().getTable().contains("ID_CATEGORIE_COMPTABLE")) {
map(getSource().getField("ID_CATEGORIE_COMPTABLE"), getDestination().getField("ID_CATEGORIE_COMPTABLE"));
}
if (tableBon.contains("ID_TAXE_PORT")) {
map(tableBon.getField("ID_TAXE_PORT"), tableFacture.getField("ID_TAXE_PORT"));
}
77,9 → 80,9
final SQLTable tableElementSource = getSource().getTable("BON_DE_LIVRAISON_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("SAISIE_VENTE_FACTURE_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "NOM", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE", "NOM", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE", "INFOS", "INFOS");
if (getDestination().contains("ID_TAXE_FRAIS_DOCUMENT")) {
final SQLRowAccessor rowClient = srcRow.getForeign("ID_CLIENT");
SQLRowAccessor rowFrais = rowClient.getForeign("ID_FRAIS_DOCUMENT");
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/DevisBlSQLInjector.java
45,6 → 45,9
if (getSource().getTable().contains("ID_ADRESSE_LIVRAISON")) {
map(getSource().getField("ID_ADRESSE_LIVRAISON"), getDestination().getField("ID_ADRESSE_LIVRAISON"));
}
if (getSource().getTable().contains("ID_CATEGORIE_COMPTABLE") && getDestination().getTable().contains("ID_CATEGORIE_COMPTABLE")) {
map(getSource().getField("ID_CATEGORIE_COMPTABLE"), getDestination().getField("ID_CATEGORIE_COMPTABLE"));
}
}
 
@Override
55,9 → 58,9
final SQLTable tableElementSource = getSource().getTable("DEVIS_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("BON_DE_LIVRAISON_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "NOM", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON", "NOM", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON", "INFOS", "INFOS");
 
if (myListItem.size() != 0) {
final SQLInjector injector = SQLInjector.getInjector(tableElementSource, tableElementDestination);
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/FactureBonSQLInjector.java
49,9 → 49,9
final SQLTable tableElementSource = getSource().getTable("SAISIE_VENTE_FACTURE_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("BON_DE_LIVRAISON_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "NOM", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON", "NOM", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON", "INFOS", "INFOS");
 
if (myListItem.size() != 0) {
final SQLInjector injector = SQLInjector.getInjector(tableElementSource, tableElementDestination);
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/FactureAvoirSQLInjector.java
43,7 → 43,9
if (getSource().contains("ID_ADRESSE_LIVRAISON") && getDestination().contains("ID_ADRESSE_LIVRAISON")) {
map(getSource().getField("ID_ADRESSE_LIVRAISON"), getDestination().getField("ID_ADRESSE_LIVRAISON"));
}
 
if (getSource().getTable().contains("ID_CATEGORIE_COMPTABLE") && getDestination().getTable().contains("ID_CATEGORIE_COMPTABLE")) {
map(getSource().getField("ID_CATEGORIE_COMPTABLE"), getDestination().getField("ID_CATEGORIE_COMPTABLE"));
}
if (getSource().getTable().contains("DATE_LIVRAISON") && getDestination().contains("DATE_LIVRAISON")) {
map(getSource().getField("DATE_LIVRAISON"), getDestination().getField("DATE_LIVRAISON"));
}
64,8 → 66,8
final SQLTable tableElementSource = getSource().getTable("SAISIE_VENTE_FACTURE_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("AVOIR_CLIENT_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "NOM", "NOM");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_AVOIR_CLIENT");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_AVOIR_CLIENT", "NOM", "NOM");
 
if (myListItem.size() != 0) {
final SQLInjector injector = SQLInjector.getInjector(tableElementSource, tableElementDestination);
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/CommandeFactureClientSQLInjector.java
72,7 → 72,9
if (tableFacture.contains("CREATE_VIRTUAL_STOCK")) {
mapDefaultValues(tableFacture.getField("CREATE_VIRTUAL_STOCK"), Boolean.FALSE);
}
 
if (getSource().getTable().contains("ID_CATEGORIE_COMPTABLE") && getDestination().getTable().contains("ID_CATEGORIE_COMPTABLE")) {
map(getSource().getField("ID_CATEGORIE_COMPTABLE"), getDestination().getField("ID_CATEGORIE_COMPTABLE"));
}
}
 
@Override
83,9 → 85,9
final SQLTable tableElementSource = getSource().getTable("COMMANDE_CLIENT_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("SAISIE_VENTE_FACTURE_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "NOM", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE", "NOM", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_SAISIE_VENTE_FACTURE", "INFOS", "INFOS");
if (getDestination().contains("ID_TAXE_FRAIS_DOCUMENT")) {
final SQLRowAccessor rowClient = srcRow.getForeign("ID_CLIENT");
SQLRowAccessor rowFrais = rowClient.getForeign("ID_FRAIS_DOCUMENT");
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/CommandeBlSQLInjector.java
69,6 → 69,9
if (getSource().getTable().contains("ID_ADRESSE_LIVRAISON")) {
map(getSource().getField("ID_ADRESSE_LIVRAISON"), getDestination().getField("ID_ADRESSE_LIVRAISON"));
}
if (getSource().getTable().contains("ID_CATEGORIE_COMPTABLE") && getDestination().getTable().contains("ID_CATEGORIE_COMPTABLE")) {
map(getSource().getField("ID_CATEGORIE_COMPTABLE"), getDestination().getField("ID_CATEGORIE_COMPTABLE"));
}
}
 
@Override
80,10 → 83,9
final SQLTable tableElementDestination = getSource().getTable("BON_DE_LIVRAISON_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
 
transfertReference(srcRow, rowVals, "NOM", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
 
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON", "NOM", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_BON_DE_LIVRAISON", "INFOS", "INFOS");
 
if (myListItem.size() != 0) {
final SQLInjector injector = SQLInjector.getInjector(tableElementSource, tableElementDestination);
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/CommandeFactureEltSQLInjector.java
20,6 → 20,7
public CommandeFactureEltSQLInjector(final DBRoot root) {
super(root, "COMMANDE_CLIENT_ELEMENT", "SAISIE_VENTE_FACTURE_ELEMENT", false);
createDefaultMap();
remove(getSource().getField("QTE_LIVREE"), getDestination().getField("QTE_LIVREE"));
if (getDestination().contains("ID_COMMANDE_CLIENT_ELEMENT")) {
map(getSource().getKey(), getDestination().getField("ID_COMMANDE_CLIENT_ELEMENT"));
}
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/CommandeFactureFournisseurSQLInjector.java
36,11 → 36,11
 
// Merge elements
final SQLTable tableElementSource = getSource().getTable("COMMANDE_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("FACTURE_FOUNRISSEUR_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("FACTURE_FOURNISSEUR_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "NOM", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_FACTURE_FOURNISSEUR");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_FACTURE_FOURNISSEUR", "NOM", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_FACTURE_FOURNISSEUR", "INFOS", "INFOS");
if (myListItem.size() != 0) {
final SQLInjector injector = SQLInjector.getInjector(tableElementSource, tableElementDestination);
for (SQLRowAccessor rowElt : myListItem) {
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/BonReceptionFactureFournisseurSQLInjector.java
34,6 → 34,12
map(getSource().getField("PORT_HT"), getDestination().getField("PORT_HT"));
map(getSource().getField("ID_TAXE_PORT"), getDestination().getField("ID_TAXE_PORT"));
}
if (getSource().contains("ID_AFFAIRE") && getDestination().contains("ID_AFFAIRE")) {
map(getSource().getField("ID_AFFAIRE"), getDestination().getField("ID_AFFAIRE"));
}
if (getSource().contains("ID_POLE_PRODUIT") && getDestination().contains("ID_POLE_PRODUIT")) {
map(getSource().getField("ID_POLE_PRODUIT"), getDestination().getField("ID_POLE_PRODUIT"));
}
}
 
@Override
44,9 → 50,9
final SQLTable tableElementSource = getSource().getTable("BON_RECEPTION_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("FACTURE_FOURNISSEUR_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertReference(srcRow, rowVals, "NOM", "NOM");
transfertReference(srcRow, rowVals, "INFOS", "INFOS");
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_FACTURE_FOURNISSEUR");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_FACTURE_FOURNISSEUR", "NOM", "NOM");
transfertReference(srcRow, rowVals, tableElementDestination, "ID_FACTURE_FOURNISSEUR", "INFOS", "INFOS");
if (myListItem.size() != 0) {
final SQLInjector injector = SQLInjector.getInjector(tableElementSource, tableElementDestination);
for (SQLRowAccessor rowElt : myListItem) {
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/CommandeBrSQLInjector.java
40,6 → 40,9
if (tableBr.contains("CREATE_VIRTUAL_STOCK")) {
mapDefaultValues(tableBr.getField("CREATE_VIRTUAL_STOCK"), Boolean.FALSE);
}
if (getSource().contains("ID_AFFAIRE") && getDestination().contains("ID_AFFAIRE")) {
map(getSource().getField("ID_AFFAIRE"), getDestination().getField("ID_AFFAIRE"));
}
}
 
@Override
50,6 → 53,7
final SQLTable tableElementSource = getSource().getTable("COMMANDE_ELEMENT");
final SQLTable tableElementDestination = getSource().getTable("BON_RECEPTION_ELEMENT");
final Collection<? extends SQLRowAccessor> myListItem = srcRow.asRow().getReferentRows(tableElementSource);
transfertNumberReference(srcRow, rowVals, tableElementDestination, "ID_BON_RECEPTION");
 
if (myListItem.size() != 0) {
final SQLInjector injector = SQLInjector.getInjector(tableElementSource, tableElementDestination);
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractJOOReportsSheet.java
27,6 → 27,7
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.FileUtils;
 
import java.awt.print.PrinterJob;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
245,9 → 246,13
return;
}
final Component doc = ooConnexion.loadDocument(fileOutOO, true);
Map<String, Object> map = new HashMap<String, Object>();
map.put("Name", printer);
doc.printDocument(map);
if (this.printer != null && this.printer.trim().length() > 0) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("Name", this.printer);
doc.printDocument(map);
} else {
doc.printDocument(PrinterJob.getPrinterJob());
}
doc.close();
} catch (LinkageError e) {
JOptionPane.showMessageDialog(new JFrame(), "Merci d'installer OpenOffice ou LibreOffice");
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetXml.java
179,19 → 179,23
 
try {
if (!useODSViewer) {
final Component doc = ComptaPropsConfiguration.getOOConnexion().loadDocument(generatedFile, !showDocument);
if (exportToPDF || printDocument) {
final Component doc = ComptaPropsConfiguration.getOOConnexion().loadDocument(generatedFile, !showDocument);
 
if (printDocument) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("Name", this.printer);
doc.printDocument(map);
if (printDocument) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("Name", this.printer);
doc.printDocument(map);
}