OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 173 → Rev 174

/trunk/OpenConcerto/lib/jOpenCalendar.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/lib/jOpenDocument-1.4rc2.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/product.properties
1,5 → 1,5
NAME=OpenConcerto
VERSION=1.6.2
VERSION=1.6.3
ORGANIZATION_NAME=OpenConcerto
ORGANIZATION_ID=org.openconcerto
/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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,6 → 376,7
final Row row = this.getRow(i);
final List<Object> rowValues = row.getValues();
for (final Object value : rowValues) {
if (value != null) {
if (recursively) {
if (value instanceof LightUIContainer) {
result.addAll(((LightUIContainer) value).findChildren(expectedClass, recursively));
394,6 → 389,7
}
}
}
}
} else {
System.out.println("LightUITable.getElementById() - No rows for table: " + this.getId());
}
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/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/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/sql/view/list/SQLTextComboTableCellEditor.java
34,6 → 34,7
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventObject;
import java.util.List;
 
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
56,7 → 57,7
private IListFrame listFrame = null;
 
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined) {
this(elt, addUndefined, false);
this(elt, addUndefined, false,null);
}
 
/**
66,6 → 67,16
* @param chooseInListe possibilité de choisir via une IListe
*/
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined, boolean chooseInListe) {
this(elt, addUndefined, chooseInListe, null);
}
 
/**
*
* @param elt Element à afficher dans la combo
* @param addUndefined ajout de l'indéfini
* @param chooseInListe possibilité de choisir via une IListe
*/
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined, boolean chooseInListe, List<String> fieldsInCombo) {
super();
 
this.addUndefined = addUndefined;
77,7 → 88,7
this.comboBox.setBorder(new LineBorder(Color.black));
this.comboBox.getPulseComponents().iterator().next().setBorder(null);
 
ComboSQLRequest c = elt.getComboRequest(true);
ComboSQLRequest c = fieldsInCombo == null || fieldsInCombo.isEmpty() ? elt.getComboRequest(true) : elt.createComboRequest(fieldsInCombo, null);
this.comboBox.uiInit(c);
 
if (chooseInListe) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTableModel.java
20,6 → 20,7
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesCluster.StoreMode;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSyntax.ConstraintType;
import org.openconcerto.sql.model.SQLTable;
300,7 → 301,7
for (int i = 0; i < size; i++) {
final SQLRowValues r = rowsToCommmit.get(i);
r.put(r.getTable().getOrderField().getFieldName(), o.add(new BigDecimal(i + 1)));
final SQLRow row = r.commit();
final SQLRow row = r.getGraph().store(StoreMode.COMMIT).getStoredRow(r);
r.setID(row.getIDNumber());
}
} catch (SQLException e) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/KeyTableCellRenderer.java
20,6 → 20,7
import org.openconcerto.sql.model.SQLTableEvent;
import org.openconcerto.sql.model.SQLTableEvent.Mode;
import org.openconcerto.sql.model.SQLTableModifiedListener;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.IComboSelectionItem;
 
import java.awt.Component;
37,13 → 38,18
private Object toSelect;
private boolean isLoading = false;
private final SQLElement el;
private final List<String> fields;
private JTable t;
static private final Map<SQLElement, Map<Integer, IComboSelectionItem>> cacheMap = new HashMap<SQLElement, Map<Integer, IComboSelectionItem>>();
 
public KeyTableCellRenderer(final SQLElement el) {
this(el, null);
}
 
