Dépôt officiel du code source de l'ERP OpenConcerto
/trunk/OpenConcerto/lib/jOpenDocument-1.3b1.jar |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/trunk/OpenConcerto/lib/fb-annotations-2.0.0.jar |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/trunk/OpenConcerto/lib/fb-annotations-2.0.0.jar |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLCache.java |
---|
28,7 → 28,11 |
import java.util.Map; |
public class OOXMLCache { |
protected static SQLRowAccessor getForeignRow(SQLRowAccessor row, SQLField field) { |
private Map<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>> cacheReferent = new HashMap<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>>(); |
private Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<String, Map<Integer, SQLRowAccessor>>(); |
protected SQLRowAccessor getForeignRow(SQLRowAccessor row, SQLField field) { |
Map<Integer, SQLRowAccessor> c = cacheForeign.get(field.getName()); |
if (row.getObject(field.getName()) == null) { |
54,15 → 58,14 |
return foreign; |
} |
// return row.getForeignRow(field.getName()); |
} |
protected static List<? extends SQLRowAccessor> getReferentRows(List<? extends SQLRowAccessor> row, SQLTable tableForeign) { |
protected List<? extends SQLRowAccessor> getReferentRows(List<? extends SQLRowAccessor> row, SQLTable tableForeign) { |
return getReferentRows(row, tableForeign, null); |
} |
protected static List<? extends SQLRowAccessor> getReferentRows(List<? extends SQLRowAccessor> row, final SQLTable tableForeign, String groupBy) { |
protected List<? extends SQLRowAccessor> getReferentRows(List<? extends SQLRowAccessor> row, final SQLTable tableForeign, String groupBy) { |
Map<SQLTable, List<SQLRowAccessor>> c = cacheReferent.get(row.get(0)); |
if (c != null && c.get(tableForeign) != null) { |
132,7 → 135,7 |
// return row.getReferentRows(tableForeign); |
} |
private static void cumulRows(final List<String> params, SQLRow sqlRow, SQLRowValues rowVals) { |
private void cumulRows(final List<String> params, SQLRow sqlRow, SQLRowValues rowVals) { |
for (int i = 1; i < params.size(); i++) { |
150,14 → 153,11 |
} |
} |
private static Map<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>> cacheReferent = new HashMap<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>>(); |
private static Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<String, Map<Integer, SQLRowAccessor>>(); |
public static Map<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>> getCacheReferent() { |
public Map<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>> getCacheReferent() { |
return cacheReferent; |
} |
public static void clearCache() { |
public void clearCache() { |
cacheReferent.clear(); |
cacheForeign.clear(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLField.java |
---|
48,8 → 48,8 |
private String op = ""; |
public OOXMLField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id, SQLRow rowLanguage) { |
super(eltField, sqlElt, id, rowLanguage); |
public OOXMLField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id, SQLRow rowLanguage, OOXMLCache cache) { |
super(eltField, sqlElt, id, rowLanguage, cache); |
String base = eltField.getAttributeValue("base"); |
this.op = eltField.getAttributeValue("op"); |
97,7 → 97,7 |
} |
} |
SQLRowAccessor foreignRow = OOXMLCache.getForeignRow(this.row, sqlField); |
SQLRowAccessor foreignRow = cache.getForeignRow(this.row, sqlField); |
if (foreignRow != null && foreignRow.getID() > 1) { |
final List<Element> children = this.elt.getChildren("field"); |
if (children.size() > 1) { |
105,7 → 105,7 |
String result = ""; |
for (Element ssComposant : children) { |
OOXMLField childElt = new OOXMLField(ssComposant, foreignRow, this.sqlElt, this.id, this.rowLanguage); |
OOXMLField childElt = new OOXMLField(ssComposant, foreignRow, this.sqlElt, this.id, this.rowLanguage, cache); |
final Object valueComposantO = childElt.getValue(); |
result += (valueComposantO == null) ? "" : valueComposantO.toString() + " "; |
} |
119,7 → 119,7 |
} |
} else { |
if (isValid()) { |
OOXMLField childElt = new OOXMLField(this.elt.getChild("field"), foreignRow, this.sqlElt, this.id, this.rowLanguage); |
OOXMLField childElt = new OOXMLField(this.elt.getChild("field"), foreignRow, this.sqlElt, this.id, this.rowLanguage, cache); |
return childElt.getValue(); |
} else { |
return ""; |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SpreadSheetCellValueContext.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.generationDoc; |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.utils.StringUtils; |
import java.io.PrintStream; |
import java.util.ArrayList; |
import java.util.Collections; |
import java.util.HashMap; |
import java.util.List; |
import java.util.Map; |
public class SpreadSheetCellValueContext { |
private SQLRowAccessor row; |
private Map<String, String> map = new HashMap<String, String>(); |
public SpreadSheetCellValueContext(SQLRowAccessor row) { |
this.row = row; |
} |
public void dump() { |
dump(System.out); |
} |
public void dump(PrintStream prt) { |
prt.println("Row id: " + row.getID() + " table:" + row.getTable()); |
List<String> fields = new ArrayList<String>(); |
fields.addAll(row.getFields()); |
Collections.sort(fields); |
for (String field : fields) { |
prt.print(StringUtils.rightAlign(field, 20)); |
prt.print(" : "); |
prt.println(row.getObject(field)); |
} |
prt.println("Parameters:"); |
List<String> params = new ArrayList<String>(); |
params.addAll(map.keySet()); |
Collections.sort(params); |
for (String param : params) { |
prt.print(StringUtils.rightAlign(param, 20)); |
prt.print(" : "); |
prt.println(row.getObject(param)); |
} |
} |
public SQLRowAccessor getRow() { |
return row; |
} |
public void put(String name, String value) { |
map.put(name, value); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SpreadSheetCellValueProviderManager.java |
---|
New file |
0,0 → 1,39 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.erp.generationDoc; |
import java.util.HashMap; |
import java.util.Map; |
public class SpreadSheetCellValueProviderManager { |
private final static SpreadSheetCellValueProviderManager instance = new SpreadSheetCellValueProviderManager(); |
private final Map<String, SpreadSheetCellValueProvider> map = new HashMap<String, SpreadSheetCellValueProvider>(); |
public static void put(String id, SpreadSheetCellValueProvider provider) { |
instance.putProvider(id, provider); |
} |
public static SpreadSheetCellValueProvider get(String id) { |
return instance.getProvider(id); |
} |
private synchronized void putProvider(String id, SpreadSheetCellValueProvider provider) { |
map.put(id, provider); |
} |
private synchronized SpreadSheetCellValueProvider getProvider(String id) { |
return map.get(id); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationXML.java |
---|
62,21 → 62,28 |
* |
*/ |
public class OOgenerationXML { |
private static int answer = JOptionPane.NO_OPTION; |
private static DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); |
private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); |
// Cache pour la recherche des styles |
private static Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<Sheet, Map<String, Map<Integer, String>>>(); |
private Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<Sheet, Map<String, Map<Integer, String>>>(); |
private Map<SQLRowAccessor, Map<String, Object>> taxe = new HashMap<SQLRowAccessor, Map<String, Object>>(); |
private Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<String, Map<Integer, SQLRowAccessor>>(); |
// Cache pour les SQLRow du tableau |
private static Map<String, List<? extends SQLRowAccessor>> rowsEltCache = new HashMap<String, List<? extends SQLRowAccessor>>(); |
private Map<String, List<? extends SQLRowAccessor>> rowsEltCache = new HashMap<String, List<? extends SQLRowAccessor>>(); |
private final OOXMLCache rowRefCache = new OOXMLCache(); |
private final SQLRow row; |
private static int answer = JOptionPane.NO_OPTION; |
public OOgenerationXML(SQLRow row) { |
this.row = row; |
} |
public static synchronized File createDocument(String templateId, File outputDirectory, final String expectedFileName, SQLRow row, SQLRow rowLanguage) { |
public synchronized File createDocument(String templateId, File outputDirectory, final String expectedFileName, SQLRow rowLanguage) { |
final String langage = rowLanguage != null ? rowLanguage.getString("CHEMIN") : null; |
cacheStyle.clear(); |
OOXMLCache.clearCache(); |
rowRefCache.clearCache(); |
rowsEltCache.clear(); |
taxe.clear(); |
cacheForeign.clear(); |
146,7 → 153,7 |
for (Element tableChild : listTable) { |
// On remplit les cellules du tableau |
parseTableauXML(tableChild, row, spreadSheet, rowLanguage); |
parseTableauXML(tableChild, spreadSheet, rowLanguage); |
} |
} catch (Exception e) { |
ExceptionHandler.handle("Impossible de remplir le document " + templateId + " " + ((rowLanguage == null) ? "" : rowLanguage.getString("CHEMIN")), e); |
182,7 → 189,7 |
* @param id |
* @param sheet |
*/ |
private static void parseTableauXML(Element tableau, SQLRow row, SpreadSheet spreadsheet, SQLRow rowLanguage) { |
private void parseTableauXML(Element tableau, SpreadSheet spreadsheet, SQLRow rowLanguage) { |
if (tableau == null) { |
return; |
284,10 → 291,8 |
* @param test remplir ou non avec les valeurs |
* @return le nombre de page |
*/ |
static Map<SQLRowAccessor, Map<String, Object>> taxe = new HashMap<SQLRowAccessor, Map<String, Object>>(); |
private static Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<String, Map<Integer, SQLRowAccessor>>(); |
protected static SQLRowAccessor getForeignRow(SQLRowAccessor row, SQLField field) { |
protected SQLRowAccessor getForeignRow(SQLRowAccessor row, SQLField field) { |
Map<Integer, SQLRowAccessor> c = cacheForeign.get(field.getName()); |
int i = row.getInt(field.getName()); |
313,7 → 318,7 |
} |
private static int fillTable(Element tableau, SQLRow row, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test, SQLRow rowLanguage) { |
private int fillTable(Element tableau, SQLRow row, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test, SQLRow rowLanguage) { |
if (tableau == null) { |
return 1; |
322,7 → 327,7 |
int nbPage = 1; |
int nbCellules = 0; |
OOXMLTableElement tableElement = new OOXMLTableElement(tableau, row); |
OOXMLTableElement tableElement = new OOXMLTableElement(tableau, row, this.rowRefCache); |
int currentLineTmp = tableElement.getFirstLine(); |
int currentLine = tableElement.getFirstLine(); |
395,7 → 400,7 |
for (Element e : listElts) { |
OOXMLTableField tableField = new OOXMLTableField(e, rowElt, tableElement.getSQLElement(), rowElt.getID(), tableElement.getTypeStyleWhere() ? -1 : tableElement.getFilterId(), |
rowLanguage, numeroRef); |
rowLanguage, numeroRef, this.rowRefCache); |
final Object value = tableField.getValue(); |
mapValues.put(e, value); |
413,7 → 418,7 |
for (Element e : listElts) { |
OOXMLTableField tableField = new OOXMLTableField(e, rowElt, tableElement.getSQLElement(), rowElt.getID(), tableElement.getTypeStyleWhere() ? -1 : tableElement.getFilterId(), |
rowLanguage, numeroRef); |
rowLanguage, numeroRef, this.rowRefCache); |
if (!test && styleName != null && tableElement.getListBlankLineStyle().contains(styleName) && first) { |
toAdd++; |
518,7 → 523,7 |
return d; |
} |
private static void fillTaxe(Element tableau, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test) { |
private void fillTaxe(Element tableau, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test) { |
int line = Integer.valueOf(tableau.getAttributeValue("firstLine")); |
List<Element> listElts = tableau.getChildren("element"); |
568,11 → 573,11 |
* @param sqlElt |
* @param id |
*/ |
private static void parseElementsXML(List<Element> elts, SQLRow row, SpreadSheet spreadSheet) { |
private void parseElementsXML(List<Element> elts, SQLRow row, SpreadSheet spreadSheet) { |
SQLElement sqlElt = Configuration.getInstance().getDirectory().getElement(row.getTable()); |
for (Element elt : elts) { |
OOXMLElement OOElt = new OOXMLElement(elt, sqlElt, row.getID(), row); |
OOXMLElement OOElt = new OOXMLElement(elt, sqlElt, row.getID(), row, this.rowRefCache); |
Object result = OOElt.getValue(); |
if (result != null) { |
Object o = elt.getAttributeValue("sheet"); |
612,7 → 617,7 |
* @param replace efface ou non le contenu original de la cellule |
* @param styleOO style à appliquer |
*/ |
private static int fill(String location, Object value, Sheet sheet, boolean replace, String replacePattern, String styleOO, boolean test, boolean controleMultiline) { |
private int fill(String location, Object value, Sheet sheet, boolean replace, String replacePattern, String styleOO, boolean test, boolean controleMultiline) { |
int nbCellule = (test && styleOO == null) ? 2 : 1; |
// est ce que la cellule est valide |
681,7 → 686,7 |
* @param value |
* @param replace |
*/ |
private static void setCellValue(MutableCell cell, Object value, boolean replace, String replacePattern) { |
private void setCellValue(MutableCell cell, Object value, boolean replace, String replacePattern) { |
if (value == null) { |
return; |
// value = ""; |
759,7 → 764,7 |
/** |
* parcourt l'ensemble de la feuille pour trouver les style définit |
*/ |
private static Map<String, Map<Integer, String>> searchStyle(Sheet sheet, int colEnd, int rowEnd) { |
private Map<String, Map<Integer, String>> searchStyle(Sheet sheet, int colEnd, int rowEnd) { |
if (cacheStyle.get(sheet) != null) { |
return cacheStyle.get(sheet); |
818,7 → 823,7 |
return mapStyleDef; |
} |
public static boolean needAnnexe(String templateId, SQLRow row, SQLRow rowLanguage) { |
public boolean needAnnexe(String templateId, SQLRow row, SQLRow rowLanguage) { |
final String langage = rowLanguage != null ? rowLanguage.getString("CHEMIN") : null; |
final SAXBuilder builder = new SAXBuilder(); |
try { |
868,8 → 873,7 |
return false; |
} |
protected static String getStringProposition(SQLRow rowProp) { |
protected String getStringProposition(SQLRow rowProp) { |
return "Notre proposition " + rowProp.getString("NUMERO") + " du " + dateFormat.format(rowProp.getObject("DATE")); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractSheetXml.java |
---|
57,8 → 57,8 |
}); |
templateId = getDefaultTemplateId(); |
} |
AbstractSheetXml.this.generatedOpenDocumentFile = OOgenerationXML.createDocument(templateId, getDocumentOutputDirectory(), getValidFileName(getName()), AbstractSheetXml.this.row, |
getRowLanguage()); |
final OOgenerationXML oXML = new OOgenerationXML(AbstractSheetXml.this.row); |
AbstractSheetXml.this.generatedOpenDocumentFile = oXML.createDocument(templateId, getDocumentOutputDirectory(), getValidFileName(getName()), getRowLanguage()); |
} catch (Exception e) { |
DEFAULT_HANDLER.uncaughtException(null, e); |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SpreadSheetCellValueProvider.java |
---|
New file |
0,0 → 1,18 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.erp.generationDoc; |
public interface SpreadSheetCellValueProvider { |
public Object getValue(final SpreadSheetCellValueContext context); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLTableElement.java |
---|
34,10 → 34,12 |
private SQLElement elt; |
private String foreignTableWhere, typeWhere, fieldWhere; |
private Element tableau; |
private OOXMLCache cache; |
public OOXMLTableElement(Element tableau, SQLRow row) { |
public OOXMLTableElement(Element tableau, SQLRow row, OOXMLCache cache) { |
this.tableau = tableau; |
this.cache = cache; |
this.foreignTableWhere = tableau.getAttributeValue("tableForeignWhere"); |
this.fieldWhere = tableau.getAttributeValue("fieldWhere"); |
122,7 → 124,7 |
// } |
// // #endif |
return OOXMLCache.getReferentRows(this.row, tableElt, this.tableau.getAttributeValue("groupBy")); |
return cache.getReferentRows(this.row, tableElt, this.tableau.getAttributeValue("groupBy")); |
} else { |
System.err.println("OOXMLTableElement.getRows() Table " + tableElt + " is null!"); |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLElement.java |
---|
19,7 → 19,6 |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.users.UserManager; |
import org.openconcerto.utils.GestionDevise; |
import java.text.DateFormat; |
29,6 → 28,7 |
import java.util.Date; |
import java.util.List; |
import org.jdom.Attribute; |
import org.jdom.Element; |
public class OOXMLElement { |
35,46 → 35,43 |
protected Element elt; |
protected SQLElement sqlElt; |
protected int id; |
protected SQLRowAccessor row = null; |
protected SQLRowAccessor row; |
protected SQLRow rowLanguage; |
protected OOXMLCache cache; |
public OOXMLElement(Element elt, SQLElement sqlElt, int id, SQLRow rowLanguage) { |
this.elt = elt; |
this.sqlElt = sqlElt; |
this.id = id; |
this.rowLanguage = rowLanguage; |
public OOXMLElement(Element elt, SQLElement sqlElt, int id, SQLRow rowLanguage, OOXMLCache cache) { |
this(elt, sqlElt, id, null, rowLanguage, cache); |
} |
public OOXMLElement(Element elt, SQLElement sqlElt, int id, SQLRowAccessor row, SQLRow rowLanguage) { |
public OOXMLElement(Element elt, SQLElement sqlElt, int id, SQLRowAccessor row, SQLRow rowLanguage, OOXMLCache cache) { |
this.elt = elt; |
this.sqlElt = sqlElt; |
this.id = id; |
this.row = row; |
this.rowLanguage = rowLanguage; |
this.cache = cache; |
} |
public Object getValue() { |
Object res = ""; |
final String attributeValue = this.elt.getAttributeValue("type"); |
if (attributeValue.equalsIgnoreCase("InitialesUtilisateur")) { |
return getInitialesUser(); |
final String type = this.elt.getAttributeValue("type"); |
SpreadSheetCellValueProvider provider = SpreadSheetCellValueProviderManager.get(type); |
if (provider != null) { |
final SpreadSheetCellValueContext context = new SpreadSheetCellValueContext(this.row); |
List<Attribute> attrs = this.elt.getAttributes(); |
for (Attribute attr : attrs) { |
context.put(attr.getName(), attr.getValue()); |
} |
if (attributeValue.equalsIgnoreCase("InitialesUtilisateurModif")) { |
return getInitialesUserModify(); |
return provider.getValue(context); |
} |
if (attributeValue.equalsIgnoreCase("InitialesUtilisateurCreate")) { |
return getInitialesUserCreate(); |
} |
if (attributeValue.equalsIgnoreCase("TotalHTTable")) { |
if (type.equalsIgnoreCase("TotalHTTable")) { |
return getTotalHTTable(row); |
} |
if (attributeValue.equalsIgnoreCase("DateEcheance")) { |
if (type.equalsIgnoreCase("DateEcheance")) { |
int idModeReglement = row.getInt("ID_MODE_REGLEMENT"); |
Date d = (Date) row.getObject("DATE"); |
return getDateEcheance(idModeReglement, d, this.elt.getAttributeValue("DatePattern")); |
87,7 → 84,7 |
String result = ""; |
for (Element eltField : eltFields) { |
OOXMLField field = new OOXMLField(eltField, this.row, this.sqlElt, this.id, this.rowLanguage); |
OOXMLField field = new OOXMLField(eltField, this.row, this.sqlElt, this.id, this.rowLanguage, cache); |
Object value = field.getValue(); |
if (value != null) { |
96,7 → 93,7 |
} |
res = result; |
} else { |
OOXMLField field = new OOXMLField(eltFields.get(0), this.row, this.sqlElt, this.id, this.rowLanguage); |
OOXMLField field = new OOXMLField(eltFields.get(0), this.row, this.sqlElt, this.id, this.rowLanguage, cache); |
res = field.getValue(); |
} |
} |
103,53 → 100,7 |
return res; |
} |
private String getInitialesUserModify() { |
SQLRowAccessor rowUser = this.row.getForeign("ID_USER_COMMON_MODIFY"); |
String s = rowUser.getString("NOM"); |
String s2 = rowUser.getString("PRENOM"); |
StringBuffer result = new StringBuffer(4); |
if (s2 != null && s2.trim().length() > 0) { |
result.append(s2.charAt(0)); |
} |
if (s != null && s.trim().length() > 0) { |
result.append(s.charAt(0)); |
} |
return result.toString(); |
} |
private String getInitialesUserCreate() { |
SQLRowAccessor rowUser = this.row.getForeign("ID_USER_COMMON_CREATE"); |
String s = rowUser.getString("NOM"); |
String s2 = rowUser.getString("PRENOM"); |
StringBuffer result = new StringBuffer(4); |
if (s2 != null && s2.trim().length() > 0) { |
result.append(s2.charAt(0)); |
} |
if (s != null && s.trim().length() > 0) { |
result.append(s.charAt(0)); |
} |
return result.toString(); |
} |
private String getInitialesUser() { |
String s = UserManager.getInstance().getCurrentUser().getLastName(); |
String s2 = UserManager.getInstance().getCurrentUser().getName(); |
StringBuffer result = new StringBuffer(4); |
if (s2 != null && s2.trim().length() > 0) { |
result.append(s2.charAt(0)); |
} |
if (s != null && s.trim().length() > 0) { |
result.append(s.charAt(0)); |
} |
return result.toString(); |
} |
public static DateFormat format = new SimpleDateFormat("dd/MM/yyyy"); |
protected String getStringProposition(SQLRowAccessor rowProp) { |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLTableField.java |
---|
29,6 → 29,7 |
import java.util.Date; |
import java.util.List; |
import org.jdom.Attribute; |
import org.jdom.Element; |
public class OOXMLTableField extends OOXMLField { |
39,8 → 40,8 |
private int idRef; |
private String style = ""; |
public OOXMLTableField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id, int filterId, SQLRow rowLanguage, int idRef) { |
super(eltField, row, sqlElt, id, rowLanguage); |
public OOXMLTableField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id, int filterId, SQLRow rowLanguage, int idRef, OOXMLCache cache) { |
super(eltField, row, sqlElt, id, rowLanguage, cache); |
this.type = eltField.getAttributeValue("type"); |
this.lineOption = eltField.getAttributeValue("lineOption"); |
this.filterId = filterId; |
62,6 → 63,16 |
public Object getValue() { |
Object value = null; |
SpreadSheetCellValueProvider provider = SpreadSheetCellValueProviderManager.get(type); |
if (provider != null) { |
final SpreadSheetCellValueContext context = new SpreadSheetCellValueContext(this.row); |
List<Attribute> attrs = this.elt.getAttributes(); |
for (Attribute attr : attrs) { |
context.put(attr.getName(), attr.getValue()); |
} |
return provider.getValue(context); |
} |
if (this.type.equalsIgnoreCase("LineReference")) { |
return idRef; |
} else if (this.type.equalsIgnoreCase("DescriptifArticle")) { |
73,7 → 84,7 |
} else if (this.type.equalsIgnoreCase("Localisation")) { |
value = getLocalisation(this.row); |
} else { |
OOXMLElement eltXml = new OOXMLElement(this.elt, this.sqlElt, this.id, this.row, this.rowLanguage); |
OOXMLElement eltXml = new OOXMLElement(this.elt, this.sqlElt, this.id, this.row, this.rowLanguage, cache); |
value = eltXml.getValue(); |
} |
147,7 → 158,7 |
* @param row |
* @return la formule de calcul du montant revise |
*/ |
private static String getMontantRevise(SQLRowAccessor row) { |
private String getMontantRevise(SQLRowAccessor row) { |
long indice0 = (Long) row.getObject("INDICE_0"); |
long indiceN = (Long) row.getObject("INDICE_N"); |
long montantInit = (Long) row.getObject("MONTANT_INITIAL"); |
160,12 → 171,12 |
try { |
SQLRowAccessor rowFact; |
if (row.getTable().getName().startsWith("SAISIE_VENTE_FACTURE")) { |
rowFact = OOXMLCache.getForeignRow(row, row.getTable().getField("ID_SAISIE_VENTE_FACTURE")); |
rowFact = cache.getForeignRow(row, row.getTable().getField("ID_SAISIE_VENTE_FACTURE")); |
} else { |
rowFact = OOXMLCache.getForeignRow(row, row.getTable().getField("ID_AVOIR_CLIENT")); |
rowFact = cache.getForeignRow(row, row.getTable().getField("ID_AVOIR_CLIENT")); |
} |
if (rowFact != null) { |
SQLRowAccessor rowClient = OOXMLCache.getForeignRow(rowFact, rowFact.getTable().getField("ID_CLIENT")); |
SQLRowAccessor rowClient = cache.getForeignRow(rowFact, rowFact.getTable().getField("ID_CLIENT")); |
if (rowClient != null) { |
clientPrive = rowClient.getBoolean("MARCHE_PRIVE"); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/PrixUnitaireRemiseProvider.java |
---|
New file |
0,0 → 1,38 |
/* |
* 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 java.math.BigDecimal; |
import java.math.MathContext; |
public class PrixUnitaireRemiseProvider extends UserInitialsValueProvider { |
@Override |
public Object getValue(SpreadSheetCellValueContext context) { |
SQLRowAccessor row = context.getRow(); |
final Long pv = row.getLong("PV_HT"); |
final BigDecimal remise = (BigDecimal) row.getObject("POURCENT_REMISE"); |
BigDecimal result = BigDecimal.ONE.subtract(remise.movePointLeft(2)).multiply(new BigDecimal(pv), MathContext.DECIMAL128); |
result = result.movePointLeft(2); |
return result; |
} |
public static void register() { |
SpreadSheetCellValueProviderManager.put("PrixUnitaireRemise", new PrixUnitaireRemiseProvider()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/UserInitialsValueProvider.java |
---|
New file |
0,0 → 1,41 |
/* |
* 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; |
public abstract class UserInitialsValueProvider implements SpreadSheetCellValueProvider { |
@Override |
public abstract Object getValue(SpreadSheetCellValueContext context); |
public String getInitials(String firstName, String name) { |
String initials = ""; |
if (firstName != null) { |
final String tFirstName = firstName.trim(); |
if (!tFirstName.isEmpty()) { |
initials += tFirstName.charAt(0); |
} |
} |
if (name != null) { |
final String tName = name.trim(); |
if (!tName.isEmpty()) { |
initials += tName.charAt(0); |
} |
} |
return initials.toUpperCase(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/UserCurrentInitialsValueProvider.java |
---|
New file |
0,0 → 1,35 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.erp.generationDoc.provider; |
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueContext; |
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueProviderManager; |
import org.openconcerto.sql.users.User; |
import org.openconcerto.sql.users.UserManager; |
public class UserCurrentInitialsValueProvider extends UserInitialsValueProvider { |
@Override |
public Object getValue(SpreadSheetCellValueContext context) { |
final User currentUser = UserManager.getInstance().getCurrentUser(); |
final String firstName = currentUser.getFirstName(); |
final String name = currentUser.getName(); |
return getInitials(firstName, name); |
} |
public static void register() { |
SpreadSheetCellValueProviderManager.put("InitialesUtilisateur", new UserCurrentInitialsValueProvider()); |
SpreadSheetCellValueProviderManager.put("user.current.initials", new UserCurrentInitialsValueProvider()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/UserCreateInitialsValueProvider.java |
---|
New file |
0,0 → 1,34 |
/* |
* 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; |
public class UserCreateInitialsValueProvider extends UserInitialsValueProvider { |
@Override |
public Object getValue(SpreadSheetCellValueContext context) { |
final SQLRowAccessor rowUser = context.getRow().getForeign("ID_USER_COMMON_CREATE"); |
final String firstName = rowUser.getString("PRENOM"); |
final String name = rowUser.getString("NOM"); |
return getInitials(firstName, name); |
} |
public static void register() { |
SpreadSheetCellValueProviderManager.put("InitialesUtilisateurCreate", new UserCreateInitialsValueProvider()); |
SpreadSheetCellValueProviderManager.put("user.create.initials", new UserCreateInitialsValueProvider()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/UserModifyInitialsValueProvider.java |
---|
New file |
0,0 → 1,34 |
/* |
* 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; |
public class UserModifyInitialsValueProvider extends UserInitialsValueProvider { |
@Override |
public Object getValue(SpreadSheetCellValueContext context) { |
final SQLRowAccessor rowUser = context.getRow().getForeign("ID_USER_COMMON_MODIFY"); |
final String firstName = rowUser.getString("PRENOM"); |
final String name = rowUser.getString("NOM"); |
return getInitials(firstName, name); |
} |
public static void register() { |
SpreadSheetCellValueProviderManager.put("InitialesUtilisateurModif", new UserModifyInitialsValueProvider()); |
SpreadSheetCellValueProviderManager.put("user.modify.initials", new UserModifyInitialsValueProvider()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/shipment/component/BonDeLivraisonSQLComponent.java |
---|
15,6 → 15,7 |
import static org.openconcerto.utils.CollectionUtils.createSet; |
import org.openconcerto.erp.core.common.component.TransfertBaseSQLComponent; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
import org.openconcerto.erp.core.sales.invoice.element.SaisieVenteFactureItemSQLElement; |
116,7 → 117,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 2)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/credit/component/AvoirClientSQLComponent.java |
---|
17,6 → 17,7 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.component.SocieteCommonSQLElement; |
import org.openconcerto.erp.core.common.component.TransfertBaseSQLComponent; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement; |
import org.openconcerto.erp.core.common.ui.AbstractArticleItemTable; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
208,7 → 209,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 1)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/component/CommandeClientSQLComponent.java |
---|
16,6 → 16,7 |
import static org.openconcerto.utils.CollectionUtils.createSet; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.component.TransfertBaseSQLComponent; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
import org.openconcerto.erp.core.common.ui.TotalPanel; |
115,9 → 116,8 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 2)); |
c.fill = GridBagConstraints.HORIZONTAL; |
c.weightx = 1; |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/component/SaisieVenteFactureSQLComponent.java |
---|
16,6 → 16,7 |
import static org.openconcerto.utils.CollectionUtils.createSet; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.component.TransfertBaseSQLComponent; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement; |
import org.openconcerto.erp.core.common.ui.AbstractArticleItemTable; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
191,7 → 192,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 1)); |
this.add(addP, c); |
996,16 → 997,8 |
this.tableFacture.updateField("ID_SAISIE_VENTE_FACTURE", idSaisieVF); |
// generation du document |
final VenteFactureXmlSheet sheet = new VenteFactureXmlSheet(rowFacture); |
createDocument(rowFacture); |
try { |
sheet.createDocumentAsynchronous(); |
sheet.showPrintAndExportAsynchronous(panelOO.isVisualisationSelected(), panelOO.isImpressionSelected(), true); |
} catch (Exception e) { |
ExceptionHandler.handle("Impossible de générer la facture", e); |
} |
int idMvt = -1; |
if (getMode() == Mode.MODIFICATION) { |
1102,6 → 1095,18 |
return idSaisieVF; |
} |
public void createDocument(SQLRow row) { |
// generation du document |
final VenteFactureXmlSheet sheet = new VenteFactureXmlSheet(row); |
try { |
sheet.createDocumentAsynchronous(); |
sheet.showPrintAndExportAsynchronous(panelOO.isVisualisationSelected(), panelOO.isImpressionSelected(), true); |
} catch (Exception e) { |
ExceptionHandler.handle("Impossible de générer la facture", e); |
} |
} |
@Override |
public void update() { |
commit(null); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/component/DevisSQLComponent.java |
---|
15,6 → 15,7 |
import static org.openconcerto.utils.CollectionUtils.createSet; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
import org.openconcerto.erp.core.common.ui.TotalPanel; |
102,7 → 103,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 2)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/component/ReferenceArticleSQLComponent.java |
---|
14,6 → 14,7 |
package org.openconcerto.erp.core.sales.product.component; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
import org.openconcerto.erp.core.common.ui.TotalPanel; |
import org.openconcerto.erp.core.finance.tax.model.TaxeCache; |
321,7 → 322,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 2)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/FamilleArticleSQLElement.java |
---|
94,7 → 94,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 2)); |
c.fill = GridBagConstraints.HORIZONTAL; |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/element/ComptaSQLConfElement.java |
---|
15,11 → 15,11 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.GlobalMapper; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.DBRoot; |
import org.openconcerto.sql.view.list.SQLTableModelColumn; |
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline; |
import org.openconcerto.ui.AutoHideListener; |
import org.openconcerto.ui.table.TableCellRendererUtils; |
import org.openconcerto.utils.GestionDevise; |
import org.openconcerto.utils.convertor.ValueConvertor; |
29,6 → 29,7 |
import java.math.BigInteger; |
import javax.swing.JLabel; |
import javax.swing.JPanel; |
import javax.swing.JTable; |
import javax.swing.SwingConstants; |
import javax.swing.table.DefaultTableCellRenderer; |
57,6 → 58,10 |
} |
}; |
static public final JPanel createAdditionalPanel() { |
return AutoHideListener.listen(new JPanel()); |
} |
private static DBRoot getBaseSociete() { |
if (baseSociete == null) |
baseSociete = ((ComptaPropsConfiguration) Configuration.getInstance()).getRootSociete(); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/element/LangueSQLElement.java |
---|
15,7 → 15,6 |
import org.openconcerto.sql.element.BaseSQLComponent; |
import org.openconcerto.sql.element.SQLComponent; |
import org.openconcerto.sql.sqlobject.ElementComboBox; |
import org.openconcerto.ui.DefaultGridBagConstraints; |
import java.awt.GridBagConstraints; |
34,9 → 33,7 |
protected List<String> getListFields() { |
final List<String> l = new ArrayList<String>(); |
l.add("NOM"); |
return l; |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/TotalPanel.java |
---|
14,6 → 14,7 |
package org.openconcerto.erp.core.common.ui; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.finance.tax.model.TaxeCache; |
import org.openconcerto.erp.model.PrixHT; |
import org.openconcerto.erp.preferences.DefaultNXProps; |
import org.openconcerto.sql.Configuration; |
408,11 → 409,13 |
Map<SQLRowAccessor, Long> mapHtTVA = new HashMap<SQLRowAccessor, Long>(); |
Map<SQLRowAccessor, Long> mapHtTVASel = new HashMap<SQLRowAccessor, Long>(); |
for (int i = 0; i < this.table.getRowValuesTableModel().getRowCount(); i++) { |
Number nHT = (Number) this.table.getRowValuesTableModel().getValueAt(i, this.columnIndexHT); |
totalHT += nHT.longValue(); |
// Total HA |
if (this.gestionHA) { |
Number nHA = (Number) this.table.getRowValuesTableModel().getValueAt(i, this.columnIndexHA); |
Number nQte = (Number) this.table.getRowValuesTableModel().getValueAt(i, this.columnIndexQte); |
422,6 → 425,8 |
totalHA += (nHA.longValue() * nQte.intValue()); |
} |
} |
// Total Service |
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService"); |
Boolean bServiceActive = Boolean.valueOf(val); |
if (bServiceActive != null && bServiceActive) { |
430,14 → 435,15 |
totalService += nHT.longValue(); |
} |
} |
// Total Devise |
Number nDevise = null; |
if (this.textTotalDevise != null) { |
nDevise = (Number) this.table.getRowValuesTableModel().getValueAt(i, this.columnIndexDevise); |
totalDevise += nDevise.longValue(); |
} |
// Number nTTC = (Number) this.table.getRowValuesTableModel().getValueAt(i, |
// this.columnIndexTTC); |
// totalTTC += nTTC.longValue(); |
// Total TVA |
if (mapHtTVA.get(this.table.getRowValuesTableModel().getRowValuesAt(i).getForeign("ID_TAXE")) == null) { |
mapHtTVA.put(this.table.getRowValuesTableModel().getRowValuesAt(i).getForeign("ID_TAXE"), nHT.longValue()); |
} else { |
445,9 → 451,11 |
mapHtTVA.put(this.table.getRowValuesTableModel().getRowValuesAt(i).getForeign("ID_TAXE"), l + nHT.longValue()); |
} |
// Total Poids |
Number nPoids = (Number) this.table.getRowValuesTableModel().getValueAt(i, this.columnIndexPoids); |
totalPoids += nPoids == null ? 0 : nPoids.doubleValue(); |
// Calcul total sélectionné |
if (containsInt(selectedRows, i)) { |
totalHTSel += nHT.longValue(); |
482,6 → 490,7 |
} |
} |
// Frais de port à inclure |
if (this.textPortHT.getText().trim().length() > 0) { |
if (!this.textPortHT.getText().trim().equals("-")) { |
valPortHT = GestionDevise.parseLongCurrency(this.textPortHT.getText().trim()); |
492,6 → 501,7 |
valPortHT = 0; |
} |
// Remise à inclure |
if (this.textRemiseHT.getText().trim().length() > 0) { |
if (!this.textRemiseHT.getText().trim().equals("-")) { |
valRemiseHT = GestionDevise.parseLongCurrency(this.textRemiseHT.getText().trim()); |
508,7 → 518,7 |
long realTotalTVA = 0; |
for (SQLRowAccessor row : mapHtTVA.keySet()) { |
BigDecimal d = new BigDecimal(row.getFloat("TAUX")); |
BigDecimal d = new BigDecimal(TaxeCache.getCache().getTauxFromId(row.getID())); |
BigDecimal result = d.multiply(new BigDecimal(mapHtTVA.get(row)), MathContext.DECIMAL128).movePointLeft(2); |
realTotalTVA += result.setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); |
} |
529,7 → 539,7 |
long realTotalTVASel = 0; |
for (SQLRowAccessor row : mapHtTVASel.keySet()) { |
BigDecimal d = new BigDecimal(row.getFloat("TAUX")); |
BigDecimal d = new BigDecimal(TaxeCache.getCache().getTauxFromId(row.getID())); |
BigDecimal result = d.multiply(new BigDecimal(mapHtTVASel.get(row)), MathContext.DECIMAL128).movePointLeft(2); |
realTotalTVASel += result.setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/credit/component/AvoirFournisseurSQLComponent.java |
---|
15,6 → 15,7 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.component.TransfertBaseSQLComponent; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement; |
import org.openconcerto.erp.core.common.ui.MontantPanel; |
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement; |
125,7 → 126,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 1)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/component/CommandeSQLComponent.java |
---|
15,6 → 15,7 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.component.TransfertBaseSQLComponent; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement; |
import org.openconcerto.erp.core.common.ui.AbstractVenteArticleItemTable; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
322,7 → 323,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 2)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/component/SaisieAchatSQLComponent.java |
---|
13,6 → 13,7 |
package org.openconcerto.erp.core.supplychain.order.component; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
import org.openconcerto.erp.core.common.ui.MontantPanel; |
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement; |
151,7 → 152,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 1)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/receipt/component/BonReceptionSQLComponent.java |
---|
15,6 → 15,7 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.component.TransfertBaseSQLComponent; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement; |
96,7 → 97,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 1)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/supplier/component/FournisseurSQLComponent.java |
---|
17,6 → 17,7 |
package org.openconcerto.erp.core.supplychain.supplier.component; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.customerrelationship.customer.element.ContactItemTable; |
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement; |
import org.openconcerto.erp.model.ISQLCompteSelector; |
188,7 → 189,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 2)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/customer/element/ClientNormalSQLComponent.java |
---|
45,6 → 45,7 |
import javax.swing.event.DocumentListener; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.common.ui.DeviseField; |
import org.openconcerto.erp.core.customerrelationship.customer.ui.AdresseClientItemTable; |
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement; |
344,7 → 345,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 1)); |
this.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/employe/element/CommercialSQLComponent.java |
---|
16,6 → 16,7 |
*/ |
package org.openconcerto.erp.core.humanresources.employe.element; |
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement; |
import org.openconcerto.erp.core.humanresources.employe.panel.ObjectifEditPanel; |
import org.openconcerto.sql.element.BaseSQLComponent; |
import org.openconcerto.sql.element.SQLElement; |
219,7 → 220,7 |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
final JPanel addP = ComptaSQLConfElement.createAdditionalPanel(); |
addP.setOpaque(false); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 1)); |
panelInfos.add(addP, c); |
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/PanelOOSQLComponent.java |
---|
64,9 → 64,8 |
@Override |
public SQLSelect transformChecked(SQLSelect input) { |
SQLTable table = Configuration.getInstance().getDirectory().getElement("TYPE_MODELE").getTable(); |
Where w = new Where(table.getField("TABLE"), "=", comp.getElement().getTable().getName()); |
Where w = new Where(input.getAlias(table.getField("TABLE")), "=", comp.getElement().getTable().getName()); |
input.setWhere(w); |
System.err.println(input.asString()); |
return input; |
} |
}); |
/trunk/OpenConcerto/src/org/openconcerto/erp/config/ComptaPropsConfiguration.java |
---|
135,6 → 135,10 |
import org.openconcerto.erp.core.supplychain.supplier.element.FournisseurSQLElement; |
import org.openconcerto.erp.generationDoc.element.ModeleSQLElement; |
import org.openconcerto.erp.generationDoc.element.TypeModeleSQLElement; |
import org.openconcerto.erp.generationDoc.provider.PrixUnitaireRemiseProvider; |
import org.openconcerto.erp.generationDoc.provider.UserCreateInitialsValueProvider; |
import org.openconcerto.erp.generationDoc.provider.UserCurrentInitialsValueProvider; |
import org.openconcerto.erp.generationDoc.provider.UserModifyInitialsValueProvider; |
import org.openconcerto.erp.injector.ArticleCommandeEltSQLInjector; |
import org.openconcerto.erp.injector.BonFactureSQLInjector; |
import org.openconcerto.erp.injector.BrFactureAchatSQLInjector; |
166,6 → 170,7 |
import org.openconcerto.sql.element.SharedSQLElement; |
import org.openconcerto.sql.model.DBRoot; |
import org.openconcerto.sql.model.DBSystemRoot; |
import org.openconcerto.sql.model.LoadingListener; |
import org.openconcerto.sql.model.SQLDataSource; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLServer; |
179,6 → 184,7 |
import org.openconcerto.utils.NetUtils; |
import org.openconcerto.utils.ProductInfo; |
import org.openconcerto.utils.StringInputStream; |
import org.openconcerto.utils.SwingWorker2; |
import java.awt.Color; |
import java.awt.Font; |
192,7 → 198,6 |
import java.io.FileInputStream; |
import java.io.IOException; |
import java.io.InputStream; |
import java.lang.reflect.InvocationTargetException; |
import java.sql.SQLException; |
import java.text.DateFormat; |
import java.text.SimpleDateFormat; |
201,8 → 206,14 |
import java.util.Collection; |
import java.util.List; |
import java.util.Properties; |
import java.util.concurrent.Executors; |
import java.util.concurrent.ScheduledExecutorService; |
import java.util.concurrent.ScheduledFuture; |
import java.util.concurrent.ThreadFactory; |
import java.util.concurrent.TimeUnit; |
import javax.imageio.ImageIO; |
import javax.swing.JDialog; |
import javax.swing.JFrame; |
import javax.swing.JOptionPane; |
import javax.swing.SwingUtilities; |
321,7 → 332,9 |
// |
String token = getToken(); |
SwingWorker2.setMaxWorkerThreads(4); |
if (token != null) { |
SwingWorker2.setMaxWorkerThreads(2); |
this.isServerless = false; |
this.isOnCloud = true; |
if (this.getProperty("storage.server") == null) { |
375,10 → 388,72 |
// ATTN this works because this is executed last (i.e. if you put this in a superclass |
// this won't work since e.g. app.name won't have its correct value) |
this.setupLogging("logs"); |
registerCellValueProvider(); |
UserRightsManager.getInstance().register(new ComptaTotalUserRight()); |
} |
private void registerCellValueProvider() { |
UserCreateInitialsValueProvider.register(); |
UserModifyInitialsValueProvider.register(); |
UserCurrentInitialsValueProvider.register(); |
PrixUnitaireRemiseProvider.register(); |
} |
@Override |
protected void initSystemRoot(DBSystemRoot input) { |
super.initSystemRoot(input); |
final JDialog f = new JOptionPane("Mise à jour des caches en cours...\nCette opération prend généralement moins d'une minute.", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, |
null, new Object[] {}).createDialog("Veuillez patienter"); |
input.addLoadingListener(new LoadingListener() { |
private int loadingCount = 0; |
private final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { |
@Override |
public Thread newThread(Runnable r) { |
return new Thread(r, "Loading listener thread"); |
} |
}); |
private ScheduledFuture<?> future = null; |
@Override |
public synchronized void loading(LoadingEvent evt) { |
this.loadingCount += evt.isStarting() ? 1 : -1; |
if (this.loadingCount < 0) { |
throw new IllegalStateException(); |
} else if (this.loadingCount == 0) { |
this.future.cancel(false); |
this.future = null; |
SwingUtilities.invokeLater(new Runnable() { |
@Override |
public void run() { |
f.setVisible(false); |
} |
}); |
} else if (this.future == null) { |
this.future = this.exec.schedule(new Runnable() { |
@Override |
public void run() { |
SwingUtilities.invokeLater(new Runnable() { |
@Override |
public void run() { |
f.setVisible(true); |
} |
}); |
} |
}, 1, TimeUnit.SECONDS); |
} |
} |
}); |
} |
@Override |
protected void initDS(SQLDataSource ds) { |
super.initDS(ds); |
ds.setInitialSize(3); |
ds.setMinIdle(2); |
ds.setMaxActive(4); |
} |
public String getToken() { |
return getProperty("token"); |
} |
825,6 → 900,7 |
setSocieteShowAs(); |
setSocieteSQLInjector(); |
setMapper(); |
String sfe = DefaultNXProps.getInstance().getStringProperty("ArticleSFE"); |
Boolean bSfe = Boolean.valueOf(sfe); |
boolean isSFE = bSfe != null && bSfe.booleanValue(); |
/trunk/OpenConcerto/src/org/openconcerto/erp/config/InstallationPanel.java |
---|
669,6 → 669,19 |
rowVals.commit(); |
} |
// Ajout de la TVA à 0 |
SQLSelect selTVA = new SQLSelect(root.getBase()); |
SQLTable tableTaxe = root.getTable("TAXE"); |
selTVA.addSelect(tableTaxe.getKey(), "COUNT"); |
selTVA.setWhere(new Where(tableTaxe.getField("TAUX"), "=", 0)); |
Object result = root.getBase().getDataSource().executeScalar(selTVA.asString()); |
if (result == null || ((Number) result).longValue() == 0) { |
SQLRowValues rowVals = new SQLRowValues(tableTaxe); |
rowVals.put("NOM", "Non applicable"); |
rowVals.put("TAUX", Float.valueOf(0)); |
rowVals.commit(); |
} |
// Bon de livraison |
{ |
SQLTable tableBL = root.getTable("BON_DE_LIVRAISON"); |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/IComboCacheListModel.java |
---|
14,6 → 14,7 |
package org.openconcerto.ui.component; |
import org.openconcerto.ui.component.combo.ISearchableCombo; |
import org.openconcerto.utils.SwingWorker2; |
import org.openconcerto.utils.change.CollectionChangeEvent; |
import org.openconcerto.utils.change.IListDataEvent; |
import org.openconcerto.utils.model.DefaultIMutableListModel; |
22,7 → 23,6 |
import java.util.Collection; |
import java.util.List; |
import javax.swing.SwingWorker; |
import javax.swing.event.ListDataEvent; |
import javax.swing.event.ListDataListener; |
76,7 → 76,7 |
public final void load(final Runnable r, final boolean readCache) { |
if (this.cache.isValid()) { |
new SwingWorker<List<String>, Object>() { |
new SwingWorker2<List<String>, Object>() { |
@Override |
protected List<String> doInBackground() throws Exception { |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextCombo.java |
---|
22,6 → 22,7 |
import org.openconcerto.ui.valuewrapper.ValueChangeSupport; |
import org.openconcerto.ui.valuewrapper.ValueWrapper; |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.utils.SwingWorker2; |
import org.openconcerto.utils.checks.ValidListener; |
import org.openconcerto.utils.checks.ValidState; |
import org.openconcerto.utils.model.ListComboBoxModel; |
43,7 → 44,6 |
import javax.swing.JButton; |
import javax.swing.JComboBox; |
import javax.swing.JComponent; |
import javax.swing.SwingWorker; |
import javax.swing.event.DocumentEvent; |
import javax.swing.text.AbstractDocument; |
import javax.swing.text.BadLocationException; |
301,7 → 301,7 |
this.setEnabled(false); |
this.objToSelect = this.getValue(); |
this.cacheLoading = true; |
final SwingWorker<List<String>, Object> sw = new SwingWorker<List<String>, Object>() { |
final SwingWorker2<List<String>, Object> sw = new SwingWorker2<List<String>, Object>() { |
@Override |
protected List<String> doInBackground() throws Exception { |
return force ? ITextCombo.this.cache.loadCache(false) : ITextCombo.this.cache.getCache(); |
/trunk/OpenConcerto/src/org/openconcerto/ui/AutoHideListener.java |
---|
New file |
0,0 → 1,57 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui; |
import java.awt.Container; |
import java.awt.event.ContainerEvent; |
import java.awt.event.ContainerListener; |
/** |
* A listener that hides components when they're empty. |
* |
* @author Sylvain CUAZ |
*/ |
public class AutoHideListener implements ContainerListener { |
static private final AutoHideListener instance = new AutoHideListener(); |
static public <T extends Container> T listen(T comp) { |
comp.addContainerListener(instance); |
setVisible(comp); |
return comp; |
} |
static public <T extends Container> T unlisten(T comp) { |
comp.removeContainerListener(instance); |
return comp; |
} |
static private void setVisible(Container comp) { |
comp.setVisible(comp.getComponentCount() > 0); |
} |
// singleton |
private AutoHideListener() { |
} |
@Override |
public void componentAdded(ContainerEvent e) { |
setVisible(e.getContainer()); |
} |
@Override |
public void componentRemoved(ContainerEvent e) { |
setVisible(e.getContainer()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/Configuration.java |
---|
30,6 → 30,8 |
import java.io.File; |
import java.io.IOException; |
import java.util.concurrent.Executor; |
import java.util.concurrent.Executors; |
/** |
* Regroupe les objets nécessaires au framework. |
56,6 → 58,8 |
Configuration.instance = instance; |
} |
private Executor nonInteractiveSQLExecutor; |
public abstract ShowAs getShowAs(); |
public abstract SQLBase getBase(); |
143,4 → 147,15 |
* Signal that this conf will not be used anymore. |
*/ |
public abstract void destroy(); |
public Executor getNonInteractiveSQLExecutor() { |
if (nonInteractiveSQLExecutor == null) { |
nonInteractiveSQLExecutor = createNonInteractiveSQLExecutor(); |
} |
return nonInteractiveSQLExecutor; |
} |
protected Executor createNonInteractiveSQLExecutor() { |
return Executors.newFixedThreadPool(2); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java |
---|
60,7 → 60,6 |
import java.awt.BorderLayout; |
import java.awt.Color; |
import java.awt.Component; |
import java.awt.Container; |
import java.awt.Dimension; |
import java.awt.Rectangle; |
import java.awt.event.MouseAdapter; |
355,13 → 354,8 |
if (spec.isAdditional()) { |
if (this.additionalFieldsPanel == null) |
Log.get().warning("No additionalFieldsPanel for " + v.getField() + " : " + v); |
else { |
final Container component = this.additionalFieldsPanel.getComponent(); |
if (!component.isVisible()) { |
component.setVisible(true); |
} |
else |
this.additionalFieldsPanel.add(getDesc(v), v.getComp()); |
} |
} else { |
this.addToUI(v, spec.getWhere()); |
} |
438,7 → 432,6 |
} |
protected final void setAdditionalFieldsPanel(FormLayouter panel) { |
panel.getComponent().setVisible(false); |
this.additionalFieldsPanel = panel; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/RowBacked.java |
---|
137,8 → 137,8 |
return this.r; |
} |
protected final SQLRow getSQLRow() { |
return (SQLRow) this.getRow(); |
public final SQLRow getSQLRow() { |
return this.getRow().asRow(); |
} |
public final int getID() { |
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ReOrder.java |
---|
13,8 → 13,10 |
package org.openconcerto.sql.utils; |
import org.openconcerto.sql.model.ConnectionHandlerNoSetup; |
import org.openconcerto.sql.model.FieldRef; |
import org.openconcerto.sql.model.SQLBase; |
import org.openconcerto.sql.model.SQLDataSource; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLSyntax; |
22,7 → 24,6 |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.request.UpdateBuilder; |
import org.openconcerto.sql.utils.SQLUtils.SQLFactory; |
import java.math.BigDecimal; |
import java.sql.Connection; |
102,12 → 103,12 |
// MAYBE return affected IDs |
public final void exec() throws SQLException { |
final Connection conn = this.t.getBase().getDataSource().getConnection(); |
final UpdateBuilder updateUndef = new UpdateBuilder(this.t).set(this.t.getOrderField().getName(), MIN_ORDER.toPlainString()); |
updateUndef.setWhere(new Where(this.t.getKey(), "=", this.t.getUndefinedID())); |
SQLUtils.executeAtomic(conn, new SQLFactory<Object>() { |
SQLUtils.executeAtomic(this.t.getBase().getDataSource(), new ConnectionHandlerNoSetup<Object, SQLException>() { |
@Override |
public Object create() throws SQLException { |
public Object handle(SQLDataSource ds) throws SQLException, SQLException { |
final Connection conn = ds.getConnection(); |
final Statement stmt = conn.createStatement(); |
if (isAll()) { |
// reorder all, undef must be at 0 |
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/BackupPanel.java |
---|
308,7 → 308,6 |
// FIXME Close Connection |
try { |
Configuration.getInstance().getBase().getDataSource().closeConnection(); |
Configuration.getInstance().getBase().getDataSource().close(); |
} catch (SQLException e) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLServer.java |
---|
16,6 → 16,7 |
*/ |
package org.openconcerto.sql.model; |
import org.openconcerto.sql.model.LoadingListener.StructureLoadingEvent; |
import org.openconcerto.sql.utils.SQL_URL; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.cc.CopyOnWriteMap; |
23,6 → 24,7 |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.utils.change.CollectionChangeEventCreator; |
import java.sql.Connection; |
import java.sql.SQLException; |
import java.util.ArrayList; |
import java.util.Collection; |
206,15 → 208,23 |
if (this.getDS() != null) { |
// for mysql we must know our children, since they can reference each other and thus the |
// graph needs them |
final StructureLoadingEvent evt = new StructureLoadingEvent(this, namesToRefresh); |
try { |
this.getDBSystemRoot().fireLoading(evt); |
synchronized (this.getTreeMutex()) { |
final Set<String> childrenToRefresh = CollectionUtils.inter(namesToRefresh, this.getChildrenNames()); |
// don't save the result in files since getCatalogs() is at least as quick as |
// executing a request to check if the cache is obsolete |
final Set<String> allCats; |
final Connection conn = this.getDS().getNewConnection(); |
try { |
@SuppressWarnings("unchecked") |
final List<String> allCats = (List<String>) SQLDataSource.COLUMN_LIST_HANDLER.handle(this.getDS().getConnection().getMetaData().getCatalogs()); |
this.getDS().returnConnection(); |
final Set<String> cats = CollectionUtils.inter(namesToRefresh, new HashSet<String>(allCats)); |
final List<String> allCatsList = (List<String>) SQLDataSource.COLUMN_LIST_HANDLER.handle(conn.getMetaData().getCatalogs()); |
allCats = new HashSet<String>(allCatsList); |
} finally { |
this.getDS().returnConnection(conn); |
} |
final Set<String> cats = CollectionUtils.inter(namesToRefresh, allCats); |
this.getDBSystemRoot().filterNodes(this, cats); |
SQLBase.mustContain(this, cats, childrenToRefresh, "bases"); |
255,6 → 265,8 |
} |
} catch (SQLException e) { |
throw new IllegalStateException("could not get children names", e); |
} finally { |
this.getDBSystemRoot().fireLoading(evt.createFinishingEvent()); |
} |
} else if (!init) { |
throw new IllegalArgumentException("Cannot create bases since this server cannot have a connection"); |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxPG.java |
---|
292,10 → 292,20 |
// you can't specify line separator to pg, so use STDOUT as it always use \n |
try { |
final String sql = "COPY (" + selectAll(t).asString() + ") to STDOUT " + getDataOptions(t.getBase()) + " FORCE QUOTE " + cols + " ;"; |
final Connection conn = ((DelegatingConnection) t.getBase().getDataSource().getConnection()).getInnermostDelegate(); |
final FileOutputStream out = new FileOutputStream(f); |
((PGConnection) conn).getCopyAPI().copyOut(sql, out); |
t.getDBSystemRoot().getDataSource().useConnection(new ConnectionHandlerNoSetup<Number, IOException>() { |
@Override |
public Number handle(SQLDataSource ds) throws SQLException, IOException { |
final Connection conn = ((DelegatingConnection) ds.getConnection()).getInnermostDelegate(); |
FileOutputStream out = null; |
try { |
out = new FileOutputStream(f); |
return ((PGConnection) conn).getCopyAPI().copyOut(sql, out); |
} finally { |
if (out != null) |
out.close(); |
} |
} |
}); |
} catch (Exception e) { |
throw new IllegalStateException("unable to store " + t + " into " + f, e); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLDataSource.java |
---|
154,9 → 154,6 |
private static int count = 0; // compteur de requetes |
private final SQLServer server; |
// une connexion par thread |
@GuardedBy("this") |
private final Map<Thread, Connection> connections; |
// no need to synchronize multiple call to this attribute since we only access the |
// Thread.currentThread() key |
@GuardedBy("handlers") |
165,9 → 162,6 |
@GuardedBy("this") |
private ExecutorService exec = null; |
@GuardedBy("this") |
private CleanUp cleanUp; |
// linked to initialSchema and uptodate |
@GuardedBy("this") |
private boolean initialShemaSet; |
178,6 → 172,8 |
private final Map<Connection, Object> uptodate; |
private volatile int retryWait; |
@GuardedBy("this") |
private boolean blockWhenExhausted; |
private final ReentrantLock testLock = new ReentrantLock(); |
269,13 → 265,11 |
/* pour le clonage */ |
private SQLDataSource(SQLServer server) { |
this.server = server; |
this.connections = new HashMap<Thread, Connection>(); |
// on a besoin d'une implementation synchronisée |
this.handlers = new Hashtable<Thread, HandlersStack>(); |
// weak, since this is only a hint to avoid initializing the connection |
// on each borrowal |
this.uptodate = new WeakHashMap<Connection, Object>(); |
this.cleanUp = null; |
this.initialShemaSet = false; |
this.initialShema = null; |
289,6 → 283,7 |
this.setMinIdle(2); |
// but not too much as it can lock out other users (the server has a max connection count) |
this.setMaxIdle(16); |
this.setBlockWhenExhausted(false); |
// see #createDataSource() for properties not supported by this class |
this.tables = Collections.emptySet(); |
this.cache = null; |
445,6 → 440,7 |
try { |
info = new QueryInfo(query, changeState, passedConn); |
try { |
long tStartSQL = System.nanoTime(); |
final Object[] res = this.executeTwice(info); |
final Statement stmt = (Statement) res[0]; |
ResultSet rs = (ResultSet) res[1]; |
457,7 → 453,7 |
// } |
// }); |
// and OK won't be returned if "req" returns a null rs. |
durationSQL = System.nanoTime() - time; |
durationSQL = System.nanoTime() - tStartSQL; |
if (rsh != null && rs != null) { |
if (this.getSystem() == SQLSystem.DERBY || this.getSystem() == SQLSystem.POSTGRESQL) { |
rs = new SQLResultSet(rs); |
948,18 → 944,7 |
// super close and unset our pool, but we need to keep it |
// to allow used connections to be closed, see #closeConnection(Connection) |
this.connectionPool = pool; |
// cleanUp will be recreated if necessary |
final CleanUp toStop = this.cleanUp; |
this.cleanUp = null; |
// happens if the datasource was never used |
if (toStop != null) |
toStop.interrupt(); |
// since we're stopping cleanUp we have to close connections |
// if you don't want your connections to close at any time: #useConnection() |
for (final Connection conn : this.connections.values()) { |
this.closeConnection(conn); |
} |
this.connections.clear(); |
// interrupt to force waiting threads to close their connections |
if (this.exec != null) { |
this.exec.shutdownNow(); |
985,79 → 970,32 |
} |
/** |
* Invalide la connection actuelle. |
* Retourne la connection à cette source de donnée. |
* |
* @return la connection à cette source de donnée. |
* @throws IllegalStateException if not called from within useConnection(). |
* @see #useConnection(ConnectionHandler) |
*/ |
public void closeConnection() { |
this.releaseConnection(Thread.currentThread(), true); |
public final Connection getConnection() { |
final HandlersStack res = this.handlers.get(Thread.currentThread()); |
if (res == null) |
throw new IllegalStateException("useConnection() wasn't called"); |
return res.getConnection(); |
} |
/** |
* Retourne la connexion actuelle dans le pool des connexions libres. Attention à partir de ce |
* moment cette connexion peut être utilisée par d'autres. |
*/ |
public void returnConnection() { |
this.releaseConnection(Thread.currentThread(), false); |
} |
// remove the connection for the passed thread, the calling method must |
// then return or close it otherwise it will stay borrowed. |
protected synchronized Connection rmConnection(Thread th) { |
return this.connections.remove(th); |
} |
public synchronized void releaseConnection(Thread th, final boolean close) { |
if (this.handlers.containsKey(th)) { |
if (close) |
throw new IllegalArgumentException("cannot close the connection, it is in use by " + this.handlers.get(th)); |
// else nothing it will be released by useConnection(). |
Log.get().fine("ignoring " + close + " for " + th); |
} else if (this.connections.containsKey(th)) { |
if (close) |
this.closeConnection(this.rmConnection(th)); |
else |
this.returnConnection(this.rmConnection(th)); |
} |
} |
protected synchronized boolean isInCharge(final CleanUp cleanUp) { |
return this.cleanUp == cleanUp; |
} |
final Set<Thread> getThreads(final Set<Thread> threads) { |
threads.clear(); |
synchronized (this) { |
threads.addAll(this.connections.keySet()); |
} |
return threads; |
} |
/** |
* Retourne une connection à cette source de donnée. Si la connexion échoue cette méthode va |
* réessayer quelques secondes plus tard. |
* Retourne une connection à cette source de donnée (generally |
* {@link #useConnection(ConnectionHandler)} should be used). Si la connexion échoue cette |
* méthode va réessayer quelques secondes plus tard. |
* <p> |
* Note : il y a une connexion par thread donc attention a ne pas créer d'instance de Thread a |
* la pelle. |
* Note : you <b>must</b> return this connection (e.g. use try/finally). |
* <p> |
* |
* @return une connection à cette source de donnée. |
* @see #returnConnection(Connection) |
* @see #closeConnection(Connection) |
*/ |
public Connection getConnection() { |
return this.getConnection(Thread.currentThread()); |
} |
private synchronized Connection getConnection(Thread th) { |
if (this.handlers.containsKey(th)) { |
return this.handlers.get(th).getConnection(); |
} |
Connection res = this.connections.get(th); |
if (res == null) { |
res = this.getNewConnection(); |
this.connections.put(th, res); |
} |
return res; |
} |
private final Connection getNewConnection() { |
protected final Connection getNewConnection() { |
try { |
return this.borrowConnection(false); |
} catch (RTInterruptedException e) { |
1122,6 → 1060,7 |
private static final String pgInterrupted = GT.tr("Interrupted while attempting to connect."); |
private Connection getRawConnection() { |
assert !Thread.holdsLock(this) : "super.getConnection() might block (see setWhenExhaustedAction()), and since return/closeConnection() need this lock, this method cannot wait while holding the lock"; |
Connection result = null; |
try { |
result = super.getConnection(); |
1153,10 → 1092,17 |
return this.connectionPool.getNumActive(); |
} |
public synchronized final Set<Thread> getThreadsWithConnection() { |
return this.connections.keySet(); |
public synchronized boolean blocksWhenExhausted() { |
return this.blockWhenExhausted; |
} |
public synchronized void setBlockWhenExhausted(boolean block) { |
this.blockWhenExhausted = block; |
if (this.connectionPool != null) { |
this.connectionPool.setWhenExhaustedAction(block ? GenericObjectPool.WHEN_EXHAUSTED_BLOCK : GenericObjectPool.WHEN_EXHAUSTED_GROW); |
} |
} |
@Override |
protected synchronized DataSource createDataSource() throws SQLException { |
if (isClosed()) { |
1163,9 → 1109,7 |
// initialize lotta things |
super.createDataSource(); |
this.connectionPool.setLifo(true); |
// don't block (threads block while owning SQLDataSource lock, thus preventing others |
// from releasing connections) |
this.connectionPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW); |
this.setBlockWhenExhausted(this.blockWhenExhausted); |
// after 40s idle connections are closed |
this.connectionPool.setTimeBetweenEvictionRunsMillis(4000); |
this.connectionPool.setNumTestsPerEvictionRun(5); |
1195,7 → 1139,6 |
throw new UnsupportedOperationException(); |
} |
}; |
this.cleanUp = new CleanUp(15000); |
} |
return this.dataSource; |
} |
1277,10 → 1220,12 |
final Connection newConn = this.getNewConnection(); |
try { |
this.setSchema(schemaName, newConn); |
} finally { |
} catch (RuntimeException e) { |
this.closeConnection(newConn); |
throw e; |
} |
this.setInitialSchema(true, schemaName); |
this.returnConnection(newConn); |
} else if (this.server.getSQLSystem().isDBPathEmpty()) { |
this.unsetInitialSchema(); |
} else |
1399,40 → 1344,4 |
ds.setDriverClassName(this.getDriverClassName()); |
return ds; |
} |
/** |
* This thread periodically check for dead borrowers and return their connection. |
*/ |
final private class CleanUp extends Thread { |
private final int period; |
public CleanUp(final int period) { |
super("Clean up for " + SQLDataSource.this); |
this.period = period; |
this.setDaemon(true); |
this.start(); |
} |
public void run() { |
final Set<Thread> threads = new HashSet<Thread>(); |
while (SQLDataSource.this.isInCharge(this)) { |
for (final Thread th : getThreads(threads)) { |
// a thread cannot re-live, so it's safe to return its connection |
// likewise it's ok if it has already returned its connection |
// (on its own, or even by another CleanUp instance) |
if (!th.isAlive()) { |
SQLDataSource.this.releaseConnection(th, false); |
} |
} |
try { |
Thread.sleep(this.period); |
} catch (InterruptedException e) { |
// ignore, ne s'arrêter que lorsque le while le dit |
Log.get().fine("Interruption ignored for " + this); |
} |
} |
Log.get().fine("done " + this); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowListRSH.java |
---|
24,6 → 24,37 |
public final class SQLRowListRSH implements ResultSetHandler { |
// hashCode()/equals() needed for data source cache |
private static final class RSH implements ResultSetHandler { |
private final Tuple2<SQLTable, List<String>> names; |
private RSH(Tuple2<SQLTable, List<String>> names) { |
this.names = names; |
} |
@Override |
public List<SQLRow> handle(ResultSet rs) throws SQLException { |
return SQLRow.createListFromRS(this.names.get0(), rs, this.names.get1()); |
} |
@Override |
public int hashCode() { |
return this.names.hashCode(); |
} |
@Override |
public boolean equals(Object obj) { |
if (this == obj) |
return true; |
if (obj == null) |
return false; |
if (getClass() != obj.getClass()) |
return false; |
final RSH other = (RSH) obj; |
return this.names.equals(other.names); |
} |
} |
private static Tuple2<SQLTable, List<String>> getIndexes(SQLSelect sel, final SQLTable passedTable, final boolean findTable) { |
final List<SQLField> selectFields = sel.getSelectFields(); |
final int size = selectFields.size(); |
80,13 → 111,8 |
} |
static private ResultSetHandler create(final Tuple2<SQLTable, List<String>> names) { |
return new ResultSetHandler() { |
@Override |
public Object handle(ResultSet rs) throws SQLException { |
return SQLRow.createListFromRS(names.get0(), rs, names.get1()); |
return new RSH(names); |
} |
}; |
} |
@SuppressWarnings("unchecked") |
static public List<SQLRow> execute(final SQLSelect sel) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/graph/Path.java |
---|
288,6 → 288,10 |
return this.add(item.getLabel()); |
} |
public final List<Step> getSteps() { |
return Collections.unmodifiableList(this.fields); |
} |
/** |
* The step connecting the table i to i+1. |
* |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBSystemRoot.java |
---|
14,6 → 14,9 |
package org.openconcerto.sql.model; |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.model.LoadingListener.GraphLoadingEvent; |
import org.openconcerto.sql.model.LoadingListener.LoadingChangeSupport; |
import org.openconcerto.sql.model.LoadingListener.LoadingEvent; |
import org.openconcerto.sql.model.graph.DatabaseGraph; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.cc.IClosure; |
65,6 → 68,8 |
private boolean incoherentPath; |
private final PropertyChangeListener coherenceListener; |
private final LoadingChangeSupport loadingListenersSupp; |
DBSystemRoot(DBStructureItemJDBC delegate) { |
super(delegate); |
this.graph = null; |
80,6 → 85,7 |
rootsChanged(evt); |
} |
}; |
this.loadingListenersSupp = new LoadingChangeSupport(this); |
this.getServer().init(this); |
} |
240,12 → 246,16 |
synchronized (this.getTreeMutex()) { |
synchronized (this.graphMutex) { |
if (this.graph == null) { |
final LoadingEvent evt = new GraphLoadingEvent(this); |
try { |
fireLoading(evt); |
// keep new DatabaseGraph() inside the synchronized to prevent two |
// concurrent expensive creations |
this.setGraph(new DatabaseGraph(this)); |
} catch (SQLException e) { |
throw new IllegalStateException("could not graph " + this, e); |
} finally { |
fireLoading(evt.createFinishingEvent()); |
} |
} |
return this.graph; |
307,6 → 317,23 |
} |
/** |
* Adds a listener for this and its children. |
* |
* @param l the listener. |
*/ |
public final void addLoadingListener(LoadingListener l) { |
this.loadingListenersSupp.addLoadingListener(l); |
} |
final void fireLoading(LoadingEvent evt) { |
this.loadingListenersSupp.fireLoading(evt); |
} |
public final void removeLoadingListener(LoadingListener l) { |
this.loadingListenersSupp.removeLoadingListener(l); |
} |
/** |
* Add the passed roots to {@link #getRootsToMap()} and to root path and {@link #reload(Set)}. |
* |
* @param roots the roots names to add. |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java |
---|
173,8 → 173,9 |
private Set<Constraint> constraints; |
// always immutable so that fire can iterate safely ; to modify it, simply copy it before |
// (adding listeners is a lot less common than firing events) |
@GuardedBy("this") |
@GuardedBy("listenersMutex") |
private List<SQLTableModifiedListener> tableModifiedListeners; |
private final Object listenersMutex = new String("tableModifiedListeners mutex"); |
// the id that foreign keys pointing to this, can use instead of NULL |
// a null value meaning not yet known |
@GuardedBy("this") |
395,13 → 396,17 |
} |
// must be called in setState() after fields have been set (for isRowable()) |
synchronized private int fetchUndefID() { |
private int fetchUndefID() { |
final int res; |
if (isRowable()) { |
final SQLField pk; |
synchronized (this) { |
pk = isRowable() ? this.getKey() : null; |
} |
if (pk != null) { |
final Tuple2<Boolean, Number> currentValue = getUndefID(this.getSchema(), this.getName()); |
if (!currentValue.get0()) { |
// no row |
res = this.findMinID(); |
res = this.findMinID(pk); |
} else { |
// a row |
final Number id = currentValue.get1(); |
413,7 → 418,7 |
} |
// no undef id found |
synchronized private int findMinID() { |
private int findMinID(SQLField pk) { |
final String debugUndef = "fwk_sql.debug.undefined_id"; |
if (System.getProperty(debugUndef) != null) |
Log.get().warning("The system property '" + debugUndef + "' is deprecated, use the '" + UNDEFINED_ID_POLICY + "' metadata"); |
420,7 → 425,7 |
final String policy = getSchema().getFwkMetadata(UNDEFINED_ID_POLICY); |
if (Boolean.getBoolean(debugUndef) || "min".equals(policy)) { |
final SQLSelect sel = new SQLSelect(this.getBase(), true).addSelect(this.getKey(), "min"); |
final SQLSelect sel = new SQLSelect(this.getBase(), true).addSelect(pk, "min"); |
final Number undef = (Number) this.getBase().getDataSource().executeScalar(sel.asString()); |
if (undef == null) { |
// empty table |
983,6 → 988,10 |
* @return the empty id or {@link SQLRow#NONEXISTANT_ID} if this table has no UNDEFINED_ID. |
*/ |
public final int getUndefinedID() { |
return this.getUndefinedID(false).intValue(); |
} |
private final Integer getUndefinedID(final boolean internal) { |
Integer res = null; |
synchronized (this) { |
if (this.undefinedID != null) |
989,16 → 998,14 |
res = this.undefinedID; |
} |
if (res == null) { |
if (this.getSchema().isFetchAllUndefinedIDs()) { |
if (!internal && this.getSchema().isFetchAllUndefinedIDs()) { |
// init all undefined, MAYBE one request with UNION ALL |
for (final SQLTable sibling : this.getSchema().getTables()) { |
synchronized (sibling) { |
if (sibling.undefinedID == null) |
sibling.undefinedID = sibling.fetchUndefID(); |
Integer siblingRes = getUndefinedID(true); |
assert siblingRes != null; |
if (sibling == this) |
res = sibling.undefinedID; |
res = siblingRes; |
} |
} |
// save all tables |
this.getBase().save(this.getSchema().getName()); |
} else { |
1006,10 → 1013,11 |
synchronized (this) { |
this.undefinedID = res; |
} |
if (!internal) |
this.save(); |
} |
} |
return res.intValue(); |
return res; |
} |
public final Number getUndefinedIDNumber() { |
1046,7 → 1054,7 |
} |
private void addTableModifiedListener(SQLTableModifiedListener l, final boolean before) { |
synchronized (this) { |
synchronized (this.listenersMutex) { |
final List<SQLTableModifiedListener> newListeners = new ArrayList<SQLTableModifiedListener>(this.tableModifiedListeners.size() + 1); |
if (before) |
newListeners.add(l); |
1058,7 → 1066,7 |
} |
public void removeTableModifiedListener(SQLTableModifiedListener l) { |
synchronized (this) { |
synchronized (this.listenersMutex) { |
final List<SQLTableModifiedListener> newListeners = new ArrayList<SQLTableModifiedListener>(this.tableModifiedListeners); |
if (newListeners.remove(l)) |
this.tableModifiedListeners = Collections.unmodifiableList(newListeners); |
1169,7 → 1177,7 |
private void fireTableModified(final SQLTableEvent evt) { |
// no need to copy since this.tableModifiedListeners is immutable |
final List<SQLTableModifiedListener> dispatchingListeners; |
synchronized (this) { |
synchronized (this.listenersMutex) { |
dispatchingListeners = this.tableModifiedListeners; |
} |
fireTableModified(Tuple2.create(dispatchingListeners.iterator(), evt)); |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/LoadingListener.java |
---|
New file |
0,0 → 1,130 |
/* |
* 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.util.ArrayList; |
import java.util.List; |
import java.util.Set; |
import net.jcip.annotations.ThreadSafe; |
/** |
* The listener interface for receiving loading events. |
*/ |
public interface LoadingListener { |
static public abstract class LoadingEvent { |
private final DBStructureItem<?> source; |
private final boolean starting; |
public LoadingEvent(final DBStructureItem<?> source) { |
this(source, true); |
} |
protected LoadingEvent(final DBStructureItem<?> source, boolean starting) { |
super(); |
this.source = source; |
this.starting = starting; |
} |
public final DBStructureItem<?> getSource() { |
return this.source; |
} |
public final boolean isStarting() { |
return this.starting; |
} |
public abstract LoadingEvent createFinishingEvent(); |
} |
static public class GraphLoadingEvent extends LoadingEvent { |
public GraphLoadingEvent(DBSystemRoot source) { |
super(source); |
} |
protected GraphLoadingEvent(DBSystemRoot source, boolean starting) { |
super(source, starting); |
} |
@Override |
public GraphLoadingEvent createFinishingEvent() { |
return new GraphLoadingEvent((DBSystemRoot) getSource(), false); |
} |
@Override |
public String toString() { |
return this.getClass().getSimpleName() + (this.isStarting() ? " starting" : " finishing") + " loading of " + this.getSource(); |
} |
} |
static public class StructureLoadingEvent extends LoadingEvent { |
private final Set<String> children; |
public StructureLoadingEvent(final DBStructureItemJDBC source, Set<String> children) { |
this(source, true, children); |
} |
protected StructureLoadingEvent(final DBStructureItemJDBC source, boolean starting, Set<String> children) { |
super(source, starting); |
this.children = children; |
} |
public final Set<String> getChildren() { |
return this.children; |
} |
@Override |
public final StructureLoadingEvent createFinishingEvent() { |
if (!this.isStarting()) |
throw new IllegalStateException("Already a finishing event"); |
return new StructureLoadingEvent((DBStructureItemJDBC) this.getSource(), false, this.children); |
} |
@Override |
public String toString() { |
final String children = this.getChildren() == null ? "all children" : this.getChildren().toString(); |
return this.getClass().getSimpleName() + (this.isStarting() ? " starting" : " finishing") + " loading " + children + " of " + this.getSource(); |
} |
} |
@ThreadSafe |
static public class LoadingChangeSupport { |
private final DBSystemRoot source; |
private final List<LoadingListener> loadingListeners; |
public LoadingChangeSupport(DBSystemRoot source) { |
this.source = source; |
this.loadingListeners = new ArrayList<LoadingListener>(4); |
} |
public synchronized final void addLoadingListener(LoadingListener l) { |
this.loadingListeners.add(l); |
} |
public synchronized final void removeLoadingListener(LoadingListener l) { |
this.loadingListeners.remove(l); |
} |
public synchronized void fireLoading(LoadingEvent evt) { |
assert evt.getSource().getDBSystemRoot() == this.source; |
for (final LoadingListener l : this.loadingListeners) { |
l.loading(evt); |
} |
} |
} |
void loading(LoadingEvent evt); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBStructureItem.java |
---|
125,6 → 125,10 |
public abstract void rmChildrenListener(final PropertyChangeListener l); |
public final D getSibling(String name) { |
return this.getParent().getChild(name); |
} |
// ** far |
public final D getDescendant(SQLName name) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBase.java |
---|
17,6 → 17,8 |
package org.openconcerto.sql.model; |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.model.LoadingListener.LoadingEvent; |
import org.openconcerto.sql.model.LoadingListener.StructureLoadingEvent; |
import org.openconcerto.sql.model.StructureSource.PrechangeException; |
import org.openconcerto.sql.model.graph.DatabaseGraph; |
import org.openconcerto.utils.CollectionUtils; |
199,8 → 201,15 |
} |
private JDBCStructureSource fetchTablesP(Set<String> childrenNames, Map<String, SQLSchema> newStruct) throws SQLException { |
final LoadingEvent evt = new StructureLoadingEvent(this, childrenNames); |
final DBSystemRoot sysRoot = this.getDBSystemRoot(); |
try { |
sysRoot.fireLoading(evt); |
return this.refreshTables(new JDBCStructureSource(this, childrenNames, newStruct)); |
} finally { |
sysRoot.fireLoading(evt.createFinishingEvent()); |
} |
} |
public final Set<String> loadTables() throws SQLException { |
return this.loadTables(null); |
/trunk/OpenConcerto/src/org/openconcerto/sql/users/UserManager.java |
---|
70,7 → 70,7 |
fetcher.setOrdered(true); |
for (final SQLRowValues v : fetcher.fetch()) { |
final User u = new User(v.getID(), v.getString("NOM")); |
u.setLastName(v.getString("PRENOM")); |
u.setFirstName(v.getString("PRENOM")); |
u.setNickName(v.getString("SURNOM")); |
this.byID.put(v.getID(), u); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/users/User.java |
---|
17,7 → 17,7 |
public class User { |
private final int id; |
private String name, lastName, nickName; |
private String name, firstName, nickName; |
private final UserRights userRights; |
public User(int id, String name) { |
43,8 → 43,8 |
return this.getFullName() + " /" + getId(); |
} |
public void setLastName(String string) { |
this.lastName = string; |
public void setFirstName(String string) { |
this.firstName = string; |
} |
public void setNickName(String string) { |
51,8 → 51,8 |
this.nickName = string; |
} |
public String getLastName() { |
return this.lastName; |
public String getFirstName() { |
return this.firstName; |
} |
public String getNickName() { |
60,7 → 60,7 |
} |
public String getFullName() { |
return getLastName() + " " + getName(); |
return getFirstName() + " " + getName(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/MoveQueue.java |
---|
20,8 → 20,8 |
import org.openconcerto.utils.SleepingQueue; |
import java.sql.SQLException; |
import java.util.concurrent.CountDownLatch; |
import java.util.concurrent.atomic.AtomicReference; |
import java.util.concurrent.Callable; |
import java.util.concurrent.FutureTask; |
final class MoveQueue extends SleepingQueue { |
35,27 → 35,21 |
public void move(final int id, final int inc) { |
this.put(new Runnable() { |
public void run() { |
final AtomicReference<Integer> destID = new AtomicReference<Integer>(); |
final CountDownLatch latch = new CountDownLatch(1); |
MoveQueue.this.tableModel.invokeLater(new Runnable() { |
public void run() { |
destID.set(MoveQueue.this.tableModel.getDestID(id, inc)); |
latch.countDown(); |
final FutureTask<Integer> destID = new FutureTask<Integer>(new Callable<Integer>() { |
@Override |
public Integer call() { |
return MoveQueue.this.tableModel.getDestID(id, inc); |
} |
}); |
MoveQueue.this.tableModel.invokeLater(destID); |
try { |
latch.await(); |
} catch (InterruptedException e) { |
throw ExceptionUtils.createExn(IllegalStateException.class, "move failed", e); |
} |
if (destID.get() != null) { |
try { |
moveQuick(id, destID.get()); |
} catch (SQLException e) { |
} |
} catch (Exception e) { |
throw ExceptionUtils.createExn(IllegalStateException.class, "move failed", e); |
} |
} |
} |
}); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/KeyTableCellRenderer.java |
---|
13,6 → 13,7 |
package org.openconcerto.sql.view.list; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLTableEvent; |
86,7 → 87,7 |
private void loadCacheAsynchronous() { |
this.isLoading = true; |
final Thread thread = new Thread(new Runnable() { |
Configuration.getInstance().getNonInteractiveSQLExecutor().execute(new Runnable() { |
public void run() { |
List<IComboSelectionItem> items = KeyTableCellRenderer.this.el.getComboRequest().getComboItems(); |
final Map<Integer, IComboSelectionItem> m = new HashMap<Integer, IComboSelectionItem>(); |
111,6 → 112,6 |
} |
} |
}); |
thread.start(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java |
---|
134,7 → 134,7 |
* |
* @author ILM Informatique |
*/ |
public final class IListe extends JPanel implements AncestorListener { |
public final class IListe extends JPanel { |
static private final class FormatRenderer extends DefaultTableCellRenderer { |
private final Format fmt; |
644,7 → 644,27 |
for (final Map.Entry<Class<?>, FormatGroup> e : this.getFormats().entrySet()) |
this.jTable.setDefaultEditor(e.getKey(), new FormatEditor(e.getValue())); |
this.sorter.setTableHeader(this.jTable.getTableHeader()); |
this.addAncestorListener(this); |
this.addAncestorListener(new AncestorListener() { |
// these callbacks are called later than the change, and by that time the visibility |
// might have changed several times thus use isVisible() to avoid flip-flopping for |
// nothing |
@Override |
public void ancestorRemoved(AncestorEvent event) { |
visibilityChanged(); |
} |
@Override |
public void ancestorAdded(AncestorEvent event) { |
visibilityChanged(); |
} |
@Override |
public void ancestorMoved(AncestorEvent event) { |
// nothing to do |
} |
}); |
// we used to rm this listener, possibly to avoid events once dead, but this doesn't seem |
// necessary anymore |
this.jTable.getSelectionModel().addListSelectionListener(this.selectionListener); |
1003,32 → 1023,14 |
getModel().rmPropertyChangeListener(l); |
} |
// *** Ancestors ***// |
@Override |
public void ancestorAdded(AncestorEvent event) { |
// there was an if added in r989, but from the javadoc it isn't needed |
assert event.getAncestor().isVisible(); |
// ancestorAdded means we've just been added to a visible hierarchy, not that we were added |
// to our parent |
this.getModel().setSleeping(false); |
} |
@Override |
public void ancestorRemoved(AncestorEvent event) { |
protected final void visibilityChanged() { |
// test isDead() since in JComponent.removeNotify() first setDisplayable(false) (in super) |
// then firePropertyChange("ancestor", null). |
// thus we can still be visible while not displayable anymore |
assert !event.getAncestor().isVisible() || !event.getAncestor().isDisplayable(); |
if (!this.isDead()) |
this.getModel().setSleeping(true); |
this.getModel().setSleeping(!this.isVisible()); |
} |
@Override |
public void ancestorMoved(AncestorEvent event) { |
// nothing to do |
} |
public void setSQLEditable(boolean b) { |
this.getModel().setEditable(b); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/PropsConfiguration.java |
---|
381,6 → 381,7 |
@Override |
public void executeChecked(final DBSystemRoot input) { |
input.getRootsToMap().addAll(getRootsToMap()); |
initSystemRoot(input); |
} |
}, new IClosure<SQLDataSource>() { |
@Override |
476,6 → 477,10 |
return res; |
} |
// called at the end of the DBSystemRoot constructor (before having a data source) |
protected void initSystemRoot(DBSystemRoot input) { |
} |
protected void initDS(final SQLDataSource ds) { |
ds.setCacheEnabled(true); |
propIterate(new IClosure<String>() { |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/ConnexionPanel.java |
---|
17,6 → 17,7 |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.preferences.UserProps; |
import org.openconcerto.sql.request.ComboSQLRequest; |
import org.openconcerto.sql.sqlobject.IComboModel; |
import org.openconcerto.sql.sqlobject.IComboSelectionItem; |
import org.openconcerto.sql.sqlobject.SQLRequestComboBox; |
68,7 → 69,8 |
if (Boolean.getBoolean(QUICK_LOGIN) && lastLogin.length() > 0 && pass != null && (!societeSelector || UserProps.getInstance().getLastSocieteID() >= SQLRow.MIN_VALID_ID)) { |
final Tuple2<String, String> res = new Login(Configuration.getInstance().getRoot()).connectEnc(lastLogin, pass); |
if (res.get0() == null) { |
r.run(); |
// ConnexionPanel normally executes r outside of the EDT, do the same |
execute(r); |
// no need to display a panel |
return true; |
} |
226,7 → 228,10 |
} |
this.comboSociete = new SQLRequestComboBox(false, 25); |
final IComboModel model = new IComboModel(Configuration.getInstance().getDirectory().getElement(tableSociete).getComboRequest()); |
final ComboSQLRequest req = Configuration.getInstance().getDirectory().getElement(tableSociete).getComboRequest(true); |
// keep rows for checkValidity() |
req.keepRows(true); |
final IComboModel model = new IComboModel(req); |
final int lastSociete = UserProps.getInstance().getLastSocieteID(); |
if (lastSociete >= SQLRow.MIN_VALID_ID) { |
model.setValue(lastSociete); |
280,7 → 285,7 |
panelButton.add(this.reloadPanel, c2); |
c2.gridx++; |
c2.weightx = 0; |
buttonConnect.setOpaque(false); |
this.buttonConnect.setOpaque(false); |
panelButton.add(this.buttonConnect, c2); |
c.gridy++; |
325,12 → 330,15 |
setConnecting(true); |
final Thread t = new Thread(new Runnable() { |
execute(new Runnable() { |
public void run() { |
connect(); |
} |
}); |
t.setName("ConnexionPanel Login"); |
} |
static private void execute(Runnable runnable) { |
final Thread t = new Thread(runnable, "ConnexionPanel Login"); |
t.setPriority(Thread.MIN_PRIORITY); |
t.start(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextWithCompletion.java |
---|
21,6 → 21,7 |
import org.openconcerto.sql.request.ComboSQLRequest; |
import org.openconcerto.ui.component.text.TextComponent; |
import org.openconcerto.utils.OrderedSet; |
import org.openconcerto.utils.SwingWorker2; |
import org.openconcerto.utils.checks.MutableValueObject; |
import org.openconcerto.utils.model.DefaultIMutableListModel; |
import org.openconcerto.utils.text.DocumentFilterList; |
50,7 → 51,6 |
import javax.swing.JTextArea; |
import javax.swing.JTextField; |
import javax.swing.SwingUtilities; |
import javax.swing.SwingWorker; |
import javax.swing.event.DocumentEvent; |
import javax.swing.event.DocumentListener; |
import javax.swing.text.AbstractDocument; |
258,7 → 258,7 |
synchronized (this) { |
this.isLoading = true; |
} |
final SwingWorker worker = new SwingWorker<Object, Object>() { |
final SwingWorker2<Object, Object> worker = new SwingWorker2<Object, Object>() { |
// Runs on the event-dispatching thread. |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/IComboModel.java |
---|
24,6 → 24,7 |
import org.openconcerto.sql.view.search.SearchSpecUtils; |
import org.openconcerto.ui.component.combo.Log; |
import org.openconcerto.utils.RTInterruptedException; |
import org.openconcerto.utils.SwingWorker2; |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.utils.checks.EmptyChangeSupport; |
import org.openconcerto.utils.checks.EmptyListener; |
42,7 → 43,6 |
import java.util.concurrent.ExecutionException; |
import javax.swing.SwingUtilities; |
import javax.swing.SwingWorker; |
import javax.swing.event.ListDataEvent; |
import javax.swing.event.ListDataListener; |
68,7 → 68,7 |
private final PropertyChangeSupport propSupp; |
// est ce que la combo va se remplir, access must be synchronized |
private SwingWorker<?, ?> willUpdate; |
private SwingWorker2<?, ?> willUpdate; |
protected final List<Runnable> runnables; |
// true from when the combo is filled with the sole "dots" item until it is loaded with actual |
// items, no need to synchronize (EDT) |
280,7 → 280,7 |
// copy the current search, if it changes fillCombo() will be called |
final SearchSpec search = this.getSearch(); |
// commencer l'update après, sinon modeToSelect == 0 |
final SwingWorker<List<IComboSelectionItem>, Object> worker = new SwingWorker<List<IComboSelectionItem>, Object>() { |
final SwingWorker2<List<IComboSelectionItem>, Object> worker = new SwingWorker2<List<IComboSelectionItem>, Object>() { |
@Override |
protected List<IComboSelectionItem> doInBackground() throws InterruptedException { |
663,7 → 663,7 |
return this.getSearch() != null && !this.getSearch().isEmpty(); |
} |
private synchronized void setWillUpdate(SwingWorker<?, ?> w) { |
private synchronized void setWillUpdate(SwingWorker2<?, ?> w) { |
this.willUpdate = w; |
this.propSupp.firePropertyChange("willUpdate", null, this.willUpdate); |
if (this.willUpdate == null) { |
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/ITransformer.java |
---|
13,8 → 13,9 |
package org.openconcerto.utils.cc; |
public interface ITransformer<E, T> { |
public interface ITransformer<E, T> extends ITransformerExn<E, T, RuntimeException> { |
@Override |
public abstract T transformChecked(E input); |
} |
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/ExnTransformer.java |
---|
26,7 → 26,7 |
* @param <T> return type |
* @param <X> exception type |
*/ |
public abstract class ExnTransformer<E, T, X extends Exception> implements Transformer { |
public abstract class ExnTransformer<E, T, X extends Exception> implements Transformer, ITransformerExn<E, T, X> { |
@SuppressWarnings("unchecked") |
public final Object transform(Object input) { |
92,6 → 92,7 |
} |
} |
@Override |
public abstract T transformChecked(E input) throws X; |
} |
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/ITransformerExn.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 ITransformerExn<E, T, X extends Exception> { |
public abstract T transformChecked(E input) throws X; |
} |
/trunk/OpenConcerto/src/org/openconcerto/utils/OSXAdapter.java |
---|
70,7 → 70,10 |
package org.openconcerto.utils; |
import java.lang.reflect.*; |
import java.lang.reflect.InvocationHandler; |
import java.lang.reflect.InvocationTargetException; |
import java.lang.reflect.Method; |
import java.lang.reflect.Proxy; |
public class OSXAdapter implements InvocationHandler { |
/trunk/OpenConcerto/src/org/openconcerto/utils/Messages.java |
---|
15,7 → 15,6 |
import java.util.Locale; |
import java.util.MissingResourceException; |
import java.util.ResourceBundle; |
/trunk/OpenConcerto/src/org/openconcerto/utils/html/HTMLManipulatorFrame.java |
---|
16,7 → 16,6 |
import java.awt.Dimension; |
import java.awt.GridBagConstraints; |
import java.awt.GridBagLayout; |
import java.awt.GridLayout; |
import java.awt.Insets; |
import java.awt.event.ActionEvent; |
import java.awt.event.ActionListener; |
/trunk/OpenConcerto/src/org/openconcerto/utils/SwingWorker2.java |
---|
New file |
0,0 → 1,808 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.utils; |
import java.awt.event.ActionEvent; |
import java.awt.event.ActionListener; |
import java.beans.PropertyChangeEvent; |
import java.beans.PropertyChangeListener; |
import java.beans.PropertyChangeSupport; |
import java.lang.ref.WeakReference; |
import java.security.AccessController; |
import java.security.PrivilegedAction; |
import java.util.List; |
import java.util.concurrent.Callable; |
import java.util.concurrent.ExecutionException; |
import java.util.concurrent.ExecutorService; |
import java.util.concurrent.Executors; |
import java.util.concurrent.FutureTask; |
import java.util.concurrent.LinkedBlockingQueue; |
import java.util.concurrent.RunnableFuture; |
import java.util.concurrent.ThreadPoolExecutor; |
import java.util.concurrent.TimeUnit; |
import java.util.concurrent.TimeoutException; |
import java.util.concurrent.ThreadFactory; |
import javax.swing.SwingUtilities; |
import javax.swing.Timer; |
import sun.awt.AppContext; |
import sun.swing.AccumulativeRunnable; |
/** |
* An abstract class to perform lengthy GUI-interacting tasks in a dedicated thread. |
* |
* <p> |
* When writing a multi-threaded application using Swing, there are two constraints to keep in mind: |
* (refer to <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html"> How to Use |
* Threads </a> for more details): |
* <ul> |
* <li>Time-consuming tasks should not be run on the <i>Event Dispatch Thread</i>. Otherwise the |
* application becomes unresponsive.</li> |
* <li>Swing components should be accessed on the <i>Event Dispatch Thread</i> only.</li> |
* </ul> |
* |
* <p> |
* |
* <p> |
* These constraints mean that a GUI application with time intensive computing needs at least two |
* threads: 1) a thread to perform the lengthy task and 2) the <i>Event Dispatch Thread</i> (EDT) |
* for all GUI-related activities. This involves inter-thread communication which can be tricky to |
* implement. |
* |
* <p> |
* {@code SwingWorker2} is designed for situations where you need to have a long running task run in |
* a background thread and provide updates to the UI either when done, or while processing. |
* Subclasses of {@code SwingWorker2} must implement the {@link #doInBackground} method to perform |
* the background computation. |
* |
* |
* <p> |
* <b>Workflow</b> |
* <p> |
* There are three threads involved in the life cycle of a {@code SwingWorker2} : |
* <ul> |
* <li> |
* <p> |
* <i>Current</i> thread: The {@link #execute} method is called on this thread. It schedules |
* {@code SwingWorker2} for the execution on a <i>worker</i> thread and returns immediately. One can |
* wait for the {@code SwingWorker2} to complete using the {@link #get get} methods. |
* <li> |
* <p> |
* <i>Worker</i> thread: The {@link #doInBackground} method is called on this thread. This is where |
* all background activities should happen. To notify {@code PropertyChangeListeners} about bound |
* properties changes use the {@link #firePropertyChange firePropertyChange} and |
* {@link #getPropertyChangeSupport} methods. By default there are two bound properties available: |
* {@code state} and {@code progress}. |
* <li> |
* <p> |
* <i>Event Dispatch Thread</i>: All Swing related activities occur on this thread. |
* {@code SwingWorker2} invokes the {@link #process process} and {@link #done} methods and notifies |
* any {@code PropertyChangeListeners} on this thread. |
* </ul> |
* |
* <p> |
* Often, the <i>Current</i> thread is the <i>Event Dispatch Thread</i>. |
* |
* |
* <p> |
* Before the {@code doInBackground} method is invoked on a <i>worker</i> thread, |
* {@code SwingWorker2} notifies any {@code PropertyChangeListeners} about the {@code state} |
* property change to {@code StateValue.STARTED}. After the {@code doInBackground} method is |
* finished the {@code done} method is executed. Then {@code SwingWorker2} notifies any |
* {@code PropertyChangeListeners} about the {@code state} property change to |
* {@code StateValue.DONE}. |
* |
* <p> |
* {@code SwingWorker2} is only designed to be executed once. Executing a {@code SwingWorker2} more |
* than once will not result in invoking the {@code doInBackground} method twice. |
* |
* <p> |
* <b>Sample Usage</b> |
* <p> |
* The following example illustrates the simplest use case. Some processing is done in the |
* background and when done you update a Swing component. |
* |
* <p> |
* Say we want to find the "Meaning of Life" and display the result in a {@code JLabel}. |
* |
* <pre> |
* final JLabel label; |
* class MeaningOfLifeFinder extends SwingWorker2<String, Object> { |
* {@code @Override} |
* public String doInBackground() { |
* return findTheMeaningOfLife(); |
* } |
* |
* {@code @Override} |
* protected void done() { |
* try { |
* label.setText(get()); |
* } catch (Exception ignore) { |
* } |
* } |
* } |
* |
* (new MeaningOfLifeFinder()).execute(); |
* </pre> |
* |
* <p> |
* The next example is useful in situations where you wish to process data as it is ready on the |
* <i>Event Dispatch Thread</i>. |
* |
* <p> |
* Now we want to find the first N prime numbers and display the results in a {@code JTextArea}. |
* While this is computing, we want to update our progress in a {@code JProgressBar}. Finally, we |
* also want to print the prime numbers to {@code System.out}. |
* |
* <pre> |
* class PrimeNumbersTask extends |
* SwingWorker2<List<Integer>, Integer> { |
* PrimeNumbersTask(JTextArea textArea, int numbersToFind) { |
* //initialize |
* } |
* |
* {@code @Override} |
* public List<Integer> doInBackground() { |
* while (! enough && ! isCancelled()) { |
* number = nextPrimeNumber(); |
* publish(number); |
* setProgress(100 * numbers.size() / numbersToFind); |
* } |
* } |
* return numbers; |
* } |
* |
* {@code @Override} |
* protected void process(List<Integer> chunks) { |
* for (int number : chunks) { |
* textArea.append(number + "\n"); |
* } |
* } |
* } |
* |
* JTextArea textArea = new JTextArea(); |
* final JProgressBar progressBar = new JProgressBar(0, 100); |
* PrimeNumbersTask task = new PrimeNumbersTask(textArea, N); |
* task.addPropertyChangeListener( |
* new PropertyChangeListener() { |
* public void propertyChange(PropertyChangeEvent evt) { |
* if ("progress".equals(evt.getPropertyName())) { |
* progressBar.setValue((Integer)evt.getNewValue()); |
* } |
* } |
* }); |
* |
* task.execute(); |
* System.out.println(task.get()); //prints all prime numbers we have got |
* </pre> |
* |
* <p> |
* Because {@code SwingWorker2} implements {@code Runnable}, a {@code SwingWorker2} can be submitted |
* to an {@link java.util.concurrent.Executor} for execution. |
* |
* @author Igor Kushnirskiy |
* @version %I% %G% |
* |
* @param <T> the result type returned by this {@code SwingWorker2's} {@code doInBackground} and |
* {@code get} methods |
* @param <V> the type used for carrying out intermediate results by this {@code SwingWorker2's} |
* {@code publish} and {@code process} methods |
* |
* @since 1.6 |
*/ |
public abstract class SwingWorker2<T, V> implements RunnableFuture<T> { |
/** |
* number of worker threads. |
*/ |
private static int maxWorkerThreads = 10; |
/** |
* current progress. |
*/ |
private volatile int progress; |
/** |
* current state. |
*/ |
private volatile StateValue state; |
/** |
* everything is run inside this FutureTask. Also it is used as a delegatee for the Future API. |
*/ |
private final FutureTask<T> future; |
/** |
* all propertyChangeSupport goes through this. |
*/ |
private final PropertyChangeSupport propertyChangeSupport; |
/** |
* handler for {@code process} mehtod. |
*/ |
private AccumulativeRunnable<V> doProcess; |
/** |
* handler for progress property change notifications. |
*/ |
private AccumulativeRunnable<Integer> doNotifyProgressChange; |
private final AccumulativeRunnable<Runnable> doSubmit = getDoSubmit(); |
/** |
* Values for the {@code state} bound property. |
* |
* @since 1.6 |
*/ |
public enum StateValue { |
/** |
* Initial {@code SwingWorker2} state. |
*/ |
PENDING, |
/** |
* {@code SwingWorker2} is {@code STARTED} before invoking {@code doInBackground}. |
*/ |
STARTED, |
/** |
* {@code SwingWorker2} is {@code DONE} after {@code doInBackground} method is finished. |
*/ |
DONE |
}; |
/** |
* Constructs this {@code SwingWorker2}. |
*/ |
public SwingWorker2() { |
Callable<T> callable = new Callable<T>() { |
public T call() throws Exception { |
setState(StateValue.STARTED); |
return doInBackground(); |
} |
}; |
future = new FutureTask<T>(callable) { |
@Override |
protected void done() { |
doneEDT(); |
setState(StateValue.DONE); |
} |
}; |
state = StateValue.PENDING; |
propertyChangeSupport = new SwingWorker2PropertyChangeSupport(this); |
doProcess = null; |
doNotifyProgressChange = null; |
} |
/** |
* Defines the maximum number of threads the worker will use It MUST be called before the first |
* SwingWorker2 use |
* |
* @param max the max number of threads |
* */ |
public static void setMaxWorkerThreads(int max) { |
maxWorkerThreads = max; |
} |
/** |
* Computes a result, or throws an exception if unable to do so. |
* |
* <p> |
* Note that this method is executed only once. |
* |
* <p> |
* Note: this method is executed in a background thread. |
* |
* |
* @return the computed result |
* @throws Exception if unable to compute a result |
* |
*/ |
protected abstract T doInBackground() throws Exception; |
/** |
* Sets this {@code Future} to the result of computation unless it has been cancelled. |
*/ |
public final void run() { |
future.run(); |
} |
/** |
* Sends data chunks to the {@link #process} method. This method is to be used from inside the |
* {@code doInBackground} method to deliver intermediate results for processing on the <i>Event |
* Dispatch Thread</i> inside the {@code process} method. |
* |
* <p> |
* Because the {@code process} method is invoked asynchronously on the <i>Event Dispatch |
* Thread</i> multiple invocations to the {@code publish} method might occur before the |
* {@code process} method is executed. For performance purposes all these invocations are |
* coalesced into one invocation with concatenated arguments. |
* |
* <p> |
* For example: |
* |
* <pre> |
* publish("1"); |
* publish("2", "3"); |
* publish("4", "5", "6"); |
* </pre> |
* |
* might result in: |
* |
* <pre> |
* process("1", "2", "3", "4", "5", "6") |
* </pre> |
* |
* <p> |
* <b>Sample Usage</b>. This code snippet loads some tabular data and updates |
* {@code DefaultTableModel} with it. Note that it safe to mutate the tableModel from inside the |
* {@code process} method because it is invoked on the <i>Event Dispatch Thread</i>. |
* |
* <pre> |
* class TableSwingWorker2 extends |
* SwingWorker2<DefaultTableModel, Object[]> { |
* private final DefaultTableModel tableModel; |
* |
* public TableSwingWorker2(DefaultTableModel tableModel) { |
* this.tableModel = tableModel; |
* } |
* |
* {@code @Override} |
* protected DefaultTableModel doInBackground() throws Exception { |
* for (Object[] row = loadData(); |
* ! isCancelled() && row != null; |
* row = loadData()) { |
* publish((Object[]) row); |
* } |
* return tableModel; |
* } |
* |
* {@code @Override} |
* protected void process(List<Object[]> chunks) { |
* for (Object[] row : chunks) { |
* tableModel.addRow(row); |
* } |
* } |
* } |
* </pre> |
* |
* @param chunks intermediate results to process |
* |
* @see #process |
* |
*/ |
protected final void publish(V... chunks) { |
synchronized (this) { |
if (doProcess == null) { |
doProcess = new AccumulativeRunnable<V>() { |
@Override |
public void run(List<V> args) { |
process(args); |
} |
@Override |
protected void submit() { |
doSubmit.add(this); |
} |
}; |
} |
} |
doProcess.add(chunks); |
} |
/** |
* Receives data chunks from the {@code publish} method asynchronously on the <i>Event Dispatch |
* Thread</i>. |
* |
* <p> |
* Please refer to the {@link #publish} method for more details. |
* |
* @param chunks intermediate results to process |
* |
* @see #publish |
* |
*/ |
protected void process(List<V> chunks) { |
} |
/** |
* Executed on the <i>Event Dispatch Thread</i> after the {@code doInBackground} method is |
* finished. The default implementation does nothing. Subclasses may override this method to |
* perform completion actions on the <i>Event Dispatch Thread</i>. Note that you can query |
* status inside the implementation of this method to determine the result of this task or |
* whether this task has been cancelled. |
* |
* @see #doInBackground |
* @see #isCancelled() |
* @see #get |
*/ |
protected void done() { |
} |
/** |
* Sets the {@code progress} bound property. The value should be from 0 to 100. |
* |
* <p> |
* Because {@code PropertyChangeListener}s are notified asynchronously on the <i>Event Dispatch |
* Thread</i> multiple invocations to the {@code setProgress} method might occur before any |
* {@code PropertyChangeListeners} are invoked. For performance purposes all these invocations |
* are coalesced into one invocation with the last invocation argument only. |
* |
* <p> |
* For example, the following invokations: |
* |
* <pre> |
* setProgress(1); |
* setProgress(2); |
* setProgress(3); |
* </pre> |
* |
* might result in a single {@code PropertyChangeListener} notification with the value {@code 3}. |
* |
* @param progress the progress value to set |
* @throws IllegalArgumentException is value not from 0 to 100 |
*/ |
protected final void setProgress(int progress) { |
if (progress < 0 || progress > 100) { |
throw new IllegalArgumentException("the value should be from 0 to 100"); |
} |
if (this.progress == progress) { |
return; |
} |
int oldProgress = this.progress; |
this.progress = progress; |
if (!getPropertyChangeSupport().hasListeners("progress")) { |
return; |
} |
synchronized (this) { |
if (doNotifyProgressChange == null) { |
doNotifyProgressChange = new AccumulativeRunnable<Integer>() { |
@Override |
public void run(List<Integer> args) { |
firePropertyChange("progress", args.get(0), args.get(args.size() - 1)); |
} |
@Override |
protected void submit() { |
doSubmit.add(this); |
} |
}; |
} |
} |
doNotifyProgressChange.add(oldProgress, progress); |
} |
/** |
* Returns the {@code progress} bound property. |
* |
* @return the progress bound property. |
*/ |
public final int getProgress() { |
return progress; |
} |
/** |
* Schedules this {@code SwingWorker2} for execution on a <i>worker</i> thread. There are a |
* number of <i>worker</i> threads available. In the event all <i>worker</i> threads are busy |
* handling other {@code SwingWorker2s} this {@code SwingWorker2} is placed in a waiting queue. |
* |
* <p> |
* Note: {@code SwingWorker2} is only designed to be executed once. Executing a |
* {@code SwingWorker2} more than once will not result in invoking the {@code doInBackground} |
* method twice. |
*/ |
public final void execute() { |
getWorkersExecutorService().execute(this); |
} |
// Future methods START |
/** |
* {@inheritDoc} |
*/ |
public final boolean cancel(boolean mayInterruptIfRunning) { |
return future.cancel(mayInterruptIfRunning); |
} |
/** |
* {@inheritDoc} |
*/ |
public final boolean isCancelled() { |
return future.isCancelled(); |
} |
/** |
* {@inheritDoc} |
*/ |
public final boolean isDone() { |
return future.isDone(); |
} |
/** |
* {@inheritDoc} |
* <p> |
* Note: calling {@code get} on the <i>Event Dispatch Thread</i> blocks <i>all</i> events, |
* including repaints, from being processed until this {@code SwingWorker2} is complete. |
* |
* <p> |
* When you want the {@code SwingWorker2} to block on the <i>Event Dispatch Thread</i> we |
* recommend that you use a <i>modal dialog</i>. |
* |
* <p> |
* For example: |
* |
* <pre> |
* class SwingWorker2CompletionWaiter extends PropertyChangeListener { |
* private JDialog dialog; |
* |
* public SwingWorker2CompletionWaiter(JDialog dialog) { |
* this.dialog = dialog; |
* } |
* |
* public void propertyChange(PropertyChangeEvent event) { |
* if ("state".equals(event.getPropertyName()) && SwingWorker2.StateValue.DONE == event.getNewValue()) { |
* dialog.setVisible(false); |
* dialog.dispose(); |
* } |
* } |
* } |
* JDialog dialog = new JDialog(owner, true); |
* swingWorker.addPropertyChangeListener(new SwingWorker2CompletionWaiter(dialog)); |
* swingWorker.execute(); |
* // the dialog will be visible until the SwingWorker2 is done |
* dialog.setVisible(true); |
* </pre> |
*/ |
public final T get() throws InterruptedException, ExecutionException { |
return future.get(); |
} |
/** |
* {@inheritDoc} |
* <p> |
* Please refer to {@link #get} for more details. |
*/ |
public final T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { |
return future.get(timeout, unit); |
} |
// Future methods END |
// PropertyChangeSupports methods START |
/** |
* Adds a {@code PropertyChangeListener} to the listener list. The listener is registered for |
* all properties. The same listener object may be added more than once, and will be called as |
* many times as it is added. If {@code listener} is {@code null}, no exception is thrown and no |
* action is taken. |
* |
* <p> |
* Note: This is merely a convenience wrapper. All work is delegated to |
* {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}. |
* |
* @param listener the {@code PropertyChangeListener} to be added |
*/ |
public final void addPropertyChangeListener(PropertyChangeListener listener) { |
getPropertyChangeSupport().addPropertyChangeListener(listener); |
} |
/** |
* Removes a {@code PropertyChangeListener} from the listener list. This removes a |
* {@code PropertyChangeListener} that was registered for all properties. If {@code listener} |
* was added more than once to the same event source, it will be notified one less time after |
* being removed. If {@code listener} is {@code null}, or was never added, no exception is |
* thrown and no action is taken. |
* |
* <p> |
* Note: This is merely a convenience wrapper. All work is delegated to |
* {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}. |
* |
* @param listener the {@code PropertyChangeListener} to be removed |
*/ |
public final void removePropertyChangeListener(PropertyChangeListener listener) { |
getPropertyChangeSupport().removePropertyChangeListener(listener); |
} |
/** |
* Reports a bound property update to any registered listeners. No event is fired if {@code old} |
* and {@code new} are equal and non-null. |
* |
* <p> |
* This {@code SwingWorker2} will be the source for any generated events. |
* |
* <p> |
* When called off the <i>Event Dispatch Thread</i> {@code PropertyChangeListeners} are notified |
* asynchronously on the <i>Event Dispatch Thread</i>. |
* <p> |
* Note: This is merely a convenience wrapper. All work is delegated to |
* {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}. |
* |
* |
* @param propertyName the programmatic name of the property that was changed |
* @param oldValue the old value of the property |
* @param newValue the new value of the property |
*/ |
public final void firePropertyChange(String propertyName, Object oldValue, Object newValue) { |
getPropertyChangeSupport().firePropertyChange(propertyName, oldValue, newValue); |
} |
/** |
* Returns the {@code PropertyChangeSupport} for this {@code SwingWorker2}. This method is used |
* when flexible access to bound properties support is needed. |
* <p> |
* This {@code SwingWorker2} will be the source for any generated events. |
* |
* <p> |
* Note: The returned {@code PropertyChangeSupport} notifies any {@code PropertyChangeListener}s |
* asynchronously on the <i>Event Dispatch Thread</i> in the event that |
* {@code firePropertyChange} or {@code fireIndexedPropertyChange} are called off the <i>Event |
* Dispatch Thread</i>. |
* |
* @return {@code PropertyChangeSupport} for this {@code SwingWorker2} |
*/ |
public final PropertyChangeSupport getPropertyChangeSupport() { |
return propertyChangeSupport; |
} |
// PropertyChangeSupports methods END |
/** |
* Returns the {@code SwingWorker2} state bound property. |
* |
* @return the current state |
*/ |
public final StateValue getState() { |
/* |
* DONE is a speacial case to keep getState and isDone is sync |
*/ |
if (isDone()) { |
return StateValue.DONE; |
} else { |
return state; |
} |
} |
/** |
* Sets this {@code SwingWorker2} state bound property. |
* |
* @param state the state to set |
*/ |
private void setState(StateValue state) { |
StateValue old = this.state; |
this.state = state; |
firePropertyChange("state", old, state); |
} |
/** |
* Invokes {@code done} on the EDT. |
*/ |
private void doneEDT() { |
Runnable doDone = new Runnable() { |
public void run() { |
done(); |
} |
}; |
if (SwingUtilities.isEventDispatchThread()) { |
doDone.run(); |
} else { |
doSubmit.add(doDone); |
} |
} |
/** |
* returns workersExecutorService. |
* |
* returns the service stored in the appContext or creates it if necessary. |
* |
* @return ExecutorService for the {@code SwingWorker2s} |
*/ |
private static synchronized ExecutorService getWorkersExecutorService() { |
final AppContext appContext = AppContext.getAppContext(); |
ExecutorService executorService = (ExecutorService) appContext.get(SwingWorker2.class); |
if (executorService == null) { |
// this creates daemon threads. |
ThreadFactory threadFactory = new ThreadFactory() { |
final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); |
public Thread newThread(final Runnable r) { |
Thread thread = defaultFactory.newThread(r); |
thread.setName("SwingWorker2-" + thread.getName()); |
thread.setDaemon(true); |
return thread; |
} |
}; |
executorService = new ThreadPoolExecutor(maxWorkerThreads, maxWorkerThreads, 10L, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(), threadFactory); |
appContext.put(SwingWorker2.class, executorService); |
// Don't use ShutdownHook here as it's not enough. We should track |
// AppContext disposal instead of JVM shutdown, see 6799345 for details |
final ExecutorService es = executorService; |
appContext.addPropertyChangeListener(AppContext.DISPOSED_PROPERTY_NAME, new PropertyChangeListener() { |
@Override |
public void propertyChange(PropertyChangeEvent pce) { |
boolean disposed = (Boolean) pce.getNewValue(); |
if (disposed) { |
final WeakReference<ExecutorService> executorServiceRef = new WeakReference<ExecutorService>(es); |
final ExecutorService executorService = executorServiceRef.get(); |
if (executorService != null) { |
AccessController.doPrivileged(new PrivilegedAction<Void>() { |
public Void run() { |
executorService.shutdown(); |
return null; |
} |
}); |
} |
} |
} |
}); |
} |
return executorService; |
} |
private static final Object DO_SUBMIT_KEY = new Object(); // doSubmit |
private static AccumulativeRunnable<Runnable> getDoSubmit() { |
synchronized (DO_SUBMIT_KEY) { |
final AppContext appContext = AppContext.getAppContext(); |
Object doSubmit = appContext.get(DO_SUBMIT_KEY); |
if (doSubmit == null) { |
doSubmit = new DoSubmitAccumulativeRunnable(); |
appContext.put(DO_SUBMIT_KEY, doSubmit); |
} |
return (AccumulativeRunnable<Runnable>) doSubmit; |
} |
} |
private static class DoSubmitAccumulativeRunnable extends AccumulativeRunnable<Runnable> implements ActionListener { |
private final static int DELAY = (int) (1000 / 30); |
@Override |
protected void run(List<Runnable> args) { |
for (Runnable runnable : args) { |
runnable.run(); |
} |
} |
@Override |
protected void submit() { |
Timer timer = new Timer(DELAY, this); |
timer.setRepeats(false); |
timer.start(); |
} |
public void actionPerformed(ActionEvent event) { |
run(); |
} |
} |
private class SwingWorker2PropertyChangeSupport extends PropertyChangeSupport { |
SwingWorker2PropertyChangeSupport(Object source) { |
super(source); |
} |
@Override |
public void firePropertyChange(final PropertyChangeEvent evt) { |
if (SwingUtilities.isEventDispatchThread()) { |
super.firePropertyChange(evt); |
} else { |
doSubmit.add(new Runnable() { |
public void run() { |
SwingWorker2PropertyChangeSupport.this.firePropertyChange(evt); |
} |
}); |
} |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/task/TodoListPanel.java |
---|
249,7 → 249,7 |
c.weighty = 0; |
c.gridwidth = 6; |
// SEP |
TitledSeparator sep = new TitledSeparator(currentUser.getLastName() + " " + currentUser.getName().toUpperCase() + " Tâches en cours..."); |
TitledSeparator sep = new TitledSeparator(currentUser.getFirstName() + " " + currentUser.getName().toUpperCase() + " Tâches en cours..."); |
this.add(sep, c); |
c.gridwidth = 1; |
/trunk/OpenConcerto/src/org/openconcerto/task/ui/UserRightPanelDetail.java |
---|
225,7 → 225,7 |
this.selectedUser = selectedUser; |
labelDocumentation1.setText(" Autorisations de l'utilisateur " + selectedUser.getLastName() + " " + selectedUser.getName()); |
labelDocumentation1.setText(" Autorisations de l'utilisateur " + selectedUser.getFirstName() + " " + selectedUser.getName()); |
labelDocumentation2.setText(" Double cliquez sur un nom d'une des colonnes suivantes pour activer/désactiver le droit correspondant."); |
List<UserTaskRight> l = UserTaskRight.getUserTaskRight(selectedUser); |
cellRenderer1.setUserTaskRight(l); |
/trunk/OpenConcerto/src/org/openconcerto/task/ui/UserListCellRenderer.java |
---|
24,7 → 24,7 |
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { |
User user=(User)value; |
String newValue=user.getLastName()+" "+user.getName(); |
String newValue=user.getFirstName()+" "+user.getName(); |
return super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus); |
} |
/trunk/OpenConcerto/src/org/openconcerto/task/ui/UserTaskRightListCellRenderer.java |
---|
38,7 → 38,7 |
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { |
User user = (User) value; |
String newValue = user.getLastName() + " " + user.getName(); |
String newValue = user.getFirstName() + " " + user.getName(); |
Component c = super.getListCellRendererComponent(list, newValue, index, false, cellHasFocus); |
setForeground(Color.LIGHT_GRAY); |
if (usersRight != null) { |
/trunk/OpenConcerto/src/product.properties |
---|
1,2 → 1,2 |
NAME=OpenConcerto |
VERSION=1.2b4 |
VERSION=1.2b5 |