public KeyTableCellRenderer(final SQLElement el, final List<String> fields) {
super();
this.el = el;
 
this.fields = fields;
if (cacheMap.get(this.el) == null) {
loadCacheAsynchronous();
}
107,7 → 113,9
Configuration.getInstance().getNonInteractiveSQLExecutor().execute(new Runnable() {
public void run() {
 
List<IComboSelectionItem> items = KeyTableCellRenderer.this.el.getComboRequest().getComboItems();
final ComboSQLRequest comboRequest = KeyTableCellRenderer.this.fields == null || KeyTableCellRenderer.this.fields.isEmpty() ? KeyTableCellRenderer.this.el.getComboRequest()
: KeyTableCellRenderer.this.el.createComboRequest(KeyTableCellRenderer.this.fields, null);
List<IComboSelectionItem> items = comboRequest.getComboItems();
final Map<Integer, IComboSelectionItem> m = new HashMap<Integer, IComboSelectionItem>();
for (IComboSelectionItem comboSelectionItem : items) {
m.put(comboSelectionItem.getId(), comboSelectionItem);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java
30,6 → 30,7
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.users.User;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.sql.users.rights.TableAllRights;
import org.openconcerto.sql.view.FileTransfertHandler;
import org.openconcerto.sql.view.IListener;
import org.openconcerto.sql.view.list.IListeAction.ButtonsBuilder;
146,6 → 147,8
public final class IListe extends JPanel {
 
static private final class LockAction extends RowAction {
private final boolean lock;
 
public LockAction(final boolean lock) {
super(new AbstractAction(TM.tr(lock ? "ilist.lockRows" : "ilist.unlockRows")) {
@Override
167,12 → 170,13
t.fireTableModified(fireID.intValue(), update.getFieldsNames());
}
}, false, true);
this.lock = lock;
}
 
@Override
public boolean enabledFor(IListeEvent evt) {
// TODO use right
return evt.getSelectedRows().size() > 0;
boolean hasRight = TableAllRights.currentUserHasRight(this.lock ? TableAllRights.USER_UI_LOCK_ROW : TableAllRights.USER_UI_UNLOCK_ROW, evt.getTable());
return !evt.getSelectedRows().isEmpty() && hasRight;
}
}
 
1204,8 → 1208,7
try {
res.add(getRow(i, clazz));
} catch (IndexOutOfBoundsException e) {
throw new IllegalStateException(
"The selected row at " + i
throw new IllegalStateException("The selected row at " + i
+ " is not in the model : it has been changed before Swing could update the selection. E.g. the DB was changed on mousePressed and Swing updated the selection on mouseReleased.",
e);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_en.xml
12,7 → 12,8
<FIELD name="ID_USER_RIGHT_COMMON" label="User rights" />
<FIELD name="MAIL" label="E-Mail" />
<FIELD name="DISABLED" label="Account disabled" />
<FIELD name="TEL" label="Phone" titlelabel="Phone" />
<FIELD name="TEL" label="Phone" />
<FIELD name="COLOR" label="Color" />
</element>
<element refid="sql.right">
<name base="right" />
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/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/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,6 → 83,10
final int lineChildCount = panelChild.getChildrenCount();
for (int j = 0; j < lineChildCount; j++) {
final LightUIElement element = panelChild.getChild(j);
if (mapEditor.containsKey(element.getId())) {
mapEditor.get(element.getId()).fillFrom(element, sqlRow);
} else {
 
final SQLField sqlField = configuration.getFieldMapper().getSQLFieldForItem(element.getId());
 
SQLRowAccessor sqlRowTmp = this.getSQLRowForField(sqlRow, sqlField);
115,7 → 129,7
element.setValue(JSONConverter.getJSON(date).toString());
}
} else if (type == LightUIElement.TYPE_PANEL) {
this.fillFromRow((LightUIPanel) element, configuration, sqlRowTmp);
this.fillFromRow((LightUIPanel) element, configuration, sqlElement, sqlRowTmp, sessionSecurityToken);
} else if (type == LightUIElement.TYPE_SLIDER) {
final Integer value = sqlRowTmp.getInt(sqlField.getName());
if (value != null) {
125,6 → 139,7
}
}
}
}
 
public SQLRowAccessor getSQLRowForField(final SQLRowAccessor sqlRow, final SQLField sqlField) {
SQLRowAccessor sqlRowResult = sqlRow;
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightForeignRowValuesTableOffline.java
16,11 → 16,12
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.SQLTableModelLinesSourceOffline;
import org.openconcerto.ui.light.LightUIElement;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableContent;
import org.openconcerto.ui.light.UserSearch;
 
import java.util.concurrent.Future;
 
31,14 → 32,19
private SQLField foreignField;
private Number parentRowId;
 
public LightForeignRowValuesTableOffline(final Configuration configuration, final Number userId, final String id, final ITableModel model, final SQLField foreignField, final Number parentRowId) {
public LightForeignRowValuesTableOffline(final Configuration configuration, final Number userId, final String id, final ITableModel model, final SQLField foreignField) {
super(configuration, userId, id, model);
 
this.foreignField = foreignField;
this.parentRowId = parentRowId;
this.init();
}
 
public void setParentRowId(Number parentRowId) {
this.parentRowId = parentRowId;
// FIXME : d'apres Sylvain, on pourrait ne pas a utiliser le ITableMobel car on veut du
// synchrone
this.getModel().getReq().getReq().setWhere(new Where(this.foreignField, "=", parentRowId));
}
 
public LightForeignRowValuesTableOffline(final LightForeignRowValuesTableOffline table) {
super(table);
 
70,7 → 76,7
}
 
@Override
public void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset) {
public void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset) {
// TODO: Implement search in offline table
this.getModel().fireTableRowsInserted(0, Integer.MAX_VALUE);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/GroupToLightUIConvertor.java
23,7 → 23,6
import org.openconcerto.ui.group.Group;
import org.openconcerto.ui.group.Item;
import org.openconcerto.ui.group.LayoutHints;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.LightUIAutoCompleteComboBox;
import org.openconcerto.ui.light.LightUICheckBox;
import org.openconcerto.ui.light.LightUIDate;
43,6 → 42,7
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class GroupToLightUIConvertor {
49,7 → 49,7
private final int maxColumnCount;
private PropsConfiguration configuration;
private FieldMapper mapper;
private Map<String, CustomEditorProvider> customEditorProviders = new HashMap<String, CustomEditorProvider>();
private Map<String, CustomRowEditor> customRowEditors = new HashMap<>();
 
public GroupToLightUIConvertor(PropsConfiguration conf) {
this(conf, 4);
73,6 → 73,15
}
 
final SQLElement sqlElement = this.configuration.getDirectory().getElement(defaultRow.getTable());
if (sqlElement == null) {
throw new IllegalArgumentException("not SQLElement found for default row table : " + defaultRow.getTable().getName());
}
if (sqlElement.getGroupForCreation() == null) {
throw new IllegalArgumentException("no group for creation defined in " + sqlElement.getClass().getName());
}
if (sqlElement.getGroupForModification() == null) {
throw new IllegalArgumentException("no group for creation defined in " + sqlElement.getClass().getName());
}
if (!sqlElement.getGroupForCreation().equals(group) && sqlElement.getGroupForModification().equals(group)) {
throw new IllegalArgumentException("This group isn't attached to this SQLElement, group ID: " + group.getId() + " element code: " + sqlElement.getCode());
}
313,11 → 322,14
}
 
private LightUIElement getCustomEditor(final String id) {
final CustomEditorProvider customEditorProvider = this.customEditorProviders.get(id);
if (id == null) {
throw new IllegalArgumentException("null id");
}
final CustomRowEditor customEditorProvider = this.customRowEditors.get(id);
if (customEditorProvider != null) {
final LightUIElement element = customEditorProvider.createUIElement(id);
final LightUIElement element = customEditorProvider.createUIElement();
if (element.getId() == null) {
throw new IllegalStateException("Null id for custom editor for id: " + id);
throw new IllegalStateException("Null id for custom editor for id: " + id + " element : " + element);
}
return element;
}
324,11 → 336,12
return null;
}
 
public void putCustomEditorProvider(final String id, final CustomEditorProvider provider) {
this.customEditorProviders.put(id, provider);
public void putCustomEditorProvider(final CustomRowEditor e) {
this.customRowEditors.put(e.getItemId(), e);
}
 
public void putAllCustomEditorProvider(final Map<String, CustomEditorProvider> map) {
this.customEditorProviders.putAll(map);
public void putAllCustomEditorProvider(final List<CustomRowEditor> editors) {
for (CustomRowEditor e : editors)
this.customRowEditors.put(e.getItemId(), e);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTable.java
14,8 → 14,14
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.ListSQLLine;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
26,12 → 32,21
import org.openconcerto.ui.light.LightUIElement;
import org.openconcerto.ui.light.LightUITable;
import org.openconcerto.ui.light.Row;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableSearchParameter;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearch;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
 
import javax.swing.SwingUtilities;
55,8 → 70,10
 
private transient ITransformer<SQLSelect, SQLSelect> orginTransformer;
 
private transient List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>();
private transient List<TableModelListener> tableModelListeners = new ArrayList<>();
 
private Map<TableSearchParameter, TableSearchMatcher> searchMap = new HashMap<>();
 
public LightRowValuesTable() {
// Serialization
}
72,6 → 89,74
if (model.getReq() instanceof SQLTableModelSourceOnline) {
final SQLTableModelSourceOnline source = (SQLTableModelSourceOnline) model.getReq();
this.orginTransformer = source.getReq().getSelectTransf();
 
List<SQLTableModelColumn> columns = model.getReq().getColumns();
// all
// TODO : traduire
TableSearchParameter tableSearchParameterAll = new TableSearchParameter("all", "Tous");
 
TableSearchMatcher m = new TableSearchMatcher() {
 
@Override
public boolean useMatch() {
return false;
}
 
@Override
public boolean match(SQLRowValues r, TableSearchParameterType type, String txt) {
return true;
}
 
@Override
public Where getWhere(SQLSelect sel, TableSearchParameterType type, String txt) {
final Set<FieldPath> fields = new HashSet<>();
for (SQLTableModelColumn col : columns) {
fields.addAll(col.getPaths());
}
final List<Where> wFields = new ArrayList<>(fields.size());
for (final FieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final FieldRef fieldRef = sel.followFieldPath(fpath);
if (type.getType().equals(UserSearchItem.TYPE_CONTAINS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", "%" + txt.toLowerCase() + "%");
wFields.add(w);
}
if (type.getType().equals(UserSearchItem.TYPE_STARTS_WITH)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase() + "%");
wFields.add(w);
}
if (type.getType().equals(UserSearchItem.TYPE_IS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase());
wFields.add(w);
}
}
}
return Where.or(wFields);
}
 
@Override
public List<FieldPath> getAdditionnalFieldsToFetch() {
return Collections.emptyList();
}
};
tableSearchParameterAll.add(TableSearchParameterType.getContainsStringInstance(Locale.FRENCH));
tableSearchParameterAll.add(TableSearchParameterType.getIsStringInstance(Locale.FRENCH));
 
this.addSearchParameter(tableSearchParameterAll, m);
 
//
for (int i = 0; i < columns.size(); i++) {
SQLTableModelColumn col = columns.get(i);
TableSearchParameter tableSearchParameter = new TableSearchParameter("col" + i, col.getName());
// FIXME : locale à recuperer depuis le user
// TODO : mettre d'autres TableSearchParameterType en fonction du type de la colonne
tableSearchParameter.add(TableSearchParameterType.getContainsStringInstance(Locale.FRENCH));
tableSearchParameter.add(TableSearchParameterType.getIsStringInstance(Locale.FRENCH));
 
TableSearchMatcher tableSearchMatcher = new TableSearchColumnMatcher(col);
this.addSearchParameter(tableSearchParameter, tableSearchMatcher);
}
 
} else {
this.orginTransformer = null;
}
108,9 → 193,15
 
public final void addTableModelListener(final TableModelListener tableModelListener) {
this.tableModelListeners.add(tableModelListener);
this.model.addTableModelListener(tableModelListener);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
LightRowValuesTable.this.model.addTableModelListener(tableModelListener);
}
});
 
}
 
public final void removeTableModelListener(final TableModelListener tableModelListener) {
this.tableModelListeners.remove(tableModelListener);
this.model.removeTableModelListener(tableModelListener);
270,8 → 361,26
}
 
// TODO: merge with OpenConcerto List search system
public abstract void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset);
public abstract void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset);
 
public void addSearchParameter(TableSearchParameter tableSearchParameter, TableSearchMatcher tableSearchMatcher) {
this.searchMap.put(tableSearchParameter, tableSearchMatcher);
this.getTableSpec().addSearchParameter(tableSearchParameter);
}
 
protected TableSearchMatcher getSearchMatcher(String colId, String searchType) {
for (TableSearchParameter p : this.searchMap.keySet()) {
if (p.getId().equals(colId)) {
for (TableSearchParameterType t : p.getTypes()) {
if (t.getType().equals(searchType)) {
return this.searchMap.get(p);
}
}
}
}
return null;
}
 
@Override
public Row getRowById(Number rowId) {
for (int i = 0; i < this.model.getRowCount(); i++) {
314,9 → 423,10
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
final List<TableModelListener> tableModelListeners = LightRowValuesTable.this.tableModelListeners;
for (int i = tableModelListeners.size() - 1; i > -1; i--) {
LightRowValuesTable.this.removeTableModelListener(tableModelListeners.get(i));
 
final List<TableModelListener> listeners = LightRowValuesTable.this.tableModelListeners;
for (int i = listeners.size() - 1; i > -1; i--) {
LightRowValuesTable.this.removeTableModelListener(listeners.get(i));
}
}
});
325,5 → 435,6
}
 
this.clearRows();
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightEditFrame.java
41,6 → 41,8
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
 
145,19 → 147,18
 
final SQLElement sqlElement = configuration.getDirectory().getElement(this.sqlRow.getTable());
 
final Map<String, CustomEditorProvider> customEditors;
if (this.editMode.equals(EditMode.CREATION)) {
customEditors = sqlElement.getCustomEditorProviderForCreation(configuration, sessionSecurityToken);
} else {
customEditors = sqlElement.getCustomEditorProviderForModification(configuration, this.sqlRow, sessionSecurityToken);
final List<CustomRowEditor> customRowEditors = sqlElement.getCustomRowEditors(configuration, sessionSecurityToken);
 
final Map<String, CustomRowEditor> customEditors = new HashMap<>(customRowEditors.size());
for (CustomRowEditor e : customRowEditors) {
customEditors.put(e.getItemId(), e);
}
 
this.createRowValues(configuration, sqlElement, fieldMapper, this.group, customEditors);
this.setMetaData(userId);
}
 
final protected void createRowValues(final Configuration configuration, final SQLElement sqlElement, final FieldMapper fieldMapper, final Group group,
final Map<String, CustomEditorProvider> customEditors) {
protected final void createRowValues(final Configuration configuration, final SQLElement sqlElement, final FieldMapper fieldMapper, final Group group,
final Map<String, CustomRowEditor> customEditors) {
final int itemCount = group.getSize();
for (int i = 0; i < itemCount; i++) {
final Item item = group.getItem(i);
176,26 → 177,29
this.putValueFromUserControl(configuration, sqlElement, field, uiElement, customEditors);
}
} else {
final LightUIElement uiElement = this.findChildByID(item.getId(), LightUIElement.class);
if (uiElement == null) {
throw new IllegalArgumentException("Impossible to find UI Element with id: " + item.getId());
}
if (customEditors.containsKey(uiElement.getId())) {
final CustomRowEditor customEditor = customEditors.get(uiElement.getId());
customEditor.store(uiElement, this.sqlRow);
} else {
Log.get().warning("No field attached to " + item.getId());
}
}
}
}
}
 
protected final void putValueFromUserControl(final Configuration configuration, final SQLElement sqlElement, final SQLField sqlField, final LightUIElement uiElement,
final Map<String, CustomEditorProvider> customEditors) {
final Map<String, CustomRowEditor> customEditors) {
if (!uiElement.isNotSaved()) {
boolean useElementValue = true;
final Class<?> fieldType = sqlField.getType().getJavaType();
if (customEditors.containsKey(uiElement.getId())) {
final CustomEditorProvider customEditor = customEditors.get(uiElement.getId());
if (customEditor instanceof SavableCustomEditorProvider) {
((SavableCustomEditorProvider) customEditor).save(this.sqlRow, sqlField, uiElement);
useElementValue = false;
}
}
 
if (useElementValue) {
final CustomRowEditor customEditor = customEditors.get(uiElement.getId());
customEditor.store(uiElement, this.sqlRow);
} else {
final String fieldName = sqlField.getFieldName();
if (sqlField.isKey()) {
if (!(uiElement instanceof LightUIComboBox)) {
268,11 → 272,13
* @param row Element saved row
* @param customEditors List of custom editors used in element edit frame
*/
final public void saveReferentRows(final Configuration configuration, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors, final String sessionSecurityToken) {
@Deprecated
public final void saveReferentRows(final Configuration configuration, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors, final String sessionSecurityToken) {
this.saveReferentRows(configuration, this.group, parentSqlRow, customEditors, sessionSecurityToken);
}
 
final private void saveReferentRows(final Configuration configuration, final Group group, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors,
@Deprecated
private final void saveReferentRows(final Configuration configuration, final Group group, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors,
final String sessionSecurityToken) {
for (int i = 0; i < group.getSize(); i++) {
final Item item = group.getItem(i);
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/CustomRowEditor.java
New file
0,0 → 1,49
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.ui.light.LightUIElement;
 
public abstract class CustomRowEditor {
private final String itemId;
 
public CustomRowEditor(String itemId) {
this.itemId = itemId;
}
 
public String getItemId() {
return this.itemId;
}
 
/**
* Create the UI element filled with the row
*
*/
public abstract LightUIElement createUIElement();
 
public abstract void fillFrom(final LightUIElement uiElement, final SQLRowAccessor row);
 
/**
* Store the values in the row from the UI element
*/
public abstract void store(final LightUIElement uiElement, final SQLRowValues row);
 
public void afterCommit(LightUIElement uiElement, SQLRow insertedRow) {
// nothing
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTableOnline.java
14,29 → 14,23
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.IFieldPath;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.Log;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelSource;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearch;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
 
import javax.swing.SwingUtilities;
 
import net.minidev.json.JSONObject;
 
public class LightRowValuesTableOnline extends LightRowValuesTable {
48,7 → 42,6
 
public LightRowValuesTableOnline(final Configuration configuration, final Number userId, final String id, final ITableModel model) {
super(configuration, userId, id, model);
 
this.orginTransformer = ((SQLTableModelSourceOnline) model.getReq()).getReq().getSelectTransf();
}
 
55,7 → 48,6
// Clone constructor
public LightRowValuesTableOnline(final LightRowValuesTableOnline tableElement) {
super(tableElement);
 
this.orginTransformer = tableElement.orginTransformer;
}
 
66,19 → 58,31
}
 
@Override
public void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset) {
public void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset) {
 
this.getTableSpec().setSearch(searchSpec);
 
this.setOffset(offset);
 
final SQLTableModelSource tableSource = this.getModel().getReq();
final SearchInfo sInfo = (searchSpec != null) ? new SearchInfo(searchSpec) : null;
final ListSQLRequest req = tableSource.getReq();
final List<UserSearchItem> content = new ArrayList<>();
if (searchSpec != null) {
content.addAll(searchSpec.getContent());
 
final FutureTask<ListSQLRequest> f = new FutureTask<ListSQLRequest>(new Callable<ListSQLRequest>() {
@Override
public ListSQLRequest call() throws Exception {
final ListSQLRequest req = tableSource.getReq();
final List<SQLTableModelColumn> columns = tableSource.getColumns();
for (UserSearchItem item : content) {
// ex "col0"
String colId = item.getColumn();
// ex "contains"
String searchType = item.getType();
TableSearchMatcher m = LightRowValuesTableOnline.this.getSearchMatcher(colId, searchType);
if (m != null && m.getAdditionnalFieldsToFetch() != null) {
for (FieldPath p : m.getAdditionnalFieldsToFetch()) {
req.addToGraphToFetch(p.getPath(), Arrays.asList(p.getField().getFieldName()));
}
}
}
}
req.setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(final SQLSelect sel) {
85,60 → 89,30
if (LightRowValuesTableOnline.this.orginTransformer != null) {
LightRowValuesTableOnline.this.orginTransformer.transformChecked(sel);
}
setWhere(sel, sInfo, columns);
return sel;
if (searchSpec != null) {
//
final List<Where> wheres = new ArrayList<>();
for (UserSearchItem item : content) {
// ex "col0"
String colId = item.getColumn();
// ex "hello"
String userText = item.getText();
// ex "contains"
String searchType = item.getType();
TableSearchMatcher m = LightRowValuesTableOnline.this.getSearchMatcher(colId, searchType);
if (m != null) {
final Where where = m.getWhere(sel, new TableSearchParameterType(searchType), userText);
if (where != null) {
wheres.add(where);
}
});
return req;
} else {
Log.get().warning("no TableSearchMatcher for " + item);
}
});
 
// TODO: clean swing
SwingUtilities.invokeLater(f);
 
try {
final ListSQLRequest req = f.get();
 
// get values
long t4 = System.currentTimeMillis();
final List<SQLRowValues> rowValues = req.getValues();
final int size = rowValues.size();
long t5 = System.currentTimeMillis();
 
System.err.println("DefaultTableContentHandler.handle() getValues() :" + size + " : " + (t5 - t4) + " ms");
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}
 
/**
* Apply filter on ListSQLRequest
*
* @param sel - The ListSQLRequest select
* @param sInfo - Search parameters
*/
private final void setWhere(final SQLSelect sel, final SearchInfo sInfo, final List<SQLTableModelColumn> cols) {
if (sInfo != null) {
final Set<IFieldPath> fields = new HashSet<>(cols.size() * 2);
for (final SQLTableModelColumn sqlTableModelColumn : cols) {
fields.addAll(sqlTableModelColumn.getPaths());
}
final List<Where> wheres = new ArrayList<>();
final List<Where> wFields = new ArrayList<>();
 
final List<String> texts = sInfo.getTexts();
for (String string : texts) {
wFields.clear();
for (final IFieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, sel.followFieldPath(fpath)), "LIKE", "%" + string.toLowerCase() + "%");
wFields.add(w);
}
}
wheres.add(Where.or(wFields));
}
 
final Where w;
if (!wheres.isEmpty()) {
if (sel.getWhere() != null) {
w = Where.and(sel.getWhere(), Where.and(wheres));
} else {
147,4 → 121,10
sel.setWhere(w);
}
}
return sel;
}
});
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_fr.xml
2,21 → 2,23
<translations>
<element refid="sql.user">
<name base="utilisateur" nounClass="masculine" />
<FIELD name="NOM" label="Nom" titlelabel="Nom" />
<FIELD name="PRENOM" label="Prénom" titlelabel="Prénom" />
<FIELD name="PASSWORD" label="Mot de passe" titlelabel="Mot de passe" />
<FIELD name="NOM" label="Nom" />
<FIELD name="PRENOM" label="Prénom" />
<FIELD name="PASSWORD" label="Mot de passe" />
<FIELD name="PASSWORD_CONFIRM" label="Confirmation" />
<FIELD name="LOGIN" label="Identifiant" titlelabel="Identifiant" />
<FIELD name="SURNOM" label="Surnom" titlelabel="Surnom" />
<FIELD name="LOGIN" label="Identifiant" />
<FIELD name="SURNOM" label="Surnom" />
<FIELD name="ADMIN" label="Administrateur" titlelabel="Admin." />
<FIELD name="ID_USER_RIGHT_COMMON" label="Droits utilisateur" titlelabel="Droits utilisateur" />
<FIELD name="ID_USER_RIGHT_COMMON" label="Droits utilisateur" />
<FIELD name="MAIL" label="E-Mail" titlelabel="E-Mail" />
<FIELD name="COMPTE_NUMERO" label="N° compte comptable" />
<FIELD name="DISABLED" label="Compte désactivé" />
<FIELD name="TEL" label="Téléphone" titlelabel="Téléphone" />
<FIELD name="TEL" label="Téléphone" />
<FIELD name="COLOR" label="Couleur" />
</element>
<element refid="sql.right">
<name base="droit" nounClass="masculine" />
<FIELD name="CODE" label="Code" titlelabel="Code" />
<FIELD name="CODE" label="Code" />
<FIELD name="NOM" label="Nom" titlelabel="Nom du droit" />
<FIELD name="DESCRIPTION" label="Description" titlelabel="Desc." />
</element>
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java
202,10 → 202,55
* @return the corresponding SQLElement, or <code>null</code> if none can be found.
* @throws IllegalArgumentException if there's more than one match.
*/
public synchronized final <S extends SQLElement> S getElement(Class<S> clazz) {
return clazz.cast(this.getElement(getSoleTable(this.byClass, clazz)));
public final <S extends SQLElement> S getElement(Class<S> clazz) {
return this.getElementOfClass(clazz, false);
}
 
public final <S extends SQLElement> S getElementOfClass(Class<S> clazz, final boolean allowSubclass) {
final List<S> res = getElementsOfClass(clazz, allowSubclass);
if (res.size() > 1)
throw new IllegalArgumentException(clazz + " is not unique: " + res);
return res.isEmpty() ? null : res.get(0);
}
 
/**
* Search for SQLElement whose class is <code>clazz</code>.
*
* @param clazz the class.
* @param allowSubclass <code>true</code> to include {@link Class#isInstance(Object)
* subclasses}, <code>false</code> to only return exact match.
* @return the corresponding elements.
*/
public final <S extends SQLElement> List<S> getElementsOfClass(final Class<S> clazz, final boolean allowSubclass) {
final List<S> res;
synchronized (this) {
if (allowSubclass) {
res = new ArrayList<>();
for (final SQLElement elem : this.elements.values()) {
if (clazz.isInstance(elem))
res.add(clazz.cast(elem));
}
} else {
final Set<SQLTable> tables = this.byClass.get(clazz);
if (tables != null) {
res = new ArrayList<>(tables.size());
for (final SQLTable t : tables) {
res.add(clazz.cast(this.getElement(t)));
}
} else {
res = Collections.emptyList();
}
}
}
if (res.isEmpty()) {
return Collections.emptyList();
} else if (res.size() == 1) {
return Collections.singletonList(res.get(0));
} else {
return Collections.unmodifiableList(res);
}
}
 
public synchronized final SQLElement getElementForCode(String code) {
return this.getElement(getSoleTable(this.byCode, code));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GroupSQLComponent.java
64,8 → 64,8
 
private final Group group;
private final int columns = 2;
private final Map<String, JComponent> labels = new HashMap<String, JComponent>();
private final Map<String, JComponent> editors = new HashMap<String, JComponent>();
private final Map<String, JComponent> labels = new HashMap<>();
private final Map<String, JComponent> editors = new HashMap<>();
private String startTabAfter = null;
private boolean tabGroup;
private int tabDepth;
80,6 → 80,12
 
public GroupSQLComponent(final SQLElement element, final Group group) {
super(element);
if (element == null) {
throw new IllegalArgumentException("null SQLElement");
}
if (group == null) {
throw new IllegalArgumentException("null group (SQLElement : " + element + ")");
}
this.group = group;
this.hasAdditionnalFields = this.getElement().getAdditionalFields().size() > 0;
this.additionnalFieldsGroup = getAdditionalFieldsGroup(group.getDescendantGroups());
99,7 → 105,7
}
 
public void startTabGroupAfter(String id) {
startTabAfter = id;
this.startTabAfter = id;
}
 
@Override
155,7 → 161,8
c.gridx = 0;
c.weightx = 1;
c.gridwidth = 4;
panel.add(getLabel(id), c);
JComponent comp = getLabel(id);
panel.add(comp, c);
c.gridy++;
}
}
276,13 → 283,13
}
 
}
if (id.equals(startTabAfter)) {
if (tabGroup) {
if (id.equals(this.startTabAfter)) {
if (this.tabGroup) {
throw new IllegalArgumentException("ID " + id + " already set as tab");
}
tabGroup = true;
tabDepth = level;
pane = new JTabbedPane();
this.tabGroup = true;
this.tabDepth = level;
this.pane = new JTabbedPane();
c.gridx = 0;
c.gridy++;
c.weightx = 1;
289,7 → 296,7
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 4;
panel.add(pane, c);
panel.add(this.pane, c);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
57,10 → 57,10
import org.openconcerto.sql.request.SQLCache;
import org.openconcerto.sql.request.SQLFieldTranslator;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.ui.light.CustomRowEditor;
import org.openconcerto.sql.ui.light.GroupToLightUIConvertor;
import org.openconcerto.sql.ui.light.LightEditFrame;
import org.openconcerto.sql.ui.light.LightUIPanelFiller;
import org.openconcerto.sql.ui.light.SavableCustomEditorProvider;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
74,7 → 74,6
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.group.Group;
import org.openconcerto.ui.light.ComboValueConvertor;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.IntValueConvertor;
import org.openconcerto.ui.light.LightUIComboBox;
import org.openconcerto.ui.light.LightUIElement;
337,10 → 336,10
editFrame.createTitlePanel(this.getCreationFrameTitle());
} else if (editMode.equals(EditMode.MODIFICATION)) {
editFrame.createTitlePanel(this.getModificationFrameTitle(sqlRow));
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, sqlRow);
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, this, sqlRow, sessionSecurityToken);
} else if (editMode.equals(EditMode.READONLY)) {
editFrame.createTitlePanel(this.getReadOnlyFrameTitle(sqlRow));
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, sqlRow);
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, this, sqlRow, sessionSecurityToken);
}
 
this.setEditFrameModifiers(editFrame, sessionSecurityToken);
389,11 → 388,12
*/
public GroupToLightUIConvertor getGroupToLightUIConvertor(final PropsConfiguration configuration, final EditMode editMode, final SQLRowAccessor sqlRow, final String token) {
final GroupToLightUIConvertor convertor = new GroupToLightUIConvertor(configuration);
if (editMode.equals(EditMode.CREATION)) {
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForCreation(configuration, token));
} else {
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForModification(configuration, sqlRow, token));
}
// if (editMode.equals(EditMode.CREATION)) {
convertor.putAllCustomEditorProvider(this.getCustomRowEditors(configuration, token));
// } else {
// convertor.putAllCustomEditorProvider(this.getCustomRowEditors(configuration, sqlRow,
// token));
// }
return convertor;
}
 
418,76 → 418,55
public void setEditFrameModifiers(final LightEditFrame frame, final String sessionToken) {
}
 
public final Map<String, CustomEditorProvider> getCustomEditorProviderForCreation(final Configuration configuration, final String sessionToken) {
final Map<String, CustomEditorProvider> map = this.getDefaultCustomEditorProvider(configuration, null, sessionToken);
map.putAll(this._getCustomEditorProviderForCreation(configuration, sessionToken));
return map;
}
 
public final Map<String, CustomEditorProvider> getCustomEditorProviderForModification(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
final Map<String, CustomEditorProvider> map = this.getDefaultCustomEditorProvider(configuration, sqlRow, sessionToken);
map.putAll(this._getCustomEditorProviderForModification(configuration, sqlRow, sessionToken));
return map;
}
 
protected Map<String, CustomEditorProvider> _getCustomEditorProviderForCreation(final Configuration configuration, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
protected Map<String, CustomEditorProvider> _getCustomEditorProviderForModification(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
protected Map<String, CustomEditorProvider> _getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
private final Map<String, CustomEditorProvider> getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
public List<CustomRowEditor> getCustomRowEditors(final Configuration configuration, final String sessionToken) {
final Map<String, ComboValueConvertor<?>> comboConvertors = this.getComboConvertors();
final Map<String, CustomEditorProvider> result = new HashMap<String, CustomEditorProvider>();
final List<CustomRowEditor> result = new ArrayList<>();
for (final Entry<String, ComboValueConvertor<?>> entry : comboConvertors.entrySet()) {
result.put(entry.getKey(), new SavableCustomEditorProvider() {
 
final String itemId = entry.getKey();
result.add(new CustomRowEditor(itemId) {
final ComboValueConvertor<?> convertor = entry.getValue();
 
@Override
public LightUIElement createUIElement(final String elementId) {
final LightUIComboBox uiCombo = new LightUIComboBox(elementId);
public LightUIElement createUIElement() {
final LightUIComboBox uiCombo = new LightUIComboBox(getItemId());
this.convertor.fillCombo(uiCombo, null);
return uiCombo;
}
 
if (sqlRow == null) {
this.convertor.fillCombo(uiCombo, null);
} else {
final SQLField field = configuration.getFieldMapper().getSQLFieldForItem(elementId);
@Override
public void fillFrom(LightUIElement uiElement, SQLRowAccessor sqlRow) {
final LightUIComboBox uiCombo = (LightUIComboBox) uiElement;
final SQLField field = configuration.getFieldMapper().getSQLFieldForItem(getItemId());
if (this.convertor instanceof StringValueConvertor) {
((StringValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getString(field.getFieldName()));
} else if (this.convertor instanceof IntValueConvertor) {
if (sqlRow.getObject(field.getFieldName()) == null) {
this.convertor.fillCombo(uiCombo, null);
} else {
if (sqlRow.getObject(field.getFieldName()) != null) {
((IntValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getInt(field.getFieldName()));
}
}
 
}
return uiCombo;
}
 
@Override
protected void _save(final SQLRowValues sqlRow, final SQLField sqlField, final LightUIElement uiElement) {
final LightUIComboBox combo = (LightUIComboBox) uiElement;
if (combo.hasSelectedValue()) {
public void store(LightUIElement uiElement, SQLRowValues sqlRow) {
final LightUIComboBox combobox = (LightUIComboBox) uiElement;
final String fieldName = configuration.getFieldMapper().getSQLFieldForItem(getItemId()).getName();
if (combobox.hasSelectedValue()) {
if (this.convertor instanceof StringValueConvertor) {
sqlRow.put(sqlField.getName(), ((StringValueConvertor) this.convertor).getIdFromIndex(combo.getSelectedValue().getId()));
sqlRow.put(fieldName, ((StringValueConvertor) this.convertor).getIdFromIndex(combobox.getSelectedValue().getId()));
} else if (this.convertor instanceof IntValueConvertor) {
sqlRow.put(sqlField.getName(), combo.getSelectedValue().getId());
sqlRow.put(fieldName, combobox.getSelectedValue().getId());
} else {
throw new IllegalArgumentException("the save is not implemented for the class: " + this.convertor.getClass().getName() + " - ui element id: " + uiElement.getId());
throw new IllegalArgumentException("the save is not implemented for the class: " + this.convertor.getClass().getName() + " - ui id: " + getItemId());
}
} else {
sqlRow.put(sqlField.getName(), null);
sqlRow.put(fieldName, null);
}
 
}
});
}
result.putAll(this._getDefaultCustomEditorProvider(configuration, sqlRow, sessionToken));
return result;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java
434,7 → 434,13
if (!(this instanceof GroupSQLComponent)) {
 
for (final Entry<String, JComponent> e : this.getElement().getAdditionalFields().entrySet()) {
final SpecParser spec = new SpecParser(null, true);
final SpecParser spec;
// FIXME Required à spécifier directement depuis le module
if (this.requiredNames != null && this.requiredNames.contains(e.getKey())) {
spec = new SpecParser(REQ, true);
} else {
spec = new SpecParser(null, true);
}
final JComponent comp = e.getValue();
if (comp == null)
// infer component
726,7 → 732,6
return this.getRequest().setLastKnownDBVals(current, this.getRequest().fetchRow(current.getID(), ls));
}
 
 
@Override
public final void select(int id) {
// TODO in an executor outside of the EDT
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/SQLUtils.java
372,9 → 372,8
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute, afterHandle;
final Statement stmt = conn.createStatement();
int count = 0;
try {
try (final Statement stmt = conn.createStatement()){
if (Thread.currentThread().isInterrupted())
throw new RTInterruptedException("Interrupted before executing : " + query);
stmt.execute(query);
392,8 → 391,6
stmt.getMoreResults();
}
afterHandle = System.nanoTime();
} finally {
stmt.close();
}
SQLRequestLog.log(query, "executeMultiple", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), count);
return null;
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java
1006,7 → 1006,7
}
 
// TODO support java.time.LocalDateTime in Java 8
static private <T, U> U convert(final Class<T> source, final Object value, final Class<U> dest) {
public static <T, U> U convert(final Class<T> source, final Object value, final Class<U> dest) {
final ValueConvertor<T, U> conv = ValueConvertorFactory.find(source, dest);
if (conv == null)
throw new IllegalArgumentException("No convertor to " + dest + " from " + source);
2447,7 → 2447,6
return insert(t, sql, ReturnMode.NO_FIELDS).getCount();
}
 
// if scalar is null primary keys aren't fetched
private static final Insertion<?> insert(final SQLTable t, final String sql, final ReturnMode mode) throws SQLException {
return new Inserter(t).insert(sql, mode, true);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRequestLog.java
25,6 → 25,7
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.text.DateFormat;
60,7 → 61,23
private static final String ACTIVER_LA_CAPTURE = "Enable monitoring";
private static final String DESACTIVER_LA_CAPTURE = "Disable monitoring";
private static Vector<SQLRequestLog> list = new Vector<SQLRequestLog>(500);
@GuardedBy("this")
private static boolean enabled;
 
public static synchronized void setEnabled(boolean enable) {
enabled = enable;
}
 
public static synchronized boolean toggleEnabled() {
final boolean newVal = !isEnabled();
setEnabled(newVal);
return newVal;
}
 
public static synchronized boolean isEnabled() {
return enabled;
}
 
private String query;
private String comment;
private long startAsMs;
85,10 → 102,6
return l == 0 ? "" : dformat.format(l / 1000000D) + " ms";
}
 
public static void setEnabled(boolean enable) {
enabled = enable;
}
 
public SQLRequestLog(String query, String comment, int connectionId, long starAtMs, String ex, boolean inSwing, long startTime, long afterCache, long afterQueryInfo, long afterExecute,
long afterHandle, long endTime, int count) {
this.query = query;
116,7 → 129,7
public static void log(String query, String comment, int connectionId, long starAtMs, long startTime, long afterCache, long afterQueryInfo, long afterExecute, long afterHandle, long endTime,
int count) {
 
if (enabled) {
if (isEnabled()) {
if (list.size() < 50000) {
final String ex = ExceptionUtils.getStackTrace(new Exception());
 
135,7 → 148,7
 
public static void log(PreparedStatement pStmt, String comment, long timeMs, long startTime, long afterCache, long afterQueryInfo, long afterExecute, long afterHandle, long endTime) {
// only call potentially expensive and/or exceptions throwing methods if necessary
if (enabled) {
if (isEnabled()) {
try {
log(pStmt.toString(), comment, pStmt.getConnection(), timeMs, startTime, afterCache, afterQueryInfo, afterExecute, afterHandle, endTime, 0);
} catch (Exception e) {
433,7 → 446,7
JPanel bar = new JPanel(new FlowLayout());
 
final JButton b0 = new JButton();
if (enabled) {
if (isEnabled()) {
b0.setText(DESACTIVER_LA_CAPTURE);
} else {
b0.setText(ACTIVER_LA_CAPTURE);
441,11 → 454,9
b0.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (enabled) {
enabled = false;
if (!toggleEnabled()) {
b0.setText(ACTIVER_LA_CAPTURE);
} else {
enabled = true;
b0.setText(DESACTIVER_LA_CAPTURE);
}
 
620,4 → 631,15
model.fireTableRowsUpdated(0, model.getRowCount() - 1);
}
}
 
public static void dump(PrintStream out) {
final DecimalFormat dformat = new DecimalFormat("##0.00");
for (SQLRequestLog log : list) {
out.print(dformat.format(log.getDurationTotalNano() / 1000000D) + " ms ");
out.print("\t");
out.print(log.getQuery());
out.println();
}
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLInsert.java
New file
0,0 → 1,314
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.model;
 
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
 
import org.postgresql.copy.CopyManager;
import org.postgresql.core.BaseConnection;
import org.postgresql.jdbc.PgConnection;
 
public class SQLInsert {
private List<SQLField> fields = new ArrayList<>();
private List<Object> values = new ArrayList<>();
private SQLTable table;
 
public void add(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
this.fields.add(field);
this.values.add(value);
}
 
public void set(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
this.values.set(index, value);
}
 
public boolean contains(SQLField field) {
return this.fields.indexOf(field) >= 0;
}
 
public Object getValue(SQLField field) {
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
return this.values.get(index);
}
 
public String asString() {
if (this.fields.isEmpty()) {
throw new IllegalStateException("not fields added");
}
final StringBuilder builder = new StringBuilder();
builder.append("INSERT INTO ");
builder.append(this.table.getSQLName());
builder.append(" (");
//
int stop = this.fields.size();
for (int i = 0; i < stop; i++) {
builder.append(this.fields.get(i).getQuotedName());
if (i < stop - 1) {
builder.append(',');
}
}
 
builder.append(") VALUES (");
 
for (int i = 0; i < stop; i++) {
Object value = this.values.get(i);
final SQLField field = this.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (value != null && !javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
builder.append(field.getType().toString(str));
 
if (i < stop - 1) {
builder.append(',');
}
}
 
builder.append(")");
return builder.toString();
}
 
/**
* Insert multiple rows. Rows can be from different tables.
*
* Speed : 19 000 inserts /s on PostgreSQL
*/
public static void executeMultiple(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
final Map<SQLTable, List<SQLInsert>> map = new HashMap<>();
for (final SQLInsert q : queries) {
List<SQLInsert> list = map.get(q.table);
if (list == null) {
list = new ArrayList<>();
map.put(q.table, list);
}
list.add(q);
}
for (Entry<SQLTable, List<SQLInsert>> entry : map.entrySet()) {
executeSimilarInserts(sysRoot, entry.getValue(), false);
}
}
 
/**
* Insert multiple rows with a batch. Rows can be from different tables.
*
* Speed : 8 000 inserts /s on PostgreSQL
*/
public static long executeMultipleWithBatch(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
final List<String> l = new ArrayList<>(queries.size());
for (final SQLInsert i : queries)
l.add(i.asString());
return sysRoot.getDataSource().executeBatch(l, true).get0();
}
 
/**
* Insert multiple rows in the same table, using COPY on PostgreSQL for the maximum speed
*
* Speed : 26 000 inserts /s on PostgreSQL
*/
public static long executeSimilarWithCopy(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
SQLDataSource dataSource = sysRoot.getDataSource();
if (dataSource.getSystem() != SQLSystem.POSTGRESQL) {
return executeSimilarInserts(sysRoot, queries, true).size();
}
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
SQLInsert insert0 = queries.get(0);
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
 
final String query = insert0 + "..." + queries.size() + " queries";
 
return dataSource.useConnection(new ConnectionHandlerNoSetup<Long, SQLException>() {
@Override
public Long handle(SQLDataSource ds) throws SQLException {
final Connection conn = ds.getConnection().unwrap(PgConnection.class);
final CopyManager copyManager = new CopyManager((BaseConnection) conn);
final StringBuilder allValues = new StringBuilder(insert0.fields.size() * 10 * queries.size());
final List<String> fi = new ArrayList<>();
for (SQLField f : insert0.fields) {
fi.add(f.getQuotedName());
}
for (final SQLInsert q : queries) {
if (!q.table.equals(insert0.table)) {
throw new IllegalArgumentException("table " + q.table.getName() + " is not " + insert0.table.getTable());
}
if (!q.fields.equals(insert0.fields)) {
throw new IllegalArgumentException("fields" + q.fields + " not equals to " + insert0.fields);
}
int stop = q.values.size();
for (int i = 0; i < stop; i++) {
Object value = q.values.get(i);
final SQLField field = q.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
// FIXME null, escapes (see SQLSyntaxPG)
allValues.append(field.getType().toString(str));
if (i < stop - 1) {
allValues.append('\t');
}
}
allValues.append('\n');
}
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute;
final long afterHandle;
final long count;
try {
count = copyManager.copyIn("COPY " + insert0.table.getSQLName() + "(" + String.join(",", fi) + ") FROM STDIN WITH (ENCODING 'UTF-8') ", new StringReader(allValues.toString()));
} catch (IOException e) {
throw new SQLException(e);
}
afterExecute = System.nanoTime();
afterHandle = afterExecute;
SQLRequestLog.log(query, "multiple similar with copy", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), queries.size());
 
return count;
}
});
}
 
/**
* Insert multiple rows in the same table
*
* Speed : 20 000 inserts /s on PostgreSQL
*/
public static List<Number> executeSimilarInserts(final DBSystemRoot sysRoot, final List<SQLInsert> queries, boolean returnIds) throws SQLException {
SQLDataSource dataSource = sysRoot.getDataSource();
 
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
SQLInsert insert0 = queries.get(0);
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
 
final String query = insert0 + "..." + queries.size() + " queries";
if (sysRoot.getServer().getSQLSystem() != SQLSystem.POSTGRESQL) {
List<Number> res = new ArrayList<>();
for (SQLInsert sqlInsert : queries) {
res.add((Number) sysRoot.getDataSource().executeScalar(sqlInsert.asString()));
}
return res;
} else {
return dataSource.useConnection(new ConnectionHandlerNoSetup<List<Number>, SQLException>() {
@Override
public List<Number> handle(SQLDataSource ds) throws SQLException {
final Connection conn = ds.getConnection();
final List<String> fi = new ArrayList<>();
for (SQLField f : insert0.fields) {
fi.add(f.getQuotedName());
}
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute;
final long afterHandle;
final StringBuilder sql = new StringBuilder(insert0.fields.size() * 10 * (queries.size() + 1));
sql.append("(" + String.join(",", fi) + ")");
sql.append(" VALUES ");
int size = queries.size();
for (int j = 0; j < size; j++) {
final SQLInsert q = queries.get(j);
if (!q.table.equals(insert0.table)) {
throw new IllegalArgumentException("table " + q.table.getName() + " is not " + insert0.table.getTable());
}
if (!q.fields.equals(insert0.fields)) {
throw new IllegalArgumentException("fields" + q.fields + " not equals to " + insert0.fields);
}
sql.append("(");
int stop = q.values.size();
for (int i = 0; i < stop; i++) {
Object value = q.values.get(i);
final SQLField field = q.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!field.isNullable() && value == null) {
throw new IllegalStateException("null value for " + field);
}
if (value != null && !javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
// FIXME : escape ' (quote)
sql.append(field.getType().toString(str));
 
if (i < stop - 1) {
sql.append(',');
}
}
sql.append(")");
if (j < size - 1) {
sql.append(',');
}
}
List<Number> res;
if (!returnIds) {
// TODO return count
SQLRowValues.insertCount(insert0.table, sql.toString());
res = null;
} else {
res = SQLRowValues.insertIDs(insert0.table, sql.toString());
}
afterExecute = System.nanoTime();
afterHandle = afterExecute;
SQLRequestLog.log(query, "multiple similar insert", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), queries.size());
 
return res;
}
});
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLInjector.java
166,18 → 166,28
rowVals.put(field.getName(), value);
}
 
protected void transfertReference(SQLRowAccessor srcRow, SQLRowValues rowVals, String from, String to) {
protected void transfertReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField, String from, String to) {
 
String label = rowVals.getString(to);
SQLPreferences prefs = SQLPreferences.getMemCached(srcRow.getTable().getDBRoot());
 
if (prefs.getBoolean("TransfertRef", true) || !to.equals("NOM")) {
if (label != null && label.trim().length() > 0) {
rowVals.put(to, label + ", " + srcRow.getString(from));
} else {
rowVals.put(to, srcRow.getString(from));
}
} else if (prefs.getBoolean("TransfertMultiRef", false)) {
SQLRowValues rowValsHeader = new SQLRowValues(UndefinedRowValuesCache.getInstance().getDefaultRowValues(tableElementDestination));
// TODO taxe may be undefined set it to default
rowValsHeader.put("NOM", srcRow.getString(from));
rowValsHeader.put(refField, rowVals);
}
 
}
 
protected void transfertNumberReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField) {
SQLPreferences prefs = new SQLPreferences(srcRow.getTable().getDBRoot());
SQLPreferences prefs = SQLPreferences.getMemCached(srcRow.getTable().getDBRoot());
 
if (prefs.getBoolean("TransfertRef", true)) {
String label = rowVals.getString("NOM");
412,7 → 422,7
* register manually a transfer, use with caution
*
* @throws SQLException
* */
*/
public void addTransfert(int idFrom, int idTo) throws SQLException {
final SQLTable tableTransfert = getSource().getTable(getTableTranferName());
final SQLRowValues rowTransfer = new SQLRowValues(tableTransfert);
/trunk/OpenConcerto/src/org/openconcerto/sql/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/SQLBackgroundTableCacheItem.java
28,6 → 28,11
public SQLBackgroundTableCacheItem(final SQLTable t, final int second) {
this.table = t;
this.timeout = second;
 
if (second == -1) {
reloadFromDB();
}
 
this.table.addTableModifiedListener(new SQLTableModifiedListener() {
 
@Override
44,16 → 49,20
this.enableReloadIfTableModified = enableReloadIfTableModified;
}
 
@SuppressWarnings("unchecked")
public synchronized void reloadFromDbIfNeeded() {
final long delta = System.currentTimeMillis() - this.lastReload;
if (delta / 1000 > this.timeout) {
if (this.timeout >= 0 && delta / 1000 > this.timeout) {
reloadFromDB();
}
}
 
@SuppressWarnings("unchecked")
private void reloadFromDB() {
final SQLSelect sel = new SQLSelect();
sel.addSelectStar(this.table);
this.rows = Collections.unmodifiableList((List<SQLRow>) this.table.getBase().getDataSource().execute(sel.asString(), SQLRowListRSH.createFromSelect(sel, this.table)));
this.lastReload = System.currentTimeMillis();
}
}
 
public synchronized SQLRow getFirstRowContains(final int value, final SQLField field) {
for (SQLRow r : this.rows) {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBackgroundTableCache.java
19,7 → 19,7
 
public class SQLBackgroundTableCache {
private static SQLBackgroundTableCache instance;
private Map<SQLTable, SQLBackgroundTableCacheItem> list = new HashMap<SQLTable, SQLBackgroundTableCacheItem>();
private Map<SQLTable, SQLBackgroundTableCacheItem> list = new HashMap<>();
 
/**
* @param args
90,7 → 90,8
item.reloadFromDbIfNeeded();
} else {
System.err.println("SQLBackgroundTableCache.getCacheForTable() WARNING " + t.getName() + " is not registered (use add to register)");
this.add(t, 0);
// Start cache without autorefresh for Caisse offline
this.add(t, -1);
item = this.list.get(t);
item.reloadFromDbIfNeeded();
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLUpdate.java
New file
0,0 → 1,115
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.model;
 
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
public class SQLUpdate {
private List<SQLField> fields = new ArrayList<>();
private List<Object> values = new ArrayList<>();
private SQLTable table;
private Where where;
 
public SQLUpdate(Where where) {
this.where = where;
}
 
public void add(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
this.fields.add(field);
this.values.add(value);
}
 
public void set(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
this.values.set(index, value);
}
 
public boolean contains(SQLField field) {
return this.fields.indexOf(field) >= 0;
}
 
public Object getValue(SQLField field) {
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
return this.values.get(index);
}
 
public String asString() {
if (this.fields.isEmpty()) {
throw new IllegalStateException("not fields added");
}
final StringBuilder builder = new StringBuilder();
builder.append("UPDATE ");
builder.append(this.table.getSQLName());
builder.append(" SET ");
//
int stop = this.fields.size();
for (int i = 0; i < stop; i++) {
final SQLField field = this.fields.get(i);
builder.append(field.getQuotedName());
builder.append("=");
 
Object value = this.values.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
builder.append(field.getType().toString(str));
if (i < stop - 1) {
builder.append(',');
}
}
builder.append(" WHERE ");
builder.append(this.where.getClause());
return builder.toString();
}
 
/**
* Update multiple rows with a batch. Rows can be from different tables.
*
* Speed : 5000 /s
*/
public static long executeMultipleWithBatch(final DBSystemRoot sysRoot, final List<SQLUpdate> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no updates");
}
final List<String> l = new ArrayList<>(queries.size());
for (final SQLUpdate i : queries)
l.add(i.asString());
return sysRoot.getDataSource().executeBatch(l, true).get0();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLDataSource.java
16,11 → 16,13
import org.openconcerto.sql.Log;
import org.openconcerto.sql.State;
import org.openconcerto.sql.request.SQLCache;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.ExceptionUtils;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.ThreadFactory;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cache.ICacheSupport;
 
48,6 → 50,8
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
 
import org.apache.commons.dbcp.AbandonedConfig;
993,7 → 997,66
return res;
}
 
private static final Tuple2<Long, int[]> NO_QUERIES_RES = Tuple2.create(0l, new int[0]);
 
/**
* Execute multiple queries in batch.
*
* @param queries what to execute.
* @param atomic <code>true</code> if all queries should be executed in a transaction.
* @return the total update count (&lt; 0 if unknown), followed by the individual update counts.
* @throws SQLException if an error occurs.
* @see Statement#executeBatch()
*/
public final Tuple2<Long, int[]> executeBatch(final List<String> queries, final boolean atomic) throws SQLException {
if (queries.isEmpty())
return NO_QUERIES_RES;
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
final AtomicLong afterQueryInfo = new AtomicLong();
final AtomicLong afterExecute = new AtomicLong();
final AtomicReference<Connection> conn = new AtomicReference<>();
final ConnectionHandlerNoSetup<int[], SQLException> handler = new ConnectionHandlerNoSetup<int[], SQLException>() {
@Override
public int[] handle(SQLDataSource ds) throws SQLException {
afterQueryInfo.set(System.nanoTime());
conn.set(ds.getConnection());
final int[] res;
try (final Statement stmt = conn.get().createStatement()) {
for (final String s : queries) {
stmt.addBatch(s);
}
if (Thread.currentThread().isInterrupted())
throw new RTInterruptedException("Interrupted before executing : " + queries);
res = stmt.executeBatch();
}
afterExecute.set(System.nanoTime());
return res;
}
};
final int[] res = atomic ? SQLUtils.executeAtomic(this, handler) : this.useConnection(handler);
long totalCount = 0;
int i = 0;
for (final int count : res) {
if (count == Statement.SUCCESS_NO_INFO) {
totalCount = -1;
break;
} else {
if (count < 0)
throw new SQLException("Invalid count (" + count + ") for query " + i + " : " + queries.get(i));
totalCount += count;
}
i++;
}
if (SQLRequestLog.isEnabled()) {
final long afterHandle = System.nanoTime();
SQLRequestLog.log(queries.toString(), "executeBatch", conn.get(), timeMs, time, afterCache, afterQueryInfo.get(), afterExecute.get(), afterHandle, afterHandle, (int) totalCount);
}
return Tuple2.create(totalCount, res);
}
 
/**
* Try to execute a {@link #getValidationQuery() simple query} on the database server. This
* method even works when the pool is exhausted.
*
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowListRSH.java
19,10 → 19,12
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
 
import org.apache.commons.dbutils.ResultSetHandler;
 
37,16 → 39,18
// ATTN doesn't check that the types of columns are coherent with the types of the fields
public RSH(final SQLTable t, final List<String> names) {
this(Tuple2.create(t, names));
if (!t.getFieldsName().containsAll(names))
throw new IllegalArgumentException("Not all names are fields of " + t + " : " + names);
// null are OK (they're ignored)
final List<String> unknown = names.stream().filter(n -> n != null && !t.getFieldsName().contains(n)).collect(Collectors.toList());
if (!unknown.isEmpty())
throw new IllegalArgumentException("Not all names are fields of " + t + " : " + unknown);
}
 
private RSH(Tuple2<SQLTable, List<String>> names) {
private RSH(final Tuple2<SQLTable, List<String>> names) {
this.names = names;
}
 
@Override
public List<SQLRow> handle(ResultSet rs) throws SQLException {
public List<SQLRow> handle(final ResultSet rs) throws SQLException {
// since the result will be cached, disallow its modification (e.g.avoid
// ConcurrentModificationException)
return Collections.unmodifiableList(SQLRow.createListFromRS(this.names.get0(), rs, this.names.get1()));
58,7 → 62,7
}
 
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
78,7 → 82,7
return t;
}
 
static Tuple2<SQLTable, List<String>> getIndexes(SQLSelect sel, final TableRef passedTable, final boolean findTable) {
static Tuple2<SQLTable, List<String>> getIndexes(final SQLSelect sel, final TableRef passedTable, final boolean findTable) {
final List<FieldRef> selectFields = sel.getSelectFields();
final int size = selectFields.size();
if (size == 0)
124,6 → 128,7
* @return a handler creating a list of {@link SQLRow}.
* @deprecated use {@link SQLSelectHandlerBuilder}
*/
@Deprecated
static public ResultSetHandler createFromSelect(final SQLSelect sel) {
return create(getIndexes(sel, null, true));
}
137,6 → 142,7
* @return a handler creating a list of {@link SQLRow}.
* @deprecated use {@link SQLSelectHandlerBuilder}
*/
@Deprecated
static public ResultSetHandler createFromSelect(final SQLSelect sel, final TableRef t) {
return create(getIndexes(sel, t, false));
}
145,6 → 151,20
return new RSH(names);
}
 
static public List<SQLRow> fetch(final SQLTable t, final Collection<? extends Number> ids) throws IllegalArgumentException {
return fetch(t, ids, null);
}
 
static public List<SQLRow> fetch(final SQLTable t, final Collection<? extends Number> ids, final Collection<String> fields) throws IllegalArgumentException {
final SQLSelect sel = new SQLSelect();
if (fields == null)
sel.addSelectStar(t);
else
sel.addAllSelect(t, fields);
sel.setWhere(new Where(t.getKey(), ids));
return execute(sel);
}
 
/**
* Execute the passed select and return rows. NOTE if there's more than one table in the query
* {@link #execute(SQLSelect, TableRef)} must be used.
195,17 → 215,18
private final SQLTable t;
private final boolean tableOnly;
 
public SQLRowListRSH(SQLTable t) {
public SQLRowListRSH(final SQLTable t) {
this(t, false);
}
 
public SQLRowListRSH(SQLTable t, final boolean tableOnly) {
public SQLRowListRSH(final SQLTable t, final boolean tableOnly) {
super();
this.t = t;
this.tableOnly = tableOnly;
}
 
public Object handle(ResultSet rs) throws SQLException {
@Override
public List<SQLRow> handle(final ResultSet rs) throws SQLException {
return SQLRow.createListFromRS(this.t, rs, this.tableOnly);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/users/User.java
15,6 → 15,8
 
import org.openconcerto.sql.model.SQLRowAccessor;
 
import java.awt.Color;
 
import net.jcip.annotations.Immutable;
 
@Immutable
22,6 → 24,7
private final int id;
private final String name, firstName, nickName;
private final Boolean active;
private final Color color;
 
public User(final SQLRowAccessor r) {
this.id = r.getID();
33,7 → 36,12
} else {
this.active = null;
}
if (r.contains("COLOR")) {
this.color = new Color(r.getInt("COLOR"));
} else {
this.color = null;
}
}
 
public String getName() {
return this.name;
63,4 → 71,8
public boolean isActive() {
return this.active;
}
 
public Color getColor() {
return this.color;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/TableAllRights.java
31,9 → 31,11
public static final String ADD_ROW_TABLE = "INSERT_ROW";
public static final String VIEW_ROW_TABLE = "SELECT_ROW";
public static final String SAVE_ROW_TABLE = "SAVE_ROW";
public static final String USER_UI_LOCK_ROW = "LIST_UI_LOCK_ROWS";
public static final String USER_UI_UNLOCK_ROW = "LIST_UI_UNLOCK_ROWS";
 
public static final List<String> getCodes() {
return Arrays.asList(CODE, CODE_MODIF, DELETE_ROW_TABLE, MODIFY_ROW_TABLE, ADD_ROW_TABLE, VIEW_ROW_TABLE, SAVE_ROW_TABLE);
return Arrays.asList(CODE, CODE_MODIF, DELETE_ROW_TABLE, MODIFY_ROW_TABLE, ADD_ROW_TABLE, VIEW_ROW_TABLE, SAVE_ROW_TABLE, USER_UI_UNLOCK_ROW, USER_UI_LOCK_ROW);
}
 
public static RightTuple createRight(final SQLTable t, final boolean b) {
119,6 → 121,8
res.add(new RightTuple(DELETE_ROW_TABLE, object, haveRight));
res.add(new RightTuple(MODIFY_ROW_TABLE, object, haveRight));
res.add(new RightTuple(ADD_ROW_TABLE, object, haveRight));
res.add(new RightTuple(USER_UI_LOCK_ROW, object, haveRight));
res.add(new RightTuple(USER_UI_UNLOCK_ROW, object, haveRight));
if (getCode() == CODE)
res.add(new RightTuple(VIEW_ROW_TABLE, object, haveRight));
return res;
/trunk/OpenConcerto/src/org/openconcerto/sql/users/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/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/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/TableSorter.java
348,8 → 348,12
* @return the corresponding index in the model.
*/
public int modelIndex(int viewIndex) {
try {
return getViewToModel()[viewIndex].modelIndex;
} catch (Exception e) {
throw new IllegalStateException(this + " couldn't get model index for view index " + viewIndex + " with " + this.getTableModel().getRowCount() + " row(s) in our model", e);
}
}
 
private int[] getModelToView() {
if (!SwingUtilities.isEventDispatchThread()) {
430,6 → 434,11
this.supp.removePropertyChangeListener(l);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " on " + this.getTableModel();
}
 
// Helper classes
 
private class Row implements Comparable<Row> {
/trunk/OpenConcerto/src/org/openconcerto/utils/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/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/IFactory.java
13,8 → 13,9
package org.openconcerto.utils.cc;
 
public interface IFactory<E> {
public interface IFactory<E> extends IExnFactory<E, RuntimeException> {
 
@Override
public abstract E createChecked();
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/CustomEquals.java
19,7 → 19,10
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
import java.util.Set;
import java.util.function.BiPredicate;
 
/**
* Allow to create a proxy object which uses a {@link HashingStrategy}.
103,6 → 106,28
return CompareUtils.equals(sA, sB);
}
 
static public final <S, T1 extends S> int indexOf(final List<T1> s1, final S o, final HashingStrategy<S> s) {
return indexOf(s1, o, s::equals);
}
 
static public final <S, T1 extends S> int indexOf(final List<T1> s1, final S o, final BiPredicate<S, S> s) {
if (s1 instanceof RandomAccess) {
final int stop = s1.size();
for (int i = 0; i < stop; i++) {
if (s.test(s1.get(i), o))
return i;
}
} else {
final ListIterator<T1> listIter = s1.listIterator();
while (listIter.hasNext()) {
final T1 item = listIter.next();
if (s.test(item, o))
return listIter.previousIndex();
}
}
return -1;
}
 
static public class ProxyFull<S, E extends S> implements ProxyItf<E> {
 
static public final <S, E extends S> Set<ProxyFull<S, E>> createSet(final HashingStrategy<S> strategy, final Collection<E> coll) {
192,7 → 217,12
else
return this.strategy.equals(this.getDelegate(), delegate2);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " using strategy " + this.getStrategy() + " for " + this.getDelegate();
}
}
 
/**
* A proxy object which uses a {@link HashingStrategy}.
/trunk/OpenConcerto/src/org/openconcerto/utils/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/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/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/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/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/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/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/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/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/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/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/BonReceptionFactureFournisseurSQLInjector.java
34,7 → 34,13
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
protected void merge(SQLRowAccessor srcRow, SQLRowValues rowVals) {
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,7 → 40,10
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
protected void merge(SQLRowAccessor srcRow, SQLRowValues rowVals) {
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/injector/DevisCommandeSQLInjector.java
68,7 → 68,10
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
protected void merge(SQLRowAccessor srcRow, SQLRowValues rowVals) {
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,7 → 67,10
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
protected void merge(SQLRowAccessor srcRow, SQLRowValues rowVals) {
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/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/DevisBlSQLInjector.java
45,7 → 45,10
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
protected void merge(SQLRowAccessor srcRow, SQLRowValues rowVals) {
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/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/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,8 → 72,10
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
protected void merge(SQLRowAccessor srcRow, SQLRowValues rowVals) {
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,7 → 69,10
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
protected void merge(SQLRowAccessor srcRow, SQLRowValues rowVals) {
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/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/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/generationDoc/provider/ArticleCodeFournisseurProvider.java
New file
0,0 → 1,69
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationDoc.provider;
 
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueContext;
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueProvider;
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueProviderManager;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
 
import java.util.List;
 
public class ArticleCodeFournisseurProvider implements SpreadSheetCellValueProvider {
 
public ArticleCodeFournisseurProvider() {
}
 
public Object getValue(SpreadSheetCellValueContext context) {
SQLRowAccessor row = context.getRow();
String code = row.getString("CODE");
if (row.getObject("ID_ARTICLE") != null && !row.isForeignEmpty("ID_ARTICLE")) {
if (row.getTable().contains("ID_CODE_FOURNISSEUR")) {
if (row.getObject("ID_CODE_FOURNISSEUR") != null && !row.isForeignEmpty("ID_CODE_FOURNISSEUR")) {
 
code = row.getForeign("ID_CODE_FOURNISSEUR").getString("CODE");
 
} else {
 
int idFournisseur = row.getForeign("ID_" + row.getTable().getName().replaceAll("_ELEMENT", "")).getForeignID("ID_FOURNISSEUR");
SQLSelect sel = new SQLSelect();
final SQLTable tableCodeFournisseur = row.getTable().getTable("CODE_FOURNISSEUR");
sel.addSelectStar(tableCodeFournisseur);
Where w = new Where(tableCodeFournisseur.getField("ID_ARTICLE"), "=", row.getForeignID("ID_ARTICLE"));
w = w.and(new Where(tableCodeFournisseur.getField("ID_FOURNISSEUR"), "=", idFournisseur));
sel.setWhere(w);
List<SQLRow> result = SQLRowListRSH.execute(sel);
if (!result.isEmpty()) {
final String val = result.get(0).getString("CODE");
if (val.length() > 0) {
code = val;
}
}
}
}
}
return code;
}
 
public static void register() {
SpreadSheetCellValueProviderManager.put("supplier.product.code", new ArticleCodeFournisseurProvider());
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/QteTotalDocProvider.java
New file
0,0 → 1,68
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationDoc.provider;
 
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueContext;
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueProviderManager;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLTable;
 
import java.math.BigDecimal;
import java.util.Collection;
 
public class QteTotalDocProvider extends UserInitialsValueProvider {
 
private enum TypeQteTotalDocProvider {
QTE, COLIS
};
 
private final TypeQteTotalDocProvider type;
 
public QteTotalDocProvider(TypeQteTotalDocProvider t) {
this.type = t;
}
 
@Override
public Object getValue(SpreadSheetCellValueContext context) {
SQLRowAccessor row = context.getRow();
 
final SQLTable table = row.getTable();
Collection<? extends SQLRowAccessor> cols = row.getReferentRows(table.getTable(table.getName() + "_ELEMENT"));
BigDecimal total = BigDecimal.ZERO;
for (SQLRowAccessor sqlRowAccessor : cols) {
 
if (!sqlRowAccessor.getTable().contains("NIVEAU") || sqlRowAccessor.getInt("NIVEAU") == 1) {
 
if (this.type == TypeQteTotalDocProvider.QTE) {
BigDecimal qte = sqlRowAccessor.getBigDecimal("QTE_UNITAIRE").multiply(new BigDecimal(sqlRowAccessor.getInt("QTE")));
 
total = total.add(qte);
 
} else {
if (sqlRowAccessor.getObject("NB_COLIS") != null) {
total = total.add(new BigDecimal(sqlRowAccessor.getInt("NB_COLIS")));
}
}
 
}
}
 
return total;
}
 
public static void register() {
SpreadSheetCellValueProviderManager.put("sales.qty.total", new QteTotalDocProvider(TypeQteTotalDocProvider.QTE));
SpreadSheetCellValueProviderManager.put("sales.package.total", new QteTotalDocProvider(TypeQteTotalDocProvider.COLIS));
}
}
/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);
if (this.printer != null && this.printer.trim().length() > 0) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("Name", printer);
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/gestcomm/EtatVentesXmlSheet.java
24,6 → 24,8
import org.openconcerto.sql.model.AliasedTable;
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.SQLSelectJoin;
import org.openconcerto.sql.model.SQLTable;
62,11 → 64,13
 
private Timestamp du, au;
public boolean ticketCaisse = false;
public boolean facture = false;
 
public EtatVentesXmlSheet(Date du, Date au, boolean ticketCaisse) {
public EtatVentesXmlSheet(Date du, Date au, boolean ticketCaisse, boolean facture) {
super();
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter");
this.ticketCaisse = ticketCaisse;
this.facture = facture;
if (du != null) {
final Calendar c1 = Calendar.getInstance();
c1.setTime(du);
128,7 → 132,11
styleAllSheetValues.put(0, style);
}
 
final ArrayList<Map<String, Object>> listValuesStock = new ArrayList<>();
final Map<Integer, String> styleStock = new HashMap<>();
 
// Ventes
final SQLTable foreignTableArticle = tableFactureElement.getForeignTable("ID_ARTICLE");
{
 
final AliasedTable tableModeReglement1 = new AliasedTable(tableModeReglement, MODE1);
135,6 → 143,17
final AliasedTable tableModeReglement2 = new AliasedTable(tableModeReglement, MODE2);
final AliasedTable tableTicket = new AliasedTable(eltTicketCaisse.getTable(), "ticket");
 
// Stock
SQLRowValues rowValsArtStock = new SQLRowValues(foreignTableArticle);
rowValsArtStock.putNulls("ID", "CODE", "NOM");
rowValsArtStock.putRowValues("ID_STOCK").putNulls("QTE_REEL", "QTE_TH", "QTE_MIN", "QTE_RECEPT_ATTENTE", "QTE_LIV_ATTENTE");
SQLRowValuesListFetcher fetcherStock = SQLRowValuesListFetcher.create(rowValsArtStock);
List<SQLRowValues> resultStock = fetcherStock.fetch();
Map<Integer, SQLRowValues> mapStock = new HashMap<>();
for (SQLRowValues sqlRowValues : resultStock) {
mapStock.put(sqlRowValues.getID(), sqlRowValues);
}
 
// Requete Pour obtenir les quantités pour chaque type de réglement
SQLSelect sel = new SQLSelect();
 
193,12 → 212,16
selQte.addSelect(tableFactureElement.getField("T_PV_TTC"), "SUM");
selQte.addSelect(tableFactureElement.getField("ID_TAXE"));
selQte.addSelect(tableFactureElement.getField("ID_ARTICLE"));
if (!this.ticketCaisse) {
if (this.ticketCaisse) {
selQte.addJoin("LEFT", tableFactureElement.getField("ID_SAISIE_VENTE_FACTURE")).setWhere(Where.FALSE);
selQte.addJoin("LEFT", tableFactureElement.getField("ID_TICKET_CAISSE"), "ticket").setWhere(w2);
} else if (this.facture) {
selQte.addJoin("LEFT", tableFactureElement.getField("ID_SAISIE_VENTE_FACTURE")).setWhere(w);
selQte.addJoin("LEFT", tableFactureElement.getField("ID_TICKET_CAISSE"), "ticket").setWhere(Where.FALSE);
} else {
selQte.addJoin("LEFT", tableFactureElement.getField("ID_SAISIE_VENTE_FACTURE")).setWhere(Where.FALSE);
selQte.addJoin("LEFT", tableFactureElement.getField("ID_SAISIE_VENTE_FACTURE")).setWhere(w);
selQte.addJoin("LEFT", tableFactureElement.getField("ID_TICKET_CAISSE"), "ticket").setWhere(w2);
}
selQte.addJoin("LEFT", tableFactureElement.getField("ID_TICKET_CAISSE"), "ticket").setWhere(w2);
SQLSelectJoin joinArt2 = selQte.addJoin("LEFT", tableFactureElement.getField("ID_ARTICLE"));
SQLSelectJoin joinFamArt2 = selQte.addJoin("LEFT", joinArt2.getJoinedTable().getField("ID_FAMILLE_ARTICLE"));
selQte.addSelect(joinFamArt2.getJoinedTable().getField("NOM"));
234,8 → 257,8
mapTVAVT.put(tvaID.intValue(), Tuple2.create(t.get0().add((BigDecimal) ht), t.get1().add(ttc)));
}
Number articleID = (Number) sqlRow[7];
ArticleVendu a = new ArticleVendu(code, nom, qteVendu.intValue(), (BigDecimal) ht, (BigDecimal) ha, ttc, tvaID.intValue(),
tableFactureElement.getForeignTable("ID_ARTICLE").getRow(articleID.intValue()));
ArticleVendu a = new ArticleVendu(code, nom, qteVendu.intValue(), (BigDecimal) ht, (BigDecimal) ha, ttc, tvaID.intValue(), foreignTableArticle.getRow(articleID.intValue()));
 
map.put(articleID + "##" + code + "##" + nom + "##" + tvaID, a);
 
}
256,6 → 279,8
mValues.put("NOM", famille);
style.put(listValues.size(), "Titre 1");
listValues.add(mValues);
styleStock.put(listValuesStock.size(), "Titre 1");
listValuesStock.add(mValues);
} else if (valueFam != null && !valueFam.toString().equalsIgnoreCase(famille)) {
famille = valueFam.toString();
Map<String, Object> mValues = new HashMap<String, Object>();
262,6 → 287,8
mValues.put("NOM", famille);
style.put(listValues.size(), "Titre 1");
listValues.add(mValues);
styleStock.put(listValuesStock.size(), "Titre 1");
listValuesStock.add(mValues);
}
 
Map<String, Object> mValues = new HashMap<String, Object>();
291,7 → 318,26
totalTPVTTC = totalTPVTTC.add(a.ttc);
style.put(listValues.size(), "Normal");
listValues.add(mValues);
 
Map<String, Object> mValuesStock = new HashMap<String, Object>();
mValuesStock.put("CODE", code);
mValuesStock.put("NOM", nom);
mValuesStock.put("QTE", a.qte);
if (mapStock.containsKey(articleID)) {
SQLRowValues rowValsArt = mapStock.get(articleID);
if (rowValsArt.getObject("ID_STOCK") != null && !rowValsArt.isForeignEmpty("ID_STOCK")) {
SQLRowAccessor rowValsStock = rowValsArt.getForeign("ID_STOCK");
mValuesStock.put("QTE_TH", rowValsStock.getObject("QTE_TH"));
mValuesStock.put("QTE_REEL", rowValsStock.getObject("QTE_REEL"));
mValuesStock.put("QTE_MIN", rowValsStock.getObject("QTE_MIN"));
mValuesStock.put("QTE_RECEPT_ATTENTE", rowValsStock.getObject("QTE_RECEPT_ATTENTE"));
mValuesStock.put("QTE_LIV_ATTENTE", rowValsStock.getObject("QTE_LIV_ATTENTE"));
}
styleStock.put(listValuesStock.size(), "Normal");
listValuesStock.add(mValuesStock);
}
 
}
// System.out.println("EtatVentesXmlSheet.createListeValues():" + listValues);
}
}
440,7 → 486,7
}
Number articleID = (Number) sqlRow[7];
ArticleVendu a = new ArticleVendu(code, nom, -qteVendu.intValue(), ((BigDecimal) ht).negate(), ((BigDecimal) ha).negate(), ttc.negate(), tvaID.intValue(),
tableFactureElement.getForeignTable("ID_ARTICLE").getRow(articleID.intValue()));
foreignTableArticle.getRow(articleID.intValue()));
map.put(articleID + "##" + code + "##" + nom + "##" + tvaID, a);
 
}
713,6 → 759,10
this.listAllSheetValues.put(3, listValuesTVA);
valuesTVA.put("DATE", periode);
this.mapAllSheetValues.put(3, valuesTVA);
 
this.listAllSheetValues.put(4, listValuesStock);
this.styleAllSheetValues.put(4, styleStock);
this.mapAllSheetValues.put(4, values);
}
 
public static SQLRow rowDefaultCptService, rowDefaultCptProduit;
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationXML.java
195,6 → 195,7
}
} catch (Exception e) {
ExceptionHandler.handle("Impossible de remplir le document " + templateId + " " + ((rowLanguage == null) ? "" : rowLanguage.getString("CHEMIN")), e);
e.printStackTrace();
return null;
}
 
444,6 → 445,12
}
calc.setRemise(valRemiseHTReel, totalAvtRemise);
 
// Fix TVA si nécessaire pour facture fournisseur
if (row.getTable().contains("TVA_ADJUSTMENT")) {
BigDecimal tvaFix = row.getBigDecimal("TVA_ADJUSTMENT");
calc.addTVAAdjust(tvaFix);
}
 
for (int i = 0; i < rows.size(); i++) {
SQLRowAccessor sqlRow = rows.get(i);
calc.addLine(sqlRow, sqlRow.getForeign("ID_ARTICLE"), i, i == rows.size() - 1);
490,6 → 497,20
 
calc.addLine(rowValsPort, rowValsPort.getForeign("ID_ARTICLE"), 1, false);
}
if (row.getTable().contains("FRAIS_DOCUMENT_HT") && row.getTable().contains("ID_TAXE_FRAIS_DOCUMENT")) {
BigDecimal fraisDoc = BigDecimal.valueOf(row.getLong("FRAIS_DOCUMENT_HT")).movePointLeft(2);
SQLRowAccessor tvafraisDoc = row.getForeign("ID_TAXE_FRAIS_DOCUMENT");
if (tvafraisDoc != null && fraisDoc.signum() != 0 && !tvafraisDoc.isUndefined()) {
SQLRowValues rowValsfraisDoc = new SQLRowValues(tableElt);
rowValsfraisDoc.put("T_PV_HT", fraisDoc);
rowValsfraisDoc.put("QTE", 1);
rowValsfraisDoc.put("ID_TAXE", tvafraisDoc.getIDNumber());
rowValsfraisDoc.put("SERVICE", Boolean.TRUE);
rowValsfraisDoc.put("ID_FAMILLE_ARTICLE", null);
calc.addLine(rowValsfraisDoc, null, 1, false);
}
}
 
calc.checkResult();
Map<SQLRowAccessor, Tuple2<BigDecimal, BigDecimal>> taxeCalc = calc.getMapHtTVARowTaux();
for (SQLRowAccessor sqlRow : taxeCalc.keySet()) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetXml.java
179,6 → 179,7
 
try {
if (!useODSViewer) {
if (exportToPDF || printDocument) {
final Component doc = ComptaPropsConfiguration.getOOConnexion().loadDocument(generatedFile, !showDocument);
 
if (printDocument) {
193,6 → 194,9
doc.close();
}
} else {
openDocument(false);
}
} else {
final OpenDocument doc = new OpenDocument(generatedFile);
 
if (showDocument) {
543,9 → 547,13
}
 
public void showPreviewDocument() throws Exception {
showPreviewDocument(null, null);
}
 
public void showPreviewDocument(String actionName, Runnable r) throws Exception {
File f = null;
f = getOrCreateDocumentFile();
PreviewFrame.show(f);
PreviewFrame.show(f, actionName, r);
}
 
public void printDocument() {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLField.java
266,6 → 266,9
result += stringValue;
}
if (suffix != null) {
if (suffix.contains("#n")) {
suffix = suffix.replaceAll("#n", "\n");
}
result += suffix;
}
if (cellSize != null && cellSize.trim().length() != 0) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/MouvementPostInsertionAction.java
New file
0,0 → 1,22
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationEcritures;
 
import java.sql.SQLException;
 
public interface MouvementPostInsertionAction {
 
public void afterInsert(Mouvement m) throws SQLException;
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/Ecriture.java
New file
0,0 → 1,237
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInsert;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.users.User;
 
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class Ecriture {
private Date date;
private BigDecimal debit;
private BigDecimal credit;
private Mouvement mouvement;
private String nom;
private String compteNumero;
private String compteNom;
private Number compteID;
private String journalNom;
private String journalCode;
private Number journalID;
private List<AssociationAnalytique> associations;
private Number id;
private Map<String, Object> cookies;
private boolean cloture;
private boolean aNouveau;
private Date dateValidation;
private Date dateLettrage;
private String lettrage;
 
public Ecriture(Date date, BigDecimal debit, BigDecimal credit) {
this.date = date;
this.debit = debit;
this.credit = credit;
}
 
public SQLInsert createInsert(DBRoot root, User user) {
final SQLInsert insert = new SQLInsert();
final SQLTable table = root.getTable("ECRITURE");
insert.add(table.getField("DATE"), this.date);
insert.add(table.getField("ID_MOUVEMENT"), this.mouvement.getId().intValue());
insert.add(table.getField("DEBIT"), this.debit.multiply(new BigDecimal(100)).longValue());
insert.add(table.getField("CREDIT"), this.credit.multiply(new BigDecimal(100)).longValue());
insert.add(table.getField("NOM"), this.nom);
 
if (this.compteNom == null) {
throw new IllegalStateException("nom du compte manquant");
}
if (this.compteNumero == null || this.compteNumero.isEmpty()) {
throw new IllegalStateException("numéro du compte manquant");
}
insert.add(table.getField("ID_COMPTE_PCE"), this.compteID);
insert.add(table.getField("COMPTE_NUMERO"), this.compteNumero);
insert.add(table.getField("COMPTE_NOM"), this.compteNom);
if (this.journalNom == null) {
throw new IllegalStateException("nom du journal manquant");
}
if (this.journalCode == null || this.journalCode.isEmpty()) {
throw new IllegalStateException("code du journal manquant");
}
insert.add(table.getField("ID_JOURNAL"), this.journalID);
insert.add(table.getField("JOURNAL_NOM"), this.journalNom);
insert.add(table.getField("JOURNAL_CODE"), this.journalCode);
insert.add(table.getField("NOM_PIECE"), this.mouvement.getPiece().getNom());
insert.add(table.getField("ID_USER_COMMON_CREATE"), user.getId());
insert.add(table.getField("ID_USER_COMMON_MODIFY"), user.getId());
insert.add(table.getField("CLOTURE"), this.cloture);
insert.add(table.getField("RAN"), this.aNouveau);
if (this.dateValidation != null) {
insert.add(table.getField("DATE_VALIDE"), this.dateValidation);
insert.add(table.getField("VALIDE"), Boolean.TRUE);
} else {
insert.add(table.getField("DATE_VALIDE"), null);
insert.add(table.getField("VALIDE"), Boolean.FALSE);
}
insert.add(table.getField("DATE_LETTRAGE"), this.dateLettrage);
insert.add(table.getField("LETTRAGE"), this.lettrage == null || this.lettrage.isEmpty() ? " " : this.lettrage);
return insert;
}
 
public void setDateValidation(Date dateValidation) {
this.dateValidation = dateValidation;
}
 
public void setDateLettrage(Date dateLettrage) {
this.dateLettrage = dateLettrage;
}
 
public void setLettrage(String lettrage) {
this.lettrage = lettrage;
}
 
public void setCloture(boolean cloture) {
this.cloture = cloture;
}
 
public void setaNouveau(boolean aNouveau) {
this.aNouveau = aNouveau;
}
 
public String getNom() {
return this.nom;
}
 
public void setNom(String nom) {
this.nom = nom;
}
 
void setId(Number id) {
this.id = id;
}
 
public Number getId() {
return this.id;
}
 
public Number getCompteID() {
return this.compteID;
}
 
public void setCompteID(Number compteID) {
this.compteID = compteID;
}
 
public void setCompte(String numero, String nom) {
this.compteNumero = numero;
this.compteNom = nom;
}
 
public String getCompteNumero() {
return this.compteNumero;
}
 
public String getCompteNom() {
return this.compteNom;
}
 
public Number getJournalID() {
return this.journalID;
}
 
public void setJournalID(Number journalID) {
this.journalID = journalID;
}
 
public void setJournal(String code, String nom) {
this.journalCode = code;
this.journalNom = nom;
}
 
public String getJournalCode() {
return this.journalCode;
}
 
public String getJournalNom() {
return this.journalNom;
}
 
public BigDecimal getDebit() {
return this.debit;
}
 
public BigDecimal getCredit() {
return this.credit;
}
 
public Date getDate() {
return this.date;
}
 
public void setMouvement(Mouvement mouvement) {
this.mouvement = mouvement;
}
 
public List<AssociationAnalytique> getAssociationsAnalytiques() {
return this.associations;
}
 
public void addAssociationAnalytique(AssociationAnalytique a) {
if (this.associations == null) {
this.associations = new ArrayList<>();
}
a.setEcriture(this);
this.associations.add(a);
}
 
public void removeAssociationAnalytique(AssociationAnalytique a) {
if (this.associations == null) {
a.setEcriture(null);
return;
}
this.associations.remove(a);
a.setEcriture(null);
if (this.associations.isEmpty()) {
this.associations = null;
}
}
 
public boolean hasAnalytique() {
return this.associations != null;
}
 
public void putCookie(String key, Object value) {
if (this.cookies == null) {
this.cookies = new HashMap<>();
}
this.cookies.put(key, value);
}
 
public Object getCookie(String key) {
return this.cookies.get(key);
}
 
@Override
public String toString() {
return "Ecriture : " + this.nom + ", Compte (id:" + this.compteID + ") " + this.compteNumero + " " + this.compteNom + ", Débit : " + this.debit + ", Crédit:" + this.credit;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationReglementVenteNG.java
392,7 → 392,12
}
}
 
this.putValue("ID_JOURNAL", JournalSQLElement.BANQUES);
int idJournal = JournalSQLElement.BANQUES;
if (rowPrefsCompte.getObject("ID_JOURNAL_VALEUR_ENCAISSEMENT") != null && !rowPrefsCompte.isForeignEmpty("ID_JOURNAL_VALEUR_ENCAISSEMENT")) {
idJournal = rowPrefsCompte.getForeignID("ID_JOURNAL_VALEUR_ENCAISSEMENT");
}
this.putValue("ID_JOURNAL", idJournal);
this.putValue("ID_COMPTE_PCE", idCompteClient);
this.putValue("DEBIT", Long.valueOf(0));
this.putValue("CREDIT", Long.valueOf(ttc.getLongValue()));
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/Piece.java
New file
0,0 → 1,58
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInsert;
 
import java.util.ArrayList;
import java.util.List;
 
public class Piece {
private String nom;
private List<Mouvement> mouvements = new ArrayList<>();
private Number id;
 
public Piece(String nom) {
this.nom = nom;
}
 
public String getNom() {
return nom;
}
 
public void add(Mouvement mouvement) {
this.mouvements.add(mouvement);
mouvement.setPiece(this);
}
 
public List<Mouvement> getMouvements() {
return mouvements;
}
 
public SQLInsert createInsert(final DBRoot root) {
final SQLInsert insert = new SQLInsert();
insert.add(root.getTable("PIECE").getField("NOM"), this.nom);
return insert;
}
 
public Number getId() {
return this.id;
}
 
public void setId(Number id) {
this.id = id;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtDepotChequeClient.java
93,7 → 93,7
 
List<Integer> pieceIDs = new ArrayList<Integer>();
SQLRowValues rowValsDepotElt = new SQLRowValues(depot.getTable().getTable("DEPOT_CHEQUE_ELEMENT"));
rowValsDepotElt.putNulls("MONTANT", "TIERS");
rowValsDepotElt.putNulls("MONTANT", "TIERS", "PIECE");
rowValsDepotElt.putRowValues("ID_CLIENT").putNulls("NOM", "ID_COMPTE_PCE");
final SQLRowValues rowValuesChq = rowValsDepotElt.putRowValues("ID_CHEQUE_A_ENCAISSER");
rowValuesChq.putNulls("SANS_VALEUR_ENCAISSEMENT").putRowValues("ID_MOUVEMENT").putNulls("ID_PIECE");
102,7 → 102,7
for (SQLRowValues sqlRowAccessor : cheques) {
final SQLRowAccessor clientRow = sqlRowAccessor.getForeign("ID_CLIENT");
// this.nom = this.nom + " " + StringUtils.limitLength(clientRow.getString("NOM"), 20);
this.putValue("NOM", this.nom + " " + StringUtils.limitLength(clientRow.getString("NOM"), 20));
this.putValue("NOM", this.nom + " " + sqlRowAccessor.getString("PIECE") + " " + StringUtils.limitLength(clientRow.getString("NOM"), 20));
SQLRowAccessor chequeRow = sqlRowAccessor.getForeign("ID_CHEQUE_A_ENCAISSER");
pieceIDs.add(chequeRow.getForeign("ID_MOUVEMENT").getForeignID("ID_PIECE"));
// compte Clients
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/AssociationAnalytique.java
New file
0,0 → 1,67
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInsert;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.users.User;
 
import java.math.BigDecimal;
 
public class AssociationAnalytique {
private final int idPosteAnalytique;
private int idSaisieKmElement = 1;
private BigDecimal pourcentage;
private long montant; // centimes
private boolean gestionAuto = false;
private Ecriture ecriture;
 
public AssociationAnalytique(int idPosteAnalytique) {
this.idPosteAnalytique = idPosteAnalytique;
}
 
public void setIdSaisieKmElement(int idSaisieKmElement) {
this.idSaisieKmElement = idSaisieKmElement;
}
 
public void setPourcentage(BigDecimal pourcentage) {
this.pourcentage = pourcentage;
}
 
public void setMontant(long montant) {
this.montant = montant;
}
 
public void setGestionAuto(boolean gestionAuto) {
this.gestionAuto = gestionAuto;
}
 
public void setEcriture(Ecriture ecriture) {
this.ecriture = ecriture;
}
 
public SQLInsert createInsert(DBRoot root, User user) {
final SQLInsert insert = new SQLInsert();
final SQLTable table = root.getTable("ASSOCIATION_ANALYTIQUE");
insert.add(table.getField("ID_ECRITURE"), this.ecriture.getId().intValue());
insert.add(table.getField("ID_SAISIE_KM_ELEMENT"), this.idSaisieKmElement);
insert.add(table.getField("ID_POSTE_ANALYTIQUE"), this.idPosteAnalytique);
insert.add(table.getField("POURCENT"), this.pourcentage);
insert.add(table.getField("MONTANT"), this.montant);
insert.add(table.getField("GESTION_AUTO"), this.gestionAuto);
return insert;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/Journal.java
New file
0,0 → 1,69
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInsert;
import org.openconcerto.sql.model.SQLTable;
 
public class Journal {
private final Long id;
private final String code;
private final String nom;
 
public Journal(Long id, final String code, final String nom) {
this.id = id;
this.code = code;
this.nom = nom;
}
 
public Long getId() {
return this.id;
}
 
public String getNom() {
return this.nom;
}
 
public String getCode() {
return this.code;
}
 
@Override
public int hashCode() {
return this.code.hashCode();
}
 
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
return ((Journal) obj).code.equalsIgnoreCase(this.code);
}
 
SQLInsert createInsert(DBRoot root) {
final SQLInsert insert = new SQLInsert();
final SQLTable table = root.getTable("JOURNAL");
insert.add(table.getField("CODE"), this.code);
insert.add(table.getField("NOM"), this.nom);
return insert;
}
 
@Override
public String toString() {
return "Journal code:" + this.code + " " + this.nom + " (id:" + this.id + ")";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/Mouvement.java
New file
0,0 → 1,114
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInsert;
import org.openconcerto.sql.model.SQLTable;
 
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
 
public class Mouvement {
private String numero;
private List<Ecriture> ecritures = new ArrayList<>();
private Number id;
private BigDecimal debit = BigDecimal.ZERO;
private BigDecimal credit = BigDecimal.ZERO;
private Piece piece;
// Source
private Number idSource;
private String source;
private Mouvement pere;
private MouvementPostInsertionAction postInsertionAction;
 
public Mouvement() {
}
 
public void setSource(Number idSource, String source) {
this.idSource = idSource;
this.source = source;
}
 
public void add(Ecriture e) {
this.ecritures.add(e);
this.debit = this.debit.add(e.getDebit());
this.credit = this.credit.add(e.getCredit());
e.setMouvement(this);
}
 
List<Ecriture> getEcritures() {
return this.ecritures;
}
 
void setId(Number id) {
this.id = id;
}
 
public Number getId() {
return this.id;
}
 
SQLInsert createInsert(DBRoot root) {
final SQLInsert insert = new SQLInsert();
final SQLTable table = root.getTable("MOUVEMENT");
// FIXME le numero doit être généré en auto
// Thread.dumpStack();
// NUMERO = SELECT (MAX) ?
// insert.add(table.getField("NUMERO"), this.numero);
// select for update max(numero)
if (this.idSource != null) {
insert.add(table.getField("IDSOURCE"), this.idSource);
insert.add(table.getField("SOURCE"), this.source);
}
insert.add(table.getField("ID_PIECE"), this.piece.getId().intValue());
if (this.pere != null) {
insert.add(table.getField("ID_MOUVEMENT_PERE"), this.pere.getId().intValue());
}
// TODO CREATION_DATE MODIFICATION_DATE
return insert;
}
 
public boolean isBalanced() {
BigDecimal d = BigDecimal.ZERO;
BigDecimal c = BigDecimal.ZERO;
for (Ecriture e : this.ecritures) {
d = d.add(e.getDebit());
c = c.add(e.getCredit());
}
return d.compareTo(c) == 0;
}
 
public Piece getPiece() {
return this.piece;
}
 
public void setPiece(Piece piece) {
this.piece = piece;
 
}
 
public boolean isEmpty() {
return this.ecritures.isEmpty();
}
 
public MouvementPostInsertionAction getPostInsertionAction() {
return this.postInsertionAction;
}
 
public void setAfterInsert(MouvementPostInsertionAction insertionAction) {
this.postInsertionAction = insertionAction;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationEcritures.java
396,6 → 396,10
if (tiers.getObject("ID_CATEGORIE_COMPTABLE") != null && !tiers.isForeignEmpty("ID_CATEGORIE_COMPTABLE")) {
rowCatCompta = tiers.getForeign("ID_CATEGORIE_COMPTABLE");
}
 
if (row.getTable().contains("ID_CATEGORIE_COMPTABLE") && row.getObject("ID_CATEGORIE_COMPTABLE") != null && !row.isForeignEmpty("ID_CATEGORIE_COMPTABLE")) {
rowCatCompta = row.getForeign("ID_CATEGORIE_COMPTABLE");
}
TotalCalculator calc = new TotalCalculator("T_PA_HT", fieldTotalHT, null, achat, defaultCompte, rowCatCompta);
calc.setIntraComm(intra);
 
436,6 → 440,7
calc.addEchantillon((BigDecimal) sqlRow.getObject("T_PV_HT"), sqlRow.getForeign("ID_TAXE"));
}
}
 
calc.checkResult();
totalAvtRemise = calc.getTotalHT();
}
514,6 → 519,12
calc.addLine(rowValsFraisDoc, null, 1, false);
}
 
// Fix TVA si nécessaire pour facture fournisseur
if (row.getTable().contains("TVA_ADJUSTMENT")) {
BigDecimal tvaFix = row.getBigDecimal("TVA_ADJUSTMENT");
calc.addTVAAdjust(tvaFix);
}
 
calc.checkResult();
return calc;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/Compte.java
New file
0,0 → 1,69
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInsert;
import org.openconcerto.sql.model.SQLTable;
 
public class Compte {
private final Long id;
private String numero;
private String nom;
 
public Compte(Long id, String numero, String nom) {
this.id = id;
this.numero = numero;
this.nom = nom;
}
 
public Long getId() {
return this.id;
}
 
public String getNumero() {
return this.numero;
}
 
public String getNom() {
return this.nom;
}
 
@Override
public int hashCode() {
return this.numero.hashCode();
}
 
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
return ((Compte) obj).numero.equalsIgnoreCase(this.numero);
}
 
SQLInsert createInsert(DBRoot root) {
final SQLInsert insert = new SQLInsert();
final SQLTable table = root.getTable("COMPTE_PCE");
insert.add(table.getField("NUMERO"), this.numero);
insert.add(table.getField("NOM"), this.nom);
return insert;
}
 
@Override
public String toString() {
return "Compte numero:" + this.numero + " " + this.nom + " (id:" + this.id + ")";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/Exercice.java
New file
0,0 → 1,517
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBSystemRoot;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLInsert;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLUpdate;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.users.User;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
 
import org.apache.commons.dbutils.ResultSetHandler;
 
public class Exercice {
private Date debut;
private Date fin;
private static final Logger LOGGER = Logger.getLogger(Exercice.class.getName());
 
public Exercice() {
 
}
 
public Exercice(Date debut, Date fin) {
if (debut != null && debut.after(fin)) {
throw new IllegalArgumentException("date de fin invalide");
}
this.debut = debut;
this.fin = fin;
}
 
public String toString() {
return "Exercice " + this.debut + " -> " + this.fin;
}
 
public void insert(SQLElementDirectory directory, final DBRoot root, User user, List<Piece> pieces) throws SQLException {
final DBSystemRoot sysRoot = root.getDBSystemRoot();
final List<SQLInsert> insertsPiece = new ArrayList<>();
LOGGER.log(Level.INFO, "insertion de {0} pièces comptables", pieces.size());
for (Piece p : pieces) {
// Pièces
insertsPiece.add(p.createInsert(root));
 
// Vérification des mouvements
final List<Mouvement> mouvements = p.getMouvements();
if (mouvements.isEmpty()) {
throw new IllegalStateException("Piece vide : " + p);
}
 
for (Mouvement m : mouvements) {
if (!m.isBalanced()) {
throw new IllegalStateException("Mouvement non balancé : " + m);
}
if (m.isEmpty()) {
throw new IllegalStateException("Mouvement vide : " + m);
}
 
for (Ecriture e : m.getEcritures()) {
if (this.debut != null && e.getDate().before(this.debut)) {
throw new IllegalStateException("Mouvement invalide : " + m + " : une écriture est définie avant la date de début d'exercice : " + e);
}
if (e.getNom() == null) {
throw new IllegalStateException("Ecriture sans nom : " + e);
}
}
 
if (this.fin != null) {
for (Ecriture e : m.getEcritures()) {
if (e.getDate().after(this.fin)) {
throw new IllegalStateException("Mouvement invalide : " + m + " : une écriture est définie après la date de fin d'exercice : " + e.getDate() + ">" + this.fin);
}
 
}
}
 
}
}
 
SQLUtils.executeAtomic(sysRoot.getDataSource(), new ConnectionHandlerNoSetup<Object, SQLException>() {
@Override
public Object handle(SQLDataSource ds) throws SQLException {
// Insertion des journaux et comptes manquants et remplissage des champs journaux et
// comptes des
// écritures depuis les ids
final Set<Journal> journauxACreerOuFetcher = new HashSet<>();
final Set<Number> journauxAresoudre = new HashSet<>();
final Set<Compte> comptesACreerOuFetcher = new HashSet<>();
final Set<Number> comptesAresoudre = new HashSet<>();
final List<Ecriture> ecrituresSansJournalID = new LinkedList<>();
final List<Ecriture> ecrituresSansCompteID = new LinkedList<>();
for (Piece p : pieces) {
for (Mouvement m : p.getMouvements()) {
for (Ecriture e : m.getEcritures()) {
if (e.getJournalID() == null) {
// Journal à creer
journauxACreerOuFetcher.add(new Journal(null, e.getJournalCode(), e.getJournalNom()));
ecrituresSansJournalID.add(e);
} else {
journauxAresoudre.add(e.getJournalID());
}
if (e.getCompteID() == null) {
// Compte à creer
comptesACreerOuFetcher.add(new Compte(null, e.getCompteNumero(), e.getCompteNom()));
ecrituresSansCompteID.add(e);
} else {
comptesAresoudre.add(e.getJournalID());
}
}
 
}
}
final Map<Long, Journal> mapJournaux = new HashMap<>();
if (!journauxACreerOuFetcher.isEmpty()) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(journauxACreerOuFetcher.size() + " journaux à créer : " + journauxACreerOuFetcher);
}
// On récupère tous les journaux car il y en a peu
final Map<String, Journal> codesDesJournauxExistants = getCodesJournaux(root);
 
final List<SQLInsert> insertsJournaux = new ArrayList<>();
final List<Journal> list = new ArrayList<>();
for (Journal journal : journauxACreerOuFetcher) {
// journal non déjà existant
if (codesDesJournauxExistants.get(journal.getCode().toLowerCase()) == null) {
list.add(journal);
insertsJournaux.add(journal.createInsert(root));
}
}
final List<Number> journauxIds = new ArrayList<>();
if (!insertsJournaux.isEmpty()) {
journauxIds.addAll(SQLInsert.executeSimilarInserts(sysRoot, insertsJournaux, true));
journauxAresoudre.addAll(journauxIds);
}
// Mise à jour de l'ID du journal pour les écritures dont le journal vient
// d'être créé
final int size = list.size();
for (int i = 0; i < size; i++) {
final String journalCode = list.get(i).getCode();
final Number journalID = journauxIds.get(i);
final Iterator<Ecriture> it = ecrituresSansJournalID.iterator();
while (it.hasNext()) {
final Ecriture e = it.next();
 
if (e.getJournalCode().equalsIgnoreCase(journalCode)) {
e.setJournalID(journalID);
it.remove();
}
 
}
}
final Iterator<Ecriture> it = ecrituresSansJournalID.iterator();
while (it.hasNext()) {
final Ecriture e = it.next();
final Journal journal = codesDesJournauxExistants.get(e.getJournalCode().toLowerCase());
e.setJournalID(journal.getId());
it.remove();
}
for (Journal journal : codesDesJournauxExistants.values()) {
mapJournaux.put(journal.getId(), journal);
}
}
final Map<Long, Compte> mapComptes = new HashMap<>();
if (!comptesACreerOuFetcher.isEmpty()) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(comptesACreerOuFetcher.size() + " comptes à créer ou fetcher: " + comptesACreerOuFetcher);
}
final Map<String, Compte> numerosDesComptesExistants = getNumeroDesComptes(root, pieces);
 
final List<SQLInsert> insertsComptes = new ArrayList<>();
final List<Compte> list = new ArrayList<>();
for (Compte c : comptesACreerOuFetcher) {
if (numerosDesComptesExistants.get(c.getNumero().toLowerCase()) == null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("création du compte : " + c.getNumero().toLowerCase());
}
list.add(c);
insertsComptes.add(c.createInsert(root));
}
}
List<Number> comptesIds = new ArrayList<>();
if (!insertsComptes.isEmpty()) {
 
final List<Number> insertedIDs = SQLInsert.executeSimilarInserts(sysRoot, insertsComptes, true);
comptesIds.addAll(insertedIDs);
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("IDs des comptes créés : " + comptesIds);
}
 
comptesAresoudre.addAll(comptesIds);
}
 
// Mise à jour de l'ID du compte pour les écritures dont le compte vient
// d'être créé
final int size = list.size();
for (int i = 0; i < size; i++) {
final String compteCode = list.get(i).getNumero();
final Number compteID = comptesIds.get(i);
final Iterator<Ecriture> it = ecrituresSansCompteID.iterator();
while (it.hasNext()) {
final Ecriture e = it.next();
if (e.getCompteNumero().equalsIgnoreCase(compteCode)) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest("mise à jour de l'écriture " + e + " avec le compte d'ID " + compteID);
}
e.setCompteID(compteID);
it.remove();
}
}
 
}
final Iterator<Ecriture> it = ecrituresSansCompteID.iterator();
while (it.hasNext()) {
final Ecriture e = it.next();
Compte compte = numerosDesComptesExistants.get(e.getCompteNumero().toLowerCase());
if (compte != null) {
e.setCompteID(compte.getId());
it.remove();
}
 
}
for (Compte compte : numerosDesComptesExistants.values()) {
mapComptes.put(compte.getId(), compte);
}
 
}
 
// fetch journaux et comptes, update des code/numéro et nom
final List<String> queries = new ArrayList<>();
final List<ResultSetHandler> handlers = new ArrayList<>();
 
if (!comptesAresoudre.isEmpty()) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(comptesAresoudre.size() + " comptes à résoudre : ids " + comptesAresoudre);
}
final SQLTable tableCompte = root.getTable("COMPTE_PCE");
final SQLSelect selCompte = new SQLSelect();
selCompte.addSelect(tableCompte.getKey());
selCompte.addSelect(tableCompte.getField("NUMERO"));
selCompte.addSelect(tableCompte.getField("NOM"));
selCompte.setWhere(new Where(tableCompte.getKey(), comptesAresoudre));
queries.add(selCompte.asString());
handlers.add(new ResultSetHandler() {
 
@Override
public Object handle(ResultSet rs) throws SQLException {
while (rs.next()) {
final Long id = rs.getLong(1);
final String numero = rs.getString(2);
final String nom = rs.getString(3);
mapComptes.put(id, new Compte(id, numero, nom));
 
}
return null;
}
});
}
if (!journauxAresoudre.isEmpty()) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(journauxAresoudre.size() + " journaux à résoudre ids : " + journauxAresoudre);
}
final SQLTable tableJournal = root.getTable("JOURNAL");
final SQLSelect selJournal = new SQLSelect();
selJournal.addSelect(tableJournal.getKey());
selJournal.addSelect(tableJournal.getField("CODE"));
selJournal.addSelect(tableJournal.getField("NOM"));
selJournal.setWhere(new Where(tableJournal.getKey(), journauxAresoudre));
queries.add(selJournal.asString());
handlers.add(new ResultSetHandler() {
 
@Override
public Object handle(ResultSet rs) throws SQLException {
while (rs.next()) {
final Long id = rs.getLong(1);
final String code = rs.getString(2);
final String nom = rs.getString(3);
mapJournaux.put(id, new Journal(id, code, nom));
 
}
return null;
}
});
 
}
 
SQLUtils.executeMultiple(sysRoot, queries, handlers);
for (Piece p : pieces) {
for (Mouvement m : p.getMouvements()) {
for (Ecriture e : m.getEcritures()) {
Number compteID = e.getCompteID();
if (compteID == null) {
throw new IllegalStateException("pas d'ID compte dans l'écriture " + e);
}
final Long idCompte = compteID.longValue();
final Compte c = mapComptes.get(idCompte);
if (c == null) {
throw new IllegalStateException("pas de compte d'ID " + idCompte + " dans la map " + mapComptes.keySet());
}
e.setCompte(c.getNumero(), c.getNom());
 
final Long idJournal = e.getJournalID().longValue();
final Journal j = mapJournaux.get(idJournal);
if (j == null) {
throw new IllegalStateException("pas de journal d'ID " + idJournal + " dans la map " + mapJournaux.keySet());
}
e.setJournal(j.getCode(), j.getNom());
 
}
}
}
 
// Insertion des pieces
final List<Number> idsPieces = SQLInsert.executeSimilarInserts(sysRoot, insertsPiece, true);
 
// Creation des inserts des mouvements
final List<SQLInsert> insertsMouvement = new ArrayList<>(insertsPiece.size() * 3);
final List<Mouvement> listMvtWithoutIDs = new ArrayList<>(insertsPiece.size() * 3);
for (int i = 0; i < pieces.size(); i++) {
Piece piece = pieces.get(i);
piece.setId(idsPieces.get(i));
for (Mouvement m : piece.getMouvements()) {
listMvtWithoutIDs.add(m);
insertsMouvement.add(m.createInsert(root));
}
}
 
// Insertion des mouvements
final List<Number> idsMouvements = SQLInsert.executeSimilarInserts(sysRoot, insertsMouvement, true);
 
// Mise à jour des numeros de mouvements
SQLSelect sel = new SQLSelect();
final SQLTable tableMvt = root.getTable("MOUVEMENT");
sel.addSelect(tableMvt.getField("NUMERO"), "MAX");
Number maxMvtNumber = (Number) sysRoot.getDataSource().executeScalar(sel.asString());
int maxMvt = 1;
if (maxMvtNumber != null) {
maxMvt = maxMvtNumber.intValue();
}
List<SQLUpdate> mvtUpdate = new ArrayList<>();
for (int i = 0; i < idsMouvements.size(); i++) {
Number mvtId = idsMouvements.get(i);
SQLUpdate update = new SQLUpdate(new Where(tableMvt.getKey(), "=", mvtId));
update.add(tableMvt.getField("NUMERO"), maxMvt);
mvtUpdate.add(update);
maxMvt++;
listMvtWithoutIDs.get(i).setId(mvtId);
}
 
SQLUpdate.executeMultipleWithBatch(sysRoot, mvtUpdate);
 
// Creation des inserts des écritures sans analytique
final List<SQLInsert> insertsEcrituresSansAnalytique = new ArrayList<>(insertsMouvement.size() * 2);
final List<SQLInsert> insertsEcrituresAvecAnalytique = new ArrayList<>(insertsMouvement.size() * 2);
final List<Ecriture> ecrituresAvecAnalytique = new ArrayList<>(insertsEcrituresAvecAnalytique.size());
for (Piece p : pieces) {
final List<Mouvement> mouvements = p.getMouvements();
final int stop = mouvements.size();
for (int i = 0; i < stop; i++) {
final Mouvement m = mouvements.get(i);
for (Ecriture e : m.getEcritures()) {
if (e.hasAnalytique()) {
insertsEcrituresAvecAnalytique.add(e.createInsert(root, user));
ecrituresAvecAnalytique.add(e);
} else {
insertsEcrituresSansAnalytique.add(e.createInsert(root, user));
}
}
 
}
}
// Insertions des écritures des mouvements
SQLInsert.executeSimilarInserts(sysRoot, insertsEcrituresSansAnalytique, false);
// Insertions des écritures avec analytique
if (!ecrituresAvecAnalytique.isEmpty()) {
final List<Number> idsEcritues = SQLInsert.executeSimilarInserts(sysRoot, insertsEcrituresAvecAnalytique, true);
// Analytique
final List<SQLInsert> insertsAssociationAnalytique = new ArrayList<>(insertsEcrituresAvecAnalytique.size());
final int size = ecrituresAvecAnalytique.size();
for (int i = 0; i < size; i++) {
final Ecriture e = ecrituresAvecAnalytique.get(i);
e.setId(idsEcritues.get(i));
for (AssociationAnalytique a : e.getAssociationsAnalytiques()) {
insertsAssociationAnalytique.add(a.createInsert(root, user));
}
}
SQLInsert.executeSimilarInserts(sysRoot, insertsAssociationAnalytique, false);
}
for (Piece p : pieces) {
final List<Mouvement> mouvements = p.getMouvements();
for (Mouvement m : mouvements) {
if (m.getPostInsertionAction() != null) {
m.getPostInsertionAction().afterInsert(m);
}
}
 
}
 
return null;
}
});
 
}
 
/**
* Map des numero de compte en minuscule <-> Compte
*
* @param pieces pièces servant à déterminer sur quels numéros de compte on limite la requête
*/
protected Map<String, Compte> getNumeroDesComptes(DBRoot root, List<Piece> pieces) {
// tous les comptes dont le numero
// est parmis celles des écritures des pièces
final Set<String> numerosDesComptes = new HashSet<>();
for (Piece p : pieces) {
final List<Mouvement> mouvements = p.getMouvements();
for (Mouvement m : mouvements) {
for (Ecriture e : m.getEcritures()) {
numerosDesComptes.add(e.getCompteNumero().toLowerCase());
}
}
}
 
final Map<String, Compte> result = new HashMap<>();
final SQLTable tableCompte = root.getTable("COMPTE_PCE");
final SQLSelect selCompte = new SQLSelect();
selCompte.addSelect(tableCompte.getKey());
final SQLField fNumero = tableCompte.getField("NUMERO");
selCompte.addSelect(fNumero);
selCompte.addSelect(tableCompte.getField("NOM"));
String numeros = CollectionUtils.join(numerosDesComptes, ",", new ITransformer<Object, String>() {
@Override
public String transformChecked(final Object input) {
return fNumero.getField().getType().toString(input);
}
});
final Where w = Where.createRaw("lower(" + fNumero.getFieldRef() + ") in (" + numeros + ")", fNumero);
selCompte.setWhere(w);
 
final ResultSetHandler resultSetHandler = new ResultSetHandler() {
 
@Override
public Object handle(ResultSet rs) throws SQLException {
while (rs.next()) {
final Long id = rs.getLong(1);
final String numero = rs.getString(2);
final String nom = rs.getString(3);
result.put(numero.toLowerCase(), new Compte(id, numero, nom));
}
return null;
}
};
 
root.getDBSystemRoot().getDataSource().execute(selCompte.asString(), resultSetHandler);
return result;
}
 
/**
* Map des codes en minuscule <-> Journal
*/
protected Map<String, Journal> getCodesJournaux(DBRoot root) {
final Map<String, Journal> result = new HashMap<>();
final SQLTable tableJournal = root.getTable("JOURNAL");
final SQLSelect selJournal = new SQLSelect();
selJournal.addSelect(tableJournal.getKey());
selJournal.addSelect(tableJournal.getField("CODE"));
selJournal.addSelect(tableJournal.getField("NOM"));
 
final ResultSetHandler resultSetHandler = new ResultSetHandler() {
 
@Override
public Object handle(ResultSet rs) throws SQLException {
while (rs.next()) {
final Long id = rs.getLong(1);
final String code = rs.getString(2);
final String nom = rs.getString(3);
result.put(code.toLowerCase(), new Journal(id, code, nom));
}
return null;
}
};
 
root.getDBSystemRoot().getDataSource().execute(selJournal.asString(), resultSetHandler);
return result;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtFactureFournisseur.java
166,6 → 166,10
}
}
this.putValue("ID_COMPTE_PCE", new Integer(idCompteFourn));
if (rowFournisseur.getTable().getTable("ECRITURE").contains("CODE_CLIENT")) {
this.putValue("CODE_CLIENT", rowFournisseur.getString("CODE"));
}
 
this.putValue("DEBIT", new Long(0));
if (rowFournisseur.getBoolean("UE")) {
this.putValue("CREDIT", new Long(htLongValue));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/stock/element/DepotStockSQLElement.java
14,16 → 14,27
package org.openconcerto.erp.core.supplychain.stock.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.common.ui.ListeViewPanel;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.IListFrame;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FrameUtil;
import org.openconcerto.utils.ListMap;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.AbstractAction;
import javax.swing.JLabel;
import javax.swing.JTextField;
 
33,7 → 44,22
 
public DepotStockSQLElement() {
super("DEPOT_STOCK", "un dépôt", "dépôts");
 
PredicateRowAction actionStock = new PredicateRowAction(new AbstractAction("Voir le détails du stock") {
 
@Override
public void actionPerformed(ActionEvent e) {
SQLRowAccessor selRow = IListe.get(e).getSelectedRow();
final SQLElement elementStock = getDirectory().getElement("STOCK");
IListFrame frame = new IListFrame(
new ListeViewPanel(elementStock, new IListe(elementStock.createTableSource(new Where(elementStock.getTable().getField("ID_DEPOT_STOCK"), "=", selRow.getID())))));
FrameUtil.showPacked(frame);
 
}
}, true);
actionStock.setPredicate(IListeEvent.getSingleSelectionPredicate());
getRowActions().add(actionStock);
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/stock/element/StockItemsUpdater.java
25,6 → 25,8
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTableEvent;
import org.openconcerto.sql.model.SQLTableEvent.Mode;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.DecimalUtils;
154,12 → 156,13
for (String s : requests) {
handlers.add(null);
}
// FIXME FIRE TABLE CHANGED TO UPDATE ILISTE ??
try {
SQLUtils.executeAtomic(stockTable.getDBSystemRoot().getDataSource(), new ConnectionHandlerNoSetup<Object, IOException>() {
@Override
public Object handle(SQLDataSource ds) throws SQLException, IOException {
SQLUtils.executeMultiple(stockTable.getDBSystemRoot(), requests, handlers);
// FIXME FIRE ONLY CHANGED ROWS
stockTable.fire(new SQLTableEvent(stockTable, SQLRow.NONEXISTANT_ID, Mode.ROW_UPDATED));
return null;
}
});
264,35 → 267,6
SQLUtils.executeMultiple(table.getDBSystemRoot(), multipleRequests, handlers);
}
 
private void fillProductComponent(List<ProductComponent> productComponents, int qte, int index, int level) {
if (level > 0) {
for (int i = index; i < items.size(); i++) {
SQLRowAccessor r = items.get(i);
 
if (!r.getTable().contains("NIVEAU") || r.getInt("NIVEAU") >= level) {
// On ne calcul pas les stocks pour les éléments ayant des fils (le mouvement de
// stock
// des fils impactera les stocks automatiquement)
if (r.getTable().contains("NIVEAU")) {
if (i + 1 < items.size()) {
SQLRowAccessor rNext = items.get(i + 1);
if (rNext.getInt("NIVEAU") > r.getInt("NIVEAU")) {
fillProductComponent(productComponents, qte * r.getInt("QTE"), i + 1, rNext.getInt("NIVEAU"));
continue;
}
}
}
if ((!r.getTable().contains("NIVEAU") || r.getInt("NIVEAU") == level) && !r.isForeignEmpty("ID_ARTICLE") && r.getForeign("ID_ARTICLE") != null) {
productComponents.add(ProductComponent.createFrom(r, qte, r));
}
} else if (r.getInt("NIVEAU") < level) {
// BREAK si on sort de l'article composé
break;
}
}
}
}
 
/**
* Récupére les stocks associés aux articles non composés (inclus les fils des nomenclatures) et
* les met à jour
305,9 → 279,10
 
String mvtStockTableQuoted = rowSource.getTable().getTable("MOUVEMENT_STOCK").getSQLName().quote();
 
ProductHelper helper = new ProductHelper(rowSource.getTable().getDBRoot());
// Liste des éléments à mettre à jour
List<ProductComponent> productComponents = new ArrayList<ProductComponent>();
fillProductComponent(productComponents, 1, 0, 1);
helper.fillProductComponent(this.items, productComponents, 1, 0, 1);
// for (int i = 0; i < items.size(); i++) {
// SQLRowAccessor r = items.get(i);
//
327,7 → 302,6
// }
 
// Liste des articles non composés à mettre à jour (avec les fils des nomenclatures)
ProductHelper helper = new ProductHelper(rowSource.getTable().getDBRoot());
List<ProductComponent> boms = helper.getChildWithQtyFrom(productComponents);
 
for (ProductComponent productComp : boms) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/stock/element/StockSQLElement.java
20,6 → 20,7
import org.openconcerto.erp.model.MouseSheetXmlListeListener;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
100,7 → 101,7
@Override
public ListMap<String, String> getShowAs() {
if (getTable().contains("ID_DEPOT_STOCK")) {
return ListMap.singleton(null, "QTE_TH", "QTE_REEL", "QTE_LIV_ATTENTE", "QTE_RECEPT_ATTENTE", "ID_DEPOT_STOCK");
return ListMap.singleton(null, "QTE_TH", "QTE_REEL", "QTE_MIN", "QTE_LIV_ATTENTE", "QTE_RECEPT_ATTENTE", "ID_DEPOT_STOCK");
} else {
return ListMap.singleton(null, "QTE_TH", "QTE_REEL", "QTE_LIV_ATTENTE", "QTE_RECEPT_ATTENTE");
}
134,8 → 135,15
if (rowValsSource.getForeign("ID_DEPOT_STOCK") != null && !rowValsSource.isForeignEmpty("ID_DEPOT_STOCK")) {
idDepot = rowValsSource.getForeignID("ID_DEPOT_STOCK");
} else {
idDepot = rowValsSource.getForeign("ID_ARTICLE").getForeignID("ID_DEPOT_STOCK");
SQLRowAccessor rowValsArt = rowValsSource.getForeign("ID_ARTICLE");
if (rowValsArt.getObject("ID_DEPOT_STOCK") == null) {
rowValsArt = rowValsArt.asRow();
((SQLRow) rowValsArt).fetchValues();
System.err.println("REFETCH ARTICLE");
Thread.dumpStack();
}
idDepot = rowValsArt.getForeignID("ID_DEPOT_STOCK");
}
SQLTable stockTable = rowValsSource.getTable().getTable("STOCK");
SQLRowValues putRowValuesStock = new SQLRowValues(stockTable);
putRowValuesStock.putNulls(stockTable.getTable().getFieldsName());
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/stock/element/MouvementStockSQLElement.java
16,10 → 16,12
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.erp.core.sales.product.element.UniteVenteArticleSQLElement;
import org.openconcerto.erp.core.supplychain.order.component.CommandeSQLComponent;
import org.openconcerto.erp.core.supplychain.order.ui.CommandeItemTable;
import org.openconcerto.erp.core.supplychain.supplier.component.MouvementStockSQLComponent;
import org.openconcerto.erp.preferences.GestionArticleGlobalPreferencePanel;
import org.openconcerto.erp.preferences.GestionCommercialeGlobalPreferencePanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
50,6 → 52,7
import java.util.List;
import java.util.Map.Entry;
 
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
 
public class MouvementStockSQLElement extends ComptaSQLConfElement {
246,10 → 249,10
}
 
public static void createCommandeF(final ListMap<SQLRow, SQLRowValues> col, final SQLRow rowDevise) {
createCommandeF(col, rowDevise, "", true);
createCommandeF(col, rowDevise, "");
}
 
public static void createCommandeF(final ListMap<SQLRow, SQLRowValues> col, final SQLRow rowDevise, final String ref, final boolean useCommandeEnCours) {
public static void createCommandeF(final ListMap<SQLRow, SQLRowValues> col, final SQLRow rowDevise, final String ref) {
if (SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("This method must be called outside of EDT");
}
256,6 → 259,7
if (col.size() > 0) {
 
final SQLElement commande = Configuration.getInstance().getDirectory().getElement("COMMANDE");
Boolean useCommandeEnCours = SQLPreferences.getMemCached(commande.getTable().getDBRoot()).getBoolean(GestionCommercialeGlobalPreferencePanel.COMMANDE_FOURNISSEUR_EN_COURS, false);
for (final Entry<SQLRow, List<SQLRowValues>> e : col.entrySet()) {
final SQLRow fournisseur = e.getKey();
// On regarde si il existe une commande en cours existante
324,9 → 328,23
}
}
if (rowValsMatch != null) {
final int qte = rowValsMatch.getInt("QTE");
model.putValue(qte + rowValsElt.getInt("QTE"), index, "QTE");
 
int qte = rowValsMatch.getInt("QTE");
BigDecimal qteUV = rowValsMatch.getBigDecimal("QTE_UNITAIRE");
 
if (rowValsMatch.getObject("ID_UNITE_VENTE") != null && rowValsMatch.getForeignID("ID_UNITE_VENTE") != UniteVenteArticleSQLElement.A_LA_PIECE) {
qteUV = qteUV.multiply(new BigDecimal(qte));
int qteElt = rowValsElt.getInt("QTE");
BigDecimal qteUVElt = rowValsElt.getBigDecimal("QTE_UNITAIRE");
qteUV = qteUV.add(qteUVElt.multiply(new BigDecimal(qteElt)));
qte = 1;
} else {
qte += rowValsElt.getInt("QTE");
}
 
model.putValue(qte, index, "QTE");
model.putValue(qteUV, index, "QTE_UNITAIRE");
} else {
model.addRow(rowValsElt);
if (rowValsElt.getObject("ID_ARTICLE") != null && !rowValsElt.isForeignEmpty("ID_ARTICLE")) {
Object o = itemTable.tarifCompletion(rowValsElt.getForeign("ID_ARTICLE").asRow(), "PRIX_METRIQUE_HA_1");
342,9 → 360,16
 
}
});
}
} else {
SwingUtilities.invokeLater(new Runnable() {
 
@Override
public void run() {
JOptionPane.showMessageDialog(null, "Aucune commande à passer", "Commande fournisseur", JOptionPane.INFORMATION_MESSAGE);
}
 
});
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/element/DemandeAchatItemSQLElement.java
25,6 → 25,7
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.SQLInjector;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
92,7 → 93,6
 
@Override
public void actionPerformed(ActionEvent e) {
List<SQLRowValues> rows = IListe.get(e).getSelectedRows();
StyleSQLElement styleElt = getDirectory().getElement(StyleSQLElement.class);
int idNormal = styleElt.getAllStyleByName().get("Normal");
 
99,9 → 99,10
SQLRowValues rowVals = new SQLRowValues(getTable().getTable("DEMANDE_PRIX"));
rowVals.put("DATE", new Date());
SQLInjector inj = SQLInjector.getInjector(getTable(), getTable().getTable("DEMANDE_PRIX_ELEMENT"));
for (SQLRowValues sqlRowValues : rows) {
SQLRow row = sqlRowValues.asRow();
row.fetchValues();
 
final List<SQLRow> rows = SQLRowListRSH.fetch(IListe.get(e).getRequest().getPrimaryTable(), IListe.get(e).getSelection().getSelectedIDs());
 
for (SQLRow row : rows) {
rowVals.put("ID_AFFAIRE", row.getForeignID("ID_AFFAIRE"));
SQLRowValues rowValsCmdElt = inj.createRowValuesFrom(row);
rowValsCmdElt.put("ID_STYLE", idNormal);
152,7 → 153,6
 
@Override
public void actionPerformed(ActionEvent e) {
List<SQLRowValues> rows = IListe.get(e).getSelectedRows();
StyleSQLElement styleElt = getDirectory().getElement(StyleSQLElement.class);
int idNormal = styleElt.getAllStyleByName().get("Normal");
 
159,9 → 159,8
SQLRowValues rowVals = new SQLRowValues(getTable().getTable("COMMANDE"));
rowVals.put("DATE", new Date());
SQLInjector inj = SQLInjector.getInjector(getTable(), getTable().getTable("COMMANDE_ELEMENT"));
for (SQLRowValues sqlRowValues : rows) {
SQLRow row = sqlRowValues.asRow();
row.fetchValues();
final List<SQLRow> rows = SQLRowListRSH.fetch(IListe.get(e).getRequest().getPrimaryTable(), IListe.get(e).getSelection().getSelectedIDs());
for (SQLRow row : rows) {
rowVals.put("ID_AFFAIRE", row.getForeignID("ID_AFFAIRE"));
SQLRowValues rowValsCmdElt = inj.createRowValuesFrom(row);
rowValsCmdElt.put("ID_STYLE", idNormal);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/element/CommandeSQLElement.java
21,6 → 21,7
import org.openconcerto.erp.core.supplychain.receipt.component.BonReceptionSQLComponent;
import org.openconcerto.erp.generationDoc.gestcomm.CommandeXmlSheet;
import org.openconcerto.erp.model.MouseSheetXmlListeListener;
import org.openconcerto.erp.preferences.GestionCommercialeGlobalPreferencePanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
33,6 → 34,7
import org.openconcerto.sql.model.SQLSelectJoin;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanel;
import org.openconcerto.sql.view.list.IListe;
50,6 → 52,8
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
 
import org.apache.commons.dbutils.handlers.ArrayListHandler;
 
67,11 → 71,57
transfertBR(selectedRows);
}
 
}, false, "supplychain.order.create.receipt");
}, true, "supplychain.order.create.receipt");
 
bonAction.setPredicate(IListeEvent.getSingleSelectionPredicate());
getRowActions().add(bonAction);
 
PredicateRowAction actionsTRFA = new PredicateRowAction(new AbstractAction("Transfert vers facture fournisseur") {
public void actionPerformed(ActionEvent e) {
final List<SQLRowValues> selectedRows = IListe.get(e).getSelectedRows();
SwingWorker<Boolean, Object> worker = new SwingWorker<Boolean, Object>() {
@Override
protected Boolean doInBackground() throws Exception {
 
boolean b = TransfertBaseSQLComponent.isAlreadyAllTransfert(selectedRows, getTable(), getTable().getTable("FACTURE_FOURNISSEUR"), "T_HT", "T_HT");
 
if (b) {
String label = "Attention ";
if (selectedRows.size() > 1) {
label += " les " + getPluralName() + " ont déjà été transféré!";
} else {
label += getSingularName() + " a déjà été transféré!";
}
label += "\n Voulez vous continuer?";
 
int ans = JOptionPane.showConfirmDialog(null, label, "Transfert " + getSingularName(), JOptionPane.YES_NO_OPTION);
if (ans == JOptionPane.NO_OPTION) {
return Boolean.FALSE;
}
}
 
return Boolean.TRUE;
 
}
 
@Override
protected void done() {
try {
Boolean b = get();
if (b) {
TransfertBaseSQLComponent.openTransfertFrame(selectedRows, "FACTURE_FOURNISSEUR");
}
} catch (Exception e) {
ExceptionHandler.handle("Erreur lors du transfert des " + getPluralName() + "!", e);
}
}
};
worker.execute();
}
}, false);
actionsTRFA.setPredicate(IListeEvent.getNonEmptySelectionPredicate());
getRowActions().add(actionsTRFA);
 
// Transfert vers facture
PredicateRowAction factureAction = new PredicateRowAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
107,9 → 157,13
l.add("NOM");
l.add("DATE");
l.add("ID_FOURNISSEUR");
l.add("ID_COMMERCIAL");
l.add("T_HT");
l.add("T_TTC");
Boolean useCommandeEnCours = SQLPreferences.getMemCached(getTable().getDBRoot()).getBoolean(GestionCommercialeGlobalPreferencePanel.COMMANDE_FOURNISSEUR_EN_COURS, false);
if (useCommandeEnCours) {
l.add("EN_COURS");
}
l.add("INFOS");
return l;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/element/EtatDemandeAchatItemSQLElement.java
17,9 → 17,9
package org.openconcerto.erp.core.supplychain.order.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.common.ui.IColorChooser;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.ui.IColorChooser;
import org.openconcerto.utils.ListMap;
 
import java.util.ArrayList;
68,7 → 68,7
return new UISQLComponent(this) {
public void addViews() {
this.addRequiredSQLObject(new JTextField(), "NOM", "left");
this.addRequiredSQLObject(new IColorChooser(), "COLOR", "right");
this.addRequiredSQLObject(new IColorChooser("Couleur"), "COLOR", "right");
}
};
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/element/FactureFournisseurSQLElement.java
19,15 → 19,23
import org.openconcerto.erp.generationDoc.gestcomm.FactureFournisseurXmlSheet;
import org.openconcerto.erp.model.MouseSheetXmlListeListener;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanel;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.utils.ListMap;
 
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
import javax.swing.AbstractAction;
 
public class FactureFournisseurSQLElement extends ComptaSQLConfElement {
 
public FactureFournisseurSQLElement() {
41,7 → 49,22
actionAttachment.setPredicate(IListeEvent.getSingleSelectionPredicate());
getRowActions().add(actionAttachment);
}
RowAction actionClone = new RowAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
 
EditFrame editFrame = new EditFrame(FactureFournisseurSQLElement.this, EditPanel.CREATION);
 
((FactureFournisseurSQLComponent) editFrame.getSQLComponent()).loadFactureExistante(IListe.get(e).getSelectedId());
editFrame.setVisible(true);
}
}, true, "supplychain.invoice.clone") {
public boolean enabledFor(IListeEvent evt) {
List<? extends SQLRowAccessor> l = evt.getSelectedRows();
return (l != null && l.size() == 1);
}
};
getRowActions().add(actionClone);
}
 
@Override
public Set<String> getReadOnlyFields() {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/action/ListeDesCommandesAction.java
14,9 → 14,11
package org.openconcerto.erp.core.supplychain.order.action;
 
import org.openconcerto.erp.action.CreateFrameAbstractAction;
import org.openconcerto.erp.core.common.ui.IListFilterDatePanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.model.graph.PathBuilder;
25,13 → 27,17
import org.openconcerto.sql.view.list.BaseSQLTableModelColumn;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.table.PercentTableCellRenderer;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.DecimalUtils;
 
import java.awt.GridBagConstraints;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
import javax.swing.Action;
47,28 → 53,135
 
final SQLElement elementCmd = Configuration.getInstance().getDirectory().getElement("COMMANDE");
final SQLTableModelSourceOnline tableSource = elementCmd.getTableSource(true);
BaseSQLTableModelColumn colAvancement = new BaseSQLTableModelColumn("Avancement réception", BigDecimal.class) {
BaseSQLTableModelColumn colAvancementR = new BaseSQLTableModelColumn("Avancement réception", BigDecimal.class) {
 
@Override
protected Object show_(SQLRowAccessor r) {
 
return getAvancement(r);
return getAvancementLFromBR(r);
}
 
@Override
public Set<FieldPath> getPaths() {
final Path p = new PathBuilder(elementCmd.getTable()).addTable("TR_COMMANDE").addTable("BON_RECEPTION").build();
return CollectionUtils.createSet(new FieldPath(p, "TOTAL_HT"));
final Path p = new PathBuilder(elementCmd.getTable()).addTable("COMMANDE_ELEMENT").build();
return CollectionUtils.createSet(new FieldPath(p, "RECU_FORCED"), new FieldPath(p, "RECU"), new FieldPath(p, "QTE_RECUE"), new FieldPath(p, "PA_HT"), new FieldPath(p, "ID_ARTICLE"),
new FieldPath(p, "QTE"), new FieldPath(p, "QTE_UNITAIRE"));
}
};
tableSource.getColumns().add(colAvancementR);
colAvancementR.setRenderer(new PercentTableCellRenderer());
 
BaseSQLTableModelColumn colAvancement = new BaseSQLTableModelColumn("Avancement facturation", BigDecimal.class) {
 
@Override
protected Object show_(SQLRowAccessor r) {
 
return getAvancementFact(r);
}
 
@Override
public Set<FieldPath> getPaths() {
final Path p = new PathBuilder(elementCmd.getTable()).addTable("TR_COMMANDE").addTable("SAISIE_ACHAT").build();
final Path p2 = new PathBuilder(elementCmd.getTable()).addTable("TR_COMMANDE").addTable("FACTURE_FOURNISSEUR").build();
 
final Path pBr = new PathBuilder(elementCmd.getTable()).addTable("TR_COMMANDE").addTable("BON_RECEPTION").build();
final Path trBr = pBr.add(elementCmd.getTable().getTable("TR_BON_RECEPTION"));
final Path pFact2 = trBr.addTable("FACTURE_FOURNISSEUR");
final Path pAchat2 = trBr.addTable("SAISIE_ACHAT");
return CollectionUtils.createSet(new FieldPath(p, "MONTANT_HT"), new FieldPath(p2, "T_HT"), new FieldPath(pAchat2, "MONTANT_HT"), new FieldPath(pFact2, "T_HT"));
}
};
tableSource.getColumns().add(colAvancement);
colAvancement.setRenderer(new PercentTableCellRenderer());
 
final IListFrame frame = new IListFrame(new ListeAddPanel(elementCmd, new IListe(tableSource)));
final ListeAddPanel panel = new ListeAddPanel(elementCmd, new IListe(tableSource));
// Date panel
Map<IListe, SQLField> map = new HashMap<IListe, SQLField>();
map.put(panel.getListe(), elementCmd.getTable().getField("DATE"));
 
IListFilterDatePanel datePanel = new IListFilterDatePanel(map, IListFilterDatePanel.getDefaultMap());
GridBagConstraints c = new DefaultGridBagConstraints();
c.weightx = 0;
c.fill = GridBagConstraints.NONE;
c.gridy = 4;
c.anchor = GridBagConstraints.CENTER;
c.weighty = 0;
datePanel.setFilterOnDefault();
panel.add(datePanel, c);
final IListFrame frame = new IListFrame(panel);
 
return frame;
}
 
private BigDecimal getAvancementLFromBR(SQLRowAccessor r) {
Collection<? extends SQLRowAccessor> rows = r.getReferentRows(r.getTable().getTable("COMMANDE_ELEMENT"));
BigDecimal totalQte = BigDecimal.ZERO;
BigDecimal totalQteL = BigDecimal.ZERO;
for (SQLRowAccessor row : rows) {
BigDecimal qte = row.getBigDecimal("QTE_UNITAIRE").multiply(new BigDecimal(row.getInt("QTE")));
// On ne prend en compte que les articles ou les lignes différentes de 0
if (!row.isForeignEmpty("ID_ARTICLE") || row.getBigDecimal("PA_HT").signum() != 0) {
totalQte = totalQte.add(qte);
if (row.getBoolean("RECU_FORCED") || row.getBoolean("RECU")) {
totalQteL = totalQteL.add(qte);
} else if (row.getBigDecimal("QTE_RECUE") != null) {
final BigDecimal qteLivree = row.getBigDecimal("QTE_RECUE");
if (qteLivree != null) {
totalQteL = totalQteL.add(qteLivree);
}
}
}
}
if (totalQte.signum() != 0) {
return totalQteL.divide(totalQte, DecimalUtils.HIGH_PRECISION).movePointRight(2).setScale(2, RoundingMode.HALF_UP);
} else {
return BigDecimal.ONE.movePointRight(2);
}
}
 
BigDecimal bigDecimal100 = new BigDecimal(100.0);
 
private BigDecimal getAvancementFact(SQLRowAccessor r) {
Collection<? extends SQLRowAccessor> rows = r.getReferentRows(r.getTable().getTable("TR_COMMANDE"));
long totalFact = 0;
long total = r.getLong("T_HT");
for (SQLRowAccessor row : rows) {
if (!row.isForeignEmpty("ID_FACTURE_FOURNISSEUR")) {
SQLRowAccessor rowFact = row.getForeign("ID_FACTURE_FOURNISSEUR");
Long l = rowFact.getLong("T_HT");
totalFact += l;
}
if (!row.isForeignEmpty("ID_SAISIE_ACHAT")) {
SQLRowAccessor rowFact = row.getForeign("ID_SAISIE_ACHAT");
Long l = rowFact.getLong("MONTANT_HT");
totalFact += l;
}
 
if (!row.isForeignEmpty("ID_BON_RECEPTION")) {
Collection<? extends SQLRowAccessor> rowsBr = row.getForeign("ID_BON_RECEPTION").getReferentRows(r.getTable().getTable("TR_BON_RECEPTION"));
for (SQLRowAccessor rowTrBr : rowsBr) {
if (!rowTrBr.isForeignEmpty("ID_FACTURE_FOURNISSEUR")) {
SQLRowAccessor rowFact = rowTrBr.getForeign("ID_FACTURE_FOURNISSEUR");
Long l = rowFact.getLong("T_HT");
totalFact += l;
}
if (!rowTrBr.isForeignEmpty("ID_SAISIE_ACHAT")) {
SQLRowAccessor rowFact = rowTrBr.getForeign("ID_SAISIE_ACHAT");
Long l = rowFact.getLong("MONTANT_HT");
totalFact += l;
}
 
}
}
}
 
if (total > 0) {
return this.bigDecimal100.min(new BigDecimal(totalFact).divide(new BigDecimal(total), DecimalUtils.HIGH_PRECISION).movePointRight(2).setScale(2, RoundingMode.HALF_UP));
} else {
return BigDecimal.ONE.movePointRight(2);
}
}
 
private BigDecimal getAvancement(SQLRowAccessor r) {
Collection<? extends SQLRowAccessor> rows = r.getReferentRows(r.getTable().getTable("TR_COMMANDE"));
long totalFact = 0;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/component/FactureFournisseurSQLComponent.java
59,6 → 59,9
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
import javax.swing.JLabel;
import javax.swing.JPanel;
65,6 → 68,7
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.TableModelEvent;
102,7 → 106,7
 
int idModeRegl = rowFourn.getInt("ID_MODE_REGLEMENT");
if (idModeRegl > 1 && FactureFournisseurSQLComponent.this.eltModeRegl != null && getMode() == Mode.INSERTION) {
SQLElement sqlEltModeRegl = Configuration.getInstance().getDirectory().getElement("MODE_REGLEMENT");
SQLElement sqlEltModeRegl = getElement().getDirectory().getElement("MODE_REGLEMENT");
SQLRow rowModeRegl = sqlEltModeRegl.getTable().getRow(idModeRegl);
SQLRowValues rowVals = rowModeRegl.createUpdateRow();
rowVals.clearPrimaryKeys();
124,6 → 128,15
return this.fourn;
}
 
@Override
protected Set<String> createRequiredNames() {
final Set<String> s = new HashSet<>(1);
if (getTable().contains("ID_TYPE_CMD")) {
s.add("ID_TYPE_CMD");
}
return s;
}
 
public void addViews() {
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new DefaultGridBagConstraints();
480,10 → 493,10
ElementComboBox comboTaxePort = new ElementComboBox();
DeviseField textRemiseHT = new DeviseField();
 
final JPanel panelPoids = new JPanel(new GridBagLayout());
GridBagConstraints cPort = new DefaultGridBagConstraints();
if (getTable().contains("PORT_HT")) {
addSQLObject(textPortHT, "PORT_HT");
final JPanel panelPoids = new JPanel(new GridBagLayout());
GridBagConstraints cPort = new DefaultGridBagConstraints();
cPort.gridx = 0;
cPort.weightx = 0;
panelPoids.add(new JLabel(getLabelFor("PORT_HT")), cPort);
562,6 → 575,49
final TotalPanel totalTTC = new TotalPanel(this.table, fieldEco, fieldHT, fieldTVA, fieldTTC, textPortHT, textRemiseHT, fieldService, null, fieldDevise, null, null,
(getTable().contains("ID_TAXE_PORT") ? comboTaxePort : null), null);
 
if (getTable().contains("TVA_ADJUSTMENT")) {
final JTextField textTvaAdujs = new JTextField(15);
 
JLabel labelTvaAdujst = new JLabel(getLabelFor("TVA_ADJUSTMENT"));
labelTvaAdujst.setHorizontalAlignment(SwingConstants.RIGHT);
 
cPort.gridx = 0;
cPort.gridy++;
panelPoids.add(labelTvaAdujst, cPort);
cPort.gridx++;
panelPoids.add(textTvaAdujs, cPort);
addView(textTvaAdujs, "TVA_ADJUSTMENT");
totalTTC.setTextFixTVA(textTvaAdujs);
textTvaAdujs.getDocument().addDocumentListener(new SimpleDocumentListener() {
@Override
public void update(final DocumentEvent e) {
final String text = textTvaAdujs.getText();
if (text != null && text.trim().length() > 0) {
if (!text.trim().equals("-")) {
BigDecimal tvaFix = new BigDecimal(text);
if (tvaFix.abs().compareTo(new BigDecimal(0.05)) > 0) {
final String limitedFix;
if (tvaFix.signum() > 0) {
limitedFix = tvaFix.min(new BigDecimal(0.05)).toString();
} else {
limitedFix = tvaFix.max(new BigDecimal(-0.05)).toString();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
 
textTvaAdujs.setText(limitedFix);
}
});
}
}
}
totalTTC.updateTotal();
}
});
DefaultGridBagConstraints.lockMinimumSize(textTvaAdujs);
}
 
c.gridx++;
c.gridy--;
c.gridwidth = GridBagConstraints.REMAINDER;
858,4 → 914,48
 
}
 
public void loadFactureExistante(int idFacture) {
 
SQLElement fact = getElement();
SQLElement factElt = getElement().getDirectory().getElement("FACTURE_FOURNISSEUR_ELEMENT");
 
// On duplique la facture
if (idFacture > 1) {
SQLRow row = fact.getTable().getRow(idFacture);
SQLRowValues rowVals = new SQLRowValues(fact.getTable());
rowVals.put("ID_FOURNISSEUR", row.getInt("ID_FOURNISSEUR"));
// if (getTable().contains("ID_NUMEROTATION_AUTO")) {
// rowVals.put("NUMERO",
// NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new
// Date(), row.getForeign("ID_NUMEROTATION_AUTO")));
// } else {
// rowVals.put("NUMERO",
// NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new
// Date()));
// }
rowVals.put("NOM", row.getObject("NOM"));
this.select(rowVals);
}
 
// On duplique les elements de facture
List<SQLRow> myListItem = fact.getTable().getRow(idFacture).getReferentRows(factElt.getTable());
 
if (myListItem.size() != 0) {
this.table.getModel().clearRows();
 
for (SQLRow rowElt : myListItem) {
 
SQLRowValues rowVals = rowElt.createUpdateRow();
rowVals.clearPrimaryKeys();
this.table.getModel().addRow(rowVals);
int rowIndex = this.table.getModel().getRowCount() - 1;
this.table.getModel().fireTableModelModified(rowIndex);
}
} else {
this.table.getModel().clearRows();
}
this.table.getModel().fireTableDataChanged();
this.table.repaint();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/component/CommandeSQLComponent.java
31,6 → 31,7
import org.openconcerto.erp.generationDoc.gestcomm.CommandeXmlSheet;
import org.openconcerto.erp.panel.PanelOOSQLComponent;
import org.openconcerto.erp.preferences.DefaultNXProps;
import org.openconcerto.erp.preferences.GestionCommercialeGlobalPreferencePanel;
import org.openconcerto.erp.utils.TM;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.DefaultElementSQLObject;
47,9 → 48,11
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.sql.sqlobject.JUniqueTextField;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.list.RowValuesTable;
import org.openconcerto.sql.view.list.RowValuesTableModel;
import org.openconcerto.ui.AutoHideListener;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FormLayouter;
61,6 → 64,7
import org.openconcerto.ui.component.InteractionMode;
import org.openconcerto.ui.preferences.DefaultProps;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Color;
import java.awt.GridBagConstraints;
70,7 → 74,9
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
import javax.swing.JCheckBox;
import javax.swing.JLabel;
109,6 → 115,17
return this.fourn;
}
 
@Override
protected Set<String> createRequiredNames() {
final Set<String> s = new HashSet<>(4);
if (getTable().contains("ID_TYPE_CMD")) {
s.add("ID_TYPE_CMD");
s.add("DA1");
s.add("ID_POLE_PRODUIT");
}
return s;
}
 
public void addViews() {
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new DefaultGridBagConstraints();
184,7 → 201,9
} else {
table.setRowCatComptable(null);
}
 
if (getTable().contains("OFFRE_COM")) {
((SQLTextCombo) getView("OFFRE_COM").getComp()).setValue(rowF.getString("RESPONSABLE"));
}
} else {
table.setRowCatComptable(null);
}
191,7 → 210,9
}
});
 
if (!getTable().getFieldsName().contains("LIVRER")) {
Boolean useCommandeEnCours = SQLPreferences.getMemCached(getElement().getTable().getDBRoot()).getBoolean(GestionCommercialeGlobalPreferencePanel.COMMANDE_FOURNISSEUR_EN_COURS, false);
 
if (!getTable().getFieldsName().contains("LIVRER") && useCommandeEnCours) {
// Commande en cours
JCheckBox boxEnCours = new JCheckBox(getLabelFor("EN_COURS"));
c.gridx += 2;
1004,6 → 1025,27
stockUpdater.update();
}
 
@Override
public synchronized ValidState getValidState() {
if (getTable().contains("ID_TYPE_CMD") && getTable().contains("ID_AFFAIRE") && getTable().getTable("COMMANDE_ELEMENT").contains("ID_AFFAIRE")) {
SQLRequestComboBox boxAff = (SQLRequestComboBox) getView("ID_AFFAIRE").getComp();
final SQLRow selectedAff = boxAff.getSelectedRow();
if (selectedAff == null || selectedAff.isUndefined()) {
RowValuesTableModel tableRow = this.table.getRowValuesTable().getRowValuesTableModel();
 
for (int i = 0; i < tableRow.getRowCount(); i++) {
SQLRowValues rowVals = tableRow.getRowValuesAt(i);
if (rowVals.getInt("QTE") != 0 && (rowVals.getObject("ID_AFFAIRE") == null || rowVals.isForeignEmpty("ID_AFFAIRE"))) {
return ValidState.create(false, "Aucune affaire globale sélectionnée et une ligne avec une quantité > 0 n'est pas affectée à une affaire!");
}
}
} else {
ValidState.create(false, "Aucune affaire globale sélectionnée!");
}
}
return super.getValidState();
}
 
public void setDefaults() {
this.resetValue();
this.numeroUniqueCommande.setText(NumerotationAutoSQLElement.getNextNumero(getElement().getClass()));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/receipt/element/BonReceptionSQLElement.java
27,6 → 27,7
import org.openconcerto.sql.model.AliasedTable;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
35,6 → 36,7
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.ListMap;
 
import java.awt.event.ActionEvent;
45,6 → 47,8
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
 
import org.apache.commons.dbutils.handlers.ArrayListHandler;
 
55,8 → 59,46
 
PredicateRowAction actionsTRFA = new PredicateRowAction(new AbstractAction("Transfert vers facture fournisseur") {
public void actionPerformed(ActionEvent e) {
TransfertBaseSQLComponent.openTransfertFrame(IListe.get(e).getSelectedRows(), "FACTURE_FOURNISSEUR");
final List<SQLRowValues> selectedRows = IListe.get(e).getSelectedRows();
SwingWorker<Boolean, Object> worker = new SwingWorker<Boolean, Object>() {
@Override
protected Boolean doInBackground() throws Exception {
 
boolean b = TransfertBaseSQLComponent.isAlreadyAllTransfert(selectedRows, getTable(), getTable().getTable("FACTURE_FOURNISSEUR"), "TOTAL_HT", "T_HT");
 
if (b) {
String label = "Attention ";
if (selectedRows.size() > 1) {
label += " les " + getPluralName() + " ont déjà été transféré!";
} else {
label += getSingularName() + " a déjà été transféré!";
}
label += "\n Voulez vous continuer?";
 
int ans = JOptionPane.showConfirmDialog(null, label, "Transfert " + getSingularName(), JOptionPane.YES_NO_OPTION);
if (ans == JOptionPane.NO_OPTION) {
return Boolean.FALSE;
}
}
 
return Boolean.TRUE;
 
}
 
@Override
protected void done() {
try {
Boolean b = get();
if (b) {
TransfertBaseSQLComponent.openTransfertFrame(selectedRows, "FACTURE_FOURNISSEUR");
}
} catch (Exception e) {
ExceptionHandler.handle("Erreur lors du transfert des " + getPluralName() + "!", e);
}
}
};
worker.execute();
}
}, true);
actionsTRFA.setPredicate(IListeEvent.getNonEmptySelectionPredicate());
 
85,6 → 127,7
protected List<String> getListFields() {
final List<String> l = new ArrayList<>(5);
l.add("NUMERO");
l.add("NOM");
l.add("DATE");
l.add("ID_FOURNISSEUR");
l.add("TOTAL_HT");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/receipt/action/ListeDesBonsReceptionsAction.java
94,6 → 94,8
return frame;
}
 
private BigDecimal bigDecimal100 = new BigDecimal(100);
 
private BigDecimal getAvancement(SQLRowAccessor r) {
Collection<? extends SQLRowAccessor> rows = r.getReferentRows(r.getTable().getTable("TR_BON_RECEPTION"));
long totalFact = 0;
106,7 → 108,7
}
}
if (total > 0) {
return new BigDecimal(totalFact).divide(new BigDecimal(total), DecimalUtils.HIGH_PRECISION).movePointRight(2).setScale(2, RoundingMode.HALF_UP);
return this.bigDecimal100.min(new BigDecimal(totalFact).divide(new BigDecimal(total), DecimalUtils.HIGH_PRECISION).movePointRight(2).setScale(2, RoundingMode.HALF_UP));
} else {
return BigDecimal.ONE.movePointRight(2);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/receipt/component/BonReceptionSQLComponent.java
60,11 → 60,14
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
91,6 → 94,15
}
 
@Override
protected Set<String> createRequiredNames() {
final Set<String> s = new HashSet<>(1);
if (getTable().contains("ID_TYPE_CMD")) {
s.add("ID_TYPE_CMD");
}
return s;
}
 
@Override
protected SQLRowValues createDefaults() {
this.tableBonItem.getModel().clearRows();
this.textNumeroUnique.setText(NumerotationAutoSQLElement.getNextNumero(getElement().getClass()));
628,6 → 640,8
}
}
int count = this.tableBonItem.getModel().getRowCount();
int receipt = 0;
 
for (int i = 0; i < count; i++) {
SQLRowValues r = this.tableBonItem.getModel().getRowValuesAt(i);
SQLRowValues rowTR = map.get(r.getForeignID("ID_ARTICLE"));
634,14 → 648,28
if (rowTR != null && !rowTR.isUndefined()) {
if (r.getInt("QTE") > 0) {
if (NumberUtils.areNumericallyEqual(r.getBigDecimal("QTE_UNITAIRE"), BigDecimal.ONE) || r.getInt("QTE") > 1) {
this.tableBonItem.getModel().putValue(r.getInt("QTE") - rowTR.getInt("QTE"), i, "QTE");
int value = r.getInt("QTE") - rowTR.getInt("QTE");
if ((value <= 0)) {
receipt++;
}
 
this.tableBonItem.getModel().putValue(Math.max(0, value), i, "QTE");
} else {
this.tableBonItem.getModel().putValue(r.getBigDecimal("QTE_UNITAIRE").subtract(rowTR.getBigDecimal("QTE_UNITAIRE")), i, "QTE_UNITAIRE");
BigDecimal subtract = r.getBigDecimal("QTE_UNITAIRE").subtract(rowTR.getBigDecimal("QTE_UNITAIRE"));
if (subtract.signum() <= 0) {
receipt++;
}
this.tableBonItem.getModel().putValue(subtract.max(BigDecimal.ZERO), i, "QTE_UNITAIRE");
}
} else {
receipt++;
}
}
}
if (receipt == count) {
JOptionPane.showMessageDialog(null, "Attention tous les articles ont déjà été réceptionné!");
}
}
 
@Override
public void update() {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/mail/EmailTemplateSQLComponent.java
New file
0,0 → 1,32
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.customerrelationship.mail;
 
import org.openconcerto.sql.element.GroupSQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRowValues;
 
public class EmailTemplateSQLComponent extends GroupSQLComponent {
 
public EmailTemplateSQLComponent(SQLElement element) {
super(element);
}
 
@Override
protected SQLRowValues createDefaults() {
final SQLRowValues defaultValues = super.createDefaults();
defaultValues.put("FORMAT_DATE", "dd/MM/yyyy");
return defaultValues;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/mail/EmailTemplateSQLElement.java
New file
0,0 → 1,52
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.customerrelationship.mail;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.GlobalMapper;
import org.openconcerto.sql.element.SQLComponent;
 
import java.util.Arrays;
import java.util.List;
 
public class EmailTemplateSQLElement extends ComptaSQLConfElement {
public static final String TABLE_NAME = "MODELE_EMAIL";
 
public EmailTemplateSQLElement() {
super(TABLE_NAME, "un modèle d'email", "modèles d'emails");
final EmailTemplateGroup group = new EmailTemplateGroup();
GlobalMapper.getInstance().map(EmailTemplateGroup.ID, group);
setDefaultGroup(group);
}
@Override
protected List<String> getListFields() {
return Arrays.asList("NOM", "PAR_DEFAUT");
}
 
@Override
protected List<String> getComboFields() {
return Arrays.asList("NOM");
}
 
@Override
protected SQLComponent createComponent() {
return new EmailTemplateSQLComponent(this);
}
 
@Override
protected String createCode() {
return "customerrelationship.mail.email.template";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/mail/action/ListeDesModelesEmailAction.java
New file
0,0 → 1,35
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/