Dépôt officiel du code source de l'ERP OpenConcerto
/trunk/OpenConcerto/Configuration/Template/Default/VenteFacture.xml |
---|
95,8 → 95,8 |
<element location="B63" type="fill"> |
<field base="Societe" table="SAISIE_VENTE_FACTURE" name="ID_MODE_REGLEMENT"> |
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Règlement souhaité" conditionField="COMPTANT" conditionExpValue="false" display="false"/> |
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Facture acquitée par" conditionField="COMPTANT" conditionExpValue="true" display="false"/> |
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Règlement souhaité" conditionField="COMPTANT" conditionExpValue="true" display="false"/> |
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Facture acquitée par" conditionField="COMPTANT" conditionExpValue="false" display="false"/> |
<field base="Societe" table="MODE_REGLEMENT" name="ID_TYPE_REGLEMENT"> |
<field base="Societe" table="TYPE_REGLEMENT" name="NOM" valuesExpected="Indéfini"/> |
112,6 → 112,10 |
<element location="B64" type="fill"> |
<field base="Societe" table="SAISIE_VENTE_FACTURE" name="DATE" type="DateEcheance" prefix="Règlement de cette facture au plus tard le " valuesExpected=" "/> |
</element> |
<element location="B64" type="fill"> |
<field base="Societe" table="SAISIE_VENTE_FACTURE" name="ID_MODE_REGLEMENT"> |
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Règlement à date de réception de facture" conditionField="COMPTANT" conditionExpValue="false" display="false"/> |
118,11 → 122,7 |
</field> |
</element> |
<element location="B64" type="fill"> |
<field base="Societe" table="SAISIE_VENTE_FACTURE" name="DATE" type="DateEcheance" prefix="Règlement de cette facture au plus tard le " valuesExpected=" "/> |
</element> |
<table endPageLine="65" firstLine="63" endLine="65" lastColumn="I" base="Societe" table="TVA"> |
<element location="I" name="NOM" prefix="Total "> |
</element> |
/trunk/OpenConcerto/src/org/openconcerto/map/ui/ITextComboVilleViewer.java |
---|
14,9 → 14,9 |
package org.openconcerto.map.ui; |
import org.openconcerto.map.model.Ville; |
import org.openconcerto.ui.PopupMouseListener; |
import org.openconcerto.ui.component.ComboLockedMode; |
import org.openconcerto.ui.component.ITextSelector; |
import org.openconcerto.ui.component.IComboCacheListModel; |
import org.openconcerto.ui.component.combo.ISearchableTextCombo; |
import org.openconcerto.ui.component.text.DocumentComponent; |
import org.openconcerto.ui.component.text.TextComponent; |
import org.openconcerto.ui.state.WindowStateManager; |
27,6 → 27,7 |
import org.openconcerto.utils.checks.EmptyObjectHelper; |
import org.openconcerto.utils.checks.ValidListener; |
import org.openconcerto.utils.checks.ValidState; |
import org.openconcerto.utils.text.SimpleDocumentListener; |
import java.awt.BorderLayout; |
import java.awt.Dimension; |
39,12 → 40,9 |
import javax.swing.JButton; |
import javax.swing.JComponent; |
import javax.swing.JFrame; |
import javax.swing.JMenuItem; |
import javax.swing.JPanel; |
import javax.swing.JPopupMenu; |
import javax.swing.WindowConstants; |
import javax.swing.event.DocumentEvent; |
import javax.swing.event.DocumentListener; |
import javax.swing.text.Document; |
import javax.swing.text.JTextComponent; |
55,7 → 53,7 |
* Selecteur de Ville |
*/ |
private static final long serialVersionUID = 3397210337907076649L; |
private final ITextSelector text = new ITextSelector(ComboLockedMode.ITEMS_LOCKED); |
private final ISearchableTextCombo text = new ISearchableTextCombo(ComboLockedMode.UNLOCKED); |
private final JButton button = new JButton("Afficher sur la carte"); |
private Ville currentVille = null; |
private final EmptyObjectHelper emptyHelper; |
81,7 → 79,7 |
}); |
this.cache = new ITextComboCacheVille(); |
this.text.initCache(this.cache); |
new IComboCacheListModel(this.cache).initCacheLater(this.text); |
this.add(this.text, BorderLayout.CENTER); |
this.add(this.button, BorderLayout.EAST); |
108,44 → 106,16 |
} |
} |
}); |
this.text.getDocument().addDocumentListener(new DocumentListener() { |
public void changedUpdate(final DocumentEvent e) { |
ITextComboVilleViewer.this.currentVille = Ville.getVilleFromVilleEtCode(ITextComboVilleViewer.this.text.getValue()); |
this.text.getDocument().addDocumentListener(new SimpleDocumentListener() { |
@Override |
public void update(DocumentEvent e) { |
ITextComboVilleViewer.this.currentVille = Ville.getVilleFromVilleEtCode(getText(e.getDocument())); |
ITextComboVilleViewer.this.button.setEnabled(ITextComboVilleViewer.this.currentVille != null && ITextComboVilleViewer.this.isEnabled()); |
} |
public void insertUpdate(final DocumentEvent e) { |
this.changedUpdate(e); |
} |
public void removeUpdate(final DocumentEvent e) { |
this.changedUpdate(e); |
} |
}); |
final JPopupMenu popupMenu = new JPopupMenu(); |
// FIXME ajouter la possibilité de supprimer une ville précédemment enregistrée |
final JMenuItem menuItem = new JMenuItem("Enregistrer cette ville"); |
menuItem.addActionListener(new ActionListener() { |
public void actionPerformed(final ActionEvent e) { |
final String t = ITextComboVilleViewer.this.text.getTextComp().getText(); |
ITextComboVilleViewer.this.cache.addToCache(t); |
final Ville createVilleFrom = ITextComboVilleViewer.this.cache.createVilleFrom(t); |
if (createVilleFrom != null) { |
final String villeEtCode = createVilleFrom.getVilleEtCode(); |
ITextComboVilleViewer.this.setValue(villeEtCode); |
ITextComboVilleViewer.this.firePropertyChange("value", null, villeEtCode); |
} |
} |
}); |
popupMenu.add(menuItem); |
this.text.getTextComp().addMouseListener(new PopupMouseListener(popupMenu)); |
} |
@Override |
public void addEmptyListener(final EmptyListener l) { |
this.emptyHelper.addListener(l); |
198,6 → 168,9 |
@Override |
public ValidState getValidState() { |
// TODO listen to Ville list, otherwise if we type a city that doesn't exist, the value |
// change and we're invalid, then we add the city but this does not change the value of the |
// combo and thus we're still invalid even though the city is now in the list |
final Ville villeFromVilleEtCode = Ville.getVilleFromVilleEtCode(this.getValue()); |
final boolean b = villeFromVilleEtCode != null; |
if (b) { |
224,7 → 197,6 |
public void setEnabled(final boolean enabled) { |
super.setEnabled(enabled); |
this.text.setEnabled(enabled); |
this.text.setEditable(enabled); |
this.button.setEnabled(enabled); |
} |
/trunk/OpenConcerto/src/org/openconcerto/map/ui/ITextComboCacheVille.java |
---|
21,7 → 21,6 |
import javax.swing.JOptionPane; |
public class ITextComboCacheVille implements ITextComboCache { |
final ArrayList<String> villesNames = Ville.getVillesNames(); |
private Ville lastGood; |
44,6 → 43,11 |
return v; |
} |
@Override |
public boolean isValid() { |
return this.villesNames.size() > 0; |
} |
public void addToCache(String string) { |
Ville v = this.createVilleFrom(string); |
if (v != null) { |
55,6 → 59,9 |
} |
public void deleteFromCache(String string) { |
final Ville v = Ville.getVilleFromVilleEtCode(string); |
if (v != null) |
Ville.removeVille(v); |
} |
public List<String> getCache() { |
64,7 → 71,8 |
return villesNames; |
} |
public List<String> loadCache() { |
@Override |
public List<String> loadCache(final boolean readCache) { |
return villesNames; |
} |
/trunk/OpenConcerto/src/org/openconcerto/map/ui/StatusPanel.java |
---|
16,7 → 16,8 |
import org.openconcerto.map.model.Ville; |
import org.openconcerto.ui.component.ComboLockedMode; |
import org.openconcerto.ui.component.ITextComboCache; |
import org.openconcerto.ui.component.ITextSelector; |
import org.openconcerto.ui.component.combo.ISearchableTextCombo; |
import org.openconcerto.utils.model.DefaultIListModel; |
import java.awt.Dimension; |
import java.awt.GridBagConstraints; |
37,7 → 38,6 |
import javax.swing.event.ChangeEvent; |
import javax.swing.event.ChangeListener; |
public class StatusPanel extends JPanel implements VilleRendererListener, ZoomListener { |
/** |
81,7 → 81,7 |
} |
/* final JButton button = new JButton("Centrer"); */ |
ITextSelector txt = new ITextSelector("", ComboLockedMode.ITEMS_LOCKED, 40); |
ISearchableTextCombo txt = new ISearchableTextCombo(ComboLockedMode.ITEMS_LOCKED, 1, 40); |
txt.addValueListener(new PropertyChangeListener() { |
public void propertyChange(PropertyChangeEvent evt) { |
100,8 → 100,7 |
txt.setMinimumSearch(0); |
txt.setMaximumResult(200); |
ITextComboCache cache = new ITextComboCacheVille(); |
txt.initCache(cache); |
txt.initCache(new DefaultIListModel<String>(new ITextComboCacheVille().getCache())); |
c.weightx = 1; |
c.gridx++; |
this.add(txt, c); |
/trunk/OpenConcerto/src/org/openconcerto/map/model/DatabaseAccessor.java |
---|
18,6 → 18,7 |
public interface DatabaseAccessor { |
public void store(Ville v); |
public void delete(Ville v); |
public List<Ville> read(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/map/model/Ville.java |
---|
32,7 → 32,6 |
import javax.swing.JFrame; |
import javax.swing.UIManager; |
public class Ville { |
private static Map<String, Ville> map = new HashMap<String, Ville>(); |
130,6 → 129,16 |
// FIXME: fire missing |
} |
public static synchronized void removeVille(final Ville v) { |
villes.remove(v); |
final String villeEtCode = v.getVilleEtCode(); |
villesNames.remove(villeEtCode); |
map.remove(villeEtCode); |
accessor.delete(v); |
// FIXME: fire missing |
} |
// ** getter |
private static final synchronized void await() { |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/StyleDesc.java |
---|
186,18 → 186,74 |
} |
/** |
* Resolve the passed style name. |
* Resolve the passed style name. Note: this always return the style named <code>name</code>, |
* possibly ignoring conditions. |
* |
* @param pkg the package of the searched for style. |
* @param doc the document of the searched for style. |
* @param name the name of the style. |
* @return a corresponding StyleStyle. |
* @return the corresponding style, <code>null</code> if not found. |
* @see #findStyleForNode(StyledNode, String) |
*/ |
public final S findStyle(final ODPackage pkg, final Document doc, final String name) { |
final Element styleElem = pkg.getStyle(doc, this, name); |
return styleElem == null ? null : this.create(pkg, styleElem); |
public final S findStyleWithName(final ODPackage pkg, final Document doc, final String name) { |
return this.findStyle(pkg, doc, name, null); |
} |
/** |
* Find the style for the passed node. Depending on conditions the returned style might not be |
* named <code>name</code>. |
* |
* @param styledNode needed to evaluate conditions, not <code>null</code>. |
* @param name the name of the style. |
* @return the corresponding style, <code>null</code> if not found. |
* @see #findStyleWithName(ODPackage, Document, String) |
*/ |
public final S findStyleForNode(final StyledNode<S, ?> styledNode, final String name) { |
return this.findStyleForNode(styledNode.getODDocument().getPackage(), styledNode.getElement().getDocument(), styledNode, name); |
} |
public final S findStyleForNode(final ODPackage pkg, final Document doc, final StyledNode<S, ?> styledNode, final String name) { |
if (styledNode == null) |
throw new NullPointerException("null node"); |
return this.findStyle(pkg, doc, name, styledNode); |
} |
/** |
* Resolve the passed style name. If <code>styledNode</code> is <code>null</code> the returned |
* style will be the one named <code>name</code> otherwise depending on conditions it can be |
* another one. |
* |
* @param pkg the package of the searched for style. |
* @param doc the document of the searched for style. |
* @param name the name of the style. |
* @param styledNode needed to evaluate conditions, can be <code>null</code>. |
* @return the corresponding style, <code>null</code> if not found. |
*/ |
private final S findStyle(final ODPackage pkg, final Document doc, final String name, final StyledNode<S, ?> styledNode) { |
Element styleElem = pkg.getStyle(doc, this, name); |
if (styleElem == null) |
return null; |
if (styledNode != null && supportConditions()) { |
@SuppressWarnings("unchecked") |
final List<Element> styleMaps = styleElem.getChildren("map", getVersion().getSTYLE()); |
final Element styleMap = evaluateConditions(styledNode, styleMaps); |
if (styleMap != null) { |
if (styleElem != styleMap.getParent()) |
throw new IllegalStateException("map element not in " + styleElem); |
styleElem = pkg.getStyle(doc, this, styleMap.getAttributeValue("apply-style-name", getVersion().getSTYLE())); |
} |
} |
return this.create(pkg, styleElem); |
} |
protected boolean supportConditions() { |
return false; |
} |
protected Element evaluateConditions(final StyledNode<S, ?> styledNode, final List<Element> styleMaps) { |
return null; |
} |
public final S createAutoStyle(final ODPackage pkg) { |
return this.createAutoStyle(pkg, getBaseName()); |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ImmutableDocStyledNode.java |
---|
42,7 → 42,11 |
* @param styleClass our class of style, cannot be <code>null</code>. |
*/ |
public ImmutableDocStyledNode(D parent, Element local, final Class<S> styleClass) { |
super(local, styleClass); |
this(parent, local, getStyleDesc(local, styleClass)); |
} |
protected ImmutableDocStyledNode(D parent, Element local, StyleDesc<S> styleDesc) { |
super(local, styleDesc); |
this.parent = parent; |
assert getDocuments(this.parent.getPackage()).contains(local.getDocument()) : "Local not in parent: " + parent; |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/Style.java |
---|
105,6 → 105,7 |
if (elemName2Desc.get(desc.getVersion()).put(desc.getElementName(), desc) != null) |
throw new IllegalStateException(desc.getElementName() + " duplicate element name"); |
} |
assert desc != null : "Will need containsKey() in getStyleDesc()"; |
if (class2Desc.get(desc.getVersion()).put(desc.getStyleClass(), desc) != null) |
throw new IllegalStateException(desc.getStyleClass() + " duplicate"); |
} |
184,7 → 185,7 |
public static <S extends Style> S getStyle(final ODPackage pkg, final Class<S> clazz, final String name) { |
final StyleDesc<S> styleDesc = getStyleDesc(clazz, pkg.getVersion()); |
return styleDesc.create(pkg, pkg.getStyle(styleDesc, name)); |
return styleDesc.findStyleWithName(pkg, pkg.getContent().getDocument(), name); |
} |
/** |
227,16 → 228,14 |
return (StyleStyleDesc<S>) getStyleDesc(clazz, version); |
} |
@SuppressWarnings("unchecked") |
private static <S extends Style> StyleDesc<S> getStyleDesc(Class<S> clazz, final XMLVersion version, final boolean mustExist) { |
loadDescs(); |
final Map<Class<? extends Style>, StyleDesc<?>> map = class2Desc.get(version); |
if (map.containsKey(clazz)) |
return (StyleDesc<S>) map.get(clazz); |
else if (mustExist) |
@SuppressWarnings("unchecked") |
final StyleDesc<S> res = (StyleDesc<S>) map.get(clazz); |
if (res == null && mustExist) |
throw new IllegalArgumentException("unregistered " + clazz + " for version " + version); |
else |
return null; |
return res; |
} |
protected static <S extends Style> StyleDesc<S> getNonNullStyleDesc(final Class<S> clazz, final XMLVersion version, final Element styleElem, final String styleName) { |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODDocument.java |
---|
13,15 → 13,84 |
package org.openconcerto.openoffice; |
import java.io.File; |
import java.io.FileNotFoundException; |
import java.io.IOException; |
import java.text.ParseException; |
import org.jdom.Document; |
import org.jdom.Element; |
import org.jdom.Namespace; |
/** |
* An ODF document, like a spreadsheet or a text file. |
* |
* @author Sylvain |
*/ |
public interface ODDocument { |
public XMLVersion getVersion(); |
public abstract class ODDocument { |
public XMLFormatVersion getFormatVersion(); |
private final ODPackage pkg; |
private ODEpoch epoch; |
public ODPackage getPackage(); |
protected ODDocument(final ODPackage orig) { |
// don't want multiple document per package. |
if (orig.hasODDocument()) |
throw new IllegalStateException("ODPackage already has an ODDocument"); |
this.pkg = orig; |
} |
public final XMLVersion getVersion() { |
return this.getFormatVersion().getXMLVersion(); |
} |
public final XMLFormatVersion getFormatVersion() { |
return this.getPackage().getFormatVersion(); |
} |
public final ODPackage getPackage() { |
return this.pkg; |
} |
public final Document getContentDocument() { |
return this.getPackage().getContent().getDocument(); |
} |
protected final Element getBody() { |
return getPackage().getContentType().getBody(this.getContentDocument()); |
} |
private final String findEpoch() throws ParseException { |
final Namespace tableNS = getVersion().getTABLE(); |
final Element settings = this.getBody().getChild("calculation-settings", tableNS); |
if (settings != null) { |
final Element nullDateElem = settings.getChild("null-date", tableNS); |
if (nullDateElem != null) |
return nullDateElem.getAttributeValue("date-value", tableNS); |
} |
return null; |
} |
public final ODEpoch getEpoch() { |
return this.getEpoch(false); |
} |
public final ODEpoch getEpoch(final boolean updateFromXML) { |
if (this.epoch == null || updateFromXML) { |
try { |
this.epoch = ODEpoch.getInstance(this.findEpoch()); |
} catch (ParseException e) { |
// quite rare |
throw new IllegalStateException("Unable to parse the epoch of " + this, e); |
} |
} |
assert this.epoch != null; |
return this.epoch; |
} |
// *** Files |
public File saveAs(File file) throws FileNotFoundException, IOException { |
this.getPackage().setFile(file); |
return this.getPackage().save(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODValueType.java |
---|
14,6 → 14,7 |
package org.openconcerto.openoffice; |
import org.openconcerto.utils.FormatGroup; |
import org.openconcerto.utils.TimeUtils; |
import org.openconcerto.utils.XMLDateFormat; |
import java.math.BigDecimal; |
25,8 → 26,6 |
import java.util.Date; |
import java.util.List; |
import javax.xml.datatype.DatatypeConfigurationException; |
import javax.xml.datatype.DatatypeFactory; |
import javax.xml.datatype.Duration; |
/** |
109,12 → 108,7 |
return o.toString(); |
} else { |
final Calendar cal = (Calendar) o; |
// adjust the format TZ to the calendar's |
// that way even you pass a non default Calendar, if you did |
// myCal.set(HOUR_OF_DAY, 22), the string will have "22H" |
final SimpleDateFormat fmt = (SimpleDateFormat) TIME_FORMAT.clone(); |
fmt.setTimeZone(cal.getTimeZone()); |
return fmt.format(cal.getTime()); |
return TimeUtils.timePartToDuration(cal).toString(); |
} |
} |
123,7 → 117,7 |
if (date.length() == 0) |
return null; |
else { |
return getTypeFactory().newDuration(date); |
return TimeUtils.getTypeFactory().newDuration(date); |
} |
} |
206,8 → 200,11 |
* |
* @param o the object. |
* @return a value type capable of formatting <code>o</code> or <code>null</code>. |
* @throws NullPointerException if <code>o</code> is <code>null</code>. |
*/ |
public static ODValueType forObject(Object o) { |
public static ODValueType forObject(Object o) throws NullPointerException { |
if (o == null) |
throw new NullPointerException(); |
if (o instanceof Number) |
return FLOAT; |
else if (o instanceof Boolean) |
214,7 → 211,7 |
return BOOLEAN; |
else if (o instanceof String) |
return STRING; |
else if (o instanceof Duration || o instanceof Calendar && !((Calendar) o).isSet(Calendar.DATE)) |
else if (o instanceof Duration) |
return TIME; |
else if (DATE.canFormat(o.getClass())) |
return DATE; |
224,8 → 221,6 |
// see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#isoformats |
// time means Duration for OpenDocument (see 6.7.1) |
static private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("'PT'HH'H'mm'M'ss.S'S'"); |
static private final Format DATE_FORMAT; |
static { |
// first date and time so we don't loose time information on format() or parse() |
232,16 → 227,4 |
// MAYBE add HH':'mm':'ss,SSS for OOo 1 |
DATE_FORMAT = new FormatGroup(new XMLDateFormat(), new SimpleDateFormat("yyyy-MM-dd'T'HH':'mm':'ss"), new SimpleDateFormat("yyyy-MM-dd")); |
} |
static private DatatypeFactory typeFactory = null; |
static public final DatatypeFactory getTypeFactory() { |
if (typeFactory == null) |
try { |
typeFactory = DatatypeFactory.newInstance(); |
} catch (DatatypeConfigurationException e) { |
throw new IllegalStateException(e); |
} |
return typeFactory; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/text/TextNode.java |
---|
13,7 → 13,7 |
package org.openconcerto.openoffice.text; |
import org.openconcerto.openoffice.ODSingleXMLDocument; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.StyleStyle; |
import org.openconcerto.openoffice.StyledNode; |
26,28 → 26,32 |
* |
* @param <S> type of style. |
*/ |
public abstract class TextNode<S extends StyleStyle> extends StyledNode<S, ODSingleXMLDocument> { |
public abstract class TextNode<S extends StyleStyle> extends StyledNode<S, TextDocument> { |
protected ODSingleXMLDocument parent; |
protected TextDocument parent; |
public TextNode(Element local, final Class<S> styleClass) { |
this(local, styleClass, null); |
} |
protected TextNode(Element local, final Class<S> styleClass, final TextDocument parent) { |
super(local, styleClass); |
this.parent = null; |
this.parent = parent; |
} |
@Override |
public final ODSingleXMLDocument getODDocument() { |
public final TextDocument getODDocument() { |
return this.parent; |
} |
public final void setDocument(ODSingleXMLDocument doc) { |
public final void setDocument(TextDocument doc) { |
if (doc != this.parent) { |
if (doc == null) { |
this.parent = null; |
this.getElement().detach(); |
} else if (doc.getDocument() != this.getElement().getDocument()) |
} else if (doc.getContentDocument() != this.getElement().getDocument()) { |
doc.add(this); |
else { |
} else { |
this.checkDocument(doc); |
this.parent = doc; |
} |
54,5 → 58,5 |
} |
} |
protected abstract void checkDocument(ODSingleXMLDocument doc); |
protected abstract void checkDocument(ODDocument doc); |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/text/TextDocument.java |
---|
New file |
0,0 → 1,92 |
/* |
* 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.openoffice.text; |
import org.openconcerto.openoffice.ContentType; |
import org.openconcerto.openoffice.ContentTypeVersioned; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.XMLFormatVersion; |
import java.io.File; |
import java.io.IOException; |
import org.jdom.Element; |
public class TextDocument extends ODDocument { |
public static TextDocument createFromFile(File f) throws IOException { |
return new ODPackage(f).getTextDocument(); |
} |
/** |
* This method should be avoided, use {@link ODPackage#getTextDocument()}. |
* |
* @param fd a package. |
* @return the text document. |
*/ |
public static TextDocument get(final ODPackage fd) { |
return fd.hasODDocument() ? fd.getTextDocument() : new TextDocument(fd); |
} |
public static TextDocument createEmpty(String s) throws IOException { |
return createEmpty(s, XMLFormatVersion.getDefault()); |
} |
public static TextDocument createEmpty(String s, XMLFormatVersion ns) throws IOException { |
final ContentTypeVersioned ct = ContentType.TEXT.getVersioned(ns.getXMLVersion()); |
final TextDocument res = ct.createPackage(ns).getTextDocument(); |
final Element textP = Paragraph.createEmpty(ns.getXMLVersion()); |
textP.addContent(s); |
res.getBody().addContent(textP); |
return res; |
} |
private TextDocument(final ODPackage orig) { |
super(orig); |
} |
public final Paragraph getParagraph(int i) { |
final Element proto = Paragraph.createEmpty(getVersion()); |
final Element child = (Element) this.getBody().getChildren(proto.getName(), proto.getNamespace()).get(i); |
return new Paragraph(child, this); |
} |
/** |
* Append a paragraph or a heading. |
* |
* @param p paragraph to add. |
*/ |
public synchronized void add(TextNode<?> p) { |
this.add(p, null, -1); |
} |
public synchronized void add(TextNode<?> p, Element where, int index) { |
// add it first to avoid infinite loop, since setDocument() can call this method |
final Element addToElem = where == null ? this.getBody() : where; |
if (index < 0) |
addToElem.addContent(p.getElement()); |
else |
addToElem.addContent(index, p.getElement()); |
try { |
p.setDocument(this); |
} catch (RuntimeException e) { |
// the paragraph can throw an exception to notify that is not compatible with us (eg |
// missing styles), in that case remove it |
p.getElement().detach(); |
throw e; |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/text/Paragraph.java |
---|
13,8 → 13,8 |
package org.openconcerto.openoffice.text; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.ODSingleXMLDocument; |
import java.util.HashSet; |
import java.util.Set; |
55,8 → 55,12 |
return res; |
} |
Paragraph(Element elem, TextDocument parent) { |
super(elem, ParagraphStyle.class, parent); |
} |
public Paragraph(Element elem) { |
super(elem, ParagraphStyle.class); |
this(elem, null); |
} |
public Paragraph(XMLVersion ns) { |
72,6 → 76,21 |
addContent(text); |
} |
// MAYBE add updateStyle() which evaluates the conditions in style:map of the conditional style |
// to update style-name |
/** |
* A style containing conditions and maps to other styles. |
* |
* @return the conditional style or <code>null</code> if none or if this isn't in a document. |
*/ |
public final ParagraphStyle getConditionalStyle() { |
final String condName = this.getElement().getAttributeValue("cond-style-name", this.getElement().getNamespace()); |
if (condName == null) |
return null; |
else |
return getStyle(condName); |
} |
public final void setStyle(String styleName) { |
getElement().setAttribute("style-name", styleName, getElement().getNamespace()); |
} |
99,11 → 118,12 |
return getTextStyles(getElement()); |
} |
protected void checkDocument(ODSingleXMLDocument doc) { |
if (this.getStyleName() != null && getStyle(doc.getPackage(), doc.getDocument()) == null) |
@Override |
protected void checkDocument(ODDocument doc) { |
if (this.getStyleName() != null && getStyle(doc.getPackage(), doc.getContentDocument()) == null) |
throw new IllegalArgumentException("unknown style " + getStyleName() + " in " + doc); |
for (final String styleName : this.getUsedTextStyles()) { |
if (doc.getStyle(TextStyle.DESC, styleName) == null) { |
if (doc.getPackage().getStyle(TextStyle.DESC, styleName) == null) { |
throw new IllegalArgumentException(this + " is using a text:span with an undefined style : " + styleName); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/StyledNode.java |
---|
26,6 → 26,10 |
*/ |
public abstract class StyledNode<S extends Style, D extends ODDocument> extends ODNode { |
static protected final <S extends Style> StyleDesc<S> getStyleDesc(final Element local, final Class<S> styleClass) { |
return Style.getStyleDesc(styleClass, XMLVersion.getVersion(local)); |
} |
private final StyleDesc<S> styleClass; |
/** |
36,10 → 40,18 |
* @param styleClass our class of style, cannot be <code>null</code>. |
*/ |
public StyledNode(Element local, final Class<S> styleClass) { |
this(local, getStyleDesc(local, styleClass)); |
} |
// allow to pass StyleDesc since Style.getStyleDesc() was the longest operation of this |
// constructor, and this constructor is called for every Table, Column, Row and Cell, i.e. |
// up to millions of times. |
protected StyledNode(Element local, final StyleDesc<S> styleDesc) { |
super(local); |
if (styleClass == null) |
throw new NullPointerException("null style class"); |
this.styleClass = Style.getStyleDesc(styleClass, XMLVersion.getVersion(getElement())); |
if (styleDesc == null) |
throw new NullPointerException("null style desc"); |
this.styleClass = styleDesc; |
assert styleDesc.getVersion().equals(XMLVersion.getVersion(local)); |
assert this.styleClass.getRefElements().contains(this.getElement().getQualifiedName()) : this.getElement().getQualifiedName() + " not in " + this.styleClass; |
} |
47,14 → 59,23 |
public abstract D getODDocument(); |
public final S getStyle() { |
// null avoid getting styleName if we haven't any Document |
return this.getStyle(null); |
} |
protected final S getStyle(final String styleName) { |
final D doc = this.getODDocument(); |
return doc == null ? null : this.getStyle(doc.getPackage(), getElement().getDocument()); |
return doc == null ? null : this.getStyle(doc.getPackage(), getElement().getDocument(), styleName == null ? getStyleName() : styleName); |
} |
protected final S getStyle(final ODPackage pkg, final Document doc) { |
return this.styleClass.findStyle(pkg, doc, getStyleName()); |
return this.getStyle(pkg, doc, getStyleName()); |
} |
protected final S getStyle(final ODPackage pkg, final Document doc, final String styleName) { |
return this.styleClass.findStyleForNode(pkg, doc, this, styleName); |
} |
/** |
* Assure that this node's style is only referenced by this. I.e. after this method returns the |
* style of this node can be safely modified without affecting other nodes. |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODPackage.java |
---|
15,15 → 15,21 |
import static org.openconcerto.openoffice.ODPackage.RootElement.CONTENT; |
import static org.openconcerto.openoffice.ODPackage.RootElement.META; |
import static org.openconcerto.openoffice.ODPackage.RootElement.SETTINGS; |
import static org.openconcerto.openoffice.ODPackage.RootElement.STYLES; |
import org.openconcerto.openoffice.spreadsheet.SpreadSheet; |
import org.openconcerto.openoffice.text.ParagraphStyle; |
import org.openconcerto.openoffice.text.TextDocument; |
import org.openconcerto.utils.CollectionMap; |
import org.openconcerto.utils.CopyUtils; |
import org.openconcerto.utils.ExceptionUtils; |
import org.openconcerto.utils.FileUtils; |
import org.openconcerto.utils.StreamUtils; |
import org.openconcerto.utils.StringInputStream; |
import org.openconcerto.utils.Tuple3; |
import org.openconcerto.utils.Zip; |
import org.openconcerto.utils.ZippedFilesProcessor; |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.xml.JDOMUtils; |
import org.openconcerto.xml.Validator; |
import java.io.BufferedInputStream; |
37,14 → 43,19 |
import java.io.InputStream; |
import java.io.OutputStream; |
import java.nio.charset.Charset; |
import java.util.ArrayList; |
import java.util.Arrays; |
import java.util.EnumSet; |
import java.util.HashMap; |
import java.util.HashSet; |
import java.util.Iterator; |
import java.util.List; |
import java.util.Map; |
import java.util.Map.Entry; |
import java.util.Set; |
import java.util.zip.ZipEntry; |
import org.jdom.Attribute; |
import org.jdom.DocType; |
import org.jdom.Document; |
import org.jdom.Element; |
62,6 → 73,7 |
// use raw format, otherwise spaces are added to every spreadsheet cell |
private static final XMLOutputter OUTPUTTER = new XMLOutputter(Format.getRawFormat()); |
static final String MIMETYPE_ENTRY = "mimetype"; |
/** Normally mimetype contains only ASCII characters */ |
static final Charset MIMETYPE_ENC = Charset.forName("UTF-8"); |
89,6 → 101,10 |
return EnumSet.of(CONTENT, STYLES, META, SETTINGS); |
} |
public final static RootElement fromDocument(final Document doc) { |
return fromElementName(doc.getRootElement().getName()); |
} |
public final static RootElement fromElementName(final String name) { |
for (final RootElement e : values()) { |
if (e.getElementName().equals(name)) |
98,8 → 114,7 |
} |
static final Document createSingle(final Document from) { |
final XMLFormatVersion version = XMLFormatVersion.get(from); |
return SINGLE_CONTENT.createDocument(version.getXMLVersion(), version.getOfficeVersion()); |
return SINGLE_CONTENT.createDocument(XMLFormatVersion.get(from)); |
} |
private final String nsPrefix; |
120,20 → 135,25 |
return this.name; |
} |
public final Document createDocument(final XMLVersion version, final String officeVersion) { |
public final Document createDocument(final XMLFormatVersion fv) { |
final XMLVersion version = fv.getXMLVersion(); |
final Element root = new Element(getElementName(), version.getNS(getElementNSPrefix())); |
// 19.388 office:version identifies the version of ODF specification |
if (officeVersion != null) |
root.setAttribute("version", officeVersion, version.getOFFICE()); |
if (fv.getOfficeVersion() != null) |
root.setAttribute("version", fv.getOfficeVersion(), version.getOFFICE()); |
// avoid declaring namespaces in each child |
for (final Namespace ns : version.getALL()) |
root.addNamespaceDeclaration(ns); |
final Document res = new Document(root); |
return new Document(root, createDocType(version)); |
} |
public final DocType createDocType(final XMLVersion version) { |
// OpenDocument use relaxNG |
if (version == XMLVersion.OOo) |
res.setDocType(new DocType(getElementNSPrefix() + ":" + getElementName(), "-//OpenOffice.org//DTD OfficeDocument 1.0//EN", "office.dtd")); |
return res; |
return new DocType(getElementNSPrefix() + ":" + getElementName(), "-//OpenOffice.org//DTD OfficeDocument 1.0//EN", "office.dtd"); |
else |
return null; |
} |
/** |
162,17 → 182,69 |
* @return <code>true</code> if <code>name</code> is a standard file, eg <code>true</code>. |
*/ |
public static final boolean isStandardFile(final String name) { |
return name.equals("mimetype") || subdocNames.contains(name) || name.startsWith("Thumbnails") || name.startsWith("META-INF") || name.startsWith("Configurations"); |
return name.equals(MIMETYPE_ENTRY) || subdocNames.contains(name) || name.startsWith("Thumbnails") || name.startsWith("META-INF") || name.startsWith("Configurations"); |
} |
/** |
* Create a package from a collection of sub-documents. |
* |
* @param content the content. |
* @param style the styles, can be <code>null</code>. |
* @return a package containing the XML documents. |
*/ |
public static ODPackage createFromDocuments(Document content, Document style) { |
return createFromDocuments(null, content, style, null, null); |
} |
public static ODPackage createFromDocuments(final ContentTypeVersioned type, Document content, Document style, Document meta, Document settings) { |
final ODPackage pkg = new ODPackage(); |
if (type != null) |
pkg.setContentType(type); |
pkg.putFile(RootElement.CONTENT.getZipEntry(), content); |
pkg.putFile(RootElement.STYLES.getZipEntry(), style); |
pkg.putFile(RootElement.META.getZipEntry(), meta); |
pkg.putFile(RootElement.SETTINGS.getZipEntry(), settings); |
return pkg; |
} |
static private XMLVersion getVersion(final XMLFormatVersion fv, final ContentTypeVersioned ct) { |
final XMLVersion v; |
if (ct == null && fv == null) |
v = null; |
else if (ct != null) |
v = ct.getVersion(); |
else |
v = fv.getXMLVersion(); |
assert fv == null || ct == null || fv.getXMLVersion() == ct.getVersion(); |
return v; |
} |
static private <T> void checkVersion(final Class<T> clazz, final String s, final T actual, final T required) { |
if (actual != null && required != null) { |
final boolean ok; |
if (actual instanceof ContentTypeVersioned) { |
// we can change our template status since it doesn't affect our content |
ok = ((ContentTypeVersioned) actual).getNonTemplate().equals(((ContentTypeVersioned) required).getNonTemplate()); |
} else { |
ok = actual.equals(required); |
} |
if (!ok) |
throw new IllegalArgumentException("Cannot change " + s + " from " + required + " to " + actual); |
} |
} |
private final Map<String, ODPackageEntry> files; |
private ContentTypeVersioned type; |
private XMLFormatVersion version; |
private File file; |
private ODDocument doc; |
public ODPackage() { |
this.files = new HashMap<String, ODPackageEntry>(); |
this.type = null; |
this.version = null; |
this.file = null; |
this.doc = null; |
} |
public ODPackage(InputStream ins) throws IOException { |
186,7 → 258,7 |
final Object res; |
if (subdocNames.contains(name)) { |
try { |
res = new ODXMLDocument(OOUtils.getBuilder().build(in)); |
res = OOUtils.getBuilder().build(in); |
} catch (JDOMException e) { |
// always correct |
throw new IllegalStateException("parse error", e); |
244,7 → 316,9 |
this.putFile(name, myData, entry.getType(), entry.isCompressed()); |
} |
this.type = o.type; |
this.version = o.version; |
this.file = o.file; |
this.doc = null; |
} |
public final File getFile() { |
269,16 → 343,11 |
* @return the version of this package, can be <code>null</code>. |
*/ |
public final XMLVersion getVersion() { |
final XMLFormatVersion res = getFormatVersion(); |
return res == null ? null : res.getXMLVersion(); |
return getVersion(this.version, this.type); |
} |
public final XMLFormatVersion getFormatVersion() { |
final ODXMLDocument content = this.getContent(); |
if (content == null) |
return null; |
else |
return content.getFormatVersion(); |
return this.version; |
} |
/** |
287,25 → 356,90 |
* @return the type of this package, can be <code>null</code>. |
*/ |
public final ContentTypeVersioned getContentType() { |
if (this.type == null) { |
if (this.files.containsKey("mimetype")) |
this.type = ContentTypeVersioned.fromMime(new String(this.getBinaryFile("mimetype"), MIMETYPE_ENC)); |
else if (this.getVersion().equals(XMLVersion.OOo)) { |
final Element contentRoot = this.getContent().getDocument().getRootElement(); |
final String docClass = contentRoot.getAttributeValue("class", contentRoot.getNamespace("office")); |
this.type = ContentTypeVersioned.fromClass(docClass); |
} else if (this.getVersion().equals(XMLVersion.OD)) { |
final Element bodyChild = (Element) this.getContent().getChild("body").getChildren().get(0); |
this.type = ContentTypeVersioned.fromBody(bodyChild.getName()); |
return this.type; |
} |
public final void setContentType(final ContentTypeVersioned newType) { |
this.putFile(MIMETYPE_ENTRY, newType.getMimeType().getBytes(MIMETYPE_ENC)); |
} |
return this.type; |
private void updateTypeAndVersion(final String entry, ODXMLDocument xml) { |
this.setTypeAndVersion(entry.equals(CONTENT.getZipEntry()) ? ContentTypeVersioned.fromContent(xml) : null, xml.getFormatVersion(), entry); |
} |
private void updateTypeAndVersion(byte[] mimetype) { |
this.setTypeAndVersion(ContentTypeVersioned.fromMime(mimetype), null, MIMETYPE_ENTRY); |
} |
private final void setTypeAndVersion(final ContentTypeVersioned ct, final XMLFormatVersion fv, final String entry) { |
final Tuple3<XMLVersion, ContentTypeVersioned, XMLFormatVersion> requiredByPkg = this.getRequired(entry); |
if (requiredByPkg != null) { |
checkVersion(XMLVersion.class, "version", getVersion(fv, ct), requiredByPkg.get0()); |
checkVersion(ContentTypeVersioned.class, "type", ct, requiredByPkg.get1()); |
checkVersion(XMLFormatVersion.class, "format version", fv, requiredByPkg.get2()); |
} |
// since we're adding "entry" never set attributes to null |
if (fv != null && !fv.equals(this.version)) |
this.version = fv; |
// don't let non-template from content overwrite the correct one |
if (ct != null && !ct.equals(this.type) && (this.type == null || entry.equals(MIMETYPE_ENTRY))) |
this.type = ct; |
} |
// find the versions required by the package without the passed entry |
private final Tuple3<XMLVersion, ContentTypeVersioned, XMLFormatVersion> getRequired(final String entryToIgnore) { |
if (this.files.size() == 0 || (this.files.size() == 1 && this.files.containsKey(entryToIgnore))) |
return null; |
final byte[] mimetype; |
if (this.files.containsKey(MIMETYPE_ENTRY) && !MIMETYPE_ENTRY.equals(entryToIgnore)) { |
mimetype = this.getBinaryFile(MIMETYPE_ENTRY); |
} else { |
mimetype = null; |
} |
XMLFormatVersion fv = null; |
final Map<String, Object> versionFiles = new HashMap<String, Object>(); |
for (final String e : subdocNames) { |
if (this.files.containsKey(e) && !e.equals(entryToIgnore)) { |
final ODXMLDocument xmlFile = this.getXMLFile(e); |
versionFiles.put(e, xmlFile); |
if (fv == null) |
fv = xmlFile.getFormatVersion(); |
else |
assert fv.equals(xmlFile.getFormatVersion()) : "Incoherence"; |
} |
} |
final ODXMLDocument content = (ODXMLDocument) versionFiles.get(CONTENT.getZipEntry()); |
final ContentTypeVersioned ct; |
if (mimetype != null) |
ct = ContentTypeVersioned.fromMime(mimetype); |
else if (content != null) |
ct = ContentTypeVersioned.fromContent(content); |
else |
ct = null; |
return Tuple3.create(getVersion(fv, ct), ct, fv); |
} |
public final String getMimeType() { |
return this.getContentType().getMimeType(); |
} |
public final boolean isTemplate() { |
return this.getContentType().isTemplate(); |
} |
public final void setTemplate(boolean b) { |
if (this.type == null) |
throw new IllegalStateException("No type"); |
final ContentTypeVersioned newType = b ? this.type.getTemplate() : this.type.getNonTemplate(); |
if (newType == null) |
throw new IllegalStateException("Missing " + (b ? "" : "non-") + "template for " + this.type); |
this.setContentType(newType); |
} |
/** |
* Call {@link Validator#isValid()} on each XML subdocuments. |
* |
313,13 → 447,24 |
* if validation couldn't occur. |
*/ |
public final Map<String, String> validateSubDocuments() { |
return this.validateSubDocuments(true); |
} |
public final Map<String, String> validateSubDocuments(final boolean allowChangeToValidate) { |
final OOXML ooxml = this.getFormatVersion().getXML(); |
if (!ooxml.canValidate()) |
return null; |
final Map<String, String> res = new HashMap<String, String>(); |
for (final String s : subdocNames) { |
if (this.getEntries().contains(s)) { |
final String valid = ooxml.getValidator(this.getDocument(s)).isValid(); |
final Document doc = this.getDocument(s); |
if (doc != null) { |
if (allowChangeToValidate) { |
// OpenOffice do not generate DocType declaration |
final DocType docType = RootElement.fromDocument(doc).createDocType(ooxml.getVersion()); |
if (docType != null && doc.getDocType() == null) |
doc.setDocType(docType); |
} |
final String valid = ooxml.getValidator(doc).isValid(); |
if (valid != null) |
res.put(s, valid); |
} |
327,6 → 472,31 |
return res; |
} |
public final ODDocument getODDocument() { |
// cache ODDocument otherwise a second one can modify the XML (e.g. remove rows) without the |
// first one knowing |
if (this.doc == null) { |
final ContentType ct = this.getContentType().getType(); |
if (ct.equals(ContentType.SPREADSHEET)) |
this.doc = SpreadSheet.get(this); |
else if (ct.equals(ContentType.TEXT)) |
this.doc = TextDocument.get(this); |
} |
return this.doc; |
} |
public final boolean hasODDocument() { |
return this.doc != null; |
} |
public final SpreadSheet getSpreadSheet() { |
return (SpreadSheet) this.getODDocument(); |
} |
public final TextDocument getTextDocument() { |
return (TextDocument) this.getODDocument(); |
} |
// *** getter on files |
public final Set<String> getEntries() { |
447,6 → 617,97 |
return getStyles().getDefaultStyle(desc); |
} |
/** |
* Verify that styles referenced by this document are indeed defined. NOTE this method is not |
* perfect : not all problems are detected. |
* |
* @return <code>null</code> if no problem has been found, else a String describing it. |
*/ |
public final String checkStyles() { |
final ODXMLDocument stylesDoc = this.getStyles(); |
final ODXMLDocument contentDoc = this.getContent(); |
final Element styles; |
if (stylesDoc != null) { |
styles = stylesDoc.getChild("styles"); |
// check styles.xml |
final String res = checkStyles(stylesDoc, styles); |
if (res != null) |
return res; |
} else { |
styles = contentDoc.getChild("styles"); |
} |
// check content.xml |
return checkStyles(contentDoc, styles); |
} |
static private final String checkStyles(ODXMLDocument doc, Element styles) { |
try { |
final CollectionMap<String, String> stylesNames = getStylesNames(doc, styles, doc.getChild("automatic-styles")); |
// text:style-name : text:p, text:span |
// table:style-name : table:table, table:row, table:column, table:cell |
// draw:style-name : draw:text-box |
// style:data-style-name : <style:style style:family="table-cell"> |
// TODO check by family |
final Set<String> names = new HashSet<String>(stylesNames.values()); |
final Iterator attrs = doc.getXPath(".//@text:style-name | .//@table:style-name | .//@draw:style-name | .//@style:data-style-name | .//@style:list-style-name") |
.selectNodes(doc.getDocument()).iterator(); |
while (attrs.hasNext()) { |
final Attribute attr = (Attribute) attrs.next(); |
if (!names.contains(attr.getValue())) |
return "unknown style referenced by " + attr.getName() + " in " + JDOMUtils.output(attr.getParent()); |
} |
// TODO check other references like page-*-name (§3 of #prefix()) |
} catch (IllegalStateException e) { |
return ExceptionUtils.getStackTrace(e); |
} catch (JDOMException e) { |
return ExceptionUtils.getStackTrace(e); |
} |
return null; |
} |
static private final CollectionMap<String, String> getStylesNames(final ODXMLDocument doc, final Element styles, final Element autoStyles) throws IllegalStateException { |
// section 14.1 § Style Name : style:family + style:name is unique |
final CollectionMap<String, String> res = new CollectionMap<String, String>(HashSet.class); |
final List<Element> nodes = new ArrayList<Element>(); |
if (styles != null) |
nodes.add(styles); |
if (autoStyles != null) |
nodes.add(autoStyles); |
try { |
{ |
final Iterator iter = doc.getXPath("./style:style/@style:name").selectNodes(nodes).iterator(); |
while (iter.hasNext()) { |
final Attribute attr = (Attribute) iter.next(); |
final String styleName = attr.getValue(); |
final String family = attr.getParent().getAttributeValue("family", attr.getNamespace()); |
if (res.getNonNull(family).contains(styleName)) |
throw new IllegalStateException("duplicate style in " + family + " : " + styleName); |
res.put(family, styleName); |
} |
} |
{ |
final List<String> dataStyles = Arrays.asList("number-style", "currency-style", "percentage-style", "date-style", "time-style", "boolean-style", "text-style"); |
final String xpDataStyles = org.openconcerto.utils.CollectionUtils.join(dataStyles, " | ", new ITransformer<String, String>() { |
@Override |
public String transformChecked(String input) { |
return "./number:" + input; |
} |
}); |
final Iterator listIter = doc.getXPath("./text:list-style | " + xpDataStyles).selectNodes(nodes).iterator(); |
while (listIter.hasNext()) { |
final Element elem = (Element) listIter.next(); |
res.put(elem.getQualifiedName(), elem.getAttributeValue("name", doc.getVersion().getSTYLE())); |
} |
} |
} catch (JDOMException e) { |
throw new IllegalStateException(e); |
} |
return res; |
} |
// *** setter |
public void putFile(String entry, Object data) { |
460,29 → 721,54 |
public void putFile(final String entry, final Object data, final String mediaType, final boolean compress) { |
if (entry == null) |
throw new NullPointerException("null name"); |
if (data == null) { |
this.rmFile(entry); |
return; |
} |
final Object myData; |
if (subdocNames.contains(entry)) { |
final ODXMLDocument oodoc; |
if (data instanceof Document) |
oodoc = new ODXMLDocument((Document) data); |
oodoc = ODXMLDocument.create((Document) data); |
else |
oodoc = (ODXMLDocument) data; |
// si le package est vide n'importe quelle version convient |
if (this.getVersion() != null && !oodoc.getVersion().equals(this.getVersion())) |
throw new IllegalArgumentException("version mismatch " + this.getVersion() + " != " + oodoc); |
checkEntryForDocument(entry); |
this.updateTypeAndVersion(entry, oodoc); |
myData = oodoc; |
} else if (data != null && !(data instanceof byte[])) |
} else if (!(data instanceof byte[])) { |
throw new IllegalArgumentException("should be byte[] for " + entry + ": " + data); |
else |
} else { |
if (entry.equals(MIMETYPE_ENTRY)) |
this.updateTypeAndVersion((byte[]) data); |
myData = data; |
} |
final String inferredType = mediaType != null ? mediaType : FileUtils.findMimeType(entry); |
this.files.put(entry, new ODPackageEntry(entry, inferredType, myData, compress)); |
} |
// Perhaps add a clearODDocument() method to set doc to null and in ODDocument set pkg to null |
// (after having verified !hasDocument()). For now just copy the package. |
private void checkEntryForDocument(final String entry) { |
if (this.hasODDocument() && (entry.equals(RootElement.CONTENT.getZipEntry()) || entry.equals(RootElement.STYLES.getZipEntry()))) |
throw new IllegalArgumentException("Cannot change content or styles with existing ODDocument"); |
} |
public void rmFile(String entry) { |
this.checkEntryForDocument(entry); |
this.files.remove(entry); |
if (entry.equals(MIMETYPE_ENTRY) || subdocNames.contains(entry)) { |
final Tuple3<XMLVersion, ContentTypeVersioned, XMLFormatVersion> required = this.getRequired(entry); |
this.type = required == null ? null : required.get1(); |
this.version = required == null ? null : required.get2(); |
} |
} |
public void clear() { |
this.files.clear(); |
this.type = null; |
this.version = null; |
} |
/** |
* Transform this to use a {@link ODSingleXMLDocument}. Ie after this method, only "content.xml" |
* remains and it's an instance of ODSingleXMLDocument. |
491,13 → 777,7 |
*/ |
public ODSingleXMLDocument toSingle() { |
if (!this.isSingle()) { |
// this removes xml files used by OOSingleXMLDocument |
final Document content = removeAndGetDoc(CONTENT.getZipEntry()); |
final Document styles = removeAndGetDoc(STYLES.getZipEntry()); |
final Document settings = removeAndGetDoc(SETTINGS.getZipEntry()); |
final Document meta = removeAndGetDoc(META.getZipEntry()); |
return ODSingleXMLDocument.createFromDocument(content, styles, settings, meta, this); |
return ODSingleXMLDocument.create(this); |
} else |
return (ODSingleXMLDocument) this.getContent(); |
} |
506,13 → 786,6 |
return this.getContent() instanceof ODSingleXMLDocument; |
} |
private Document removeAndGetDoc(String name) { |
if (!this.files.containsKey(name)) |
return null; |
final ODXMLDocument xmlDoc = (ODXMLDocument) this.files.remove(name).getData(); |
return xmlDoc == null ? null : xmlDoc.getDocument(); |
} |
/** |
* Split the {@link RootElement#SINGLE_CONTENT}. If this was {@link #isSingle() single} the |
* former {@link #getContent() content} won't be useable anymore, you can check it with |
554,12 → 827,12 |
final Zip z = new Zip(out); |
// magic number, see section 17.4 |
z.zipNonCompressed("mimetype", this.getMimeType().getBytes(MIMETYPE_ENC)); |
z.zipNonCompressed(MIMETYPE_ENTRY, this.getMimeType().getBytes(MIMETYPE_ENC)); |
final Manifest manifest = new Manifest(this.getVersion(), this.getMimeType()); |
for (final String name : this.files.keySet()) { |
// added at the end |
if (name.equals("mimetype") || name.equals(Manifest.ENTRY_NAME)) |
if (name.equals(MIMETYPE_ENTRY) || name.equals(Manifest.ENTRY_NAME)) |
continue; |
final ODPackageEntry entry = this.files.get(name); |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/LengthUnit.java |
---|
25,7 → 25,7 |
* Units of length. |
* |
* @author Sylvain CUAZ |
* @see http://www.w3.org/TR/xsl/#d0e5752 |
* @see <a href="http://www.w3.org/TR/xsl/#d0e5752">W3C Definitions</a> |
*/ |
public enum LengthUnit { |
/** |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODXMLDocument.java |
---|
16,6 → 16,7 |
*/ |
package org.openconcerto.openoffice; |
import org.openconcerto.openoffice.ODPackage.RootElement; |
import org.openconcerto.openoffice.spreadsheet.ColumnStyle; |
import org.openconcerto.utils.cc.IFactory; |
import org.openconcerto.xml.JDOMUtils; |
90,6 → 91,13 |
return Collections.unmodifiableSet(namePrefixes.keySet()); |
} |
public static final ODXMLDocument create(final Document doc) { |
if (RootElement.fromDocument(doc) == RootElement.SINGLE_CONTENT) |
return new ODSingleXMLDocument(doc); |
else |
return new ODXMLDocument(doc); |
} |
private final Document content; |
private final XMLFormatVersion version; |
private final ChildCreator childCreator; |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODSingleXMLDocument.java |
---|
15,13 → 15,9 |
import static org.openconcerto.openoffice.ODPackage.RootElement.CONTENT; |
import org.openconcerto.openoffice.ODPackage.RootElement; |
import org.openconcerto.openoffice.text.TextNode; |
import org.openconcerto.utils.CollectionMap; |
import org.openconcerto.utils.CopyUtils; |
import org.openconcerto.utils.ExceptionUtils; |
import org.openconcerto.utils.ProductInfo; |
import org.openconcerto.utils.cc.IFactory; |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.xml.JDOMUtils; |
import org.openconcerto.xml.SimpleXMLPath; |
import org.openconcerto.xml.Step; |
33,7 → 29,6 |
import java.net.URI; |
import java.net.URISyntaxException; |
import java.util.ArrayList; |
import java.util.Arrays; |
import java.util.HashMap; |
import java.util.HashSet; |
import java.util.Iterator; |
56,7 → 51,7 |
* |
* @author Sylvain CUAZ 24 nov. 2004 |
*/ |
public class ODSingleXMLDocument extends ODXMLDocument implements Cloneable, ODDocument { |
public class ODSingleXMLDocument extends ODXMLDocument implements Cloneable { |
final static Set<String> DONT_PREFIX; |
static { |
82,14 → 77,12 |
* @return the merged document. |
*/ |
public static ODSingleXMLDocument createFromDocument(Document content, Document style) { |
return createFromDocument(content, style, null); |
return ODPackage.createFromDocuments(content, style).toSingle(); |
} |
public static ODSingleXMLDocument createFromDocument(Document content, Document style, Document settings) { |
return createFromDocument(content, style, settings, null, new ODPackage()); |
} |
static ODSingleXMLDocument createFromDocument(Document content, Document style, Document settings, Document meta, ODPackage files) { |
static ODSingleXMLDocument create(ODPackage files) { |
final Document content = files.getContent().getDocument(); |
final Document style = files.getDocument(RootElement.STYLES.getZipEntry()); |
// signal that the xml is a complete document (was document-content) |
final Document singleContent = RootElement.createSingle(content); |
copyNS(content, singleContent); |
97,8 → 90,8 |
final Element root = singleContent.getRootElement(); |
root.addContent(content.getRootElement().removeContent()); |
// see section 2.1.1 first meta, then settings, then the rest |
prependToRoot(settings, root); |
prependToRoot(meta, root); |
prependToRoot(files.getDocument(RootElement.SETTINGS.getZipEntry()), root); |
prependToRoot(files.getDocument(RootElement.META.getZipEntry()), root); |
final ODSingleXMLDocument single = new ODSingleXMLDocument(singleContent, files); |
if (single.getChild("body") == null) |
throw new IllegalArgumentException("no body in " + single); |
139,7 → 132,6 |
* @return the merged file. |
* @throws JDOMException if the file is not a valid OpenDocument file. |
* @throws IOException if the file can't be read. |
* @see #createFromDocument(Document, Document) |
*/ |
public static ODSingleXMLDocument createFromFile(File f) throws JDOMException, IOException { |
// this loads all linked files |
266,39 → 258,11 |
return this.numero; |
} |
@Override |
public ODPackage getPackage() { |
return this.pkg; |
} |
/** |
* Append a paragraph or a heading. |
* |
* @param p paragraph to add. |
*/ |
public synchronized void add(TextNode p) { |
this.add(p, null, -1); |
} |
public synchronized void add(TextNode p, Element where, int index) { |
// add it first to avoid infinite loop, since setDocument() can call this method |
final Element addToElem = where == null ? this.getBody() : where; |
if (index < 0) |
addToElem.addContent(p.getElement()); |
else |
addToElem.addContent(index, p.getElement()); |
try { |
p.setDocument(this); |
} catch (RuntimeException e) { |
// the paragraph can throw an exception to notify that is not compatible with us (eg |
// missing styles), in that case remove it |
p.getElement().detach(); |
throw e; |
} |
} |
/** |
* Append a document. |
* |
* @param doc the document to add. |
545,77 → 509,6 |
} |
/** |
* Verify that styles referenced by this document are indeed defined. NOTE this method is not |
* perfect : not all problems are detected. |
* |
* @return <code>null</code> if no problem has been found, else a String describing it. |
*/ |
public final String checkStyles() { |
try { |
final CollectionMap<String, String> stylesNames = this.getStylesNames(); |
// text:style-name : text:p, text:span |
// table:style-name : table:table, table:row, table:column, table:cell |
// draw:style-name : draw:text-box |
// style:data-style-name : <style:style style:family="table-cell"> |
// TODO check by family |
final Set<String> names = new HashSet<String>(stylesNames.values()); |
final Iterator attrs = this.getXPath(".//@text:style-name | .//@table:style-name | .//@draw:style-name | .//@style:data-style-name | .//@style:list-style-name") |
.selectNodes(this.getDocument()).iterator(); |
while (attrs.hasNext()) { |
final Attribute attr = (Attribute) attrs.next(); |
if (!names.contains(attr.getValue())) |
return "unknown style referenced by " + attr.getName() + " in " + JDOMUtils.output(attr.getParent()); |
} |
// TODO check other references like page-*-name (§3 of #prefix()) |
} catch (IllegalStateException e) { |
return ExceptionUtils.getStackTrace(e); |
} catch (JDOMException e) { |
return ExceptionUtils.getStackTrace(e); |
} |
return null; |
} |
private final CollectionMap<String, String> getStylesNames() throws IllegalStateException { |
// section 14.1 § Style Name : style:family + style:name is unique |
final CollectionMap<String, String> res = new CollectionMap<String, String>(HashSet.class); |
final List<Element> nodes = new ArrayList<Element>(); |
nodes.add(this.getChild("styles")); |
nodes.add(this.getChild("automatic-styles")); |
try { |
{ |
final Iterator iter = this.getXPath("./style:style/@style:name").selectNodes(nodes).iterator(); |
while (iter.hasNext()) { |
final Attribute attr = (Attribute) iter.next(); |
final String styleName = attr.getValue(); |
final String family = attr.getParent().getAttributeValue("family", attr.getNamespace()); |
if (res.getNonNull(family).contains(styleName)) |
throw new IllegalStateException("duplicate style in " + family + " : " + styleName); |
res.put(family, styleName); |
} |
} |
{ |
final List<String> dataStyles = Arrays.asList("number-style", "currency-style", "percentage-style", "date-style", "time-style", "boolean-style", "text-style"); |
final String xpDataStyles = org.openconcerto.utils.CollectionUtils.join(dataStyles, " | ", new ITransformer<String, String>() { |
@Override |
public String transformChecked(String input) { |
return "./number:" + input; |
} |
}); |
final Iterator listIter = this.getXPath("./text:list-style | " + xpDataStyles).selectNodes(nodes).iterator(); |
while (listIter.hasNext()) { |
final Element elem = (Element) listIter.next(); |
res.put(elem.getQualifiedName(), elem.getAttributeValue("name", getVersion().getSTYLE())); |
} |
} |
} catch (JDOMException e) { |
throw new IllegalStateException(e); |
} |
return res; |
} |
/** |
* Préfixe les attributs en ayant besoin. |
* |
* @param elem l'élément à préfixer. |
822,13 → 715,13 |
final Map<RootElement, Document> res = new HashMap<RootElement, Document>(); |
final XMLVersion version = getVersion(); |
final Element root = this.getDocument().getRootElement(); |
final String officeVersion = getFormatVersion().getOfficeVersion(); |
final XMLFormatVersion officeVersion = getFormatVersion(); |
// meta |
{ |
final Element thisMeta = root.getChild("meta", version.getOFFICE()); |
if (thisMeta != null) { |
final Document meta = createDocument(res, RootElement.META, version, officeVersion); |
final Document meta = createDocument(res, RootElement.META, officeVersion); |
meta.getRootElement().addContent(thisMeta.detach()); |
} |
} |
836,7 → 729,7 |
{ |
final Element thisSettings = root.getChild("settings", version.getOFFICE()); |
if (thisSettings != null) { |
final Document settings = createDocument(res, RootElement.SETTINGS, version, officeVersion); |
final Document settings = createDocument(res, RootElement.SETTINGS, officeVersion); |
settings.getRootElement().addContent(thisSettings.detach()); |
} |
} |
843,7 → 736,7 |
// styles |
// we must move office:styles, office:master-styles and referenced office:automatic-styles |
{ |
final Document styles = createDocument(res, RootElement.STYLES, version, officeVersion); |
final Document styles = createDocument(res, RootElement.STYLES, officeVersion); |
// don't bother finding out which font is used where since there isn't that many of them |
styles.getRootElement().addContent((Element) root.getChild(getFontDecls()[0], version.getOFFICE()).clone()); |
// extract common styles |
874,7 → 767,7 |
// content |
{ |
this.pkg = null; |
final Document content = createDocument(res, RootElement.CONTENT, version, officeVersion); |
final Document content = createDocument(res, RootElement.CONTENT, officeVersion); |
getContentTypeVersioned().setType(content); |
content.getRootElement().addContent(root.removeContent()); |
} |
881,8 → 774,8 |
return res; |
} |
private Document createDocument(final Map<RootElement, Document> res, RootElement rootElement, final XMLVersion version, final String officeVersion) { |
final Document doc = rootElement.createDocument(version, officeVersion); |
private Document createDocument(final Map<RootElement, Document> res, RootElement rootElement, final XMLFormatVersion version) { |
final Document doc = rootElement.createDocument(version); |
copyNS(this.getDocument(), doc); |
res.put(rootElement, doc); |
return doc; |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/RepeatedBreaker.java |
---|
New file |
0,0 → 1,97 |
/* |
* 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.openoffice.spreadsheet; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.ODNode; |
import java.util.List; |
import org.jdom.Element; |
abstract class RepeatedBreaker<P, C extends ODNode> { |
@SuppressWarnings("rawtypes") |
static private final RepeatedBreaker CELL_BREAKER = new RepeatedBreaker<Row<?>, Cell<?>>("number-columns-repeated") { |
@Override |
Cell<?> create(Element elem, Row<?> parent, int index, boolean single) { |
return createD(elem, parent, index, single); |
} |
<D extends ODDocument> Cell<D> createD(Element elem, Row<D> parent, int index, boolean single) { |
return single ? new MutableCell<D>(parent, elem, parent.getSheet().getCellStyleDesc()) : new Cell<D>(parent, elem, parent.getSheet().getCellStyleDesc()); |
} |
}; |
@SuppressWarnings("rawtypes") |
static private final RepeatedBreaker ROW_BREAKER = new RepeatedBreaker<Table<?>, Row<?>>(Axis.ROW.getRepeatedAttrName()) { |
@Override |
Row<?> create(Element elem, Table<?> parent, int index, boolean single) { |
return createD(elem, parent, index, single); |
} |
<D extends ODDocument> Row<D> createD(Element elem, Table<D> parent, int index, boolean single) { |
return new Row<D>(parent, elem, index, parent.getRowStyleDesc(), parent.getCellStyleDesc()); |
} |
}; |
@SuppressWarnings("unchecked") |
static final <D extends ODDocument> RepeatedBreaker<Row<D>, Cell<D>> getCellBreaker() { |
return (RepeatedBreaker<Row<D>, Cell<D>>) CELL_BREAKER; |
} |
@SuppressWarnings("unchecked") |
static final <D extends ODDocument> RepeatedBreaker<Table<D>, Row<D>> getRowBreaker() { |
return (RepeatedBreaker<Table<D>, Row<D>>) ROW_BREAKER; |
} |
private final String attrName; |
public RepeatedBreaker(final String attrName) { |
this.attrName = attrName; |
} |
abstract C create(final Element elem, final P parent, final int index, final boolean single); |
public final void breakRepeated(final P parent, final List<C> children, final int col) { |
final C c = children.get(col); |
final Element element = c.getElement(); |
final String repeatedS = element.getAttributeValue(this.attrName, element.getNamespace()); |
if (repeatedS != null) { |
final int repeated = Integer.parseInt(repeatedS); |
final int firstIndex = children.indexOf(c); |
final int lastIndex = firstIndex + repeated - 1; |
final int preRepeated = col - firstIndex; |
final int postRepeated = lastIndex - col; |
breakRepeated(parent, children, element, firstIndex, preRepeated, true); |
element.removeAttribute(this.attrName, element.getNamespace()); |
breakRepeated(parent, children, element, col + 1, postRepeated, false); |
} |
children.set(col, this.create(element, parent, col, true)); |
} |
private final void breakRepeated(final P parent, final List<C> children, Element element, int firstIndex, int repeat, boolean before) { |
if (repeat > 0) { |
final Element newElem = (Element) element.clone(); |
element.getParentElement().addContent(element.getParent().indexOf(element) + (before ? 0 : 1), newElem); |
newElem.setAttribute(this.attrName, repeat + "", element.getNamespace()); |
final C preCell = this.create(newElem, parent, firstIndex, false); |
for (int i = 0; i < repeat; i++) { |
children.set(firstIndex + i, preCell); |
} |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Table.java |
---|
16,6 → 16,7 |
import org.openconcerto.openoffice.LengthUnit; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.Style; |
import org.openconcerto.openoffice.StyleDesc; |
import org.openconcerto.openoffice.StyleStyleDesc; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.SheetTableModel.MutableTableModel; |
30,7 → 31,6 |
import java.util.HashMap; |
import java.util.HashSet; |
import java.util.List; |
import java.util.ListIterator; |
import java.util.Map; |
import java.util.Set; |
import java.util.regex.Matcher; |
60,92 → 60,105 |
} |
// ATTN Row have their index as attribute |
private final List<Row<D>> rows; |
private int headerRowCount; |
private final List<Column<D>> cols; |
private int headerColumnCount; |
private final ArrayList<Row<D>> rows; |
private TableGroup rowGroup; |
private final ArrayList<Column<D>> cols; |
private TableGroup columnGroup; |
public Table(D parent, Element local) { |
super(parent, local, TableStyle.class); |
this.rows = new ArrayList<Row<D>>(); |
this.cols = new ArrayList<Column<D>>(); |
this.rows = new ArrayList<Row<D>>(64); |
this.cols = new ArrayList<Column<D>>(32); |
// read columns first since Row constructor needs it |
this.readColumns(); |
this.readRows(); |
} |
private void readColumns() { |
this.read(true); |
this.read(Axis.COLUMN); |
} |
private final void readRows() { |
this.read(false); |
this.read(Axis.ROW); |
} |
private final void read(final boolean col) { |
final Tuple2<List<Element>, Integer> r = flatten(col); |
(col ? this.cols : this.rows).clear(); |
for (final Element clone : r.get0()) { |
if (col) |
this.addCol(clone); |
else |
this.addRow(clone); |
private final void read(final Axis axis) { |
final boolean col = axis == Axis.COLUMN; |
final Tuple2<TableGroup, List<Element>> r = TableGroup.createRoot(this, axis); |
final ArrayList<?> l = col ? this.cols : this.rows; |
final int oldSize = l.size(); |
l.clear(); |
final int newSize = r.get0().getSize(); |
l.ensureCapacity(newSize); |
if (col) { |
final StyleStyleDesc<ColumnStyle> colStyleDesc = getColumnStyleDesc(); |
for (final Element clone : r.get1()) |
this.addCol(clone, colStyleDesc); |
this.columnGroup = r.get0(); |
} else { |
final StyleStyleDesc<RowStyle> rowStyleDesc = getRowStyleDesc(); |
final StyleStyleDesc<CellStyle> cellStyleDesc = getCellStyleDesc(); |
for (final Element clone : r.get1()) |
this.addRow(clone, rowStyleDesc, cellStyleDesc); |
this.rowGroup = r.get0(); |
} |
if (col) |
this.headerColumnCount = r.get1(); |
else |
this.headerRowCount = r.get1(); |
// this always copy the array, so make sure we reclaim enough memory (~ 64k) |
if (oldSize - newSize > 8192) { |
l.trimToSize(); |
} |
assert newSize == (col ? this.getColumnCount() : this.getRowCount()); |
} |
private final void addCol(Element clone) { |
this.cols.add(new Column<D>(this, clone)); |
private final void addCol(Element clone, StyleStyleDesc<ColumnStyle> colStyleDesc) { |
this.cols.add(new Column<D>(this, clone, colStyleDesc)); |
} |
private Tuple2<List<Element>, Integer> flatten(boolean col) { |
final List<Element> res = new ArrayList<Element>(); |
final Element header = this.getElement().getChild("table-header-" + getName(col) + "s", getTABLE()); |
if (header != null) |
res.addAll(flatten(header, col)); |
final int headerCount = res.size(); |
static final int flattenChildren(final List<Element> res, final Element elem, final Axis axis) { |
int count = 0; |
// array so that flatten1() can modify an int |
int[] index = new int[] { 0 }; |
// copy since we will change our children (don't use List.listIterator(int) since it |
// re-filters all content) |
@SuppressWarnings("unchecked") |
final List<Element> children = new ArrayList<Element>(elem.getChildren(axis.getElemName(), elem.getNamespace())); |
final int stop = children.size(); |
for (int i = 0; i < stop; i++) { |
final Element row = children.get(i); |
count += flatten1(res, row, axis, index); |
} |
return count; |
} |
res.addAll(flatten(getElement(), col)); |
return Tuple2.create(res, headerCount); |
static int flatten1(final List<Element> res, final Element row, final Axis axis) { |
return flatten1(res, row, axis, null); |
} |
@SuppressWarnings("unchecked") |
private List<Element> flatten(final Element elem, boolean col) { |
final String childName = getName(col); |
final List<Element> children = elem.getChildren("table-" + childName, getTABLE()); |
// not final, since iter.add() does not work consistently, and |
// thus we must recreate an iterator each time |
ListIterator<Element> iter = children.listIterator(); |
while (iter.hasNext()) { |
final Element row = iter.next(); |
final Attribute repeatedAttr = row.getAttribute("number-" + childName + "s-repeated", getTABLE()); |
if (repeatedAttr != null) { |
// add XML elements to res and return the logical count |
private static int flatten1(final List<Element> res, final Element row, final Axis axis, final int[] parentIndex) { |
final int resSize = res.size(); |
final Attribute repeatedAttr = axis.getRepeatedAttr(row); |
final int repeated = repeatedAttr == null ? 1 : Integer.parseInt(repeatedAttr.getValue()); |
if (axis == Axis.COLUMN && repeated > 1) { |
row.removeAttribute(repeatedAttr); |
final int index = iter.previousIndex(); |
int repeated = Integer.parseInt(repeatedAttr.getValue()); |
if (repeated > 60000) { |
repeated = 10; |
} |
final Element parent = row.getParentElement(); |
final int index = (parentIndex == null ? parent.indexOf(row) : parentIndex[0]) + 1; |
res.add(row); |
// -1 : we keep the original row |
for (int i = 0; i < repeated - 1; i++) { |
final Element clone = (Element) row.clone(); |
// cannot use iter.add() since on JDOM 1.1 if row is the last table-column |
// before table-row the clone is added at the very end |
children.add(index, clone); |
res.add(clone); |
parent.addContent(index + i, clone); |
} |
// restart after the added rows |
iter = children.listIterator(index + repeated); |
} else { |
res.add(row); |
} |
if (parentIndex != null) |
parentIndex[0] += res.size() - resSize; |
return repeated; |
} |
return children; |
} |
public final String getName() { |
return getName(this.getElement()); |
} |
158,10 → 171,6 |
this.getElement().detach(); |
} |
private final String getName(boolean col) { |
return col ? "column" : "row"; |
} |
public final Object getPrintRanges() { |
return this.getElement().getAttributeValue("print-ranges", this.getTABLE()); |
} |
235,14 → 244,38 |
// clone xml elements and add them to our tree |
final List<Element> clones = new ArrayList<Element>(count * copies); |
for (int i = 0; i < copies; i++) { |
for (int l = start; l < stop; l++) { |
final Element r = this.rows.get(l).getElement(); |
clones.add((Element) r.clone()); |
for (int l = start; l < stop;) { |
final Row<D> immutableRow = this.getRow(l); |
final Row<D> toClone; |
// MAYBE use something else than getMutableRow() since we don't need a single row. |
// the repeated row starts before the copied range, split it at the beginning |
if (immutableRow.getY() < l) { |
toClone = this.getMutableRow(l); |
} else { |
assert immutableRow.getY() == l; |
if (immutableRow.getLastY() >= stop) { |
// the repeated row goes beyond the copied range, split it at the end |
assert this.getRow(stop) == immutableRow; |
this.getMutableRow(stop); |
toClone = this.getRow(l); |
} else { |
toClone = immutableRow; |
} |
} |
assert toClone.getY() == l; |
assert toClone.getLastY() < stop : "Row goes to far"; |
l += toClone.getRepeated(); |
clones.add((Element) toClone.getElement().clone()); |
} |
final int clonesSize = clones.size(); |
for (int i = 1; i < copies; i++) { |
for (int j = 0; j < clonesSize; j++) { |
clones.add((Element) clones.get(j).clone()); |
} |
} |
// works anywhere its XML element is |
JDOMUtils.insertAfter(this.rows.get(stop - 1).getElement(), clones); |
assert this.getRow(stop - 1).getLastY() == stop - 1 : "Adding XML element too far"; |
JDOMUtils.insertAfter(this.getRow(stop - 1).getElement(), clones); |
for (final Point coverOrigin : coverOriginsToUpdate) { |
final MutableCell<D> coveringCell = getCellAt(coverOrigin); |
249,7 → 282,7 |
coveringCell.setRowsSpanned(coveringCell.getRowsSpanned() + count * copies); |
} |
// synchronize our rows with our new tree |
// synchronize our rows with our new tree (rows' index have changed) |
this.readRows(); |
// 19.627 in OpenDocument-v1.2-cs01-part1 : The table:end-cell-address attribute specifies |
323,9 → 356,13 |
} |
} |
private synchronized void addRow(Element child) { |
this.rows.add(new Row<D>(this, child, this.rows.size())); |
private synchronized void addRow(Element child, StyleDesc<RowStyle> styleDesc, StyleDesc<CellStyle> cellStyleDesc) { |
final Row<D> row = new Row<D>(this, child, this.rows.size(), styleDesc, cellStyleDesc); |
final int toRepeat = row.getRepeated(); |
for (int i = 0; i < toRepeat; i++) { |
this.rows.add(row); |
} |
} |
public final Point resolveHint(String ref) { |
final Point res = resolve(ref); |
346,8 → 383,18 |
return this.getImmutableCellAt(x, y).isValid(); |
} |
/** |
* Return a modifiable cell at the passed coordinates. This is slower than |
* {@link #getImmutableCellAt(int, int)} since this method may modify the underlying XML (e.g. |
* break up repeated cells to allow for modification of only the returned cell). |
* |
* @param x the column. |
* @param y the row. |
* @return the cell. |
* @see #getImmutableCellAt(int, int) |
*/ |
public final MutableCell<D> getCellAt(int x, int y) { |
return this.getRow(y).getMutableCellAt(x); |
return this.getMutableRow(y).getMutableCellAt(x); |
} |
public final MutableCell<D> getCellAt(String ref) { |
375,11 → 422,20 |
// *** get cell |
protected final Cell<D> getImmutableCellAt(int x, int y) { |
/** |
* Return a non modifiable cell at the passed coordinates. This is faster than |
* {@link #getCellAt(int, int)} since this method never modifies the underlying XML. |
* |
* @param x the column. |
* @param y the row. |
* @return the cell. |
* @see #getCellAt(int, int) |
*/ |
public final Cell<D> getImmutableCellAt(int x, int y) { |
return this.getRow(y).getCellAt(x); |
} |
protected final Cell<D> getImmutableCellAt(String ref) { |
public final Cell<D> getImmutableCellAt(String ref) { |
final Point p = resolveHint(ref); |
return this.getImmutableCellAt(p.x, p.y); |
} |
457,7 → 513,7 |
} |
public final CellStyle getStyleAt(int column, int row) { |
return getCellStyleDesc().findStyle(this.getODDocument().getPackage(), this.getElement().getDocument(), this.getStyleNameAt(column, row)); |
return getCellStyleDesc().findStyleForNode(this.getImmutableCellAt(column, row), this.getStyleNameAt(column, row)); |
} |
protected StyleStyleDesc<CellStyle> getCellStyleDesc() { |
506,6 → 562,14 |
return res; |
} |
protected final StyleStyleDesc<ColumnStyle> getColumnStyleDesc() { |
return Style.getStyleStyleDesc(ColumnStyle.class, XMLVersion.getVersion(getElement())); |
} |
protected final StyleStyleDesc<RowStyle> getRowStyleDesc() { |
return Style.getStyleStyleDesc(RowStyle.class, XMLVersion.getVersion(getElement())); |
} |
/** |
* Retourne la valeur de la cellule spécifiée. |
* |
518,10 → 582,20 |
// *** get count |
private Row<D> getRow(int index) { |
final Row<D> getRow(int index) { |
return this.rows.get(index); |
} |
final Row<D> getMutableRow(int y) { |
final Row<D> c = this.getRow(y); |
if (c.getRepeated() > 1) { |
RepeatedBreaker.<D> getRowBreaker().breakRepeated(this, this.rows, y); |
return this.getRow(y); |
} else { |
return c; |
} |
} |
public final Column<D> getColumn(int i) { |
return this.cols.get(i); |
} |
530,8 → 604,22 |
return this.rows.size(); |
} |
public final TableGroup getRowGroup() { |
return this.rowGroup; |
} |
/** |
* Return the deepest group at the passed row. |
* |
* @param y a row index. |
* @return the group at the index, never <code>null</code>. |
*/ |
public final TableGroup getRowGroupAt(final int y) { |
return this.getRowGroup().getDescendentOrSelfContaining(y); |
} |
public final int getHeaderRowCount() { |
return this.headerRowCount; |
return this.getRowGroup().getFollowingHeaderCount(); |
} |
public final int getColumnCount() { |
538,8 → 626,22 |
return this.cols.size(); |
} |
public final TableGroup getColumnGroup() { |
return this.columnGroup; |
} |
/** |
* Return the deepest group at the passed column. |
* |
* @param x a column index. |
* @return the group at the index, never <code>null</code>. |
*/ |
public final TableGroup getColumnGroupAt(final int x) { |
return this.getColumnGroup().getDescendentOrSelfContaining(x); |
} |
public final int getHeaderColumnCount() { |
return this.headerColumnCount; |
return this.getColumnGroup().getFollowingHeaderCount(); |
} |
// *** set count |
595,17 → 697,22 |
} else { |
elemToClone = getColumn(colIndex).getElement(); |
} |
final StyleStyleDesc<ColumnStyle> columnStyleDesc = getColumnStyleDesc(); |
for (int i = 0; i < toGrow; i++) { |
final Element newElem = (Element) elemToClone.clone(); |
this.getElement().addContent(indexOfLastCol + 1 + i, newElem); |
this.cols.add(new Column<D>(this, newElem)); |
this.cols.add(new Column<D>(this, newElem, columnStyleDesc)); |
} |
// now update widths |
updateWidth(keepTableWidth); |
// add needed cells |
for (final Row r : this.rows) { |
r.columnCountChanged(); |
final StyleStyleDesc<CellStyle> cellStyleDesc = this.getCellStyleDesc(); |
final int rowCount = this.getRowCount(); |
for (int i = 0; i < rowCount;) { |
final Row<D> r = this.getRow(i); |
r.columnCountChanged(cellStyleDesc); |
i += r.getRepeated(); |
} |
} |
} |
629,16 → 736,21 |
*/ |
public final void removeColumn(int firstIndex, int lastIndex, final boolean keepTableWidth) { |
// first check that removeCells() will succeed, so that we avoid an incoherent XML state |
for (final Row r : this.rows) { |
final int rowCount = this.getRowCount(); |
for (int i = 0; i < rowCount;) { |
final Row<D> r = this.getRow(i); |
r.checkRemove(firstIndex, lastIndex); |
i += r.getRepeated(); |
} |
// rm column element |
remove(true, firstIndex, lastIndex - 1); |
remove(Axis.COLUMN, firstIndex, lastIndex - 1); |
// update widths |
updateWidth(keepTableWidth); |
// rm cells |
for (final Row r : this.rows) { |
for (int i = 0; i < rowCount;) { |
final Row<D> r = this.getRow(i); |
r.removeCells(firstIndex, lastIndex); |
i += r.getRepeated(); |
} |
} |
709,20 → 821,41 |
return colStyle; |
} |
private final void setCount(final boolean col, final int newSize) { |
private final void setCount(final Axis col, final int newSize) { |
this.remove(col, newSize, -1); |
} |
// both inclusive |
private final void remove(final boolean col, final int fromIndex, final int toIndexIncl) { |
// ok since rows and cols are flattened in ctor |
final List<? extends TableCalcNode> l = col ? this.cols : this.rows; |
private final void remove(final Axis col, final int fromIndex, final int toIndexIncl) { |
assert col == Axis.COLUMN || toIndexIncl < 0 : "Row index will be wrong"; |
final List<? extends TableCalcNode<?, ?>> l = col == Axis.COLUMN ? this.cols : this.rows; |
final int toIndexValid = CollectionUtils.getValidIndex(l, toIndexIncl); |
for (int i = toIndexValid; i >= fromIndex; i--) { |
// works anywhere its XML element is |
l.remove(i).getElement().detach(); |
final int toRemoveCount = toIndexValid - fromIndex + 1; |
int removedCount = 0; |
while (removedCount < toRemoveCount) { |
// works backwards to keep y OK |
final int i = toIndexValid - removedCount; |
final TableCalcNode<?, ?> removed = l.get(i); |
if (removed instanceof Row) { |
final Row<?> r = (Row<?>) removed; |
final int removeFromRepeated = i - Math.max(fromIndex, r.getY()) + 1; |
// removedCount grows each iteration |
assert removeFromRepeated > 0; |
final int newRepeated = r.getRepeated() - removeFromRepeated; |
if (newRepeated == 0) |
removed.getElement().detach(); |
else |
r.setRepeated(newRepeated); |
removedCount += removeFromRepeated; |
} else { |
// Columns are always flattened |
removed.getElement().detach(); |
removedCount++; |
} |
} |
// one remove to be efficient |
l.subList(fromIndex, toIndexValid + 1).clear(); |
} |
public final void ensureRowCount(int newSize) { |
if (newSize > this.getRowCount()) |
741,25 → 874,24 |
* @param rowIndex the index of the row to be copied, -1 for empty row (i.e. default style). |
*/ |
public final void setRowCount(int newSize, int rowIndex) { |
final int toGrow = newSize - this.getRowCount(); |
if (toGrow < 0) { |
setCount(Axis.ROW, newSize); |
} else if (toGrow > 0) { |
final Element elemToClone; |
if (rowIndex < 0) { |
elemToClone = Row.createEmpty(this.getODDocument().getVersion()); |
// each row MUST have the same number of columns |
elemToClone.addContent(Cell.createEmpty(this.getODDocument().getVersion(), this.getColumnCount())); |
} else |
elemToClone = getRow(rowIndex).getElement(); |
final int toGrow = newSize - this.getRowCount(); |
if (toGrow < 0) { |
setCount(false, newSize); |
} else { |
for (int i = 0; i < toGrow; i++) { |
final Element newElem = (Element) elemToClone.clone(); |
elemToClone = (Element) getRow(rowIndex).getElement().clone(); |
} |
Axis.ROW.setRepeated(elemToClone, toGrow); |
// as per section 8.1.1 rows are the last elements inside a table |
this.getElement().addContent(newElem); |
addRow(newElem); |
this.getElement().addContent(elemToClone); |
addRow(elemToClone, getRowStyleDesc(), getCellStyleDesc()); |
} |
} |
} |
// *** table models |
948,7 → 1080,7 |
public final Range getCurrentRegion() { |
while (this.checkFrame()) |
;// bounded by table size |
return new Range(getName(), new Point(minX, minY), new Point(maxX, maxY)); |
return new Range(getName(), new Point(this.minX, this.minY), new Point(this.maxX, this.maxY)); |
} |
} |
968,7 → 1100,8 |
* @param startX x coordinate. |
* @param startY y coordinate. |
* @return the smallest range containing the passed cell. |
* @see http://msdn.microsoft.com/library/aa214248(v=office.11).aspx |
* @see <a href="http://msdn.microsoft.com/library/aa214248(v=office.11).aspx">CurrentRegion |
* Property</a> |
*/ |
public final Range getCurrentRegion(final int startX, final int startY) { |
return this.getCurrentRegion(startX, startY, false); |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/MutableCell.java |
---|
18,11 → 18,13 |
import org.openconcerto.openoffice.ODFrame; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.OOXML; |
import org.openconcerto.openoffice.StyleDesc; |
import org.openconcerto.openoffice.spreadsheet.BytesProducer.ByteArrayProducer; |
import org.openconcerto.openoffice.spreadsheet.BytesProducer.ImageProducer; |
import org.openconcerto.openoffice.style.data.DataStyle; |
import org.openconcerto.utils.ExceptionUtils; |
import org.openconcerto.utils.FileUtils; |
import org.openconcerto.utils.Tuple3; |
import java.awt.Color; |
import java.awt.Image; |
36,6 → 38,9 |
import java.util.Date; |
import java.util.List; |
import javax.xml.datatype.DatatypeConstants; |
import javax.xml.datatype.Duration; |
import org.jdom.Attribute; |
import org.jdom.Element; |
import org.jdom.Namespace; |
51,6 → 56,7 |
static private final DateFormat TextPDateFormat = DateFormat.getDateInstance(); |
static private final DateFormat TextPTimeFormat = DateFormat.getTimeInstance(); |
static private final NumberFormat TextPMinuteSecondFormat = new DecimalFormat("00.###"); |
static private final NumberFormat TextPFloatFormat = DecimalFormat.getNumberInstance(); |
static private final NumberFormat TextPPercentFormat = DecimalFormat.getPercentInstance(); |
static private final NumberFormat TextPCurrencyFormat = DecimalFormat.getCurrencyInstance(); |
76,8 → 82,8 |
} |
} |
MutableCell(Row<D> parent, Element elem) { |
super(parent, elem); |
MutableCell(Row<D> parent, Element elem, StyleDesc<CellStyle> styleDesc) { |
super(parent, elem, styleDesc); |
} |
// ask our column to our row so we don't have to update anything when columns are removed/added |
142,6 → 148,10 |
} |
public void setValue(Object obj) { |
this.setValue(obj, true); |
} |
public void setValue(Object obj, final boolean allowTypeChange) throws UnsupportedOperationException { |
final ODValueType type; |
final ODValueType currentType = getValueType(); |
// try to keep current type, since for example a Number can work with FLOAT, PERCENTAGE |
148,18 → 158,13 |
// and CURRENCY |
if (currentType != null && currentType.canFormat(obj.getClass())) { |
type = currentType; |
} else if (obj instanceof Number) { |
type = ODValueType.FLOAT; |
} else if (obj instanceof Date || obj instanceof Calendar) { |
type = ODValueType.DATE; |
} else if (obj instanceof Boolean) { |
type = ODValueType.BOOLEAN; |
} else if (obj instanceof String) { |
type = ODValueType.STRING; |
} else { |
type = ODValueType.forObject(obj); |
} |
if (type == null) { |
throw new IllegalArgumentException("Couldn't infer type of " + obj); |
} |
this.setValue(obj, type, true); |
this.setValue(obj, type, allowTypeChange, true); |
} |
/** |
167,16 → 172,20 |
* |
* @param obj the new cell value. |
* @param vt the value type. |
* @param allowTypeChange if <code>true</code> <code>obj</code> and <code>vt</code> might be |
* changed to allow the data style to format, e.g. from Boolean.FALSE to 0. |
* @param lenient <code>false</code> to throw an exception if we can't format according to the |
* ODF, <code>true</code> to try best-effort. |
* @throws UnsupportedOperationException if <code>obj</code> couldn't be formatted. |
*/ |
public void setValue(final Object obj, final ODValueType vt, final boolean lenient) throws UnsupportedOperationException { |
public void setValue(Object obj, ODValueType vt, final boolean allowTypeChange, final boolean lenient) throws UnsupportedOperationException { |
final String text; |
final String formatted = format(obj, lenient); |
final Tuple3<String, ODValueType, Object> formatted = format(obj, vt, !allowTypeChange, lenient); |
vt = formatted.get1(); |
obj = formatted.get2(); |
if (formatted != null) { |
text = formatted; |
if (formatted.get0() != null) { |
text = formatted.get0(); |
} else { |
// either there were no format or formatting failed |
if (vt == ODValueType.FLOAT) { |
186,9 → 195,21 |
} else if (vt == ODValueType.CURRENCY) { |
text = formatCurrency((Number) obj, getDefaultStyle()); |
} else if (vt == ODValueType.DATE) { |
text = TextPDateFormat.format(obj); |
final Date d; |
if (obj instanceof Calendar) { |
d = ((Calendar) obj).getTime(); |
} else { |
d = (Date) obj; |
} |
text = TextPDateFormat.format(d); |
} else if (vt == ODValueType.TIME) { |
text = TextPTimeFormat.format(obj); |
if (obj instanceof Duration) { |
final Duration normalized = getODDocument().getEpoch().normalizeToHours((Duration) obj); |
text = "" + normalized.getHours() + ':' + TextPMinuteSecondFormat.format(normalized.getMinutes()) + ':' |
+ TextPMinuteSecondFormat.format(normalized.getField(DatatypeConstants.SECONDS)); |
} else { |
text = TextPTimeFormat.format(((Calendar) obj).getTime()); |
} |
} else if (vt == ODValueType.BOOLEAN) { |
if (lenient) |
text = obj.toString(); |
203,14 → 224,19 |
this.setValue(vt, obj, text); |
} |
// return null if no data style exists, or if one exists but we couldn't use it |
private String format(Object obj, boolean lenient) { |
// return null String if no data style exists, or if one exists but we couldn't use it |
private Tuple3<String, ODValueType, Object> format(Object obj, ODValueType valueType, boolean onlyCast, boolean lenient) { |
String res = null; |
try { |
final DataStyle ds = getDataStyle(); |
final Tuple3<DataStyle, ODValueType, Object> ds = getDataStyleAndValue(obj, valueType, onlyCast); |
if (ds != null) { |
obj = ds.get2(); |
valueType = ds.get1(); |
// act like OO, that is if we set a String to a Date cell, change the value and |
// value-type but leave the data-style untouched |
if (ds != null && ds.canFormat(obj.getClass())) |
return ds.format(obj, getDefaultStyle(), lenient); |
if (ds.get0().canFormat(obj.getClass())) |
res = ds.get0().format(obj, getDefaultStyle(), lenient); |
} |
} catch (UnsupportedOperationException e) { |
if (lenient) |
Log.get().warning(ExceptionUtils.getStackTrace(e)); |
217,12 → 243,17 |
else |
throw e; |
} |
return null; |
return Tuple3.create(res, valueType, obj); |
} |
public final DataStyle getDataStyle() { |
final Tuple3<DataStyle, ODValueType, Object> s = this.getDataStyleAndValue(this.getValue(), this.getValueType(), true); |
return s != null ? s.get0() : null; |
} |
private final Tuple3<DataStyle, ODValueType, Object> getDataStyleAndValue(Object obj, ODValueType valueType, boolean onlyCast) { |
final CellStyle s = this.getStyle(); |
return s != null ? getStyle().getDataStyle() : null; |
return s != null ? getStyle().getDataStyle(obj, valueType, onlyCast) : null; |
} |
protected final CellStyle getDefaultStyle() { |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Column.java |
---|
14,6 → 14,7 |
package org.openconcerto.openoffice.spreadsheet; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.StyleStyleDesc; |
import org.openconcerto.openoffice.XMLVersion; |
import org.jdom.Element; |
30,8 → 31,8 |
return res; |
} |
public Column(final Table<D> parent, Element tableColElem) { |
super(parent.getODDocument(), tableColElem, ColumnStyle.class); |
public Column(final Table<D> parent, Element tableColElem, StyleStyleDesc<ColumnStyle> colStyleDesc) { |
super(parent.getODDocument(), tableColElem, colStyleDesc); |
} |
public final Float getWidth() { |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/CellStyle.java |
---|
13,23 → 13,44 |
package org.openconcerto.openoffice.spreadsheet; |
import org.openconcerto.openoffice.Log; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.Style; |
import org.openconcerto.openoffice.StyleStyle; |
import org.openconcerto.openoffice.StyleStyleDesc; |
import org.openconcerto.openoffice.StyledNode; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.style.RelationalOperator; |
import org.openconcerto.openoffice.style.SideStyleProperties; |
import org.openconcerto.openoffice.style.data.BooleanStyle; |
import org.openconcerto.openoffice.style.data.DataStyle; |
import org.openconcerto.openoffice.style.data.NumberStyle; |
import org.openconcerto.openoffice.text.ParagraphStyle.StyleParagraphProperties; |
import org.openconcerto.openoffice.text.TextStyle.StyleTextProperties; |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.utils.Tuple3; |
import org.openconcerto.xml.JDOMUtils; |
import java.awt.Color; |
import java.math.BigDecimal; |
import java.util.Arrays; |
import java.util.List; |
import java.util.regex.Matcher; |
import java.util.regex.Pattern; |
import org.jdom.Attribute; |
import org.jdom.Element; |
public class CellStyle extends StyleStyle { |
private static final Pattern numberPatrn = Pattern.compile("-?\\d+(?:\\.\\d+)?"); |
private static final Pattern escapedQuotePatrn = Pattern.compile("\"\"", Pattern.LITERAL); |
private static final Pattern stringPatrn = Pattern.compile("\"(?:[^\\p{Cntrl}\"]|\\p{Space}|" + escapedQuotePatrn.pattern() + ")*\""); |
private static final String valuePatrn = "(" + numberPatrn.pattern() + "|" + stringPatrn.pattern() + ")"; |
private static final Pattern cellContentPatrn = Pattern.compile("cell-content\\(\\) *(" + RelationalOperator.OR_PATTERN + ") *" + valuePatrn + ""); |
private static final Pattern cellContentBetweenPatrn = Pattern.compile("cell-content-is(?:-not)?-between\\(" + valuePatrn + ", *" + valuePatrn + "\\)"); |
// from section 18.728 in v1.2-part1 |
public static final StyleStyleDesc<CellStyle> DESC = new StyleStyleDesc<CellStyle>(CellStyle.class, XMLVersion.OD, "table-cell", "ce", "table", Arrays.asList("table:body", |
"table:covered-table-cell", "table:even-rows", "table:first-column", "table:first-row", "table:last-column", "table:last-row", "table:odd-columns", "table:odd-rows", "table:table-cell")) { |
42,8 → 63,54 |
public CellStyle create(ODPackage pkg, Element e) { |
return new CellStyle(pkg, e); |
} |
@Override |
protected boolean supportConditions() { |
return true; |
} |
@Override |
protected Element evaluateConditions(final StyledNode<CellStyle, ?> styledNode, final List<Element> styleMaps) { |
final Cell<?> cell = (Cell<?>) styledNode; |
final Object cellValue = cell.getValue(); |
for (final Element styleMap : styleMaps) { |
final String condition = styleMap.getAttributeValue("condition", getVersion().getSTYLE()).trim(); |
Matcher matcher = cellContentPatrn.matcher(condition); |
if (matcher.matches()) { |
if (RelationalOperator.getInstance(matcher.group(1)).compare(cellValue, parse(matcher.group(2)))) |
return styleMap; |
} else if ((matcher = cellContentBetweenPatrn.matcher(condition)).matches()) { |
final boolean wantBetween = condition.startsWith("cell-content-is-between"); |
assert wantBetween ^ condition.startsWith("cell-content-is-not-between"); |
final Object o1 = parse(matcher.group(1)); |
final Object o2 = parse(matcher.group(2)); |
final boolean isBetween = CompareUtils.compare(cellValue, o1) >= 0 && CompareUtils.compare(cellValue, o2) <= 0; |
if (isBetween == wantBetween) |
return styleMap; |
} else { |
// If a consumer does not recognize a condition, it shall ignore the <style:map> |
// element containing the condition. |
Log.get().fine("Ignoring " + JDOMUtils.output(styleMap)); |
} |
} |
return null; |
} |
}; |
private static final Pattern conditionPatrn = Pattern.compile("value\\(\\) *(" + RelationalOperator.OR_PATTERN + ") *(true|false|" + numberPatrn.pattern() + ")"); |
// from style:condition : |
// "n is a number for non-Boolean data styles and true or false for Boolean data styles" |
private static final Object convertForCondition(final Object value, final DataStyle style) { |
final Object castedValue; |
if (style instanceof BooleanStyle) { |
castedValue = BooleanStyle.toBoolean(value); |
} else { |
castedValue = NumberStyle.toNumber(value, style.getEpoch()); |
} |
return castedValue; |
} |
private StyleTableCellProperties cellProps; |
private StyleTextProperties textProps; |
private StyleParagraphProperties pProps; |
52,10 → 119,67 |
super(pkg, tableColElem); |
} |
public final DataStyle getDataStyle() { |
return (DataStyle) Style.getReferencedStyle(getPackage(), getElement().getAttribute("data-style-name", getSTYLE())); |
private final DataStyle getDataStyle(final Attribute name) { |
return (DataStyle) Style.getReferencedStyle(getPackage(), name); |
} |
// return value since it can be changed depending on the data style. |
// e.g. in OO if we input 12:30 in an empty cell, it will have value-type="time" |
// but if we had previously set a number style (like 0,00) it would have been converted to 0,52 |
// value-type="float" |
final Tuple3<DataStyle, ODValueType, Object> getDataStyle(final Object cellValue, final ODValueType valueType, final boolean onlyCast) { |
DataStyle res = getDataStyle(this.getElement().getAttribute("data-style-name", this.getSTYLE())); |
ODValueType returnValueType = valueType; |
Object returnCellValue = cellValue; |
// if the type is null, then the cell is empty so don't try to convert the cell value or |
// evaluate conditions |
if (res != null && valueType != null) { |
if (!onlyCast) { |
final Object convertedForStyle = res.convert(cellValue); |
// if conversion is successful |
if (convertedForStyle != null) { |
returnCellValue = convertedForStyle; |
returnValueType = res.getDataType(); |
} |
} |
final List<?> styleMaps = res.getElement().getChildren("map", getSTYLE()); |
if (styleMaps.size() > 0) { |
final Object converted = convertForCondition(returnCellValue, res); |
// we can't compare() so don't try |
if (converted != null) { |
for (Object child : styleMaps) { |
final Element styleMap = (Element) child; |
final Matcher matcher = conditionPatrn.matcher(styleMap.getAttributeValue("condition", getSTYLE()).trim()); |
if (!matcher.matches()) |
throw new IllegalStateException("Cannot parse " + JDOMUtils.output(styleMap)); |
if (RelationalOperator.getInstance(matcher.group(1)).compare(converted, parse(matcher.group(2)))) { |
res = getDataStyle(styleMap.getAttribute("apply-style-name", getSTYLE())); |
break; |
} |
} |
} |
} |
} |
// if the type is null, then the cell is empty, we cannot make up some value, otherwise |
// don't change it to null |
assert (valueType == null) == (returnValueType == null) : "don't change type to null"; |
assert !onlyCast || (returnValueType == valueType && returnCellValue == cellValue) : "Requested to only cast, but different object"; |
// if res is null, the document is incoherent (non existing style name) |
return res == null ? null : Tuple3.create(res, returnValueType, returnCellValue); |
} |
static private Object parse(String val) { |
if (val.equalsIgnoreCase("true")) |
return Boolean.TRUE; |
else if (val.equalsIgnoreCase("false")) |
return Boolean.FALSE; |
else if (val.charAt(0) == '"') |
return escapedQuotePatrn.matcher(val.substring(1, val.length() - 1)).replaceAll("\""); |
else |
return new BigDecimal(val); |
} |
public final Color getBackgroundColor() { |
return getTableCellProperties().getBackgroundColor(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/SheetTableModel.java |
---|
14,6 → 14,7 |
package org.openconcerto.openoffice.spreadsheet; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.utils.CompareUtils; |
import javax.swing.table.AbstractTableModel; |
76,6 → 77,50 |
throw new IndexOutOfBoundsException("column: " + columnIndex + " not between 0 and " + (this.getColumnCount() - 1)); |
} |
@Override |
public int hashCode() { |
final int rowCount = getRowCount(); |
final int columnCount = getColumnCount(); |
final int prime = 17; |
int result = 1; |
result = prime * result + rowCount; |
result = prime * result + columnCount; |
// use some of the values |
final int maxX = Math.min(4, columnCount); |
final int maxY = Math.min(8, rowCount); |
for (int y = 0; y < maxY; y++) { |
for (int x = 0; x < maxX; x++) { |
final Object v = this.getValueAt(x, y); |
result = prime * result + (v == null ? 0 : v.hashCode()); |
} |
} |
return result; |
} |
@Override |
public boolean equals(Object obj) { |
if (this == obj) |
return true; |
if (obj == null) |
return false; |
if (!(obj instanceof SheetTableModel)) |
return false; |
final SheetTableModel<?> other = (SheetTableModel<?>) obj; |
final int rowCount = this.getRowCount(); |
final int columnCount = this.getColumnCount(); |
if (other.getRowCount() != rowCount || other.getColumnCount() != columnCount) |
return false; |
for (int y = 0; y < rowCount; y++) { |
for (int x = 0; x < columnCount; x++) { |
if (!CompareUtils.equals(this.getValueAt(x, y), other.getValueAt(x, y))) |
return false; |
} |
} |
return true; |
} |
static public final class MutableTableModel<D extends ODDocument> extends SheetTableModel<D> { |
MutableTableModel(final Table<D> table, final int row, final int column) { |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/TableGroup.java |
---|
New file |
0,0 → 1,174 |
/* |
* 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.openoffice.spreadsheet; |
import org.openconcerto.openoffice.ODNode; |
import org.openconcerto.openoffice.StyleProperties; |
import org.openconcerto.utils.Tuple2; |
import java.util.ArrayList; |
import java.util.Collections; |
import java.util.List; |
import org.jdom.Element; |
/** |
* A group of columns/rows that can be hidden. |
* |
* @author Sylvain CUAZ |
*/ |
public class TableGroup extends ODNode { |
static Tuple2<TableGroup, List<Element>> createRoot(final Table<?> table, final Axis col) { |
final TableGroup group = new TableGroup(table, col); |
return Tuple2.create(group, group.flatten()); |
} |
private final Table<?> table; |
private final Axis axis; |
private final TableGroup parent; |
private final List<TableGroup> children; |
private int headerCount; |
private int first; |
private int size; |
// root group |
private TableGroup(final Table<?> table, final Axis col) { |
this(table, col, null, table.getElement(), 0); |
} |
private TableGroup(Table<?> table, TableGroup parent, Element elem, final int first) { |
this(table, parent.axis, parent, elem, first); |
} |
private TableGroup(Table<?> table, final Axis col, TableGroup parent, Element elem, final int first) { |
super(elem); |
if (table == null) |
throw new NullPointerException("null table"); |
this.table = table; |
this.axis = col; |
this.parent = parent; |
this.first = first; |
this.children = new ArrayList<TableGroup>(); |
} |
private List<Element> flatten() { |
// max() since a group can have only group children |
final List<Element> res = new ArrayList<Element>(Math.max(128, getElement().getContentSize())); |
final String fullName = this.axis.getElemName(); |
final String groupName = this.axis.getGroupName(); |
final String pluralName = this.axis.getPluralName(); |
// A table shall not contain more than one <table:table-header-rows> element. |
final Element header = this.getElement().getChild(this.axis.getHeaderName(), getElement().getNamespace()); |
if (header != null) |
this.headerCount = Table.flattenChildren(res, header, this.axis); |
else |
this.headerCount = 0; |
int size = this.headerCount; |
this.children.clear(); |
@SuppressWarnings("unchecked") |
final List<Element> content = new ArrayList<Element>(getElement().getChildren()); |
for (final Element child : content) { |
if (child.getName().equals(fullName)) { |
size += Table.flatten1(res, child, this.axis); |
} else if (child.getName().equals(pluralName)) { |
// ignore table-rows element (but add its children) |
size += Table.flattenChildren(res, child, this.axis); |
} else if (child.getName().equals(groupName)) { |
final TableGroup g = new TableGroup(getTable(), this, child, this.first + size); |
this.children.add(g); |
res.addAll(g.flatten()); |
size += g.getSize(); |
} |
// else nothing to do (header or soft-page-break) |
} |
this.size = size; |
return res; |
} |
public final Table<?> getTable() { |
return this.table; |
} |
/** |
* The parent of this group. |
* |
* @return the parent, <code>null</code> if this is the root group. |
*/ |
public final TableGroup getParent() { |
return this.parent; |
} |
public final List<TableGroup> getChildren() { |
return Collections.unmodifiableList(this.children); |
} |
final TableGroup getDescendentOrSelfContaining(final int y) { |
if (!this.contains(y)) |
return null; |
for (final TableGroup g : this.getChildren()) { |
final TableGroup res = g.getDescendentOrSelfContaining(y); |
if (res != null) |
return res; |
} |
return this; |
} |
public final boolean isDisplayed() { |
if (this.getParent() == null) |
return true; |
else |
// from table:display : the default value for this attribute is true |
return StyleProperties.parseBoolean(getElement().getAttributeValue("display", getElement().getNamespace()), true); |
} |
/** |
* The index of the first row/column in this group. |
* |
* @return index of the first element. |
*/ |
public final int getFirst() { |
return this.first; |
} |
public final int getHeaderCount() { |
return this.headerCount; |
} |
public final int getSize() { |
return this.size; |
} |
public final boolean contains(final int i) { |
return i >= this.getFirst() && i < this.getFirst() + this.getSize(); |
} |
final int getFollowingHeaderCount() { |
int res = this.getHeaderCount(); |
// the table and each distinct group may contain one <table:table-header-rows> element, if |
// and only if the table rows contained in the <table:table-header-rows> elements are |
// adjacent. |
for (final TableGroup g : this.getChildren()) { |
if (g.getFirst() != this.getFirst() + res) |
break; |
res += g.getFollowingHeaderCount(); |
} |
return res; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Axis.java |
---|
New file |
0,0 → 1,79 |
/* |
* 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.openoffice.spreadsheet; |
import org.openconcerto.openoffice.StyleProperties; |
import org.jdom.Attribute; |
import org.jdom.Element; |
public enum Axis { |
ROW("row"), COLUMN("column"); |
private final String shortName, elemName, headerName, groupName, pluralName, repeatedAttrName; |
private Axis(final String shortName) { |
this.shortName = shortName; |
this.elemName = "table-" + shortName; |
this.headerName = "table-header-" + shortName + "s"; |
this.groupName = this.elemName + "-group"; |
this.pluralName = this.elemName + "s"; |
this.repeatedAttrName = "number-" + shortName + "s-repeated"; |
} |
public final String getShortName() { |
return this.shortName; |
} |
public final String getElemName() { |
return this.elemName; |
} |
public final String getHeaderName() { |
return this.headerName; |
} |
public final String getGroupName() { |
return this.groupName; |
} |
public final String getPluralName() { |
return this.pluralName; |
} |
public final String getRepeatedAttrName() { |
return this.repeatedAttrName; |
} |
final Attribute getRepeatedAttr(final Element elem) { |
assert elem.getName().equals(this.getElemName()); |
return elem.getAttribute(getRepeatedAttrName(), elem.getNamespace()); |
} |
final int getRepeated(final Element elem) { |
assert elem.getName().equals(this.getElemName()); |
return StyleProperties.parseInt(elem.getAttributeValue(getRepeatedAttrName(), elem.getNamespace()), 1); |
} |
final void setRepeated(final Element elem, final int i) { |
assert elem.getName().equals(this.getElemName()); |
if (i < 1) |
throw new IllegalArgumentException("repeated <1 : " + i); |
if (i == 1) |
elem.removeAttribute(getRepeatedAttrName(), elem.getNamespace()); |
else |
elem.setAttribute(getRepeatedAttrName(), String.valueOf(i), elem.getNamespace()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Row.java |
---|
16,10 → 16,13 |
*/ |
package org.openconcerto.openoffice.spreadsheet; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.StyleDesc; |
import org.openconcerto.openoffice.StyleProperties; |
import org.openconcerto.openoffice.StyleStyleDesc; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.ODDocument; |
import java.util.ArrayList; |
import java.util.Arrays; |
import java.util.List; |
import org.jdom.Element; |
39,46 → 42,79 |
private final Table<D> parent; |
private final int index; |
private int repeated; |
// the same immutable cell instance is repeated, but each MutableCell is only once |
// ATTN MutableCell have their index as attribute |
private final List<Cell<D>> cells; |
// array is faster than List |
private Cell<D>[] cells; |
private int cellCount; |
Row(Table<D> parent, Element tableRowElem, int index) { |
super(parent.getODDocument(), tableRowElem, RowStyle.class); |
Row(Table<D> parent, Element tableRowElem, int index, StyleDesc<RowStyle> styleDesc, StyleDesc<CellStyle> cellStyleDesc) { |
super(parent.getODDocument(), tableRowElem, styleDesc); |
this.parent = parent; |
this.index = index; |
this.cells = new ArrayList<Cell<D>>(); |
this.repeated = Axis.ROW.getRepeated(getElement()); |
@SuppressWarnings("unchecked") |
final Cell<D>[] unsafe = new Cell[parent.getColumnCount()]; |
this.cells = unsafe; |
this.cellCount = 0; |
for (final Element cellElem : this.getCellElements()) { |
addCellElem(cellElem); |
addCellElem(cellElem, cellStyleDesc); |
} |
} |
private final void ensureRoom(int additionalItems) { |
final int requiredSize = this.getCellCount() + additionalItems; |
if (requiredSize > this.cells.length) { |
this.cells = Arrays.copyOf(this.cells, requiredSize); |
} |
} |
protected final Table<D> getSheet() { |
return this.parent; |
} |
// ATTN index of the first row |
final int getY() { |
return this.index; |
} |
// plain Cell instances have multiple indexes (if repeated) but MutableCell are unique |
final int getX(MutableCell<D> c) { |
return this.cells.indexOf(c); |
// inclusive |
final int getLastY() { |
return this.getY() + this.getRepeated() - 1; |
} |
private void addCellElem(final Element cellElem) { |
final Cell<D> cell = new Cell<D>(this, cellElem); |
this.cells.add(cell); |
final int getRepeated() { |
return this.repeated; |
} |
final String repeatedS = cellElem.getAttributeValue("number-columns-repeated", this.getSheet().getTABLE()); |
if (repeatedS != null) { |
final int toRepeat = Integer.parseInt(repeatedS) - 1; |
for (int i = 0; i < toRepeat; i++) { |
this.cells.add(cell); |
final void setRepeated(int newRepeated) { |
Axis.ROW.setRepeated(getElement(), newRepeated); |
this.repeated = newRepeated; |
} |
// plain Cell instances have multiple indexes (if repeated) but MutableCell are unique |
final int getX(MutableCell<D> c) { |
final int stop = this.getCellCount(); |
for (int i = 0; i < stop; i++) { |
final Cell<D> item = this.cells[i]; |
if (c.equals(item)) |
return i; |
} |
return -1; |
} |
private void addCellElem(final Element cellElem, StyleDesc<CellStyle> cellStyleDesc) { |
final Cell<D> cell = new Cell<D>(this, cellElem, cellStyleDesc); |
final String repeatedS = cellElem.getAttributeValue("number-columns-repeated", this.getTABLE()); |
final int toRepeat = StyleProperties.parseInt(repeatedS, 1); |
final int stop = this.cellCount + toRepeat; |
for (int i = this.cellCount; i < stop; i++) { |
this.cells[i] = cell; |
} |
this.cellCount = stop; |
} |
/** |
* All cells of this row. |
* |
90,8 → 126,16 |
return this.getElement().getChildren(); |
} |
protected final int getCellCount() { |
return this.cellCount; |
} |
private final List<Cell<D>> getCellsAsList() { |
return Arrays.asList(this.cells); |
} |
protected final Cell<D> getCellAt(int col) { |
return this.cells.get(col); |
return this.cells[col]; |
} |
protected final Cell<D> getValidCellAt(int col) { |
102,68 → 146,41 |
} |
public final MutableCell<D> getMutableCellAt(final int col) { |
final Cell c = this.getValidCellAt(col); |
final Cell<D> c = this.getValidCellAt(col); |
if (!(c instanceof MutableCell)) { |
final Element element = c.getElement(); |
final String repeatedS = element.getAttributeValue("number-columns-repeated", this.getSheet().getTABLE()); |
if (repeatedS != null) { |
final int repeated = Integer.parseInt(repeatedS); |
final int firstIndex = this.cells.indexOf(c); |
final int lastIndex = firstIndex + repeated - 1; |
final int preRepeated = col - firstIndex; |
final int postRepeated = lastIndex - col; |
casse(element, firstIndex, preRepeated, true); |
element.removeAttribute("number-columns-repeated", this.getSheet().getTABLE()); |
casse(element, col + 1, postRepeated, false); |
RepeatedBreaker.<D> getCellBreaker().breakRepeated(this, getCellsAsList(), col); |
} |
this.cells.set(col, new MutableCell<D>(this, element)); |
} |
return (MutableCell<D>) this.getValidCellAt(col); |
} |
private final void casse(Element element, int firstIndex, int repeat, boolean before) { |
if (repeat > 0) { |
final Element newElem = (Element) element.clone(); |
element.getParentElement().addContent(element.getParent().indexOf(element) + (before ? 0 : 1), newElem); |
newElem.setAttribute("number-columns-repeated", repeat + "", this.getSheet().getTABLE()); |
final Cell<D> preCell = new Cell<D>(this, newElem); |
for (int i = 0; i < repeat; i++) { |
this.cells.set(firstIndex + i, preCell); |
} |
} |
} |
// rempli cette ligne avec autant de cellules vides qu'il faut |
void columnCountChanged() { |
final int diff = this.getSheet().getColumnCount() - this.cells.size(); |
void columnCountChanged(StyleStyleDesc<CellStyle> cellStyleDesc) { |
final int diff = this.getSheet().getColumnCount() - getCellCount(); |
if (diff < 0) { |
throw new IllegalStateException("should have used Table.removeColumn()"); |
} else if (diff > 0) { |
final Element e = Cell.createEmpty(this.getSheet().getODDocument().getVersion(), diff); |
this.getElement().addContent(e); |
addCellElem(e); |
this.ensureRoom(diff); |
addCellElem(e, cellStyleDesc); |
} |
if (this.cells.size() != this.getSheet().getColumnCount()) |
throw new IllegalStateException(); |
assert this.getCellCount() == this.getSheet().getColumnCount(); |
} |
void checkRemove(int firstIndex, int lastIndexExcl) { |
if (lastIndexExcl > this.cells.size()) { |
throw new IndexOutOfBoundsException(lastIndexExcl + " > " + this.cells.size()); |
if (lastIndexExcl > getCellCount()) { |
throw new IndexOutOfBoundsException(lastIndexExcl + " > " + getCellCount()); |
} |
if (!this.getCellAt(firstIndex).isValid()) |
throw new IllegalArgumentException("unable to remove covered cell at " + firstIndex); |
} |
// ATTN unsafe, must call checkRemove() first |
void removeCells(int firstIndex, int lastIndexExcl) { |
checkRemove(firstIndex, lastIndexExcl); |
this.getMutableCellAt(firstIndex).unmerge(); |
// if lastIndex == size, nothing to do |
if (lastIndexExcl < this.cells.size()) { |
if (lastIndexExcl < getCellCount()) { |
if (!this.getCellAt(lastIndexExcl - 1).isValid()) { |
int currentCol = lastIndexExcl - 2; |
// the covering cell is on this row since last cells of previous rows have been |
182,8 → 199,13 |
for (int i = firstIndex; i < lastIndexExcl; i++) { |
// ok to detach multiple times the same element (since repeated cells share the same XML |
// element) |
this.cells.remove(firstIndex).getElement().detach(); |
this.cells[firstIndex].getElement().detach(); |
} |
final int movedCount = getCellCount() - lastIndexExcl; |
System.arraycopy(this.cells, lastIndexExcl, this.cells, firstIndex, movedCount); |
this.cells = Arrays.copyOfRange(this.cells, 0, firstIndex + movedCount); |
this.cellCount = this.cells.length; |
assert this.getCellCount() == this.getSheet().getColumnCount(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/SpreadSheet.java |
---|
13,8 → 13,6 |
package org.openconcerto.openoffice.spreadsheet; |
import static org.openconcerto.openoffice.ODPackage.RootElement.CONTENT; |
import static org.openconcerto.openoffice.ODPackage.RootElement.STYLES; |
import org.openconcerto.openoffice.ContentType; |
import org.openconcerto.openoffice.ContentTypeVersioned; |
import org.openconcerto.openoffice.ODDocument; |
21,13 → 19,11 |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.OOUtils; |
import org.openconcerto.openoffice.XMLFormatVersion; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.SheetTableModel.MutableTableModel; |
import org.openconcerto.utils.Tuple2; |
import java.awt.Point; |
import java.io.File; |
import java.io.FileNotFoundException; |
import java.io.IOException; |
import java.util.ArrayList; |
import java.util.HashMap; |
39,7 → 35,6 |
import javax.swing.table.TableModel; |
import org.jdom.Document; |
import org.jdom.Element; |
import org.jdom.JDOMException; |
import org.jdom.xpath.XPath; |
49,14 → 44,20 |
* |
* @author Sylvain |
*/ |
public class SpreadSheet implements ODDocument { |
public class SpreadSheet extends ODDocument { |
public static SpreadSheet createFromFile(File f) throws IOException { |
return create(new ODPackage(f)); |
return new ODPackage(f).getSpreadSheet(); |
} |
public static SpreadSheet create(final ODPackage fd) { |
return new SpreadSheet(fd.getDocument(CONTENT.getZipEntry()), fd.getDocument(STYLES.getZipEntry()), fd); |
/** |
* This method should be avoided, use {@link ODPackage#getSpreadSheet()}. |
* |
* @param fd a package. |
* @return the spreadsheet. |
*/ |
public static SpreadSheet get(final ODPackage fd) { |
return fd.hasODDocument() ? fd.getSpreadSheet() : new SpreadSheet(fd); |
} |
public static SpreadSheet createEmpty(TableModel t) throws IOException { |
65,7 → 66,7 |
public static SpreadSheet createEmpty(TableModel t, XMLFormatVersion ns) throws IOException { |
final ContentTypeVersioned ct = ContentType.SPREADSHEET.getVersioned(ns.getXMLVersion()); |
final SpreadSheet spreadSheet = create(ct.createPackage(ns)); |
final SpreadSheet spreadSheet = ct.createPackage(ns).getSpreadSheet(); |
spreadSheet.getBody().addContent(Sheet.createEmpty(ns.getXMLVersion())); |
spreadSheet.getSheet(0).merge(t, 0, 0, true); |
return spreadSheet; |
85,46 → 86,14 |
return SpreadSheet.createEmpty(t, ns).saveAs(f); |
} |
private final ODPackage originalFile; |
private final Map<Element, Sheet> sheets; |
public SpreadSheet(Document doc, Document styles) { |
this(doc, styles, null); |
} |
private SpreadSheet(final Document doc, final Document styles, final ODPackage orig) { |
if (orig != null) { |
// ATTN OK because this is our private instance (see createFromFile()) |
this.originalFile = orig; |
} else { |
this.originalFile = new ODPackage(); |
} |
this.originalFile.putFile("content.xml", doc); |
if (styles != null) |
this.originalFile.putFile("styles.xml", styles); |
private SpreadSheet(final ODPackage orig) { |
super(orig); |
// map Sheet by XML elements so has not to depend on ordering or name |
this.sheets = new HashMap<Element, Sheet>(); |
} |
final Document getContent() { |
return this.getPackage().getContent().getDocument(); |
} |
@Override |
public final XMLVersion getVersion() { |
return this.getPackage().getVersion(); |
} |
@Override |
public XMLFormatVersion getFormatVersion() { |
return this.getPackage().getFormatVersion(); |
} |
private Element getBody() { |
return ContentType.SPREADSHEET.getVersioned(getVersion()).getBody(getContent()); |
} |
// ** from 8.3.1 Referencing Table Cells (just double the backslash for . and escape the $) |
private static final String minCell = "\\$?([A-Z]+)\\$?([0-9]+)"; |
// added parens to capture cell address |
334,17 → 303,4 |
parentElement.addContent(getContentIndex(toIndex), sheet.getElement()); |
// no need to update this.sheets since it doesn't depend on order |
} |
// *** Files |
public File saveAs(File file) throws FileNotFoundException, IOException { |
this.getPackage().setFile(file); |
return this.getPackage().save(); |
} |
@Override |
public final ODPackage getPackage() { |
return this.originalFile; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/ColumnStyle.java |
---|
14,7 → 14,6 |
package org.openconcerto.openoffice.spreadsheet; |
import org.openconcerto.openoffice.LengthUnit; |
import org.openconcerto.openoffice.ODFrame; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.StyleProperties; |
import org.openconcerto.openoffice.StyleStyle; |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Cell.java |
---|
19,6 → 19,7 |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.OOXML; |
import org.openconcerto.openoffice.StyleDesc; |
import org.openconcerto.openoffice.XMLFormatVersion; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.utils.CollectionUtils; |
80,8 → 81,8 |
private final Row<D> row; |
Cell(Row<D> parent, Element elem) { |
super(parent.getODDocument(), elem, CellStyle.class); |
Cell(Row<D> parent, Element elem, StyleDesc<CellStyle> styleDesc) { |
super(parent.getODDocument(), elem, styleDesc); |
this.row = parent; |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/TableCalcNode.java |
---|
15,6 → 15,7 |
import org.openconcerto.openoffice.ImmutableDocStyledNode; |
import org.openconcerto.openoffice.ODDocument; |
import org.openconcerto.openoffice.StyleDesc; |
import org.openconcerto.openoffice.StyleStyle; |
import org.jdom.Element; |
34,7 → 35,12 |
super(parent, local, styleClass); |
} |
protected TableCalcNode(D parent, Element local, StyleDesc<S> styleDesc) { |
super(parent, local, styleDesc); |
} |
protected final Namespace getTABLE() { |
return this.getODDocument().getVersion().getTABLE(); |
// a lot faster than asking to the version of our document |
return this.getElement().getNamespace(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/RelationalOperator.java |
---|
New file |
0,0 → 1,100 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.openoffice.style; |
import org.openconcerto.utils.CompareUtils; |
import java.util.HashMap; |
import java.util.Map; |
public enum RelationalOperator { |
LT("<") { |
@Override |
protected boolean evaluate(int i) { |
return i < 0; |
} |
}, |
GT(">") { |
@Override |
protected boolean evaluate(int i) { |
return i > 0; |
} |
}, |
LE("<=") { |
@Override |
protected boolean evaluate(int i) { |
return i <= 0; |
} |
}, |
GE(">=") { |
@Override |
protected boolean evaluate(int i) { |
return i >= 0; |
} |
}, |
EQ("=") { |
@Override |
protected boolean evaluate(int i) { |
return i == 0; |
} |
}, |
NE("!=") { |
@Override |
protected boolean evaluate(int i) { |
return !EQ.evaluate(i); |
} |
}; |
private final String s; |
private RelationalOperator(final String s) { |
this.s = s; |
} |
public final String asString() { |
return this.s; |
} |
public final boolean compare(final Object o1, final Object o2) { |
return this.evaluate(CompareUtils.compare(o1, o2)); |
} |
protected abstract boolean evaluate(int i); |
/** |
* Regular expression with all operators. |
* |
* <pre> |
* <|>|<=|>=|=|!= |
* </pre> |
*/ |
public static final String OR_PATTERN; |
private static final Map<String, RelationalOperator> instances; |
static { |
instances = new HashMap<String, RelationalOperator>(); |
final StringBuilder sb = new StringBuilder(32); |
for (final RelationalOperator op : values()) { |
instances.put(op.s, op); |
sb.append(op.asString()); |
sb.append('|'); |
} |
// remove last | |
sb.setLength(sb.length() - 1); |
OR_PATTERN = sb.toString(); |
} |
public static RelationalOperator getInstance(String op) { |
return instances.get(op); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/TextStyle.java |
---|
14,6 → 14,7 |
package org.openconcerto.openoffice.style.data; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.CellStyle; |
33,10 → 34,15 |
}; |
public TextStyle(final ODPackage pkg, Element elem) { |
super(pkg, elem, Object.class); |
super(pkg, elem, ODValueType.STRING); |
} |
@Override |
protected String convertNonNull(Object o) { |
return o.toString(); |
} |
@Override |
public String format(Object o, CellStyle defaultStyle, boolean lenient) { |
final Namespace numberNS = this.getElement().getNamespace(); |
final StringBuilder sb = new StringBuilder(); |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/NumberStyle.java |
---|
13,13 → 13,19 |
package org.openconcerto.openoffice.style.data; |
import org.openconcerto.openoffice.ODEpoch; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.CellStyle; |
import org.openconcerto.openoffice.spreadsheet.MutableCell; |
import java.util.Calendar; |
import java.util.Date; |
import java.util.List; |
import javax.xml.datatype.Duration; |
import org.jdom.Element; |
import org.jdom.Namespace; |
33,11 → 39,41 |
} |
}; |
public static final Number toNumber(Object value, ODEpoch epoch) { |
final Number res; |
if (value instanceof Number) { |
res = (Number) value; |
} else if (value instanceof Boolean) { |
res = ((Boolean) value).booleanValue() ? 1 : 0; |
} else if ((value instanceof Duration || value instanceof Date || value instanceof Calendar)) { |
if (value instanceof Duration) { |
res = epoch.getDays((Duration) value); |
} else { |
final Calendar cal; |
if (value instanceof Calendar) { |
cal = (Calendar) value; |
} else { |
cal = Calendar.getInstance(); |
cal.setTime((Date) value); |
} |
res = epoch.getDays(cal); |
} |
} else { |
res = null; |
} |
return res; |
} |
public NumberStyle(final ODPackage pkg, Element elem) { |
super(pkg, elem, Number.class); |
super(pkg, elem, ODValueType.FLOAT); |
} |
@Override |
protected Number convertNonNull(Object value) { |
return toNumber(value, getEpoch()); |
} |
@Override |
public String format(Object o, CellStyle defaultStyle, boolean lenient) { |
final Number n = (Number) o; |
final Namespace numberNS = this.getElement().getNamespace(); |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/DataStyle.java |
---|
14,7 → 14,9 |
package org.openconcerto.openoffice.style.data; |
import org.openconcerto.openoffice.Log; |
import org.openconcerto.openoffice.ODEpoch; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.Style; |
import org.openconcerto.openoffice.StyleDesc; |
import org.openconcerto.openoffice.StyleProperties; |
74,24 → 76,62 |
Arrays.asList("presentation:date-time-decl", "style:style", "text:creation-date", "text:creation-time", "text:database-display", "text:date", "text:editing-duration", |
"text:expression", "text:meta-field", "text:modification-date", "text:modification-time", "text:print-date", "text:print-time", "text:table-formula", "text:time", |
"text:user-defined", "text:user-field-get", "text:user-field-input", "text:variable-get", "text:variable-input", "text:variable-set")); |
this.getRefElementsMap().put("style:apply-style-name", "style:map"); |
} |
} |
// type accepted by #format() |
private final Class<?> type; |
private final ODValueType type; |
private StyleTextProperties textProps; |
protected DataStyle(final ODPackage pkg, Element elem, final Class<?> type) { |
protected DataStyle(final ODPackage pkg, Element elem, final ODValueType type) { |
super(pkg, elem); |
this.type = type; |
} |
protected final Class<?> getDataType() { |
public final ODValueType getDataType() { |
return this.type; |
} |
public final ODEpoch getEpoch() { |
return this.getPackage().getODDocument().getEpoch(); |
} |
/** |
* Convert the passed object to something that {@link #format(Object, CellStyle, boolean)} can |
* accept. |
* |
* @param o the object to convert. |
* @return an object that can be formatted, <code>null</code> if <code>o</code> cannot be |
* converted. |
* @throws NullPointerException if <code>o</code> is <code>null</code>. |
* @see #canFormat(Class) |
*/ |
public final Object convert(final Object o) throws NullPointerException { |
if (o == null) |
throw new NullPointerException(); |
final Object res; |
if (this.canFormat(o.getClass())) |
res = o; |
else |
res = this.convertNonNull(o); |
assert res == null || this.canFormat(res.getClass()); |
return res; |
} |
// o is not null and canFormat(o.getClass()) is false |
// return null if o cannot be converted |
protected abstract Object convertNonNull(Object o); |
/** |
* Whether instances of the passed class can be {@link #format(Object, CellStyle, boolean) |
* formatted}. |
* |
* @param toFormat the class. |
* @return <code>true</code> if instances of <code>toFormat</code> can be formatted. |
*/ |
public final boolean canFormat(Class<?> toFormat) { |
return this.getDataType().isAssignableFrom(toFormat); |
return this.getDataType().canFormat(toFormat); |
} |
public final String getTitle() { |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/CurrencyStyle.java |
---|
14,6 → 14,7 |
package org.openconcerto.openoffice.style.data; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.CellStyle; |
34,10 → 35,15 |
}; |
public CurrencyStyle(final ODPackage pkg, Element elem) { |
super(pkg, elem, Number.class); |
super(pkg, elem, ODValueType.CURRENCY); |
} |
@Override |
protected Object convertNonNull(Object o) { |
return NumberStyle.toNumber(o, getEpoch()); |
} |
@Override |
public String format(Object o, CellStyle defaultStyle, boolean lenient) { |
final Number n = (Number) o; |
final Namespace numberNS = this.getElement().getNamespace(); |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/DateStyle.java |
---|
14,9 → 14,11 |
package org.openconcerto.openoffice.style.data; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.StyleProperties; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.CellStyle; |
import org.openconcerto.utils.convertor.NumberConvertor; |
import java.math.BigDecimal; |
import java.text.DecimalFormat; |
24,6 → 26,7 |
import java.text.SimpleDateFormat; |
import java.util.Calendar; |
import java.util.Date; |
import java.util.GregorianCalendar; |
import java.util.List; |
import java.util.Locale; |
35,9 → 38,9 |
public class DateStyle extends DataStyle { |
// see http://download.oracle.com/javase/6/docs/technotes/guides/intl/calendar.doc.html |
private static final Locale BUDDHIST_LOCALE = new Locale("th", "TH"); |
private static final Locale JAPANESE_LOCALE = new Locale("ja", "JP", "JP"); |
private static final Locale GREGORIAN_LOCALE = new Locale("fr", "FR"); |
private static final Calendar BUDDHIST_CAL = Calendar.getInstance(new Locale("th", "TH")); |
private static final Calendar JAPANESE_CAL = Calendar.getInstance(new Locale("ja", "JP", "JP")); |
private static final Calendar GREGORIAN_CAL = new GregorianCalendar(); |
public static final DataStyleDesc<DateStyle> DESC = new DataStyleDesc<DateStyle>(DateStyle.class, XMLVersion.OD, "date-style", "N") { |
@Override |
63,17 → 66,17 |
return res; |
} |
private static final Locale getCalendarLocale(final Element elem, Locale defaultLocale) { |
final Locale res; |
private static final Calendar getCalendar(final Element elem, Calendar defaultCal) { |
final Calendar res; |
final String cal = elem.getAttributeValue("calendar", elem.getNamespace()); |
if (cal == null) { |
res = defaultLocale; |
res = defaultCal; |
} else if ("buddhist".equals(cal)) { |
res = BUDDHIST_LOCALE; |
res = BUDDHIST_CAL; |
} else if ("gengou".equals(cal)) { |
res = JAPANESE_LOCALE; |
res = JAPANESE_CAL; |
} else if ("gregorian".equals(cal)) { |
res = GREGORIAN_LOCALE; |
res = GREGORIAN_CAL; |
} else { |
throw new IllegalArgumentException("Unsupported calendar : " + cal); |
} |
80,16 → 83,6 |
return res; |
} |
private static final Locale getCalendarLocale(final Locale locale) { |
final Locale res; |
if (locale.equals(BUDDHIST_LOCALE) || locale.equals(JAPANESE_LOCALE)) { |
res = locale; |
} else { |
res = GREGORIAN_LOCALE; |
} |
return res; |
} |
static String formatSecondFraction(final Locale styleLocale, final BigDecimal seconds, final int decPlaces) { |
if (decPlaces > 0) { |
final DecimalFormat decFormat = new DecimalFormat(); |
106,18 → 99,35 |
} |
public DateStyle(final ODPackage pkg, Element elem) { |
super(pkg, elem, Date.class); |
super(pkg, elem, ODValueType.DATE); |
} |
@Override |
protected Object convertNonNull(Object o) { |
if (o instanceof Number) |
return getEpoch().getDate(NumberConvertor.toBigDecimal((Number) o)); |
else |
return null; |
} |
private final void format(final StringBuilder res, final StringBuilder pattern, final Locale styleLocale, final Calendar currentCalendar, final Date d) { |
if (pattern.length() > 0) { |
final SimpleDateFormat fmt = new SimpleDateFormat(pattern.toString(), styleLocale); |
pattern.setLength(0); |
fmt.setCalendar((Calendar) currentCalendar.clone()); |
res.append(fmt.format(d)); |
} |
} |
@Override |
public String format(Object o, CellStyle defaultStyle, boolean lenient) { |
final Date d = o instanceof Calendar ? ((Calendar) o).getTime() : (Date) o; |
final Namespace numberNS = this.getElement().getNamespace(); |
final Locale styleLocale = getLocale(getElement()); |
final Locale styleCalendarLocale = getCalendarLocale(styleLocale); |
final Calendar styleCalendar = Calendar.getInstance(styleLocale); |
final StringBuilder res = new StringBuilder(); |
Locale currentCalendarLocale = styleCalendarLocale; |
Calendar currentCalendar = styleCalendar; |
final StringBuilder sb = new StringBuilder(); |
@SuppressWarnings("unchecked") |
124,14 → 134,11 |
final List<Element> children = this.getElement().getChildren(); |
for (final Element elem : children) { |
if (elem.getNamespace().equals(numberNS)) { |
final Locale calendarLocaleElem = getCalendarLocale(elem, styleCalendarLocale); |
if (!calendarLocaleElem.equals(currentCalendarLocale)) { |
if (sb.length() > 0) { |
res.append(new SimpleDateFormat(sb.toString(), currentCalendarLocale).format(d)); |
sb.setLength(0); |
final Calendar calendarLocaleElem = getCalendar(elem, styleCalendar); |
if (!calendarLocaleElem.equals(currentCalendar)) { |
format(res, sb, styleLocale, currentCalendar, d); |
currentCalendar = calendarLocaleElem; |
} |
currentCalendarLocale = calendarLocaleElem; |
} |
if (elem.getName().equals("text")) { |
DataStyle.addStringLiteral(sb, elem.getText()); |
140,7 → 147,11 |
} else if (elem.getName().equals("year")) { |
sb.append(isShort(elem) ? "yy" : "yyyy"); |
} else if (elem.getName().equals("quarter")) { |
final int quarter = Calendar.getInstance(GREGORIAN_LOCALE).get(Calendar.MONTH) / 3 + 1; |
final Calendar cal = (Calendar) currentCalendar.clone(); |
cal.setTime(d); |
final double quarterLength = cal.getActualMaximum(Calendar.MONTH) / 4.0; |
final int quarter = (int) (cal.get(Calendar.MONTH) / quarterLength + 1); |
assert quarter >= 1 && quarter <= 4; |
// TODO localize and honor short/long style |
reportError("Quarters are not localized", lenient); |
DataStyle.addStringLiteral(sb, isShort(elem) ? "Q" + quarter : "Q" + quarter); |
184,6 → 195,7 |
} |
} |
} |
return new SimpleDateFormat(sb.toString(), currentCalendarLocale).format(d); |
format(res, sb, styleLocale, currentCalendar, d); |
return res.toString(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/TimeStyle.java |
---|
14,12 → 14,16 |
package org.openconcerto.openoffice.style.data; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.StyleProperties; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.CellStyle; |
import org.openconcerto.utils.TimeUtils; |
import org.openconcerto.utils.convertor.NumberConvertor; |
import java.math.BigDecimal; |
import java.text.DateFormatSymbols; |
import java.util.Calendar; |
import java.util.List; |
import java.util.Locale; |
48,12 → 52,21 |
} |
public TimeStyle(final ODPackage pkg, Element elem) { |
super(pkg, elem, Duration.class); |
super(pkg, elem, ODValueType.TIME); |
} |
@Override |
protected Duration convertNonNull(Object o) { |
if (o instanceof Number) { |
return TimeUtils.timePartToDuration(getEpoch().getDate(NumberConvertor.toBigDecimal((Number) o))); |
} else { |
return null; |
} |
} |
@Override |
public String format(Object o, CellStyle defaultStyle, boolean lenient) { |
final Duration d = (Duration) o; |
final Duration d = o instanceof Calendar ? TimeUtils.timePartToDuration((Calendar) o) : (Duration) o; |
final Namespace numberNS = this.getElement().getNamespace(); |
final StringBuilder sb = new StringBuilder(); |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/BooleanStyle.java |
---|
14,10 → 14,15 |
package org.openconcerto.openoffice.style.data; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.CellStyle; |
import org.openconcerto.utils.NumberUtils; |
import java.util.HashMap; |
import java.util.List; |
import java.util.Locale; |
import java.util.Map; |
import org.jdom.Element; |
import org.jdom.Namespace; |
32,13 → 37,47 |
} |
}; |
public static final Boolean toBoolean(Object o) { |
if (o instanceof Boolean) |
return (Boolean) o; |
else if (o instanceof Number) |
return Boolean.valueOf(!NumberUtils.areNumericallyEqual(0, (Number) o)); |
else |
return null; |
} |
private static final Map<String, String> trues = new HashMap<String, String>(), falses = new HashMap<String, String>(); |
private static final void add(final String iso3, final String trueS, final String falseS) { |
if (trueS == null || falseS == null) |
throw new NullPointerException(); |
trues.put(iso3, trueS); |
falses.put(iso3, falseS); |
} |
static { |
add(Locale.FRENCH.getISO3Language(), "VRAI", "FAUX"); |
add(Locale.ENGLISH.getISO3Language(), "TRUE", "FALSE"); |
add(Locale.GERMAN.getISO3Language(), "WAHR", "FALSCH"); |
add(Locale.ITALY.getISO3Language(), "VERO", "FALSO"); |
add("spa", "VERDADERO", "FALSO"); |
add("por", "VERDADEIRO", "FALSO"); |
} |
public BooleanStyle(final ODPackage pkg, Element elem) { |
super(pkg, elem, Boolean.class); |
super(pkg, elem, ODValueType.BOOLEAN); |
} |
@Override |
protected Boolean convertNonNull(Object o) { |
return toBoolean(o); |
} |
@Override |
public String format(Object o, CellStyle defaultStyle, boolean lenient) { |
final Boolean b = (Boolean) o; |
final Namespace numberNS = this.getElement().getNamespace(); |
final Locale styleLocale = DateStyle.getLocale(getElement()); |
final StringBuilder sb = new StringBuilder(); |
@SuppressWarnings("unchecked") |
final List<Element> children = this.getElement().getChildren(); |
47,12 → 86,20 |
if (elem.getName().equals("text")) { |
sb.append(elem.getText()); |
} else if (elem.getName().equals("boolean")) { |
// TODO localize |
// TODO localize more |
final String s; |
final String iso3Lang = styleLocale.getISO3Language(); |
final String localized = b.booleanValue() ? trues.get(iso3Lang) : falses.get(iso3Lang); |
if (localized != null) { |
s = localized; |
} else { |
reportError("Boolean not localized", lenient); |
sb.append(o.toString()); |
s = b.toString(); |
} |
sb.append(s); |
} |
} |
} |
return sb.toString(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/PercentStyle.java |
---|
14,6 → 14,7 |
package org.openconcerto.openoffice.style.data; |
import org.openconcerto.openoffice.ODPackage; |
import org.openconcerto.openoffice.ODValueType; |
import org.openconcerto.openoffice.XMLVersion; |
import org.openconcerto.openoffice.spreadsheet.CellStyle; |
33,10 → 34,15 |
}; |
public PercentStyle(final ODPackage pkg, Element elem) { |
super(pkg, elem, Number.class); |
super(pkg, elem, ODValueType.PERCENTAGE); |
} |
@Override |
protected Object convertNonNull(Object o) { |
return NumberStyle.toNumber(o, getEpoch()); |
} |
@Override |
public String format(Object o, CellStyle defaultStyle, boolean lenient) { |
final Number n = (Number) o; |
final Namespace numberNS = this.getElement().getNamespace(); |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODEpoch.java |
---|
New file |
0,0 → 1,154 |
/* |
* 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.openoffice; |
import org.openconcerto.utils.TimeUtils; |
import java.math.BigDecimal; |
import java.math.BigInteger; |
import java.math.MathContext; |
import java.text.DateFormat; |
import java.text.ParseException; |
import java.text.SimpleDateFormat; |
import java.util.Calendar; |
import java.util.LinkedHashMap; |
import java.util.Map; |
import java.util.TimeZone; |
import javax.xml.datatype.DatatypeConstants; |
import javax.xml.datatype.Duration; |
/** |
* The null date of an OpenDocument. |
*/ |
public final class ODEpoch { |
static private final BigDecimal MS_PER_DAY = BigDecimal.valueOf(24l * 60l * 60l * 1000l); |
static private final DateFormat DATE_FORMAT; |
static private final ODEpoch DEFAULT_EPOCH; |
static private final Map<String, ODEpoch> cache = new LinkedHashMap<String, ODEpoch>(4, 0.75f, true) { |
@Override |
protected boolean removeEldestEntry(Map.Entry<String, ODEpoch> eldest) { |
return this.size() > 16; |
} |
}; |
static { |
DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); |
DATE_FORMAT.setCalendar(Calendar.getInstance(TimeZone.getTimeZone("UTC"))); |
try { |
DEFAULT_EPOCH = new ODEpoch("1899-12-30"); |
} catch (ParseException e) { |
// shouldn't happen since string are constants |
throw new IllegalStateException(e); |
} |
} |
static public final ODEpoch getDefaultEpoch() { |
return DEFAULT_EPOCH; |
} |
static public final ODEpoch getInstance(String date) throws ParseException { |
if (date == null || date.equals(DEFAULT_EPOCH.getDateString())) { |
return DEFAULT_EPOCH; |
} else { |
ODEpoch res = cache.get(date); |
if (res == null) { |
res = new ODEpoch(date); |
cache.put(date, res); |
} |
return res; |
} |
} |
static private final Calendar parse(final String date) throws ParseException { |
final Calendar cal = (Calendar) DATE_FORMAT.getCalendar().clone(); |
cal.setTime(DATE_FORMAT.parse(date)); |
return cal; |
} |
private final String dateString; |
private final Calendar epochUTC; |
private ODEpoch(final String date) throws ParseException { |
this.dateString = date; |
this.epochUTC = parse(date); |
assert this.epochUTC.getTimeZone().equals(DATE_FORMAT.getTimeZone()); |
} |
public final String getDateString() { |
return this.dateString; |
} |
public final Calendar getCalendar() { |
return (Calendar) this.epochUTC.clone(); |
} |
private final Calendar getDate(final Duration duration) { |
// If we don't use the UTC calendar, we go from 0:00 (the epoch), we add n days, we get |
// to the last Sunday of March at 0:00, so far so good, but then we add say 10 hours, thus |
// going through the change of offset, and arriving at 11:00. |
final Calendar res = getCalendar(); |
duration.addTo(res); |
return res; |
} |
public final Duration normalizeToDays(final Duration dur) { |
final Duration res = dur.getYears() == 0 && dur.getMonths() == 0 ? dur : getDuration(getDays(dur)); |
assert res.getYears() == 0 && res.getMonths() == 0; |
return res; |
} |
public final Duration normalizeToHours(final Duration dur) { |
final Duration durationInDays = normalizeToDays(dur); |
final BigInteger days = (BigInteger) durationInDays.getField(DatatypeConstants.DAYS); |
final BigInteger hours = ((BigInteger) durationInDays.getField(DatatypeConstants.HOURS)).add(days.multiply(BigInteger.valueOf(24))); |
return TimeUtils.getTypeFactory().newDuration(days.signum() >= 0, BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, hours, (BigInteger) durationInDays.getField(DatatypeConstants.MINUTES), |
(BigDecimal) durationInDays.getField(DatatypeConstants.SECONDS)); |
} |
public final BigDecimal getDays(final Duration duration) { |
return getDays(getDate(duration)); |
} |
public final BigDecimal getDays(final Calendar cal) { |
// can't use Duration.normalizeWith() since it doesn't handle DST, i.e. going from winter to |
// summer at midnight will miss a day |
final long diff = TimeUtils.normalizeLocalTime(cal) - this.epochUTC.getTimeInMillis(); |
return BigDecimal.valueOf(diff).divide(MS_PER_DAY, MathContext.DECIMAL128); |
} |
public final Calendar getDate(final BigDecimal days) { |
return getDate(days, Calendar.getInstance()); |
} |
public final Calendar getDate(final BigDecimal days, final Calendar res) { |
final Calendar utcCal = getDate(getDuration(days)); |
// can't use getTimeZone().getOffset() since we have no idea for the UTC time |
return TimeUtils.copyLocalTime(utcCal, res); |
} |
private final static Duration getDuration(final BigDecimal days) { |
final BigDecimal posDays = days.abs(); |
final BigInteger wholeDays = posDays.toBigInteger().abs(); |
final BigDecimal hours = posDays.subtract(new BigDecimal(wholeDays)).multiply(BigDecimal.valueOf(24)); |
final BigInteger wholeHours = hours.toBigInteger(); |
final BigDecimal minutes = hours.subtract(new BigDecimal(wholeHours)).multiply(BigDecimal.valueOf(60)); |
final BigInteger wholeMinutes = minutes.toBigInteger(); |
// round to 16 digits, i.e. 10^-14 seconds is more than enough |
// it is required since the number coming from getDays() might have been rounded |
final BigDecimal seconds = minutes.subtract(new BigDecimal(wholeMinutes)).multiply(BigDecimal.valueOf(60)).round(MathContext.DECIMAL64); |
return TimeUtils.getTypeFactory().newDuration(days.signum() >= 0, BigInteger.ZERO, BigInteger.ZERO, wholeDays, wholeHours, wholeMinutes, seconds); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ContentTypeVersioned.java |
---|
128,7 → 128,7 |
* |
* @param version the version. |
* @return the body of the created document. |
* @see #createContent(boolean) |
* @see #createContent(XMLFormatVersion, boolean) |
*/ |
public final Element createContent(final XMLFormatVersion version) { |
return this.createContent(version, false); |
141,12 → 141,12 |
* @param singleXML <code>true</code> for {@link RootElement#SINGLE_CONTENT}, <code>false</code> |
* for {@link RootElement#CONTENT}. |
* @return the body of the created document. |
* @see #createPackage() |
* @see #createPackage(XMLFormatVersion) |
*/ |
public Element createContent(final XMLFormatVersion version, final boolean singleXML) { |
checkVersion(version); |
final RootElement rootElement = singleXML ? RootElement.SINGLE_CONTENT : RootElement.CONTENT; |
final Document doc = rootElement.createDocument(getVersion(), version.getOfficeVersion()); |
final Document doc = rootElement.createDocument(version); |
final Namespace officeNS = getVersion().getOFFICE(); |
setType(doc, rootElement, officeNS); |
// don't forget that, otherwise OO crash |
170,7 → 170,7 |
} |
public void setType(final Document doc) { |
this.setType(doc, RootElement.fromElementName(doc.getRootElement().getName()), getVersion().getOFFICE()); |
this.setType(doc, RootElement.fromDocument(doc), getVersion().getOFFICE()); |
} |
// not safe |
199,7 → 199,7 |
public Document createStyles(final XMLFormatVersion version) { |
checkVersion(version); |
final Namespace officeNS = getVersion().getOFFICE(); |
final Document styles = RootElement.STYLES.createDocument(getVersion(), version.getOfficeVersion()); |
final Document styles = RootElement.STYLES.createDocument(version); |
// some consumers demand empty children |
styles.getRootElement().addContent(asList(new Element("styles", officeNS), new Element("automatic-styles", officeNS), new Element("master-styles", officeNS))); |
return styles; |
212,12 → 212,7 |
* @return a new package with minimal {@link RootElement#CONTENT} and {@link RootElement#STYLES} |
*/ |
public ODPackage createPackage(final XMLFormatVersion version) { |
final ODPackage res = new ODPackage(); |
res.putFile(RootElement.CONTENT.getZipEntry(), this.createContent(version, false).getDocument()); |
res.putFile(RootElement.STYLES.getZipEntry(), this.createStyles(version)); |
// add mimetype since ODPackage cannot find out about templates |
res.putFile("mimetype", this.getMimeType().getBytes(ODPackage.MIMETYPE_ENC)); |
return res; |
return ODPackage.createFromDocuments(this, this.createContent(version, false).getDocument(), this.createStyles(version), null, null); |
} |
// *** static |
238,6 → 233,27 |
return null; |
} |
static public ContentTypeVersioned fromMime(byte[] mime) { |
return fromMime(new String(mime, ODPackage.MIMETYPE_ENC)); |
} |
static ContentTypeVersioned fromContent(final ODXMLDocument content) { |
final ContentTypeVersioned res; |
final XMLVersion vers = content.getVersion(); |
if (vers.equals(XMLVersion.OOo)) { |
final Element contentRoot = content.getDocument().getRootElement(); |
final String docClass = contentRoot.getAttributeValue("class", contentRoot.getNamespace("office")); |
res = ContentTypeVersioned.fromClass(docClass); |
} else if (vers.equals(XMLVersion.OD)) { |
final Element bodyChild = (Element) content.getChild("body").getChildren().get(0); |
res = ContentTypeVersioned.fromBody(bodyChild.getName()); |
} else { |
throw new IllegalStateException("Unknown content version : " + vers); |
} |
assert !res.isTemplate() : "template status cannot be inferred from content"; |
return res; |
} |
static ContentTypeVersioned fromClass(String name) { |
return fromShortName(XMLVersion.OOo, name); |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/JavaPrefPreferencePanel.java |
---|
21,6 → 21,7 |
import org.openconcerto.utils.checks.ValidObject; |
import org.openconcerto.utils.checks.ValidState; |
import java.awt.BorderLayout; |
import java.beans.PropertyChangeEvent; |
import java.beans.PropertyChangeListener; |
import java.util.ArrayList; |
47,12 → 48,16 |
private final ValidChangeSupport validSupp; |
public JavaPrefPreferencePanel(final String title, final Preferences prefs) { |
super(new BorderLayout()); |
this.title = title; |
this.prefs = prefs; |
this.layouter = new AutoLayouter(this); |
this.views = new HashSet<PrefView<?>>(); |
this.modified = false; |
this.validSupp = new ValidChangeSupport(this); |
// anchor content at the top |
final JPanel content = new JPanel(); |
this.add(content, BorderLayout.PAGE_START); |
this.layouter = new AutoLayouter(content); |
} |
public final void setPrefs(Preferences prefs) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/AbstractProps.java |
---|
128,8 → 128,11 |
public void load() { |
final File file = new File(getPropsFileName()); |
if (!file.exists()) |
System.out.println("Loading properties from " + file.getAbsolutePath()); |
if (!file.exists()) { |
System.out.println("Warning: " + file.getAbsolutePath() + " does not exist"); |
return; |
} |
BufferedInputStream bufferedInputStream = null; |
try { |
final FileInputStream fileInputStream = new FileInputStream(file); |
/trunk/OpenConcerto/src/org/openconcerto/ui/FormLayouter.java |
---|
151,6 → 151,7 |
final int realWidth = w * CELL_WIDTH - 1; |
JPanel p = new JPanel(); |
p.setOpaque(false); |
p.setLayout(new GridLayout()); |
p.setBorder(BorderFactory.createTitledBorder(desc)); |
p.add(comp); |
/trunk/OpenConcerto/src/org/openconcerto/ui/JDate.java |
---|
18,10 → 18,12 |
import org.openconcerto.utils.checks.ValidListener; |
import org.openconcerto.utils.checks.ValidState; |
import java.awt.Component; |
import java.beans.PropertyChangeListener; |
import java.util.Calendar; |
import java.util.Date; |
import javax.swing.JButton; |
import javax.swing.JComponent; |
import javax.swing.text.JTextComponent; |
63,6 → 65,16 |
this.resetValue(); |
} |
@Override |
public void updateUI() { |
super.updateUI(); |
// can't change BasicDatePickerUI behavior, so do it here |
for (final Component child : this.getComponents()) { |
if (child instanceof JButton) |
((JComponent) child).setOpaque(false); |
} |
} |
public final void resetValue() { |
if (this.fillWithCurrentDate) { |
this.setValue(new Date()); |
/trunk/OpenConcerto/src/org/openconcerto/ui/table/AlternateTableCellRenderer.java |
---|
35,7 → 35,7 |
*/ |
public class AlternateTableCellRenderer extends TableCellRendererDecorator { |
public static final Color COLOR_LIGHT_GRAY = new Color(243, 243, 243); |
public static final Color COLOR_LIGHT_GRAY = new Color(243, 247, 251); |
public static final Color DEFAULT_BG_COLOR = Color.WHITE; |
/** Default map from white to gray */ |
public static final Map<Color, Color> DEFAULT_MAP = Collections.singletonMap(DEFAULT_BG_COLOR, COLOR_LIGHT_GRAY); |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextSelectorCompletionThread.java |
---|
File deleted |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextSelectorPopup.java |
---|
File deleted |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextSelector.java |
---|
File deleted |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/MutableListComboPopupListener.java |
---|
29,6 → 29,7 |
import java.util.HashSet; |
import java.util.Set; |
import javax.swing.AbstractAction; |
import javax.swing.JComboBox; |
import javax.swing.JMenuItem; |
import javax.swing.JPopupMenu; |
130,7 → 131,15 |
MutableListComboPopupListener.this.combo.removeCurrentText(); |
} |
}); |
if (this.combo.canReload()) { |
this.popup.add(new JMenuItem(new AbstractAction("Recharger la liste") { |
public void actionPerformed(ActionEvent e) { |
MutableListComboPopupListener.this.combo.reload(); |
} |
})); |
} |
} |
// popups are never closed in a JComboBox (except when choosing a menu item) |
if (SwingThreadUtils.getAncestorOrSelf(JComboBox.class, this.combo.getPopupComp()) != null) |
addPopup(this.popup); |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextComboCache.java |
---|
18,9 → 18,16 |
public interface ITextComboCache { |
/** |
* Can this cache be used. |
* |
* @return <code>true</code> if this cache can be used. |
*/ |
public boolean isValid(); |
/** |
* Force le chargement du cache (en synchrone) et le renvoi |
*/ |
public List<String> loadCache(); |
public List<String> loadCache(final boolean readCache); |
/** |
* Retourne les éléments du cache, et le charge de manière synchrone si n'a jamais été chargé |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ImmutableITextComboCache.java |
---|
29,6 → 29,11 |
} |
@Override |
public boolean isValid() { |
return true; |
} |
@Override |
public final void addToCache(String string) { |
throw new UnsupportedOperationException(); |
} |
40,11 → 45,11 |
@Override |
public final List<String> getCache() { |
return this.loadCache(); |
return this.loadCache(true); |
} |
@Override |
public List<String> loadCache() { |
public List<String> loadCache(final boolean dsCache) { |
return this.cache; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/MutableListCombo.java |
---|
28,6 → 28,10 |
void removeCurrentText(); |
boolean canReload(); |
void reload(); |
/** |
* The component and where the popup should appear. |
* |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/IComboCacheListModel.java |
---|
New file |
0,0 → 1,125 |
/* |
* 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.component; |
import org.openconcerto.ui.component.combo.ISearchableCombo; |
import org.openconcerto.utils.change.CollectionChangeEvent; |
import org.openconcerto.utils.change.IListDataEvent; |
import org.openconcerto.utils.model.DefaultIMutableListModel; |
import org.openconcerto.utils.model.Reloadable; |
import java.util.Collection; |
import java.util.List; |
import javax.swing.SwingWorker; |
import javax.swing.event.ListDataEvent; |
import javax.swing.event.ListDataListener; |
/** |
* An IMutableListModel with items from {@link ITextComboCache}. |
* |
* @author Sylvain CUAZ |
* @see #load(Runnable) |
*/ |
public class IComboCacheListModel extends DefaultIMutableListModel<String> implements Reloadable { |
private final ITextComboCache cache; |
private final ListDataListener l; |
public IComboCacheListModel(final ITextComboCache c) { |
this.cache = c; |
this.l = new ListDataListener() { |
@SuppressWarnings("unchecked") |
public void contentsChanged(ListDataEvent e) { |
// selection change, see DefaultIMutableListModel#setSelectedItem() |
if (e.getIndex0() < 0) |
return; |
final CollectionChangeEvent evt = ((IListDataEvent) e).getCollectionChangeEvent(); |
this.remove(evt); |
this.add(evt.getItemsAdded()); |
} |
public void intervalAdded(ListDataEvent e) { |
this.add(getList().subList(e.getIndex0(), e.getIndex1() + 1)); |
} |
public void intervalRemoved(ListDataEvent e) { |
this.remove(((IListDataEvent) e).getCollectionChangeEvent()); |
} |
private void add(Collection<String> toAdd) { |
for (final String s : toAdd) { |
IComboCacheListModel.this.cache.addToCache(s); |
} |
} |
@SuppressWarnings("unchecked") |
private void remove(CollectionChangeEvent evt) { |
for (final String s : (Collection<String>) evt.getItemsRemoved()) |
IComboCacheListModel.this.cache.deleteFromCache(s); |
} |
}; |
} |
public final void load(final Runnable r, final boolean readCache) { |
if (this.cache.isValid()) { |
new SwingWorker<List<String>, Object>() { |
@Override |
protected List<String> doInBackground() throws Exception { |
return IComboCacheListModel.this.cache.loadCache(readCache); |
} |
@Override |
protected void done() { |
// don't remove and add from the cache, items just came from it |
removeListDataListener(IComboCacheListModel.this.l); |
removeAllElements(); |
try { |
addAll(get()); |
} catch (Exception e1) { |
// tant pis, pas de cache |
e1.printStackTrace(); |
} |
addListDataListener(IComboCacheListModel.this.l); |
if (r != null) |
r.run(); |
} |
}.execute(); |
} |
} |
@Override |
public void reload() { |
this.load(null, false); |
} |
/** |
* Load this and only afterwards call |
* {@link ISearchableCombo#initCache(org.openconcerto.utils.model.IListModel)}. |
* |
* @param combo the combo to initialise. |
*/ |
public void initCacheLater(final ISearchableCombo<String> combo) { |
this.load(new Runnable() { |
@Override |
public void run() { |
combo.initCache(IComboCacheListModel.this); |
} |
}, true); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextCombo.java |
---|
61,7 → 61,7 |
private final String defaultValue; |
private final ComboLockedMode locked; |
private final ValueChangeSupport supp; |
private final ValueChangeSupport<String> supp; |
protected final boolean autoComplete; |
protected boolean keyPressed; |
private boolean completing; |
181,9 → 181,19 |
public void removeCurrentText() { |
ITextCombo.this.removeCurrentText(); |
} |
@Override |
public boolean canReload() { |
return true; |
} |
@Override |
public void reload() { |
ITextCombo.this.loadCache(true); |
} |
}).listen(); |
this.loadCache(); |
this.loadCache(false); |
// ATTN marche car locked est final |
if (!this.isLocked()) { |
285,15 → 295,16 |
// *** cache |
// charge les elements de completion si besoin |
private synchronized final void loadCache() { |
private synchronized final void loadCache(final boolean force) { |
if (!this.cacheLoading) { |
this.modeToSet = this.isEnabled(); |
this.setEnabled(false); |
this.objToSelect = this.getValue(); |
this.cacheLoading = true; |
final SwingWorker sw = new SwingWorker<List<String>, Object>() { |
final SwingWorker<List<String>, Object> sw = new SwingWorker<List<String>, Object>() { |
@Override |
protected List<String> doInBackground() throws Exception { |
return ITextCombo.this.cache.getCache(); |
return force ? ITextCombo.this.cache.loadCache(false) : ITextCombo.this.cache.getCache(); |
} |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/combo/ISearchableCombo.java |
---|
26,7 → 26,9 |
import org.openconcerto.ui.valuewrapper.ValueChangeSupport; |
import org.openconcerto.ui.valuewrapper.ValueWrapper; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.utils.cc.IdentityHashSet; |
import org.openconcerto.utils.checks.ValidListener; |
import org.openconcerto.utils.checks.ValidState; |
import org.openconcerto.utils.model.DefaultIMutableListModel; |
33,6 → 35,7 |
import org.openconcerto.utils.model.IListModel; |
import org.openconcerto.utils.model.IMutableListModel; |
import org.openconcerto.utils.model.ListComboBoxModel; |
import org.openconcerto.utils.model.Reloadable; |
import org.openconcerto.utils.text.SimpleDocumentListener; |
import java.awt.Color; |
64,6 → 67,7 |
import java.util.ArrayList; |
import java.util.Collection; |
import java.util.HashMap; |
import java.util.HashSet; |
import java.util.List; |
import java.util.Map; |
408,7 → 412,7 |
/** |
* Returns the actions added at the end of the list of items. The name of the action will be |
* displayed and its actionPerformed() invoked when choosed. |
* displayed and its actionPerformed() invoked when chosen. |
* |
* @return the list of actions |
*/ |
436,6 → 440,8 |
if (!(acache instanceof IMutableListModel)) |
throw new IllegalArgumentException(this + " is unlocked but " + acache + " is not mutable"); |
final IMutableListModel<T> mutable = (IMutableListModel<T>) acache; |
final boolean isReloadable = mutable instanceof Reloadable; |
final Reloadable rel = isReloadable ? (Reloadable) mutable : null; |
new MutableListComboPopupListener(new MutableListCombo() { |
public ComboLockedMode getMode() { |
return ISearchableCombo.this.getMode(); |
454,6 → 460,16 |
public void removeCurrentText() { |
mutable.removeElement(getValue()); |
} |
@Override |
public boolean canReload() { |
return isReloadable; |
} |
@Override |
public void reload() { |
rel.reload(); |
} |
}).listen(); |
} |
497,10 → 513,29 |
} |
private void addItems(final int index, final Collection<T> originalItems) { |
// selection cannot change |
assert SwingUtilities.isEventDispatchThread(); |
final ISearchableComboItem<T> sel = getSelection(); |
final T selOriginal = sel == null ? null : sel.getOriginal(); |
final List<ISearchableComboItem<T>> toAdd = new ArrayList<ISearchableComboItem<T>>(originalItems.size()); |
for (final T originalItem : originalItems) { |
final ISearchableComboItem<T> textSelectorItem = createItem(originalItem); |
final ISearchableComboItem<T> textSelectorItem; |
if (this.itemsByOriginalItem.containsKey(originalItem)) { |
// allow another item with the same original : add another item to our model, but |
// keep the first one in itemsByOriginalItem (this map is only used in setValue() to |
// quickly find the ISearchableComboItem) |
textSelectorItem = createItem(originalItem); |
// see ISearchableComboPopup.validateSelection() |
assert !textSelectorItem.equals(this.itemsByOriginalItem.get(originalItem)) : "Have to not be equal to be able to choose one or the other"; |
} else { |
// reuse the selected value, otherwise the popup will select nothing |
if (sel != null && CompareUtils.equals(selOriginal, originalItem)) |
textSelectorItem = sel; |
else |
textSelectorItem = createItem(originalItem); |
this.itemsByOriginalItem.put(originalItem, textSelectorItem); |
} |
toAdd.add(textSelectorItem); |
} |
// only 1 fire |
510,7 → 545,8 |
private void rmItemsFromModel(final int index0, final int index1) { |
getModel().removeElementsAt(index0, index1); |
// remove from our map |
this.itemsByOriginalItem.keySet().retainAll(getCache().getList()); |
// ATTN for ~35000 items, new HashSet() got us from 6000ms to 8ms ! |
this.itemsByOriginalItem.keySet().retainAll(new HashSet<T>(getCache().getList())); |
} |
// conversion |
579,7 → 615,7 |
// set |
public void resetValue() { |
this.setValue(null); |
this.setValue((T) null); |
} |
public final void setValue(final T val) { |
603,15 → 639,20 |
} |
} |
private final void setValue(final T val, final boolean valid) { |
log("entering " + this.getClass().getSimpleName() + ".setValue " + val + " valid: " + valid); |
private final boolean setValid(final boolean valid) { |
final boolean invalidChange = this.invalidEdit != !valid; |
if (invalidChange) { |
this.invalidEdit = !valid; |
this.text.setForeground(this.invalidEdit ? Color.GRAY : Color.BLACK); |
} |
return invalidChange; |
} |
if (this.getValue() != val) { |
private final void setValue(final T val, final boolean valid) { |
log("entering " + this.getClass().getSimpleName() + ".setValue " + val + " valid: " + valid); |
final boolean invalidChange = this.setValid(valid); |
if (!CompareUtils.equals(this.getValue(), val)) { |
log("this.getValue() != val :" + this.getValue()); |
if (val == null) |
this.setSelection(null); |
634,6 → 675,24 |
} |
} |
// perhaps try to factor with the other setValue() |
final void setValue(final ISearchableComboItem<T> val) { |
log("entering " + this.getClass().getSimpleName() + ".setValue(ISearchableComboItem) " + val); |
assert new IdentityHashSet<ISearchableComboItem<T>>(this.getModelValues()).contains(val) : "Item not in model, perhaps use setValue(T)"; |
// valid since val is in our model |
final boolean invalidChange = this.setValid(true); |
if (!CompareUtils.equals(this.getSelection(), val)) { |
this.setSelection(val); |
} else if (invalidChange) { |
log("this.getSelection() == val and invalidChange"); |
// since val hasn't changed the model won't fire and thus our selectionChanged() |
// will not be called, but it has to since invalidEdit did change |
// so the text must be changed, and listeners notified |
this.selectionChanged(); |
} |
} |
private final void setSelection(final ISearchableComboItem<T> val) { |
log("entering " + this.getClass().getSimpleName() + ".setSelection " + val); |
this.getModel().setSelectedItem(val); |
787,8 → 846,8 |
* with the desired rows. |
* |
* @param rows the new row count. |
* @param textArea <code>true</code> if the editor should be a text area (ie can have more than |
* one line), <code>null</code> to retain the current editor, ignored if |
* @param textArea <code>true</code> if the editor should be a text area (i.e. can have more |
* than one line), <code>null</code> to retain the current editor, ignored if |
* <code>rows</code> >= 2. |
*/ |
public final void setRows(int rows, final Boolean textArea) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/combo/ISearchableComboPopup.java |
---|
13,8 → 13,6 |
package org.openconcerto.ui.component.combo; |
import org.openconcerto.utils.model.SimpleListDataListener; |
import java.awt.Color; |
import java.awt.Component; |
import java.awt.Dimension; |
36,7 → 34,6 |
import javax.swing.ListModel; |
import javax.swing.ListSelectionModel; |
import javax.swing.ScrollPaneConstants; |
import javax.swing.event.ListDataEvent; |
public class ISearchableComboPopup<T> extends JPopupMenu { |
53,26 → 50,7 |
uiInit(); |
// Listeners |
this.list.addMouseMotionListener(new ListMouseMotionHandler()); |
// JList always displays visibleRowCount even when fewer items exists |
// so if we put a high number we get a big blank popup |
// instead listen to model change to adjust row count |
this.getListModel().addListDataListener(new SimpleListDataListener() { |
@Override |
public void contentsChanged(ListDataEvent e) { |
// ATTN row count always gets back to zero when the contents change (because of |
// removeAll()) |
final int rowCount = Math.min(getListModel().getSize(), 30); |
// checking if rowCount changes doesn't work (one reason is probably that we're |
// called before Swing and so setVisible displays an empty list) |
ISearchableComboPopup.this.list.setVisibleRowCount(rowCount); |
if (rowCount > 0 && isVisible()) { |
// since "visible row count" is not dynamic |
setVisible(false); |
setVisible(true); |
} |
} |
}); |
} |
private ISearchableCombo<T> getCombo() { |
return this.text; |
98,6 → 76,7 |
final JLabel comp = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); |
comp.setFont(getCombo().getFont()); |
if (value instanceof Action) { |
comp.setFont(comp.getFont().deriveFont(Font.ITALIC)); |
comp.setText((String) ((Action) value).getValue(Action.NAME)); |
comp.setIcon(null); |
} else { |
207,7 → 186,9 |
// if no selection, don't change the combo |
if (sel != null) { |
if (sel instanceof ISearchableComboItem) { |
this.getCombo().setValue(((ISearchableComboItem<T>) sel).getOriginal()); |
// don't call setValue() with sel.getOriginal() to handle list with the same item |
// multiple times. |
this.getCombo().setValue((ISearchableComboItem<T>) sel); |
} else if (sel instanceof Action) { |
((Action) sel).actionPerformed(new ActionEvent(this.getCombo(), ActionEvent.ACTION_PERFORMED, this.getCombo().getName())); |
} else |
217,6 → 198,24 |
} |
public void open() { |
// JList always displays visibleRowCount even when fewer items exists |
// so if we put a high number we get a big blank popup |
// handle this in open() and not with a SimpleListDataListener since : |
// 1. open() is called only once whereas add is called multiple times in |
// ISearchableCombo.setMatchingCompletions(). |
// 2. open() is always called when the list is modified. |
final int size = getListModel().getSize(); |
// rowCount == 0 looks like a bug so show 3 empty rows |
final int rowCount = size == 0 ? 3 : Math.min(size, 30); |
if (this.list.getVisibleRowCount() != rowCount) { |
// checking if rowCount changes doesn't work (one reason is probably that we're |
// called before Swing and so setVisible displays an empty list) |
this.list.setVisibleRowCount(rowCount); |
if (this.isShowing()) { |
// since "visible row count" is not dynamic |
setVisible(false); |
} |
} |
// si on est pas déjà affiché |
// afficher même qd pas d'items : si l'user clique il faut qu'il voit la liste même vide |
if (!this.isShowing()) |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/JRadioButtons.java |
---|
144,6 → 144,7 |
private final void addBtn(String btnLabel, V id) { |
final JRadioButton btn = new JRadioButton(btnLabel); |
btn.setOpaque(false); |
for (final MouseListener l : this.mouseListeners) { |
btn.addMouseListener(l); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/AbstractFileTransfertHandler.java |
---|
New file |
0,0 → 1,137 |
/* |
* 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.view; |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.model.SQLTable; |
import java.awt.datatransfer.DataFlavor; |
import java.awt.datatransfer.Transferable; |
import java.io.File; |
import java.net.URI; |
import java.net.URISyntaxException; |
import java.util.ArrayList; |
import java.util.List; |
import java.util.StringTokenizer; |
import javax.swing.JComponent; |
import javax.swing.TransferHandler; |
public abstract class AbstractFileTransfertHandler extends TransferHandler { |
static private DataFlavor URIListFlavor = null; |
static public synchronized DataFlavor getURIListFlavor() { |
if (URIListFlavor == null) { |
try { |
URIListFlavor = new DataFlavor("text/uri-list;class=java.lang.String"); |
} catch (ClassNotFoundException e) { |
throw new IllegalStateException(e); |
} |
} |
return URIListFlavor; |
} |
public AbstractFileTransfertHandler() { |
} |
public abstract void handleFile(File f); |
@Override |
public boolean importData(final JComponent c, final Transferable t) { |
if (!canImport(c, t.getTransferDataFlavors())) { |
return false; |
} |
final List<File> list = new ArrayList<File>(); |
try { |
if (hasFileFlavor(t.getTransferDataFlavors())) { |
list.addAll((List<File>) t.getTransferData(DataFlavor.javaFileListFlavor)); |
} else if (hasURIListFlavor(t.getTransferDataFlavors())) { |
list.addAll(textURIListToFileList((String) t.getTransferData(getURIListFlavor()))); |
} |
} catch (Exception e) { |
e.printStackTrace(); |
} |
try { |
final Thread thread = new Thread("AbstractFileTransfertHandler") { |
@Override |
public void run() { |
for (File realFile : list) { |
handleFile(realFile); |
} |
} |
}; |
thread.start(); |
} catch (Exception e) { |
e.printStackTrace(); |
} |
return list.size() > 0; |
} |
@Override |
public int getSourceActions(JComponent c) { |
return COPY_OR_MOVE; |
} |
@Override |
public boolean canImport(JComponent c, DataFlavor[] flavors) { |
if (hasFileFlavor(flavors) || hasURIListFlavor(flavors)) { |
return true; |
} |
Log.get().config("No files or URL found in dropped object"); |
return false; |
} |
private boolean hasFileFlavor(DataFlavor[] flavors) { |
for (int i = 0; i < flavors.length; i++) { |
if (DataFlavor.javaFileListFlavor.equals(flavors[i]) || DataFlavor.javaRemoteObjectMimeType.equals(flavors[i])) { |
return true; |
} |
} |
return false; |
} |
private boolean hasURIListFlavor(DataFlavor[] flavors) { |
for (int i = 0; i < flavors.length; i++) { |
if (getURIListFlavor().equals(flavors[i])) { |
return true; |
} |
} |
return false; |
} |
static List<File> textURIListToFileList(String data) { |
final List<File> list = new ArrayList<File>(1); |
for (StringTokenizer st = new StringTokenizer(data, "\r\n"); st.hasMoreTokens();) { |
String s = st.nextToken(); |
if (s.startsWith("#")) { |
// the line is a comment (as per the RFC 2483) |
continue; |
} |
try { |
final URI uri = new URI(s); |
final File file = new File(uri); |
list.add(file); |
} catch (URISyntaxException e) { |
e.printStackTrace(); |
} catch (IllegalArgumentException e) { |
e.printStackTrace(); |
} |
} |
return list; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/KeyTableCellRenderer.java |
---|
15,8 → 15,9 |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableListener; |
import org.openconcerto.sql.model.SQLTableEvent; |
import org.openconcerto.sql.model.SQLTableEvent.Mode; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.sql.sqlobject.IComboSelectionItem; |
import java.util.HashMap; |
31,7 → 32,7 |
private Object toSelect; |
private boolean isLoading = false; |
private final SQLElement el; |
static final Map<SQLElement, Map<Integer, IComboSelectionItem>> cacheMap = new HashMap<SQLElement, Map<Integer, IComboSelectionItem>>(); |
static private final Map<SQLElement, Map<Integer, IComboSelectionItem>> cacheMap = new HashMap<SQLElement, Map<Integer, IComboSelectionItem>>(); |
public KeyTableCellRenderer(final SQLElement el) { |
super(); |
93,19 → 94,13 |
m.put(comboSelectionItem.getId(), comboSelectionItem); |
} |
cacheMap.put(KeyTableCellRenderer.this.el, m); |
KeyTableCellRenderer.this.el.getTable().addPremierTableListener(new SQLTableListener() { |
KeyTableCellRenderer.this.el.getTable().addPremierTableModifiedListener(new SQLTableModifiedListener() { |
@Override |
public void rowAdded(SQLTable table, int id) { |
m.put(id, KeyTableCellRenderer.this.el.getComboRequest().getComboItem(id)); |
} |
@Override |
public void rowDeleted(SQLTable table, int id) { |
public void tableModified(SQLTableEvent evt) { |
final int id = evt.getId(); |
if (evt.getMode() == Mode.ROW_DELETED) |
m.remove(id); |
} |
@Override |
public void rowModified(SQLTable table, int id) { |
else |
m.put(id, KeyTableCellRenderer.this.el.getComboRequest().getComboItem(id)); |
} |
}); |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java |
---|
59,6 → 59,7 |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.utils.convertor.StringClobConvertor; |
import java.awt.Color; |
import java.awt.Component; |
import java.awt.FlowLayout; |
import java.awt.Font; |
308,6 → 309,11 |
// don't auto start, otherwise F2 will trigger the edition |
this.jTable.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE); |
// Better look |
this.jTable.setShowHorizontalLines(false); |
this.jTable.setGridColor(new Color(230, 230, 230)); |
this.jTable.setRowHeight(this.jTable.getRowHeight() + 4); |
this.popup = new JPopupMenu(); |
TablePopupMouseListener.add(this.jTable, new ITransformer<MouseEvent, JPopupMenu>() { |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowAction.java |
---|
59,6 → 59,9 |
} |
public final PredicateRowAction setPredicate(IPredicate<? super IListeEvent> pred) { |
if (pred == null) { |
throw new IllegalArgumentException("null predicate"); |
} |
this.pred = pred; |
return this; |
} |
69,6 → 72,9 |
@Override |
public boolean enabledFor(IListeEvent evt) { |
if (pred == null) { |
throw new IllegalStateException("No predicate for action:" + this.getAction() + ":" + this.getAction().getValue(Action.NAME)); |
} |
return this.pred.evaluateChecked(evt); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/EditFrame.java |
---|
40,6 → 40,11 |
public static final EditMode MODIFICATION = EditPanel.MODIFICATION; |
public static final EditMode CREATION = EditPanel.CREATION; |
/** |
* If this system property is true, then the minimum size of an edit frame will match the one |
* from its content pane. |
*/ |
public final static String SMALL_MIN_SIZE = "org.openconcerto.sql.editFrame.smallMinSize"; |
private boolean frameResize; |
103,8 → 108,17 |
// The minimum size of the frame must be the size when packed |
this.pack(); |
Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); |
int w = Math.min(d.width - 100, getWidth()); |
int h = Math.min(d.height - 100, getHeight()); |
final int wantedW, wantedH; |
if (Boolean.getBoolean(SMALL_MIN_SIZE)) { |
final Dimension minimumSize = this.getMinimumSize(); |
wantedW = minimumSize.width; |
wantedH = minimumSize.height; |
} else { |
wantedW = getWidth(); |
wantedH = getHeight(); |
} |
final int w = Math.min(d.width - 100, wantedW); |
final int h = Math.min(d.height - 100, wantedH); |
setMinimumSize(new Dimension(w, h)); |
// View resized |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/EditPanel.java |
---|
257,6 → 257,7 |
this.p.getVerticalScrollBar().setUnitIncrement(9); |
this.p.setOpaque(false); |
this.p.getViewport().setOpaque(false); |
this.p.setMinimumSize(new Dimension(60, 60)); |
container.add(this.p, c); |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/FileTransfertHandler.java |
---|
19,11 → 19,8 |
import java.awt.datatransfer.DataFlavor; |
import java.awt.datatransfer.Transferable; |
import java.io.File; |
import java.net.URI; |
import java.net.URISyntaxException; |
import java.util.ArrayList; |
import java.util.List; |
import java.util.StringTokenizer; |
import javax.swing.JComponent; |
import javax.swing.TransferHandler; |
30,19 → 27,6 |
public class FileTransfertHandler extends TransferHandler { |
static private DataFlavor URIListFlavor = null; |
static public DataFlavor getURIListFlavor() { |
if (URIListFlavor == null) { |
try { |
URIListFlavor = new DataFlavor("text/uri-list;class=java.lang.String"); |
} catch (ClassNotFoundException e) { |
throw new IllegalStateException(e); |
} |
} |
return URIListFlavor; |
} |
private final SQLTable tableName; |
public FileTransfertHandler(SQLTable table) { |
59,7 → 43,7 |
if (hasFileFlavor(t.getTransferDataFlavors())) { |
list.addAll((List<File>) t.getTransferData(DataFlavor.javaFileListFlavor)); |
} else if (hasURIListFlavor(t.getTransferDataFlavors())) { |
list.addAll(textURIListToFileList((String) t.getTransferData(getURIListFlavor()))); |
list.addAll(AbstractFileTransfertHandler.textURIListToFileList((String) t.getTransferData(AbstractFileTransfertHandler.getURIListFlavor()))); |
} |
} catch (Exception e) { |
e.printStackTrace(); |
122,7 → 106,7 |
private boolean hasURIListFlavor(DataFlavor[] flavors) { |
for (int i = 0; i < flavors.length; i++) { |
if (getURIListFlavor().equals(flavors[i])) { |
if (AbstractFileTransfertHandler.getURIListFlavor().equals(flavors[i])) { |
return true; |
} |
} |
133,24 → 117,4 |
return DropManager.getInstance().getHandlerForTable(this.tableName); |
} |
private static List<File> textURIListToFileList(String data) { |
final List<File> list = new ArrayList<File>(1); |
for (StringTokenizer st = new StringTokenizer(data, "\r\n"); st.hasMoreTokens();) { |
String s = st.nextToken(); |
if (s.startsWith("#")) { |
// the line is a comment (as per the RFC 2483) |
continue; |
} |
try { |
final URI uri = new URI(s); |
final File file = new File(uri); |
list.add(file); |
} catch (URISyntaxException e) { |
e.printStackTrace(); |
} catch (IllegalArgumentException e) { |
e.printStackTrace(); |
} |
} |
return list; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/PropsConfiguration.java |
---|
31,16 → 31,20 |
import org.openconcerto.utils.ExceptionHandler; |
import org.openconcerto.utils.FileUtils; |
import org.openconcerto.utils.LogUtils; |
import org.openconcerto.utils.MultipleOutputStream; |
import org.openconcerto.utils.StreamUtils; |
import org.openconcerto.utils.cc.IClosure; |
import java.io.BufferedOutputStream; |
import java.io.ByteArrayOutputStream; |
import java.io.File; |
import java.io.FileDescriptor; |
import java.io.FileInputStream; |
import java.io.FileNotFoundException; |
import java.io.FileOutputStream; |
import java.io.IOException; |
import java.io.InputStream; |
import java.io.OutputStream; |
import java.io.PrintStream; |
import java.net.InetAddress; |
import java.net.UnknownHostException; |
512,6 → 516,10 |
this.setupLogging(dirName, Boolean.getBoolean(REDIRECT_TO_FILE)); |
} |
protected boolean keepStandardStreamsWhenRedirectingToFile() { |
return true; |
} |
public void setupLogging(final String dirName, final boolean redirectToFile) { |
final File logDir; |
try { |
542,9 → 550,17 |
logFile.getParentFile().mkdirs(); |
try { |
System.out.println("Log file: " + logFile.getAbsolutePath()); |
final PrintStream ps = new PrintStream(new FileOutputStream(logFile, true)); |
System.setErr(ps); |
System.setOut(ps); |
final OutputStream fileOut = new FileOutputStream(logFile, true); |
final OutputStream out, err; |
if (this.keepStandardStreamsWhenRedirectingToFile()) { |
out = new MultipleOutputStream(fileOut, new FileOutputStream(FileDescriptor.out)); |
err = new MultipleOutputStream(fileOut, new FileOutputStream(FileDescriptor.err)); |
} else { |
out = fileOut; |
err = fileOut; |
} |
System.setErr(new PrintStream(new BufferedOutputStream(err, 128), true)); |
System.setOut(new PrintStream(new BufferedOutputStream(out, 128), true)); |
} catch (FileNotFoundException e) { |
throw new IllegalStateException("unable to write to log file", e); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/IComboModel.java |
---|
16,7 → 16,8 |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableListener; |
import org.openconcerto.sql.model.SQLTableEvent; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.sql.request.ComboSQLRequest; |
import org.openconcerto.sql.view.search.SearchSpec; |
import org.openconcerto.sql.view.search.SearchSpecUtils; |
27,7 → 28,6 |
import org.openconcerto.utils.checks.EmptyListener; |
import org.openconcerto.utils.checks.EmptyObj; |
import org.openconcerto.utils.checks.MutableValueObject; |
import org.openconcerto.utils.model.DefaultIListModel; |
import org.openconcerto.utils.model.DefaultIMutableListModel; |
import java.beans.PropertyChangeEvent; |
52,7 → 52,7 |
* |
* @author Sylvain CUAZ |
*/ |
public class IComboModel extends DefaultIMutableListModel<IComboSelectionItem> implements SQLTableListener, MutableValueObject<IComboSelectionItem>, EmptyObj { |
public class IComboModel extends DefaultIMutableListModel<IComboSelectionItem> implements SQLTableModifiedListener, MutableValueObject<IComboSelectionItem>, EmptyObj { |
private final ComboSQLRequest req; |
72,8 → 72,6 |
// true from when the combo is filled with the sole "dots" item until it is loaded with actual |
// items, no need to synchronize (EDT) |
private boolean updating; |
// true if the items being changed are for display only and do not reflect the db |
private boolean uiItems; |
// l'id à sélectionner à la fin du updateAll |
private int idToSelect; |
100,7 → 98,6 |
this.search = null; |
this.runnables = new ArrayList<Runnable>(); |
this.setWillUpdate(null); |
this.uiItems = false; |
this.itemsByID = new HashMap<Integer, IComboSelectionItem>(); |
this.addMissingItem = true; |
166,7 → 163,7 |
// selection change |
comboValueChanged(); |
} else { |
itemsChanged(((DefaultIListModel) e.getSource()).getList()); |
itemsChanged(); |
} |
} |
}); |
230,14 → 227,14 |
* Reload this combo. This method is thread-safe. |
*/ |
public synchronized final void fillCombo() { |
this.fillCombo(null); |
this.fillCombo(null, true); |
} |
public synchronized final void fillCombo(final Runnable r) { |
public synchronized final void fillCombo(final Runnable r, final boolean readCache) { |
// wholly synch otherwise we might get onScreen after the if |
// and thus completely ignore that fillCombo() |
if (!this.isSleepAllowed() || this.isOnScreen() || r != null) { |
this.doUpdateAll(r); |
this.doUpdateAll(r, readCache); |
} else { |
this.isADirtyDrityGirl = true; |
} |
260,14 → 257,12 |
this.setUpdating(true); |
this.uiItems = true; |
this.removeAllItems(); |
addItem(new IComboSelectionItem(SQLRow.NONEXISTANT_ID, "....")); |
this.uiItems = false; |
// Like ITableModel, don't remove all items, so that if the request fails we still |
// keep old items (we used to have uiItems=true while setting the list to "Loading...") |
} |
} |
private void doUpdateAll(final Runnable r) { |
private void doUpdateAll(final Runnable r, final boolean readCache) { |
log("entering doUpdateAll"); |
synchronized (this) { |
this.isADirtyDrityGirl = false; |
290,13 → 285,12 |
protected List<IComboSelectionItem> doInBackground() throws InterruptedException { |
// attends 1 peu pour voir si on va pas être annulé |
Thread.sleep(50); |
return SearchSpecUtils.filter(IComboModel.this.req.getComboItems(), search); |
return SearchSpecUtils.filter(IComboModel.this.req.getComboItems(readCache), search); |
} |
// Runs on the event-dispatching thread. |
@Override |
public void done() { |
try { |
synchronized (IComboModel.this) { |
// if cancel() is called after doInBackground() nothing happens |
// but updating is set to a new instance |
304,38 → 298,49 |
// une autre maj arrive |
return; |
final List<IComboSelectionItem> items = this.get(); |
final boolean firstFill = !IComboModel.this.filledOnce; |
// store before removing since it can trigger a selection change |
final int idToSelect = IComboModel.this.idToSelect; |
List<IComboSelectionItem> items = null; |
try { |
items = this.get(); |
removeAllItems(); |
addAllItems(items); |
final boolean firstFill = !IComboModel.this.filledOnce; |
IComboModel.this.filledOnce = true; |
} catch (InterruptedException e) { |
// ne devrait pas arriver puisque done() appelée après doInBackground() |
e.printStackTrace(); |
} catch (CancellationException e) { |
// ne devrait pas arriver puisqu'on teste isCancelled() |
e.printStackTrace(); |
} catch (ExecutionException e) { |
if (!(e.getCause() instanceof RTInterruptedException)) |
// pas normal |
e.printStackTrace(); |
} finally { |
// always clear willUpdate otherwise the combo can't recover |
assert IComboModel.this.willUpdate == this; |
IComboModel.this.setWillUpdate(null); |
} |
// check if items could be retrieved |
// TODO otherwise show the error to the user so he knows that items are |
// stale and he could reload them |
if (items != null) { |
// restaurer l'état |
// if there's only one item in the list and no previous ID to select |
// and org.openconcerto.sql.sqlCombo.selectSoleItem=true,select the item |
final boolean noSelection = IComboModel.this.idToSelect == SQLRow.NONEXISTANT_ID; |
final boolean noSelection = idToSelect == SQLRow.NONEXISTANT_ID; |
if (items.size() == 1 && noSelection && Boolean.getBoolean("org.openconcerto.sql.sqlCombo.selectSoleItem")) |
IComboModel.this.setSelectedItem(items.get(0)); |
else if (noSelection && firstFill && getFirstFillSelection() != null) |
IComboModel.this.setSelectedItem(getFirstFillSelection().transformChecked(items)); |
else |
selectID(IComboModel.this.idToSelect); |
selectID(idToSelect); |
for (final Runnable r : IComboModel.this.runnables) |
r.run(); |
IComboModel.this.runnables.clear(); |
} |
} catch (InterruptedException e) { |
// ne devrait pas arriver puisque done() appelée après doInBackground() |
e.printStackTrace(); |
} catch (CancellationException e) { |
// ne devrait pas arriver puisqu'on teste isCancelled() |
e.printStackTrace(); |
} catch (ExecutionException e) { |
if (!(e.getCause() instanceof RTInterruptedException)) |
// pas normal |
e.printStackTrace(); |
} |
} |
}; |
401,10 → 406,9 |
} |
} |
private final void itemsChanged(final List newVal) { |
private final void itemsChanged() { |
final List<IComboSelectionItem> newVal = this.getList(); |
this.propSupp.firePropertyChange("items", null, newVal); |
if (!this.uiItems) |
this.propSupp.firePropertyChange("dataItems", null, newVal); |
} |
// *** value |
484,17 → 488,10 |
log("entering selectID " + id); |
assert SwingUtilities.isEventDispatchThread(); |
// selectID() caused by the removeAll() of updateAllBegun() |
// so we don't want to forget the selection |
if (this.uiItems) { |
assert id == SQLRow.NONEXISTANT_ID; |
return; |
} |
// no need to launch another updateAll() if one is already underway |
if (this.neverBeenFilled() && !isUpdating()) |
// don't use fillCombo() which won't really update unless we're on screen |
this.doUpdateAll(null); |
this.doUpdateAll(null, true); |
if (this.isUpdating()) { |
this.idToSelect = id; |
624,7 → 621,8 |
* ones (e.g. adding a '-- loading --' item). |
*/ |
public final void addItemsListener(PropertyChangeListener l, final boolean all) { |
this.addListener(all ? "items" : "dataItems", l); |
// there's no uiItems anymore, so ignore the boolean |
this.addListener("items", l); |
} |
public final void rmItemsListener(PropertyChangeListener l) { |
633,41 → 631,15 |
// *** une table que nous affichons a changé |
/* |
* (non-Javadoc) |
* |
* @see org.openconcerto.sql.model.SQLTableListener2#rowModified(org.openconcerto.sql.model.SQLTable, int) |
*/ |
public void rowModified(SQLTable table, int id) { |
if (id >= SQLRow.MIN_VALID_ID && this.getForeignTable().equals(table)) { |
@Override |
public void tableModified(SQLTableEvent evt) { |
final int id = evt.getId(); |
if (id >= SQLRow.MIN_VALID_ID && this.getForeignTable().equals(evt.getTable())) { |
this.reloadComboItem(id); |
} else |
this.fillCombo(); |
} |
/* |
* (non-Javadoc) |
* |
* @see org.openconcerto.sql.model.SQLTableListener2#rowAdded(org.openconcerto.sql.model.SQLTable, int) |
*/ |
public void rowAdded(SQLTable table, int id) { |
this.fillCombo(); |
} |
/* |
* (non-Javadoc) |
* |
* @see org.openconcerto.sql.model.SQLTableListener2#rowDeleted(org.openconcerto.sql.model.SQLTable, int) |
*/ |
public void rowDeleted(SQLTable table, int id) { |
if (this.getForeignTable().equals(table)) { |
// delete even if we're not on screen, since it takes next to no time |
this.reloadComboItem(id); |
} else { |
this.fillCombo(); |
} |
} |
// *** search |
public final void search(SearchSpec spec) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/SQLSearchableTextCombo.java |
---|
18,18 → 18,9 |
import org.openconcerto.sql.sqlobject.SQLTextCombo.ITextComboCacheSQL; |
import org.openconcerto.sql.sqlobject.itemview.RowItemViewComponent; |
import org.openconcerto.ui.component.ComboLockedMode; |
import org.openconcerto.ui.component.IComboCacheListModel; |
import org.openconcerto.ui.component.combo.ISearchableTextCombo; |
import org.openconcerto.utils.change.CollectionChangeEvent; |
import org.openconcerto.utils.change.IListDataEvent; |
import org.openconcerto.utils.model.DefaultIMutableListModel; |
import java.util.Collection; |
import java.util.List; |
import javax.swing.SwingWorker; |
import javax.swing.event.ListDataEvent; |
import javax.swing.event.ListDataListener; |
/** |
* An ISearchableTextCombo with the cache from COMPLETION. |
* |
73,87 → 64,17 |
* @param cache the cache to set. |
*/ |
public void initCacheLater(final ISQLListModel cache) { |
cache.load(new Runnable() { |
@Override |
public void run() { |
initCache(cache); |
cache.initCacheLater(this); |
} |
}); |
} |
public static class ISQLListModel extends DefaultIMutableListModel<String> { |
public static class ISQLListModel extends IComboCacheListModel { |
private final ITextComboCacheSQL cache; |
private final ListDataListener l; |
public ISQLListModel(final SQLField f) { |
this(new ITextComboCacheSQL(f)); |
} |
public ISQLListModel(final ITextComboCacheSQL c) { |
this.cache = c; |
this.l = new ListDataListener() { |
@SuppressWarnings("unchecked") |
public void contentsChanged(ListDataEvent e) { |
// selection change, see DefaultIMutableListModel#setSelectedItem() |
if (e.getIndex0() < 0) |
return; |
final CollectionChangeEvent evt = ((IListDataEvent) e).getCollectionChangeEvent(); |
this.remove(evt); |
this.add(evt.getItemsAdded()); |
super(c); |
} |
public void intervalAdded(ListDataEvent e) { |
this.add(getList().subList(e.getIndex0(), e.getIndex1() + 1)); |
} |
public void intervalRemoved(ListDataEvent e) { |
this.remove(((IListDataEvent) e).getCollectionChangeEvent()); |
} |
private void add(Collection<String> toAdd) { |
for (final String s : toAdd) { |
ISQLListModel.this.cache.addToCache(s); |
} |
} |
@SuppressWarnings("unchecked") |
private void remove(CollectionChangeEvent evt) { |
for (final String s : (Collection<String>) evt.getItemsRemoved()) |
ISQLListModel.this.cache.deleteFromCache(s); |
} |
}; |
} |
private void load(final Runnable r) { |
if (this.cache.isValid()) { |
new SwingWorker<List<String>, Object>() { |
@Override |
protected List<String> doInBackground() throws Exception { |
return ISQLListModel.this.cache.loadCache(); |
} |
@Override |
protected void done() { |
// don't remove and add from the cache, items just came from it |
removeListDataListener(ISQLListModel.this.l); |
removeAllElements(); |
try { |
addAll(get()); |
} catch (Exception e1) { |
// tant pis, pas de cache |
e1.printStackTrace(); |
} |
addListDataListener(ISQLListModel.this.l); |
if (r != null) |
r.run(); |
} |
}.execute(); |
} |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/SQLRequestComboBox.java |
---|
39,6 → 39,7 |
import java.awt.Component; |
import java.awt.GridLayout; |
import java.awt.event.ActionEvent; |
import java.awt.event.HierarchyEvent; |
import java.awt.event.HierarchyListener; |
import java.beans.PropertyChangeEvent; |
47,6 → 48,7 |
import java.util.List; |
import javax.accessibility.Accessible; |
import javax.swing.AbstractAction; |
import javax.swing.Action; |
import javax.swing.Icon; |
import javax.swing.ImageIcon; |
120,6 → 122,13 |
this.combo = new ISearchableCombo<IComboSelectionItem>(ComboLockedMode.LOCKED, 1, this.stringStuff.length()); |
this.combo.setIncludeEmpty(addUndefined); |
this.combo.getActions().add(new AbstractAction("Recharger") { |
@Override |
public void actionPerformed(ActionEvent e) { |
// ignore cache since a user explicitly asked for an update |
fillCombo(null, false); |
} |
}); |
this.emptySupp = new EmptyChangeSupport(this); |
this.supp = new ValueChangeSupport<Integer>(this); |
138,7 → 147,10 |
@Override |
public void init(SQLRowItemView v) { |
final SQLTable foreignTable = v.getField().getDBSystemRoot().getGraph().getForeignTable(v.getField()); |
if (!this.hasModel()) |
this.uiInit(Configuration.getInstance().getDirectory().getElement(foreignTable).getComboRequest()); |
else if (this.getRequest().getPrimaryTable() != foreignTable) |
throw new IllegalArgumentException("Tables are different " + getRequest().getPrimaryTable().getSQLName() + " != " + foreignTable.getSQLName()); |
} |
/** |
297,9 → 309,13 |
} |
public synchronized final void fillCombo(final Runnable r) { |
this.req.fillCombo(r); |
this.fillCombo(r, true); |
} |
public synchronized final void fillCombo(final Runnable r, final boolean readCache) { |
this.req.fillCombo(r, readCache); |
} |
// combo |
public final List<IComboSelectionItem> getItems() { |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/itemview/VWRowItemView.java |
---|
65,7 → 65,7 |
/** |
* The predicate testing whether the value is empty or not. This implementation returns |
* {@link EmptyObjFromVO#DEFAULT_PREDICATE} |
* {@link EmptyObjFromVO#getDefaultPredicate()} |
* |
* @return the predicate testing whether the value is empty. |
*/ |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ElementComboBox.java |
---|
18,6 → 18,7 |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.request.ComboSQLRequest; |
import org.openconcerto.sql.request.SQLRowItemView; |
import org.openconcerto.sql.view.EditFrame; |
import org.openconcerto.sql.view.EditPanel; |
135,8 → 136,14 |
* @return this |
*/ |
public final ElementComboBox init(SQLElement element) { |
return this.init(element, element.getComboRequest()); |
} |
public final ElementComboBox init(SQLElement element, final ComboSQLRequest req) { |
if (element.getTable() != req.getPrimaryTable()) |
throw new IllegalArgumentException("Tables are different " + element.getTable().getSQLName() + " != " + req.getPrimaryTable().getSQLName()); |
this.element = element; |
this.uiInit(this.element.getComboRequest()); |
this.uiInit(req); |
return this; |
} |
146,7 → 153,10 |
if (foreignTable == null) { |
throw new IllegalArgumentException("No foreign table for " + v.getField().getFullName()); |
} |
if (this.getElement() == null) |
this.init(Configuration.getInstance().getDirectory().getElement(foreignTable)); |
else if (this.getElement().getTable() != foreignTable) |
throw new IllegalArgumentException("Tables are different " + getElement().getTable().getSQLName() + " != " + foreignTable.getSQLName()); |
} |
public final SQLElement getElement() { |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextWithCompletion.java |
---|
15,17 → 15,16 |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableListener; |
import org.openconcerto.sql.model.SQLTableEvent; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.request.ComboSQLRequest; |
import org.openconcerto.ui.component.text.TextComponent; |
import org.openconcerto.utils.OrderedSet; |
import org.openconcerto.utils.checks.MutableValueObject; |
import org.openconcerto.utils.text.DocumentFilterList; |
import org.openconcerto.utils.text.DocumentFilterList.FilterType; |
import org.openconcerto.utils.text.LimitedSizeDocumentFilter; |
import org.openconcerto.utils.text.DocumentFilterList.FilterType; |
import java.awt.Component; |
import java.awt.GridLayout; |
118,19 → 117,12 |
this.isLoading = true; |
loadCacheAsynchronous(); |
this.comboRequest.addTableListener(new SQLTableListener() { |
public void rowAdded(SQLTable table, int id) { |
// FIXME never removed |
this.comboRequest.addTableListener(new SQLTableModifiedListener() { |
@Override |
public void tableModified(SQLTableEvent evt) { |
loadCacheAsynchronous(); |
} |
public void rowDeleted(SQLTable table, int id) { |
loadCacheAsynchronous(); |
} |
public void rowModified(SQLTable table, int id) { |
loadCacheAsynchronous(); |
} |
}); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/SQLTextCombo.java |
---|
15,6 → 15,7 |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.model.DBRoot; |
import org.openconcerto.sql.model.IResultSetHandler; |
import org.openconcerto.sql.model.SQLDataSource; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRowValues; |
85,13 → 86,25 |
return this.t.getDBSystemRoot().getDataSource(); |
} |
@SuppressWarnings("unchecked") |
public List<String> loadCache() { |
public List<String> loadCache(final boolean dsCache) { |
final SQLSelect sel = new SQLSelect(this.t.getBase()); |
sel.addSelect(this.t.getField("LABEL")); |
sel.setWhere(new Where(this.t.getField("CHAMP"), "=", this.field)); |
// ignore DS cache to allow the fetching of rows modified by another VM |
@SuppressWarnings("unchecked") |
final List<String> items = (List<String>) this.getDS().execute(sel.asString(), new IResultSetHandler(SQLDataSource.COLUMN_LIST_HANDLER) { |
@Override |
public boolean readCache() { |
return dsCache; |
} |
@Override |
public boolean writeCache() { |
return true; |
} |
}); |
this.cache.clear(); |
this.cache.addAll(this.getDS().executeCol(sel.asString())); |
this.cache.addAll(items); |
return this.cache; |
} |
98,7 → 111,7 |
public List<String> getCache() { |
if (!this.loadedOnce) { |
this.loadCache(); |
this.loadCache(true); |
this.loadedOnce = true; |
} |
return this.cache; |
/trunk/OpenConcerto/src/org/openconcerto/sql/Configuration.java |
---|
119,7 → 119,7 |
return newFile; |
} |
protected final File getConfDir(DBStructureItem<?> db) { |
public final File getConfDir(DBStructureItem<?> db) { |
return DBItemFileCache.getDescendant(new File(getConfDir(), "dataDepedent"), DBFileCache.getJDBCAncestorNames(db, true)); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLRowView.java |
---|
19,7 → 19,9 |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableListener; |
import org.openconcerto.sql.model.SQLTableEvent; |
import org.openconcerto.sql.model.SQLTableEvent.Mode; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.ui.SwingThreadUtils; |
import java.awt.Component; |
49,7 → 51,7 |
// la table cible de cette requete |
private final SQLTable table; |
private final SQLTableListener tableListener; |
private final SQLTableModifiedListener tableListener; |
// l'id affiché ou SQLRow.NONEXISTANT_ID si les valeurs affichées ne sont pas liées à une ligne |
// dans la base |
private int selectedID; |
74,7 → 76,15 |
this.filling = false; |
this.updating = false; |
this.selectedID = SQLRow.NONEXISTANT_ID; |
this.tableListener = new SQLTableListener() { |
this.tableListener = new SQLTableModifiedListener() { |
@Override |
public void tableModified(SQLTableEvent evt) { |
if (evt.getMode() == Mode.ROW_UPDATED) |
this.rowModified(evt.getTable(), evt.getId()); |
else if (evt.getMode() == Mode.ROW_DELETED) |
this.rowDeleted(evt.getTable(), evt.getId()); |
// else don't care |
} |
public void rowModified(SQLTable t, int id) { |
if (!isUpdating() && existsInDB()) { |
88,10 → 98,6 |
} |
} |
public void rowAdded(SQLTable t, int id) { |
// don't care |
} |
public void rowDeleted(SQLTable t, int id) { |
if (!isUpdating() && existsInDB()) { |
if (!t.equals(getTable())) { |
115,12 → 121,12 |
public final void activate(boolean b) { |
if (b) { |
this.table.addTableListener(this.tableListener); |
this.table.addTableModifiedListener(this.tableListener); |
if (this.existsInDB()) |
// to catch up to the changes which happened while we weren't listening |
this.select(this.getSelectedID()); |
} else |
this.table.removeTableListener(this.tableListener); |
this.table.removeTableModifiedListener(this.tableListener); |
} |
/** |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/ComboSQLRequest.java |
---|
143,6 → 143,10 |
} |
public final List<IComboSelectionItem> getComboItems() { |
return this.getComboItems(true); |
} |
public final List<IComboSelectionItem> getComboItems(final boolean readCache) { |
if (this.comboFields.isEmpty()) |
throw new IllegalStateException("La liste des items listitems est vide!! Ils faut utiliser addComboItem..."); |
151,14 → 155,17 |
final SQLRowValuesListFetcher comboSelect = this.getFetcher(null).freeze(); |
final CacheKey cacheKey = new CacheKey(comboSelect, this.fieldSeparator, this.undefLabel, this.customizeItem); |
if (readCache) { |
final CacheResult<List<IComboSelectionItem>> l = cache.check(cacheKey); |
if (l.getState() == CacheResult.State.INTERRUPTED) |
throw new RTInterruptedException("interrupted while waiting for the cache"); |
else if (l.getState() == CacheResult.State.VALID) |
return l.getRes(); |
} |
try { |
final List<IComboSelectionItem> result = new ArrayList<IComboSelectionItem>(); |
// SQLRowValuesListFetcher don't cache |
for (final SQLRowValues vals : comboSelect.fetch()) { |
if (Thread.currentThread().isInterrupted()) |
throw new RTInterruptedException("interrupted in fill"); |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLCacheWatcher.java |
---|
16,7 → 16,7 |
import org.openconcerto.sql.model.SQLData; |
import org.openconcerto.sql.model.SQLDataListener; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableListener; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.utils.cache.CacheWatcher; |
/** |
27,7 → 27,7 |
*/ |
public class SQLCacheWatcher<K> extends CacheWatcher<K, SQLData> { |
private final SQLTableListener listener; |
private final SQLTableModifiedListener listener; |
SQLCacheWatcher(final SQLCache<K, ?> c, final SQLData t) { |
super(c, t); |
36,7 → 36,7 |
clearCache(); |
} |
}); |
this.getTable().addPremierTableListener(this.listener); |
this.getTable().addPremierTableModifiedListener(this.listener); |
} |
private final SQLTable getTable() { |
45,7 → 45,7 |
@Override |
protected void dying() { |
this.getTable().removeTableListener(this.listener); |
this.getTable().removeTableModifiedListener(this.listener); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/BaseSQLRequest.java |
---|
16,7 → 16,7 |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLFieldsSet; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableListener; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import java.util.Collection; |
import java.util.Set; |
38,15 → 38,15 |
*/ |
protected abstract Collection<SQLField> getAllFields(); |
public final void addTableListener(SQLTableListener l) { |
public final void addTableListener(SQLTableModifiedListener l) { |
for (final SQLTable t : this.getTables()) { |
t.addTableListener(l); |
t.addTableModifiedListener(l); |
} |
} |
public final void removeTableListener(SQLTableListener l) { |
public final void removeTableListener(SQLTableModifiedListener l) { |
for (final SQLTable t : this.getTables()) { |
t.removeTableListener(l); |
t.removeTableModifiedListener(l); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/RowBacked.java |
---|
21,7 → 21,6 |
import org.openconcerto.sql.model.SQLTable; |
import java.util.HashMap; |
import java.util.Iterator; |
import java.util.Map; |
import org.apache.commons.collections.Transformer; |
35,6 → 34,7 |
protected static abstract class PropExtractor implements Transformer { |
@Override |
public final Object transform(Object input) { |
return this.extract((SQLRowAccessor) input); |
} |
51,9 → 51,7 |
this.propExtractors = new HashMap<String, PropExtractor>(); |
this.values = new HashMap<String, Object>(); |
final Iterator iter = PolymorphFK.findPolymorphFK(this.getTable()).iterator(); |
while (iter.hasNext()) { |
final PolymorphFK f = (PolymorphFK) iter.next(); |
for (final PolymorphFK f : PolymorphFK.findPolymorphFK(this.getTable())) { |
this.addPolymorphFK(f); |
} |
} |
110,6 → 108,7 |
protected final void addPolymorphFK(final PolymorphFK fk) { |
this.putExtractor(fk.getName(), new PropExtractor() { |
@Override |
public Object extract(SQLRowAccessor r) { |
final String tableName = r.getString(fk.getTableField().getName()); |
final SQLTable foreignT = tableName == null ? null : r.getTable().getBase().getTable(tableName); |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/DefaultElementSQLObject.java |
---|
35,6 → 35,7 |
import javax.swing.JPanel; |
import javax.swing.JSeparator; |
import javax.swing.SwingConstants; |
import javax.swing.UIManager; |
/** |
* A default ElementSQLObject that displays a button to create, and when created a button to delete |
61,6 → 62,7 |
super(parent, comp); |
this.addValidListener(new ValidListener() { |
@Override |
public void validChange(ValidObject src, ValidState newValue) { |
compChanged(); |
} |
69,24 → 71,29 |
public void showSeparator(boolean visible) { |
this.isSeparatorVisible = visible; |
if (separator != null) |
if (this.separator != null) |
this.separator.setVisible(visible); |
} |
public void setDecorated(boolean decorated) { |
this.isDecorated = decorated; |
if (expandBtn != null) |
if (this.expandBtn != null) |
this.expandBtn.setVisible(decorated); |
if (supprBtn != null) |
if (this.supprBtn != null) |
this.supprBtn.setVisible(decorated); |
if (createBtn != null) |
if (this.createBtn != null) |
this.createBtn.setVisible(decorated); |
} |
@Override |
protected void uiInit() { |
final boolean isPlastic = UIManager.getLookAndFeel().getClass().getName().startsWith("com.jgoodies.plaf.plastic"); |
this.expandBtn = new JButton("+/-"); |
this.expandBtn.setEnabled(false); |
this.expandBtn.setOpaque(false); |
this.expandBtn.addActionListener(new ActionListener() { |
@Override |
public void actionPerformed(ActionEvent e) { |
toggleExpand(); |
} |
95,8 → 102,10 |
this.supprBtn = new JButton(new ImageIcon(this.getClass().getResource("delete.png"))); |
this.supprBtn.setToolTipText("Supprimer"); |
this.supprBtn.setOpaque(false); |
if (isPlastic) |
this.supprBtn.setBorder(null); |
this.supprBtn.addActionListener(new ActionListener() { |
@Override |
public void actionPerformed(ActionEvent e) { |
if ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0 || this.confirm()) |
setCreated(false); |
107,7 → 116,10 |
} |
}); |
this.createBtn = new JButton("Créer " + this.getSQLChild().getElement().getSingularName()); |
// false leaves only a line for the button under Plastic3DLookAndFeel |
this.createBtn.setOpaque(isPlastic); |
this.createBtn.addActionListener(new ActionListener() { |
@Override |
public void actionPerformed(ActionEvent e) { |
setCreated(true); |
} |
116,6 → 128,7 |
this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); |
} |
@Override |
protected final void setCreatePanel() { |
if (this.editP != null) |
this.editP.setVisible(false); |
138,6 → 151,7 |
return this.createP; |
} |
@Override |
protected final void setEditPanel() { |
this.supprBtn.setVisible(!this.required && this.isDecorated); |
if (this.createP != null) |
195,6 → 209,7 |
return this.editP; |
} |
@Override |
protected void compChanged() { |
this.expandBtn.setEnabled(this.getCurrentID() != SQLRow.NONEXISTANT_ID && this.getValidState().isValid()); |
} |
219,6 → 234,7 |
this.expand(!this.isExpanded()); |
} |
@Override |
public void setEditable(boolean enabled) { |
super.setEditable(enabled); |
this.createBtn.setEnabled(enabled); |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java |
---|
118,6 → 118,7 |
private SQLCache<SQLRowAccessor, Object> modelCache; |
private final Map<String, JComponent> additionalFields; |
private final List<SQLTableModelColumn> additionalListCols; |
public SQLElement(String singular, String plural, SQLTable primaryTable) { |
super(); |
136,6 → 137,7 |
this.modelCache = null; |
this.additionalFields = new HashMap<String, JComponent>(); |
this.additionalListCols = new ArrayList<SQLTableModelColumn>(); |
} |
/** |
331,6 → 333,15 |
} |
/** |
* Fields that cannot be empty. |
* |
* @return fields that cannot be empty. |
*/ |
public Set<String> getRequiredFields() { |
return Collections.emptySet(); |
} |
/** |
* Fields that can only be set on insertion. |
* |
* @return fields that cannot be modified. |
759,7 → 770,8 |
// shared must be RESTRICT, parent at least CASCADE (to avoid child without a parent), |
// normal is free |
if (action.compareTo(ReferenceAction.RESTRICT) < 0 && !this.getNormalForeignFields().contains(ff)) |
throw new IllegalArgumentException(ff + " is not normal: " + this.getNormalForeignFields()); |
// getField() checks if the field exists |
throw new IllegalArgumentException(getTable().getField(ff).getSQLName() + " is not a normal foreign field : " + this.getNormalForeignFields()); |
this.getActions().put(ff, action); |
} |
877,6 → 889,7 |
private final SQLTableModelSourceOnline createAndInitTableSource() { |
final SQLTableModelSourceOnline res = this.createTableSource(); |
res.getColumns().addAll(this.additionalListCols); |
return initTableSource(res); |
} |
915,6 → 928,15 |
abstract protected List<String> getListFields(); |
public final void addListFields(final List<String> fields) { |
for (final String f : fields) |
this.addListColumn(new SQLTableModelColumnPath(getTable().getField(f))); |
} |
public final void addListColumn(SQLTableModelColumn col) { |
this.additionalListCols.add(col); |
} |
public final Collection<IListeAction> getRowActions() { |
return this.rowActions; |
} |
1365,7 → 1387,8 |
public final int hashCode() { |
// ne pas mettre getParent car des fois null |
return this.getTable().hashCode() + this.getSharedForeignFields().hashCode() + this.getPrivateForeignFields().hashCode(); |
return this.getTable().hashCode(); // + this.getSharedForeignFields().hashCode() + |
// this.getPrivateForeignFields().hashCode(); |
} |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java |
---|
170,7 → 170,7 |
} |
} |
private Tuple2<JComponent, SQLType> getComp(String field) { |
protected Tuple2<JComponent, SQLType> getComp(String field) { |
if (getElement().getPrivateElement(field) != null) |
// we create a MutableRowItemView and need SpecParser |
throw new IllegalArgumentException("Private fields not supported"); |
192,6 → 192,7 |
// regular |
comp = new SQLTextCombo(); |
} |
comp.setOpaque(false); |
return new Tuple2<JComponent, SQLType>(comp, type); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/UISQLComponent.java |
---|
153,6 → 153,8 |
this.add(this.tabbedPane); |
} |
this.currentPanel = new JPanel(); |
// from Guillaume : tabs shouldn't be opaque in Windows L&F |
this.currentPanel.setOpaque(false); |
this.tabbedPane.addTab(tabTitle, this.currentPanel); |
this.setLayouter(w, d); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/LayoutHints.java |
---|
New file |
0,0 → 1,93 |
/* |
* 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.element; |
public class LayoutHints { |
private boolean maximizeWidth; |
private boolean maximizeHeight; |
private boolean showLabel; |
private boolean separatedLabel; |
private boolean fill; |
public static final LayoutHints DEFAULT_FIELD_HINTS = new LayoutHints(false, false, true, false); |
public static final LayoutHints DEFAULT_LARGE_FIELD_HINTS = new LayoutHints(true, false, true, false); |
public static final LayoutHints DEFAULT_LIST_HINTS = new LayoutHints(true, true, false, false, true); |
public static final LayoutHints DEFAULT_GROUP_HINTS = new LayoutHints(false, false, false, false); |
public static final LayoutHints DEFAULT_LARGE_GROUP_HINTS = new LayoutHints(true, false, false, false); |
public LayoutHints(boolean maximizeWidth, boolean maximizeHeight, boolean showLabel, boolean separatedLabel) { |
this.maximizeWidth = maximizeWidth; |
this.maximizeHeight = maximizeHeight; |
this.showLabel = showLabel; |
this.separatedLabel = separatedLabel; |
this.fill = false; |
} |
public LayoutHints(boolean maximizeWidth, boolean maximizeHeight, boolean showLabel, boolean separatedLabel, boolean fill) { |
this.maximizeWidth = maximizeWidth; |
this.maximizeHeight = maximizeHeight; |
this.showLabel = showLabel; |
this.separatedLabel = separatedLabel; |
this.fill = fill; |
} |
public boolean maximizeWidth() { |
return maximizeWidth; |
} |
public boolean maximizeHeight() { |
return maximizeHeight; |
} |
public boolean showLabel() { |
return showLabel; |
} |
public boolean separatedLabel() { |
return separatedLabel; |
} |
public boolean fill() { |
return fill; |
} |
@Override |
public String toString() { |
String r = ""; |
if (maximizeHeight && maximizeWidth) { |
r += "MaxW&H"; |
} else { |
if (maximizeHeight) { |
r += "MaxH"; |
} |
if (maximizeWidth) { |
r += "MaxW"; |
} |
} |
if (showLabel && separatedLabel) { |
r += " SeparatedLabel"; |
} else { |
if (showLabel) { |
r += " StdLabel"; |
} else { |
r += " NoLabel"; |
} |
} |
if (fill) { |
r += " Fill"; |
} |
return r; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/Group.java |
---|
New file |
0,0 → 1,156 |
/* |
* 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.element; |
import java.util.ArrayList; |
import java.util.Collections; |
import java.util.Comparator; |
import java.util.List; |
import org.openconcerto.utils.Tuple3; |
public class Group { |
private String id; |
private int order = 0; |
private List<Tuple3<Group, LayoutHints, Integer>> list = new ArrayList<Tuple3<Group, LayoutHints, Integer>>(); |
public Group(String id) { |
this.id = id.trim(); |
} |
public String getId() { |
return id; |
} |
public void add(Group group) { |
order += 100; |
list.add(new Tuple3<Group, LayoutHints, Integer>(group, LayoutHints.DEFAULT_GROUP_HINTS, order)); |
} |
public void add(Group group, LayoutHints hints) { |
order += 100; |
list.add(new Tuple3<Group, LayoutHints, Integer>(group, hints, order)); |
} |
public void insert(Group group, LayoutHints hints, int order) { |
list.add(new Tuple3<Group, LayoutHints, Integer>(group, hints, order)); |
} |
public void add(String string) { |
this.add(new Group(string), LayoutHints.DEFAULT_FIELD_HINTS); |
} |
public void add(String string, LayoutHints hints) { |
this.add(new Group(string), hints); |
} |
public void dumpOneColumn() { |
dumpOneColumn(LayoutHints.DEFAULT_GROUP_HINTS, 0, 1); |
} |
public void dumpOneColumn(LayoutHints localHint, int localOrder, int level) { |
for (int i = 0; i < level - 1; i++) { |
System.out.print(" "); |
} |
if (list.size() == 0) |
System.out.print("+-- "); |
else |
System.out.print("+-+ "); |
System.out.println(localOrder + " " + this.id + " [" + localHint + "]"); |
sortSubGroup(); |
for (Tuple3<Group, LayoutHints, Integer> tuple : list) { |
((Group) tuple.get0()).dumpOneColumn(tuple.get1(), tuple.get2(), level + 1); |
} |
// System.out.println("== end" + this.id); |
} |
private void sortSubGroup() { |
if (list.size() > 1) { |
Collections.sort(list, new Comparator<Tuple3<Group, LayoutHints, Integer>>() { |
@Override |
public int compare(Tuple3<Group, LayoutHints, Integer> o1, Tuple3<Group, LayoutHints, Integer> o2) { |
return o1.get2().compareTo(o2.get2()); |
} |
}); |
} |
} |
public void dumpTwoColumn() { |
dumpTwoColumn(0, LayoutHints.DEFAULT_GROUP_HINTS, 0, 1); |
} |
public int dumpTwoColumn(int x, LayoutHints localHint, int localOrder, int level) { |
if (isEmpty()) { |
System.out.print(" (" + x + ")"); |
System.out.print(localOrder + " " + this.id + "[" + localHint + "]"); |
if ((x % 2) == 1) { |
System.out.println(); |
} |
} |
sortSubGroup(); |
for (Tuple3<Group, LayoutHints, Integer> tuple : list) { |
final Group subGroup = tuple.get0(); |
final Integer subGroupOrder = (Integer) tuple.get2(); |
x = subGroup.dumpTwoColumn(x, tuple.get1(), subGroupOrder, level + 1); |
} |
if (isEmpty()) { |
x++; |
} |
if (list.size() != 0 && localHint.maximizeWidth()) { |
x = 0; |
System.out.println(); |
} |
return x; |
} |
public int getSize() { |
return this.list.size(); |
} |
public boolean isEmpty() { |
return this.list.isEmpty(); |
} |
public void sort() { |
sortSubGroup(); |
for (Tuple3<Group, LayoutHints, Integer> tuple : list) { |
final Group subGroup = tuple.get0(); |
subGroup.sort(); |
} |
} |
public Group getGroup(int i) { |
return this.list.get(i).get0(); |
} |
public LayoutHints getLayoutHints(int i) { |
return this.list.get(i).get1(); |
} |
public Integer getOrder(int i) { |
return this.list.get(i).get2(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/ElementMapper.java |
---|
New file |
0,0 → 1,83 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.sql.element; |
import org.openconcerto.utils.StringUtils; |
import java.util.ArrayList; |
import java.util.Collections; |
import java.util.HashMap; |
import java.util.List; |
import java.util.Map; |
public class ElementMapper { |
private final Map<String, Object> idToObject = new HashMap<String, Object>(); |
private final Map<Object, List<String>> objectsToIds = new HashMap<Object, List<String>>(); |
private static ElementMapper instance = new ElementMapper(); |
public ElementMapper() { |
} |
public static ElementMapper getInstance() { |
return instance; |
} |
public void map(String id, Object obj) { |
idToObject.put(id, obj); |
List<String> l = objectsToIds.get(obj); |
if (l == null) { |
l = new ArrayList<String>(3); |
l.add(id); |
} else if (!l.contains(obj)) { |
l.add(id); |
} |
} |
public Object get(String id) { |
return idToObject.get(id); |
} |
public String getString(String id) { |
final Object object = idToObject.get(id); |
if (object instanceof String) { |
return (String) object; |
} |
return null; |
} |
public Group getGroup(String id) { |
final Object object = idToObject.get(id); |
if (object instanceof Group) { |
return (Group) object; |
} |
return null; |
} |
public List<String> getIds(Object o) { |
return objectsToIds.get(o); |
} |
public void dump() { |
System.out.println(this.getClass().getName()); |
List<String> ids = new ArrayList<String>(); |
ids.addAll(this.idToObject.keySet()); |
Collections.sort(ids); |
for (String id : ids) { |
System.out.println(StringUtils.leftAlign(id, 40) + " : " + idToObject.get(id)); |
} |
System.out.println(ids.size() + " identifiers found"); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java |
---|
104,7 → 104,15 |
for (final DirectoryListener dl : this.listeners) { |
dl.elementAdded(elem); |
} |
String canonicalName = elem.getClass().getCanonicalName(); |
if (canonicalName.contains("erp.core") && canonicalName.contains(".element")) { |
int i = canonicalName.indexOf("erp.core") + 9; |
int j = canonicalName.indexOf(".element"); |
canonicalName = canonicalName.substring(i, j); |
} |
ElementMapper.getInstance().map(canonicalName + ".element", elem); |
ElementMapper.getInstance().map(canonicalName + ".list.table", elem.getTable().getName()); |
} |
public synchronized final boolean contains(SQLTable t) { |
return this.elements.containsKey(t); |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GroupSQLComponent.java |
---|
New file |
0,0 → 1,188 |
/* |
* 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.element; |
import java.awt.Color; |
import java.awt.GridBagConstraints; |
import java.awt.GridBagLayout; |
import java.util.ArrayList; |
import java.util.Collections; |
import java.util.List; |
import java.util.Set; |
import javax.swing.JButton; |
import javax.swing.JComponent; |
import javax.swing.JLabel; |
import javax.swing.JTextField; |
import javax.swing.SwingConstants; |
import javax.swing.SwingUtilities; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLType; |
import org.openconcerto.ui.DefaultGridBagConstraints; |
import org.openconcerto.ui.JLabelBold; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.Tuple3; |
public class GroupSQLComponent extends BaseSQLComponent { |
private Group group; |
private int columns = 2; |
private boolean forceViewOnly = true; |
public GroupSQLComponent(SQLElement element, Group group) { |
super(element); |
this.group = group; |
} |
@Override |
protected void addViews() { |
group.dumpOneColumn(); |
this.setLayout(new GridBagLayout()); |
group.sort(); |
GridBagConstraints c = new DefaultGridBagConstraints(); |
layout(group, 0, LayoutHints.DEFAULT_GROUP_HINTS, 0, 0, c); |
} |
public int layout(Group currentGroup, Integer order, LayoutHints size, int x, int level, GridBagConstraints c) { |
if (currentGroup.isEmpty()) { |
System.out.print(" (" + x + ")"); |
String id = currentGroup.getId(); |
System.out.print(order + " " + id + "[" + size + "]"); |
c.gridwidth = 1; |
if (size.showLabel()) { |
c.weightx = 0; |
// Label |
if (size.separatedLabel()) { |
c.gridx = 0; |
c.gridwidth = 4; |
c.fill = GridBagConstraints.NONE; |
} else { |
c.fill = GridBagConstraints.HORIZONTAL; |
} |
this.add(getLabel(id), c); |
if (size.separatedLabel()) { |
c.gridy++; |
} else { |
c.gridx++; |
} |
} |
// Editor |
c.weightx = 1; |
if (size.maximizeWidth() && size.maximizeHeight()) { |
c.fill = GridBagConstraints.BOTH; |
} else if (size.maximizeWidth()) { |
c.fill = GridBagConstraints.HORIZONTAL; |
} else if (size.maximizeHeight()) { |
c.fill = GridBagConstraints.VERTICAL; |
} else { |
c.fill = GridBagConstraints.NONE; |
} |
if (size.fill()) { |
c.weighty = 1; |
c.gridwidth = columns * 2; |
} |
this.add(getEditor(id), c); |
c.weighty = 0; |
c.gridx++; |
if ((x % columns) != 0) { |
c.gridx = 0; |
c.gridy++; |
} |
} |
final int stop = currentGroup.getSize(); |
for (int i = 0; i < stop; i++) { |
final Group subGroup = currentGroup.getGroup(i); |
final Integer subGroupOrder = currentGroup.getOrder(i); |
final LayoutHints subGroupSize = currentGroup.getLayoutHints(i); |
x = layout(subGroup, subGroupOrder, subGroupSize, x, level + 1, c); |
} |
if (currentGroup.isEmpty()) { |
x++; |
} else { |
if (size.maximizeWidth()) { |
c.gridx = 0; |
c.gridy++; |
} |
} |
return x; |
} |
JComponent getEditor(String id) { |
if (id.startsWith("(") && id.endsWith(")*")) { |
try { |
String table = id.substring(1, id.length() - 2).trim(); |
String idEditor = ElementMapper.getInstance().getIds(table).get(0) + ".editor"; |
System.out.println("Editor: " + idEditor); |
Class cl = (Class) ElementMapper.getInstance().get(idEditor); |
return (JComponent) cl.newInstance(); |
} catch (Exception e) { |
e.printStackTrace(); |
} |
} |
SQLField field = this.getTable().getFieldRaw(id); |
if (field == null) { |
final JLabel jLabel = new JLabelBold("No field " + id); |
jLabel.setForeground(Color.RED.darker()); |
String t = "<html>"; |
final Set<SQLField> fields = this.getTable().getFields(); |
for (SQLField sqlField : fields) { |
t += sqlField.getFullName() + "<br>"; |
} |
t += "</html>"; |
jLabel.setToolTipText(t); |
return jLabel; |
} |
// if (/* this.getMode().equals(Mode.VIEW) || */forceViewOnly) { |
// final JLabel jLabel = new JLabel(); |
// jLabel.setForeground(Color.gray); |
// return jLabel; |
// } |
Tuple2<JComponent, SQLType> r = getComp(id); |
final JComponent editorComp = r.get0(); |
if (editorComp != null) { |
this.addView(editorComp, id); |
return editorComp; |
} |
return new JButton(id); |
} |
JLabel getLabel(String id) { |
final String fieldLabel = super.getLabelFor(id); |
JLabel jLabel; |
if (fieldLabel == null) { |
jLabel = new JLabel(id); |
jLabel.setForeground(Color.RED.darker()); |
} else { |
jLabel = new JLabel(fieldLabel); |
} |
jLabel.setHorizontalAlignment(SwingConstants.RIGHT); |
return jLabel; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/navigator/RowsSQLListModel.java |
---|
13,17 → 13,17 |
/* |
* Créé le 21 mai 2005 |
* |
*/ |
package org.openconcerto.sql.navigator; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.IResultSetHandler; |
import org.openconcerto.sql.model.SQLDataSource; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowListRSH; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableListener; |
import org.openconcerto.sql.model.SQLTableEvent; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.sql.model.Where; |
import java.util.List; |
31,7 → 31,7 |
import org.apache.commons.dbutils.ResultSetHandler; |
public class RowsSQLListModel extends SQLListModel<SQLRow> implements SQLTableListener { |
public class RowsSQLListModel extends SQLListModel<SQLRow> implements SQLTableModifiedListener { |
private final SQLElement element; |
private final ResultSetHandler handler; |
40,11 → 40,11 |
super(); |
this.element = element; |
this.handler = new SQLRowListRSH(this.getElement().getTable(), true); |
this.getElement().getTable().addTableListener(this); |
this.getElement().getTable().addTableModifiedListener(this); |
} |
@SuppressWarnings("unchecked") |
protected void reload() { |
@Override |
protected void reload(final boolean noCache) { |
final Set<Number> ids = getIds(); |
final String key = this.getElement().getParentForeignField(); |
60,9 → 60,21 |
// cannot just use a SwingWorker, cause some methods (like SQLBrowser#selectPath()) |
// expect reload() to by synchronous. |
this.setAll((List<SQLRow>) source.execute(sel.asString(), this.handler)); |
@SuppressWarnings("unchecked") |
final List<SQLRow> rows = (List<SQLRow>) source.execute(sel.asString(), new IResultSetHandler(this.handler) { |
@Override |
public boolean readCache() { |
return !noCache; |
} |
@Override |
public boolean writeCache() { |
return true; |
} |
}); |
this.setAll(rows); |
} |
/** |
* Search the row with the passed <code>id</code> and return its index. |
* |
86,26 → 98,18 |
return this.element; |
} |
public void rowAdded(SQLTable table, int id) { |
this.reload(); |
} |
public void rowModified(SQLTable table, int id) { |
@Override |
public void tableModified(SQLTableEvent evt) { |
// TODO test if that concern us |
this.reload(); |
} |
public void rowDeleted(SQLTable table, int id) { |
// TODO test if that concern us |
this.reload(); |
} |
public String toString() { |
return this.getClass().getName() + " on " + this.getElement(); |
} |
protected void die() { |
this.getElement().getTable().removeTableListener(this); |
this.getElement().getTable().removeTableModifiedListener(this); |
} |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/sql/navigator/ElementsSQLListModel.java |
---|
44,7 → 44,8 |
this.elements = new ArrayList<SQLElement>(elements); |
} |
protected void reload() { |
@Override |
protected void reload(boolean noCache) { |
this.counts.clear(); |
final List<SQLElement> res = new ArrayList<SQLElement>(this.elements.size()); |
for (final SQLElement elem : this.elements) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/navigator/SQLListModel.java |
---|
74,8 → 74,12 |
// more efficient than reload()) |
} |
protected abstract void reload(); |
protected final void reload() { |
this.reload(false); |
} |
protected abstract void reload(final boolean noCache); |
// *** items |
public final int getSize() { |
/trunk/OpenConcerto/src/org/openconcerto/sql/navigator/SQLBrowserColumn.java |
---|
22,6 → 22,7 |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.sqlobject.ElementComboBox; |
import org.openconcerto.ui.KeyLabel; |
import org.openconcerto.ui.PopupMouseListener; |
import org.openconcerto.ui.list.selection.ListSelectionState; |
import org.openconcerto.utils.JImage; |
import org.openconcerto.utils.cc.IPredicate; |
53,6 → 54,7 |
import java.util.List; |
import java.util.Set; |
import javax.swing.AbstractAction; |
import javax.swing.DefaultListCellRenderer; |
import javax.swing.DefaultListSelectionModel; |
import javax.swing.Icon; |
61,6 → 63,7 |
import javax.swing.JLabel; |
import javax.swing.JList; |
import javax.swing.JPanel; |
import javax.swing.JPopupMenu; |
import javax.swing.JScrollPane; |
import javax.swing.JTextField; |
import javax.swing.ListSelectionModel; |
328,10 → 331,20 |
this.title.addMouseListener(new MouseAdapter() { |
public void mouseClicked(MouseEvent e) { |
// On trie |
if (e.getButton() == MouseEvent.BUTTON1) { |
getModel().sort(); |
setTitleIcon(); |
} |
} |
}); |
final JPopupMenu menu = new JPopupMenu(); |
menu.add(new AbstractAction("Recharger") { |
@Override |
public void actionPerformed(ActionEvent e) { |
getModel().reload(true); |
} |
}); |
this.title.addMouseListener(new PopupMouseListener(menu)); |
// this.normalPanel.setBackground(new Color(239, 235, 231)); |
headerPanel.add(this.title, c2); |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTableListenerData.java |
---|
13,7 → 13,7 |
package org.openconcerto.sql.model; |
final class SQLTableListenerData<R extends SQLRowAccessor> implements SQLTableListener { |
final class SQLTableListenerData<R extends SQLRowAccessor> implements SQLTableModifiedListener { |
private final R row; |
private final SQLDataListener l; |
23,19 → 23,11 |
this.l = l; |
} |
public void rowAdded(SQLTable table, int id) { |
// if the row id was cached as non-existant, now it is |
if (this.row.getID() == id) |
this.l.dataChanged(); |
} |
public void rowDeleted(SQLTable table, int id) { |
@Override |
public void tableModified(SQLTableEvent evt) { |
final int id = evt.getId(); |
// if the row id was cached as non-existent and evt mode is ADDED, now it is |
if (id < SQLRow.MIN_VALID_ID || this.row.getID() == id) |
this.l.dataChanged(); |
} |
public void rowModified(SQLTable table, int id) { |
if (id < SQLRow.MIN_VALID_ID || this.row.getID() == id) |
this.l.dataChanged(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLType.java |
---|
17,6 → 17,7 |
package org.openconcerto.sql.model; |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.xml.JDOMUtils; |
import java.math.BigDecimal; |
import java.math.BigInteger; |
303,7 → 304,7 |
sb.append(this.decimalDigits); |
} |
sb.append("\" typeName=\""); |
sb.append(this.typeName); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(this.typeName)); |
sb.append("\"/>"); |
this.xml = sb.toString(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLField.java |
---|
21,6 → 21,7 |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.utils.ExceptionUtils; |
import org.openconcerto.xml.JDOMUtils; |
import org.openconcerto.xml.XMLCodecUtils; |
import java.sql.DatabaseMetaData; |
281,7 → 282,7 |
if (this.xml == null) { |
final StringBuilder sb = new StringBuilder(2048); |
sb.append("<field name=\""); |
sb.append(this.getName()); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(this.getName())); |
sb.append("\" >"); |
sb.append(this.type.toXML()); |
sb.append(XMLCodecUtils.encodeSimple(this.metadata)); |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesListFetcher.java |
---|
454,6 → 454,29 |
} |
@Override |
public int hashCode() { |
final int prime = 31; |
int result = 1; |
result = prime * result + this.fieldCount; |
result = prime * result + ((this.from == null) ? 0 : this.from.hashCode()); |
result = prime * result + this.linkIndex; |
result = prime * result + this.t.hashCode(); |
return result; |
} |
@Override |
public boolean equals(Object obj) { |
if (this == obj) |
return true; |
if (obj == null) |
return false; |
if (getClass() != obj.getClass()) |
return false; |
final GraphNode other = (GraphNode) obj; |
return this.fieldCount == other.fieldCount && this.linkIndex == other.linkIndex && this.t.equals(other.t) && CompareUtils.equals(this.from, other.from); |
} |
@Override |
public String toString() { |
final String link = this.from == null ? "" : " linked to " + getLinkIndex() + " by " + this.getFromName() + (this.isBackwards() ? " backwards" : " forewards"); |
return this.getFieldCount() + " fields of " + this.getTable() + link; |
460,44 → 483,19 |
} |
} |
/** |
* Execute the request transformed by <code>selTransf</code> and return the result as a list of |
* SQLRowValues. |
* |
* @return a list of SQLRowValues, one item per row, each item having the same structure as the |
* SQLRowValues passed to the constructor. |
*/ |
public final List<SQLRowValues> fetch() { |
return this.fetch(true); |
} |
static private final class RSH implements ResultSetHandler { |
private final List<String> selectFields; |
private final List<GraphNode> graphNodes; |
private final List<SQLRowValues> fetch(final boolean merge) { |
final SQLSelect req = this.getReq(); |
// getName() would take 5% of ResultSetHandler.handle() |
final List<String> selectFields = new ArrayList<String>(req.getSelectFields().size()); |
for (final SQLField f : req.getSelectFields()) |
selectFields.add(f.getName()); |
final SQLTable table = getGraph().getTable(); |
// create a flat list of the graph nodes, we just need the table, field count and the index |
// in this list of its linked table, eg for CPI -> LOCAL -> BATIMENT -> SITE : |
// <LOCAL,2,0>, <BATIMENT,2,0>, <SITE,5,1>, <CPI,4,0> |
final int graphSize = this.getGraph().getGraph().size(); |
final List<GraphNode> l = new ArrayList<GraphNode>(graphSize); |
walk(0, new ITransformer<State<Integer>, Integer>() { |
@Override |
public Integer transformChecked(State<Integer> input) { |
final int index = l.size(); |
l.add(new GraphNode(input)); |
return index; |
private RSH(List<String> selectFields, List<GraphNode> l) { |
this.selectFields = selectFields; |
this.graphNodes = l; |
} |
}); |
assert l.size() == graphSize : "All nodes weren't explored once : " + l.size() + " != " + graphSize; |
@SuppressWarnings("unchecked") |
final List<SQLRowValues> res = (List<SQLRowValues>) table.getBase().getDataSource().execute(req.asString(), new ResultSetHandler() { |
@Override |
public Object handle(final ResultSet rs) throws SQLException { |
final List<GraphNode> l = this.graphNodes; |
final int graphSize = l.size(); |
int nextToLink = 0; |
final List<Future<?>> futures = new ArrayList<Future<?>>(); |
510,7 → 508,7 |
// MAYBE cancel() futures |
if (Thread.currentThread().isInterrupted()) |
throw new RTInterruptedException("interrupted while fetching " + SQLRowValuesListFetcher.this); |
throw new RTInterruptedException("interrupted while fetching"); |
final List<SQLRowValues> row = new ArrayList<SQLRowValues>(graphSize); |
for (int i = 0; i < graphSize; i++) { |
final GraphNode node = l.get(i); |
523,7 → 521,7 |
try { |
// -1 since rs starts at 1 |
// field names checked below |
creatingVals.put(selectFields.get(rsIndex - 1), rs.getObject(rsIndex), false); |
creatingVals.put(this.selectFields.get(rsIndex - 1), rs.getObject(rsIndex), false); |
} catch (SQLException e) { |
throw new IllegalStateException("unable to fill " + creatingVals, e); |
} |
568,7 → 566,70 |
return res; |
} |
}, false); |
@Override |
public int hashCode() { |
final int prime = 31; |
int result = 1; |
result = prime * result + this.graphNodes.hashCode(); |
result = prime * result + this.selectFields.hashCode(); |
return result; |
} |
@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.graphNodes.equals(other.graphNodes) && this.selectFields.equals(other.selectFields); |
} |
} |
/** |
* Execute the request transformed by <code>selTransf</code> and return the result as a list of |
* SQLRowValues. NOTE: this method doesn't use the cache of SQLDataSource. |
* |
* @return a list of SQLRowValues, one item per row, each item having the same structure as the |
* SQLRowValues passed to the constructor. |
*/ |
public final List<SQLRowValues> fetch() { |
return this.fetch(true); |
} |
private final List<SQLRowValues> fetch(final boolean merge) { |
final SQLSelect req = this.getReq(); |
// getName() would take 5% of ResultSetHandler.handle() |
final List<String> selectFields = new ArrayList<String>(req.getSelectFields().size()); |
for (final SQLField f : req.getSelectFields()) |
selectFields.add(f.getName()); |
final SQLTable table = getGraph().getTable(); |
// create a flat list of the graph nodes, we just need the table, field count and the index |
// in this list of its linked table, eg for CPI -> LOCAL -> BATIMENT -> SITE : |
// <LOCAL,2,0>, <BATIMENT,2,0>, <SITE,5,1>, <CPI,4,0> |
final int graphSize = this.getGraph().getGraph().size(); |
final List<GraphNode> l = new ArrayList<GraphNode>(graphSize); |
walk(0, new ITransformer<State<Integer>, Integer>() { |
@Override |
public Integer transformChecked(State<Integer> input) { |
final int index = l.size(); |
l.add(new GraphNode(input)); |
return index; |
} |
}); |
assert l.size() == graphSize : "All nodes weren't explored once : " + l.size() + " != " + graphSize; |
// if we wanted to use the cache, we'd need to copy the returned list and its items (i.e. |
// deepCopy()), since we modify them afterwards. Or perhaps include the code after this line |
// into the result set handler. |
final IResultSetHandler rsh = new IResultSetHandler(new RSH(selectFields, l), false); |
@SuppressWarnings("unchecked") |
final List<SQLRowValues> res = (List<SQLRowValues>) table.getBase().getDataSource().execute(req.asString(), rsh, false); |
// e.g. list of batiment pointing to site |
final List<SQLRowValues> merged = merge && this.fetchReferents() ? merge(res) : res; |
if (this.grafts.size() > 0) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLImmutableRowValues.java |
---|
80,10 → 80,6 |
return this.delegate.isForeignEmpty(fieldName); |
} |
public boolean isEmptyLink(String fieldName) { |
return this.delegate.isEmptyLink(fieldName); |
} |
public boolean isDefault(String fieldName) { |
return this.delegate.isDefault(fieldName); |
} |
116,7 → 112,7 |
} |
@Override |
public SQLTableListener createTableListener(SQLDataListener l) { |
public SQLTableModifiedListener createTableListener(SQLDataListener l) { |
return this.delegate.createTableListener(l); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java |
---|
27,6 → 27,7 |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.CopyUtils; |
import org.openconcerto.utils.ExceptionUtils; |
import org.openconcerto.utils.NumberUtils; |
import org.openconcerto.utils.RecursionType; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.cc.IClosure; |
95,13 → 96,12 |
} |
public static final Object SQL_DEFAULT = new Object(); |
// for now the default is put in the default value of the db |
/** |
* Empty foreign field value. |
* |
* @see #putEmptyLink(String) |
*/ |
public static final Object SQL_EMPTY_LINK = SQL_DEFAULT; |
public static final Object SQL_EMPTY_LINK = new Object(); |
private static boolean checkValidity = true; |
167,26 → 167,8 |
*/ |
public SQLRowValues(SQLRowValues vals, ForeignCopyMode copyForeigns) { |
this(vals.getTable()); |
final Map<String, Object> toAdd; |
if (copyForeigns == ForeignCopyMode.COPY_ROW) |
toAdd = vals.values; |
else { |
final Set<Entry<String, Object>> entrySet = vals.values.entrySet(); |
toAdd = new LinkedHashMap<String, Object>(entrySet.size()); |
for (final Map.Entry<String, Object> e : entrySet) { |
if (!(e.getValue() instanceof SQLRowValues)) |
toAdd.put(e.getKey(), e.getValue()); |
else if (copyForeigns != ForeignCopyMode.NO_COPY) { |
final SQLRowValues foreign = (SQLRowValues) e.getValue(); |
if (foreign.hasID()) |
toAdd.put(e.getKey(), foreign.getIDNumber()); |
else if (copyForeigns == ForeignCopyMode.COPY_ID_OR_ROW) |
toAdd.put(e.getKey(), foreign); |
} |
} |
} |
// setAll() takes care of foreigns and referents |
this.setAll(toAdd); |
this.setAll(vals.getAllValues(copyForeigns)); |
} |
@Override |
272,7 → 254,9 |
* @return the foreign row, eg FAMILLE[1]. |
*/ |
public final SQLRowValues grow(String fk) { |
if (!(this.getObject(fk) instanceof SQLRowValues)) { |
final Object val = this.getContainedObject(fk); |
// if fk is in our map with a null value, nothing to grow |
if (val != null && !(val instanceof SQLRowValues)) { |
final SQLRowValues vals = new SQLRowValues(this.getTable()); |
vals.putRowValues(fk).setAllToNull(); |
this.grow(vals, true); |
402,16 → 386,53 |
@Override |
public Map<String, Object> getAbsolutelyAll() { |
return Collections.unmodifiableMap(this.values); |
return getAllValues(ForeignCopyMode.COPY_ROW); |
} |
protected final Map<String, Object> getAllValues(ForeignCopyMode copyForeigns) { |
final Map<String, Object> toAdd; |
if (copyForeigns == ForeignCopyMode.COPY_ROW || this.foreigns.size() == 0) { |
toAdd = this.values; |
} else { |
final Set<Entry<String, Object>> entrySet = this.values.entrySet(); |
toAdd = new LinkedHashMap<String, Object>(entrySet.size()); |
for (final Map.Entry<String, Object> e : entrySet) { |
if (!(e.getValue() instanceof SQLRowValues)) { |
toAdd.put(e.getKey(), e.getValue()); |
} else if (copyForeigns != ForeignCopyMode.NO_COPY) { |
final SQLRowValues foreign = (SQLRowValues) e.getValue(); |
if (foreign.hasID()) |
toAdd.put(e.getKey(), foreign.getIDNumber()); |
else if (copyForeigns == ForeignCopyMode.COPY_ID_OR_ROW) |
toAdd.put(e.getKey(), foreign); |
} |
} |
} |
return Collections.unmodifiableMap(toAdd); |
} |
/** |
* Return the foreign row, if any, for the passed field. |
* |
* @param fieldName name of the foreign field. |
* @return if <code>null</code> or a SQLRowValues one was put at <code>fieldName</code>, return |
* it ; else assume that an ID was put at <code>fieldName</code> and return a new SQLRow |
* with it. |
* @throws IllegalArgumentException if fieldName is not a foreign field or if it isn't contained |
* in this instance. |
* @throws ClassCastException if the value is neither a SQLRowValues, nor <code>null</code> nor |
* a Number. |
*/ |
@Override |
public final SQLRowAccessor getForeign(String fieldName) { |
public final SQLRowAccessor getForeign(String fieldName) throws IllegalArgumentException, ClassCastException { |
// keep getForeignTable at the 1st line since it does the check |
final SQLTable foreignTable = this.getForeignTable(fieldName); |
if (this.getObject(fieldName) instanceof SQLRowAccessor) { |
return (SQLRowAccessor) this.getObject(fieldName); |
} else if (this.isEmptyLink(fieldName)) { |
final Object val = this.getContainedObject(fieldName); |
if (val instanceof SQLRowAccessor) { |
return (SQLRowAccessor) val; |
} else if (val == null) { |
// since we used getContainedObject(), it means that a null was put in our map, not that |
// fieldName wasn't there |
return null; |
} else if (this.isDefault(fieldName)) { |
throw new IllegalStateException(fieldName + " is DEFAULT"); |
420,6 → 441,12 |
} |
} |
private Object getContainedObject(String fieldName) throws IllegalArgumentException { |
if (!this.values.containsKey(fieldName)) |
throw new IllegalArgumentException("Field not present in this : " + this.getFields()); |
return this.values.get(fieldName); |
} |
/** |
* Returns the foreign table of <i>fieldName</i>. |
* |
439,18 → 466,12 |
public boolean isForeignEmpty(String fieldName) { |
// keep getForeignTable at the 1st line since it does the check |
final SQLTable foreignTable = this.getForeignTable(fieldName); |
if (this.getObject(fieldName) instanceof Number) { |
return this.getInt(fieldName) == foreignTable.getUndefinedID(); |
} else if (this.getObject(fieldName) instanceof SQLRowValues) { |
return ((SQLRowValues) this.getObject(fieldName)).getID() == foreignTable.getUndefinedID(); |
} else |
return this.getObject(fieldName) == null || this.isEmptyLink(fieldName); |
final Object val = this.getContainedObject(fieldName); |
final Number id = val instanceof SQLRowValues ? ((SQLRowValues) val).getIDNumber() : (Number) val; |
final Number undefID = foreignTable.getUndefinedIDNumber(); |
return NumberUtils.areNumericallyEqual(id, undefID); |
} |
public boolean isEmptyLink(String fieldName) { |
return SQL_EMPTY_LINK.equals(this.getObject(fieldName)); |
} |
public boolean isDefault(String fieldName) { |
return SQL_DEFAULT.equals(this.getObject(fieldName)); |
} |
478,7 → 499,7 |
public final SQLRow asRow() { |
if (!this.hasID()) |
throw new IllegalStateException(this + " has no ID"); |
return new SQLRow(this.getTable(), this.values); |
return new SQLRow(this.getTable(), this.getAllValues(ForeignCopyMode.COPY_ID_OR_RM)); |
} |
@Override |
588,6 → 609,9 |
} |
private void _put(String fieldName, Object value) { |
if (value == SQL_EMPTY_LINK) |
// keep getForeignTable since it does the check |
value = this.getForeignTable(fieldName).getUndefinedIDNumber(); |
// use assertion since check() is not perfect |
assert check(fieldName, value); |
this.updateLinks(fieldName, this.values.put(fieldName, value), value); |
635,8 → 659,6 |
* @return this. |
*/ |
public SQLRowValues putEmptyLink(String fieldName) { |
// keep getForeignTable at the 1st line since it does the check |
this.getForeignTable(fieldName); |
return this.put(fieldName, SQL_EMPTY_LINK); |
} |
1009,7 → 1031,7 |
// verifie l'intégrité (a rowValues is obviously correct, as is EMPTY, |
// DEFAULT is the responsability of the DB) |
final Object fieldVal = this.getObject(fieldName); |
if (fk.contains(field) && fieldVal != SQL_DEFAULT && fieldVal != SQL_EMPTY_LINK && !(fieldVal instanceof SQLRowValues)) { |
if (fk.contains(field) && fieldVal != SQL_DEFAULT && !(fieldVal instanceof SQLRowValues)) { |
final SQLRow pb = this.getTable().checkValidity(field.getName(), (Number) fieldVal); |
if (pb != null) |
return new Object[] { fieldName, pb }; |
1371,7 → 1393,7 |
final Object toIns; |
if (value instanceof SQLRowValues) { |
// TODO if we already point to some row, archive it |
toIns = new Integer(((SQLRowValues) value).insert().getID()); |
toIns = ((SQLRowValues) value).insert().getIDNumber(); |
} else |
toIns = value; |
// sql index start at 1 |
1390,7 → 1412,8 |
return value == SQL_DEFAULT ? "DEFAULT" : "?"; |
} |
public SQLTableListener createTableListener(SQLDataListener l) { |
@Override |
public SQLTableModifiedListener createTableListener(SQLDataListener l) { |
return new SQLTableListenerData<SQLRowValues>(this, l); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesCluster.java |
---|
836,6 → 836,7 |
public Link(final SQLRowValues src, final SQLField f, final SQLRowValues dest) { |
if (src == null) |
throw new NullPointerException("src is null"); |
assert (f == null && dest == null) || (dest != null && f.getTable() == src.getTable()); |
this.src = src; |
this.f = f; |
this.dest = dest; |
857,8 → 858,8 |
public int hashCode() { |
final int prime = 31; |
int result = 1; |
result = prime * result + this.src.hashCode(); |
result = prime * result + ((this.dest == null) ? 0 : this.dest.hashCode()); |
result = prime * result + System.identityHashCode(this.src); |
result = prime * result + System.identityHashCode(this.dest); |
result = prime * result + ((this.f == null) ? 0 : this.f.hashCode()); |
return result; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowAccessor.java |
---|
167,6 → 167,14 |
return res; |
} |
/** |
* Return the foreign row, if any, for the passed field. |
* |
* @param fieldName name of the foreign field. |
* @return <code>null</code> if the value of <code>fieldName</code> is <code>null</code>, |
* otherwise a SQLRowAccessor with the value of <code>fieldName</code> as its ID. |
* @throws IllegalArgumentException if fieldName is not a foreign field. |
*/ |
public abstract SQLRowAccessor getForeign(String fieldName); |
public abstract boolean isForeignEmpty(String fieldName); |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesMap.java |
---|
New file |
0,0 → 1,72 |
/* |
* 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 org.openconcerto.utils.cc.IPredicate; |
import org.openconcerto.utils.checks.EmptyObjFromVO; |
import java.sql.SQLException; |
import java.util.HashMap; |
import java.util.Map; |
/** |
* Store inserted rows. This class allows to avoid having huge, slow {@link SQLRowValuesCluster} by |
* replacing a foreign link with its ID. |
* |
* @author Sylvain CUAZ |
* @param <T> type of source object. |
*/ |
public abstract class SQLRowValuesMap<T> { |
private final SQLTable t; |
private final Map<SQLRowValues, SQLRow> map; |
private final IPredicate<? super T> emptyPredicate; |
public SQLRowValuesMap(final SQLTable t) { |
this(t, EmptyObjFromVO.getDefaultPredicate()); |
} |
public SQLRowValuesMap(final SQLTable t, final IPredicate<? super T> emptyPredicate) { |
this.t = t; |
this.map = new HashMap<SQLRowValues, SQLRow>(); |
this.emptyPredicate = emptyPredicate; |
} |
protected abstract void fill(final SQLRowValues vals, T obj); |
/** |
* Return a non SQLRowValues value, thus avoiding linking two graphs together. If |
* <code>obj</code> is empty, returns {@link SQLRowValues#SQL_EMPTY_LINK}, else calls |
* {@link #fill(SQLRowValues, Object)} and if these values haven't already been inserted, insert |
* them, finally return the ID. |
* |
* @param obj the source object. |
* @return the ID or SQL_EMPTY_LINK. |
* @throws SQLException if an error occurs while inserting. |
*/ |
public final Object getValue(final T obj) throws SQLException { |
if (this.emptyPredicate.evaluateChecked(obj)) { |
return SQLRowValues.SQL_EMPTY_LINK; |
} else { |
final SQLRowValues key = new SQLRowValues(this.t); |
this.fill(key, obj); |
SQLRow res = this.map.get(key); |
if (res == null) { |
res = key.insert(); |
this.map.put(key, res); |
} |
return res.getIDNumber(); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java |
---|
26,6 → 26,7 |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.utils.ExceptionUtils; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.cc.IPredicate; |
import org.openconcerto.utils.change.CollectionChangeEventCreator; |
import org.openconcerto.xml.JDOMUtils; |
42,6 → 43,7 |
import java.util.Iterator; |
import java.util.LinkedHashMap; |
import java.util.LinkedHashSet; |
import java.util.LinkedList; |
import java.util.List; |
import java.util.Map; |
import java.util.Set; |
172,9 → 174,6 |
// 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) |
private List<SQLTableModifiedListener> tableModifiedListeners; |
private final List<SQLTableListener> listeners; |
// copy of listeners while dispatching, so that a listener can modify it |
private final List<SQLTableListener> dispatchingListeners; |
// the id that foreign keys pointing to this, can use instead of NULL |
// a null value meaning not yet known |
private Integer undefinedID; |
186,8 → 185,6 |
SQLTable(SQLSchema schema, String name) { |
super(schema, name); |
this.tableModifiedListeners = Collections.emptyList(); |
this.listeners = new ArrayList<SQLTableListener>(); |
this.dispatchingListeners = new ArrayList<SQLTableListener>(); |
// ne pas se soucier de la casse |
this.fields = createMap(); |
// order matters (eg for indexes) |
971,15 → 968,27 |
*/ |
public void addTableModifiedListener(SQLTableModifiedListener l) { |
synchronized (this.listeners) { |
final List<SQLTableModifiedListener> newListeners = new ArrayList<SQLTableModifiedListener>(this.tableModifiedListeners); |
this.addTableModifiedListener(l, false); |
} |
public void addPremierTableModifiedListener(SQLTableModifiedListener l) { |
this.addTableModifiedListener(l, true); |
} |
private void addTableModifiedListener(SQLTableModifiedListener l, final boolean before) { |
synchronized (this) { |
final List<SQLTableModifiedListener> newListeners = new ArrayList<SQLTableModifiedListener>(this.tableModifiedListeners.size() + 1); |
if (before) |
newListeners.add(l); |
newListeners.addAll(this.tableModifiedListeners); |
if (!before) |
newListeners.add(l); |
this.tableModifiedListeners = Collections.unmodifiableList(newListeners); |
} |
} |
public void removeTableModifiedListener(SQLTableModifiedListener l) { |
synchronized (this.listeners) { |
synchronized (this) { |
final List<SQLTableModifiedListener> newListeners = new ArrayList<SQLTableModifiedListener>(this.tableModifiedListeners); |
if (newListeners.remove(l)) |
this.tableModifiedListeners = Collections.unmodifiableList(newListeners); |
986,6 → 995,37 |
} |
} |
private static final class BridgeListener implements SQLTableModifiedListener { |
private final SQLTableListener l; |
private BridgeListener(SQLTableListener l) { |
super(); |
this.l = l; |
} |
@Override |
public void tableModified(SQLTableEvent evt) { |
final Mode mode = evt.getMode(); |
if (mode == Mode.ROW_ADDED) |
this.l.rowAdded(evt.getTable(), evt.getId()); |
else if (mode == Mode.ROW_UPDATED) |
this.l.rowModified(evt.getTable(), evt.getId()); |
else if (mode == Mode.ROW_DELETED) |
this.l.rowDeleted(evt.getTable(), evt.getId()); |
} |
@Override |
public int hashCode() { |
return this.l.hashCode(); |
} |
@Override |
public boolean equals(Object obj) { |
return obj instanceof BridgeListener && this.l.equals(((BridgeListener) obj).l); |
} |
} |
/** |
* Ajoute un listener sur cette table. |
* |
993,32 → 1033,13 |
* @deprecated use {@link #addTableModifiedListener(SQLTableModifiedListener)} |
*/ |
public void addTableListener(SQLTableListener l) { |
synchronized (this.listeners) { |
if (!this.listeners.contains(l)) { |
this.listeners.add(l); |
} else |
Log.get().fine(l + " already in"); |
this.addTableModifiedListener(new BridgeListener(l)); |
} |
} |
public void addPremierTableListener(SQLTableListener l) { |
synchronized (this.listeners) { |
if (!this.listeners.contains(l)) { |
this.listeners.add(0, l); |
} else |
throw new IllegalStateException(l + " is already listener of " + this); |
} |
} |
public void removeTableListener(SQLTableListener l) { |
synchronized (this.listeners) { |
this.listeners.remove(l); |
this.removeTableModifiedListener(new BridgeListener(l)); |
} |
} |
private static final int NOT_DISPATCHING = -2; |
private int dispatchingID = NOT_DISPATCHING; |
/** |
* Previent tous les listeners de la table qu'il y a eu une modification ou ajout si modif de |
* d'une ligne particuliere. |
1046,61 → 1067,55 |
} |
public final void fire(SQLTableEvent evt) { |
final int id = evt.getId(); |
synchronized (this.dispatchingListeners) { |
// FIXME peut laisser tomber des changements si un notifié rechange la même ligne |
if (this.dispatchingID != id) { |
this.dispatchingID = id; |
final Mode mode = evt.getMode(); |
this.dispatchingListeners.clear(); |
synchronized (this.listeners) { |
this.dispatchingListeners.addAll(this.listeners); |
this.fireTableModified(evt); |
} |
final int size = this.dispatchingListeners.size(); |
for (int i = 0; i < size; i++) { |
final SQLTableListener obj = this.dispatchingListeners.get(i); |
if (mode == Mode.ROW_UPDATED) |
obj.rowModified(this, id); |
else if (mode == Mode.ROW_ADDED) |
obj.rowAdded(this, id); |
else if (mode == Mode.ROW_DELETED) |
obj.rowDeleted(this, id); |
else |
throw new IllegalArgumentException("unknown mode: " + mode); |
static private final ThreadLocal<LinkedList<Tuple2<Iterator<SQLTableModifiedListener>, SQLTableEvent>>> events = new ThreadLocal<LinkedList<Tuple2<Iterator<SQLTableModifiedListener>, SQLTableEvent>>>() { |
@Override |
protected LinkedList<Tuple2<Iterator<SQLTableModifiedListener>, SQLTableEvent>> initialValue() { |
return new LinkedList<Tuple2<Iterator<SQLTableModifiedListener>, SQLTableEvent>>(); |
} |
this.fireTableModified(evt); |
this.dispatchingID = NOT_DISPATCHING; |
} else { |
System.err.println("dropping a SQLTable.fire() : fired in the listener"); |
Thread.dumpStack(); |
}; |
// allow to maintain the dispatching of events in order when a listener itself fires an event |
static private void fireTableModified(Tuple2<Iterator<SQLTableModifiedListener>, SQLTableEvent> newTuple) { |
final LinkedList<Tuple2<Iterator<SQLTableModifiedListener>, SQLTableEvent>> linkedList = events.get(); |
// add new event |
linkedList.addLast(newTuple); |
// process all pending events |
Tuple2<Iterator<SQLTableModifiedListener>, SQLTableEvent> currentTuple; |
while ((currentTuple = linkedList.peekFirst()) != null) { |
final Iterator<SQLTableModifiedListener> iter = currentTuple.get0(); |
final SQLTableEvent currentEvt = currentTuple.get1(); |
while (iter.hasNext()) { |
final SQLTableModifiedListener l = iter.next(); |
l.tableModified(currentEvt); |
} |
// not removeFirst() since the item might have been already removed |
linkedList.pollFirst(); |
} |
} |
private void fireTableModified(final SQLTableEvent evt) { |
// no need to copy since this.tableModifiedListeners is immutable |
final List<SQLTableModifiedListener> dispatchingListeners; |
synchronized (this.listeners) { |
synchronized (this) { |
dispatchingListeners = this.tableModifiedListeners; |
} |
// no need to synchronize since dispatchingListeners is immutable |
// even better, it also works if the same thread calls fireTableModified() in a callback |
// (although in that case some listeners might have events in the wrong order) |
for (final SQLTableModifiedListener l : dispatchingListeners) { |
l.tableModified(evt); |
fireTableModified(Tuple2.create(dispatchingListeners.iterator(), evt)); |
} |
} |
@SuppressWarnings("unchecked") |
public String toXML() { |
final StringBuilder sb = new StringBuilder(16000); |
sb.append("<table name=\""); |
sb.append(this.getName()); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(this.getName())); |
sb.append("\""); |
final String schemaName = this.getSchema().getName(); |
if (schemaName != null) { |
sb.append(" schema=\""); |
sb.append(schemaName); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(schemaName)); |
sb.append('"'); |
} |
1114,7 → 1129,7 |
if (getType() != null) { |
sb.append(" type=\""); |
sb.append(getType()); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(getType())); |
sb.append('"'); |
} |
1152,21 → 1167,13 |
return sb.toString(); |
} |
public SQLTableListener createTableListener(final SQLDataListener l) { |
return new SQLTableListener() { |
public void rowModified(SQLTable table, int id) { |
@Override |
public SQLTableModifiedListener createTableListener(final SQLDataListener l) { |
return new SQLTableModifiedListener() { |
@Override |
public void tableModified(SQLTableEvent evt) { |
l.dataChanged(); |
} |
public void rowAdded(SQLTable table, int id) { |
l.dataChanged(); |
} |
public void rowDeleted(SQLTable table, int id) { |
l.dataChanged(); |
} |
}; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSchema.java |
---|
53,7 → 53,7 |
sb.append(' '); |
sb.append(VERSION_XMLATTR); |
sb.append("=\""); |
sb.append(version); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(version)); |
sb.append('"'); |
} catch (IOException e) { |
throw new IllegalStateException("Couldn't append version of " + schema, e); |
218,7 → 218,7 |
sb.append("<schema "); |
if (this.getName() != null) { |
sb.append(" name=\""); |
sb.append(this.getName()); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(this.getName())); |
sb.append('"'); |
} |
getVersionAttr(this, sb); |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRow.java |
---|
400,10 → 400,12 |
} |
} |
@Override |
public SQLRow getForeign(String fieldName) { |
return this.getForeignRow(fieldName); |
} |
@Override |
public boolean isForeignEmpty(String fieldName) { |
final SQLRow foreignRow = this.getForeignRow(fieldName, SQLRowMode.NO_CHECK); |
return foreignRow == null || foreignRow.isUndefined(); |
413,7 → 415,7 |
* Retourne la ligne sur laquelle pointe le champ passé. Elle peut être archivé ou indéfinie. |
* |
* @param field le nom de la clef externe. |
* @return la ligne sur laquelle pointe le champ passé, jamais <code>null</code>. |
* @return la ligne sur laquelle pointe le champ passé. |
* @throws IllegalArgumentException si <code>field</code> n'est pas une clef étrangère de la |
* table de cette ligne. |
* @throws IllegalStateException si <code>field</code> contient l'ID d'une ligne inexistante. |
949,7 → 951,8 |
return path.split(","); |
} |
public SQLTableListener createTableListener(SQLDataListener l) { |
@Override |
public SQLTableModifiedListener createTableListener(SQLDataListener l) { |
return new SQLTableListenerData<SQLRow>(this, l); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLData.java |
---|
15,7 → 15,7 |
public interface SQLData { |
public SQLTableListener createTableListener(SQLDataListener l); |
public SQLTableModifiedListener createTableListener(SQLDataListener l); |
public SQLTable getTable(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/UserRightsManagerModel.java |
---|
19,7 → 19,9 |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableListener; |
import org.openconcerto.sql.model.SQLTableEvent; |
import org.openconcerto.sql.model.SQLTableEvent.Mode; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.sql.model.Where; |
import java.sql.SQLException; |
55,26 → 57,17 |
List<SQLRow> rowsRights = (List<SQLRow>) Configuration.getInstance().getBase().getDataSource().execute(sel2.asString(), new SQLRowListRSH(this.tableRight, true)); |
this.cache.addAll(rowsRights); |
this.tableRight.addTableListener(new SQLTableListener() { |
this.tableRight.addTableModifiedListener(new SQLTableModifiedListener() { |
@Override |
public void rowAdded(SQLTable table, int id) { |
UserRightsManagerModel.this.cache.add(table.getRow(id)); |
} |
@Override |
public void rowDeleted(SQLTable table, int id) { |
} |
@Override |
public void rowModified(SQLTable table, int id) { |
SQLRow row = table.getRow(id); |
public void tableModified(SQLTableEvent evt) { |
if (evt.getMode() == Mode.ROW_ADDED) { |
UserRightsManagerModel.this.cache.add(evt.getRow()); |
} else { |
final SQLRow row = evt.getRow(); |
for (int i = 0; i < UserRightsManagerModel.this.cache.size(); i++) { |
SQLRow row2 = UserRightsManagerModel.this.cache.get(i); |
if (row2.getID() == id) { |
if (row.isArchived()) { |
final SQLRow row2 = UserRightsManagerModel.this.cache.get(i); |
if (row2.getID() == row.getID()) { |
if (!row.isValid()) { |
UserRightsManagerModel.this.cache.remove(i); |
} else { |
UserRightsManagerModel.this.cache.set(i, row2); |
83,15 → 76,24 |
} |
} |
} |
} |
}); |
this.tableUserRight.addTableListener(new SQLTableListener() { |
this.tableUserRight.addTableModifiedListener(new SQLTableModifiedListener() { |
@Override |
public void rowAdded(SQLTable table, int id) { |
public void tableModified(SQLTableEvent evt) { |
if (evt.getMode() == Mode.ROW_ADDED) { |
rowAdded(evt); |
} else { |
rowModified(evt); |
} |
} |
SQLRow row = table.getRow(id); |
public void rowAdded(SQLTableEvent evt) { |
final SQLRow row = evt.getRow(); |
if (row.getInt("ID_USER_COMMON") == UserRightsManagerModel.this.idUser) { |
SQLRowValues rowVals = getSQLRowValuesForID(id); |
SQLRowValues rowVals = getSQLRowValuesFor(row); |
if (rowVals == null) { |
UserRightsManagerModel.this.listRowValues.add(row.createUpdateRow()); |
fireTableRowsInserted(UserRightsManagerModel.this.listRowValues.size() - 2, UserRightsManagerModel.this.listRowValues.size() - 1); |
99,17 → 101,12 |
} |
} |
@Override |
public void rowDeleted(SQLTable table, int id) { |
} |
@Override |
public void rowModified(SQLTable table, int id) { |
SQLRow row = table.getRow(id); |
public void rowModified(SQLTableEvent evt) { |
final SQLRow row = evt.getRow(); |
if (row.getInt("ID_USER_COMMON") == UserRightsManagerModel.this.idUser) { |
SQLRowValues rowVals = getSQLRowValuesForID(id); |
SQLRowValues rowVals = getSQLRowValuesFor(row); |
int index = UserRightsManagerModel.this.listRowValues.indexOf(rowVals); |
if (row.isArchived()) { |
if (!row.isValid()) { |
UserRightsManagerModel.this.listRowValues.removeElement(rowVals); |
fireTableRowsDeleted(index - 1, index + 1); |
} else { |
121,12 → 118,11 |
}); |
} |
private SQLRowValues getSQLRowValuesForID(int id) { |
SQLRow row = this.tableUserRight.getRow(id); |
private SQLRowValues getSQLRowValuesFor(final SQLRow row) { |
final String string2 = row.getString("CODE"); |
for (SQLRowValues rowVals : this.listRowValues) { |
final String string = rowVals.getString("CODE"); |
if (rowVals.getID() == id || (string != null && string2 != null && string.equalsIgnoreCase(string2))) { |
if (rowVals.getID() == row.getID() || (string != null && string2 != null && string.equalsIgnoreCase(string2))) { |
return rowVals; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/changer/correct/FixSharedPrivate.java |
---|
17,11 → 17,14 |
import org.openconcerto.sql.changer.Changer; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.DBSystemRoot; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowListRSH; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLSelect.ArchiveMode; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.model.SQLSelect.ArchiveMode; |
import org.openconcerto.sql.utils.SQLUtils; |
import org.openconcerto.sql.utils.SQLUtils.SQLFactory; |
41,7 → 44,7 |
super(b); |
} |
@SuppressWarnings("unchecked") |
@Override |
protected void changeImpl(final SQLTable t) throws SQLException { |
getStream().println(t + "... "); |
if (Configuration.getInstance() == null || Configuration.getInstance().getDirectory() == null) |
65,9 → 68,14 |
sel.addBackwardJoin("INNER", "m", t.getField(pff), null); |
final String req = sel.asString() + " GROUP BY " + privateTable.getKey().getFieldRef() + " HAVING count(" + privateTable.getKey().getFieldRef() + ")>1"; |
@SuppressWarnings("unchecked") |
final List<Number> privateIDs = t.getDBSystemRoot().getDataSource().executeCol(req); |
if (privateIDs.size() > 0) { |
getStream().println("\t" + pff + " fixing " + privateIDs.size() + " ... "); |
final SQLField archF = t.getArchiveField(); |
final SQLField privateArchF = privateTable.getArchiveField(); |
if ((archF == null) != (privateArchF == null)) |
throw new IllegalStateException("Incoherent archive field : " + archF + " / " + privateArchF); |
SQLUtils.executeAtomic(t.getDBSystemRoot().getDataSource(), new SQLFactory<Object>() { |
@Override |
public Object create() throws SQLException { |
76,11 → 84,21 |
final SQLSelect fixSel = new SQLSelect(t.getBase()); |
fixSel.setArchivedPolicy(ArchiveMode.BOTH); |
fixSel.addSelect(t.getKey()); |
if (archF != null) |
fixSel.addSelect(archF); |
fixSel.setWhere(new Where(t.getField(pff), "=", privateID)); |
final List<Number> tIDs = t.getDBSystemRoot().getDataSource().executeCol(fixSel.asString()); |
final List<SQLRow> tIDs = SQLRowListRSH.execute(fixSel); |
for (final SQLRow tID : tIDs) { |
// the first one can keep its private |
for (final Number tID : tIDs.subList(1, tIDs.size())) { |
new SQLRowValues(t).setID(tID).put(pff, privateElement.createCopy(privateID.intValue())).update(); |
final SQLRowValues reallyPrivate; |
if (tID == tIDs.get(0)) |
reallyPrivate = new SQLRowValues(privateElement.getTable()).setID(privateID); |
else |
reallyPrivate = privateElement.createCopy(privateID.intValue()); |
// keep archive coherence |
if (archF != null) |
reallyPrivate.put(privateArchF.getName(), tID.getObject(archF.getName())); |
new SQLRowValues(t).setID(tID.getIDNumber()).put(pff, reallyPrivate).update(); |
} |
} |
return null; |
/trunk/OpenConcerto/src/org/openconcerto/utils/FileUtils.java |
---|
354,6 → 354,14 |
} |
} |
public static void copyFile(File in, File out, final boolean useTime) throws IOException { |
if (!useTime || in.lastModified() != out.lastModified()) { |
copyFile(in, out); |
if (useTime) |
out.setLastModified(in.lastModified()); |
} |
} |
public static void copyDirectory(File in, File out) throws IOException { |
copyDirectory(in, out, Collections.<String> emptySet()); |
} |
361,6 → 369,10 |
public static final Set<String> VersionControl = CollectionUtils.createSet(".svn", "CVS"); |
public static void copyDirectory(File in, File out, final Set<String> toIgnore) throws IOException { |
copyDirectory(in, out, toIgnore, false); |
} |
public static void copyDirectory(File in, File out, final Set<String> toIgnore, final boolean useTime) throws IOException { |
if (toIgnore.contains(in.getName())) |
return; |
371,11 → 383,11 |
String[] children = in.list(); |
for (int i = 0; i < children.length; i++) { |
copyDirectory(new File(in, children[i]), new File(out, children[i]), toIgnore); |
copyDirectory(new File(in, children[i]), new File(out, children[i]), toIgnore, useTime); |
} |
} else { |
if (!in.getName().equals("Thumbs.db")) { |
copyFile(in, out); |
copyFile(in, out, useTime); |
} |
} |
} |
404,6 → 416,21 |
return dir.delete(); |
} |
public static void rm_R(File dir) throws IOException { |
if (dir.isDirectory()) { |
for (final File child : dir.listFiles()) { |
rmR(child); |
} |
} |
// The directory is now empty so delete it |
rm(dir); |
} |
public static void rm(File f) throws IOException { |
if (f.exists() && !f.delete()) |
throw new IOException("cannot delete " + f); |
} |
public static final File mkdir_p(File dir) throws IOException { |
if (!dir.exists()) { |
if (!dir.mkdirs()) { |
/trunk/OpenConcerto/src/org/openconcerto/utils/CompareUtils.java |
---|
57,6 → 57,32 |
} |
/** |
* Compare two objects if they're numbers or comparable. |
* |
* @param o1 first object. |
* @param o2 second object. |
* @return a negative integer, zero, or a positive integer as o1 is less than, equal to, or |
* greater than o2. |
* @throws ClassCastException if o1 is neither a {@link Number} nor a {@link Comparable}, or if |
* o2's type prevents it from being compared to o1. |
* @throws NullPointerException if o1 or o2 is <code>null</code>. |
* @see Comparable#compareTo(Object) |
* @see NumberUtils#compare(Number, Number) |
*/ |
static public final int compare(final Object o1, final Object o2) throws ClassCastException { |
if (o1 == null || o2 == null) |
throw new NullPointerException(); |
if (o1 instanceof Number && o2 instanceof Number) { |
return NumberUtils.compare((Number) o1, (Number) o2); |
} else { |
// see Arrays.mergeSort() |
@SuppressWarnings({ "rawtypes", "unchecked" }) |
final int res = ((Comparable) o1).compareTo(o2); |
return res; |
} |
} |
/** |
* Renvoie un comparateur qui utilise successivement la liste passée tant que les objets sont |
* égaux. |
* |
/trunk/OpenConcerto/src/org/openconcerto/utils/TimeUtils.java |
---|
New file |
0,0 → 1,76 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.utils; |
import java.math.BigDecimal; |
import java.math.BigInteger; |
import java.util.Calendar; |
import javax.xml.datatype.DatatypeConfigurationException; |
import javax.xml.datatype.DatatypeFactory; |
import javax.xml.datatype.Duration; |
public class TimeUtils { |
static private DatatypeFactory typeFactory = null; |
static public final DatatypeFactory getTypeFactory() { |
if (typeFactory == null) |
try { |
typeFactory = DatatypeFactory.newInstance(); |
} catch (DatatypeConfigurationException e) { |
throw new IllegalStateException(e); |
} |
return typeFactory; |
} |
/** |
* Convert the time part of a calendar to a duration. |
* |
* @param cal a calendar, e.g. 23/12/2011 11:55:33.066 GMT+02. |
* @return a duration, e.g. P0Y0M0DT11H55M33.066S. |
*/ |
public final static Duration timePartToDuration(final Calendar cal) { |
final BigDecimal seconds = BigDecimal.valueOf(cal.get(Calendar.SECOND)).add(BigDecimal.valueOf(cal.get(Calendar.MILLISECOND)).movePointLeft(3)); |
return getTypeFactory().newDuration(true, BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, BigInteger.valueOf(cal.get(Calendar.HOUR_OF_DAY)), BigInteger.valueOf(cal.get(Calendar.MINUTE)), |
seconds); |
} |
/** |
* Normalize <code>cal</code> so that any Calendar with the same local time have the same |
* result. If you don't need a Calendar this is faster than |
* {@link #copyLocalTime(Calendar, Calendar)}. |
* |
* @param cal a calendar, e.g. 0:00 CEST. |
* @return the time in millisecond of the UTC calendar with the same local time, e.g. 0:00 UTC. |
*/ |
public final static long normalizeLocalTime(final Calendar cal) { |
return cal.getTimeInMillis() + cal.getTimeZone().getOffset(cal.getTimeInMillis()); |
} |
/** |
* Copy the local time from one calendar to another. Except if both calendars have the same time |
* zone, from.getTimeInMillis() will be different from to.getTimeInMillis(). |
* |
* @param from the source calendar, e.g. 23/12/2011 11:55:33.066 GMT-12. |
* @param to the destination calendar, e.g. 01/01/2000 0:00 GMT+13. |
* @return the modified destination calendar, e.g. 23/12/2011 11:55:33.066 GMT+13. |
*/ |
public final static Calendar copyLocalTime(final Calendar from, final Calendar to) { |
to.clear(); |
for (final int field : new int[] { Calendar.YEAR, Calendar.DAY_OF_YEAR, Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND }) { |
to.set(field, from.get(field)); |
} |
return to; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/utils/MultipleOutputStream.java |
---|
New file |
0,0 → 1,68 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.utils; |
import java.io.IOException; |
import java.io.OutputStream; |
public class MultipleOutputStream extends OutputStream { |
private OutputStream[] streams; |
/** |
* OutputStream forwarding writes to multiple OutputStreams |
* */ |
public MultipleOutputStream(OutputStream o1, OutputStream o2) { |
this(new OutputStream[] { o1, o2 }); |
} |
public MultipleOutputStream(OutputStream[] outputStreams) { |
this.streams = outputStreams; |
} |
@Override |
public void write(int b) throws IOException { |
for (int i = 0; i < streams.length; i++) { |
streams[i].write(b); |
} |
} |
@Override |
public void write(byte[] b) throws IOException { |
for (int i = 0; i < streams.length; i++) { |
streams[i].write(b); |
} |
} |
@Override |
public void write(byte[] b, int off, int len) throws IOException { |
for (int i = 0; i < streams.length; i++) { |
streams[i].write(b, off, len); |
} |
} |
@Override |
public void close() throws IOException { |
for (int i = 0; i < streams.length; i++) { |
streams[i].close(); |
} |
} |
@Override |
public void flush() throws IOException { |
for (int i = 0; i < streams.length; i++) { |
streams[i].flush(); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/EmptyObjFromVO.java |
---|
18,8 → 18,6 |
import java.beans.PropertyChangeEvent; |
import java.beans.PropertyChangeListener; |
import org.apache.commons.collections.Predicate; |
/** |
* Implement EmptyObj with a ValueObject and a predicate. |
* |
28,21 → 26,20 |
*/ |
public class EmptyObjFromVO<V> implements EmptyObj { |
/** |
* A predicate returning <code>true</code> if the passed object is <code>null</code> or the |
* empty string. |
* |
* @param <T> type of the value object. |
* @return a predicate returning <code>true</code> if the object is empty. |
*/ |
@SuppressWarnings("unchecked") |
public static final <T> IPredicate<T> getDefaultPredicate() { |
return new IPredicate<T>() { |
@Override |
public boolean evaluateChecked(T input) { |
return DEFAULT_PREDICATE.evaluate(input); |
return (IPredicate<T>) DEFAULT_PREDICATE; |
} |
}; |
} |
/** |
* This predicate returns <code>true</code> if the passed object is <code>null</code> or the |
* empty string. |
*/ |
public static final Predicate DEFAULT_PREDICATE = new Predicate() { |
public boolean evaluate(Object object) { |
private static final IPredicate<Object> DEFAULT_PREDICATE = new IPredicate<Object>() { |
public boolean evaluateChecked(Object object) { |
if (object instanceof String) |
return ((String) object).length() == 0; |
else |
/trunk/OpenConcerto/src/org/openconcerto/utils/model/Reloadable.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.utils.model; |
public interface Reloadable { |
void reload(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/utils/StringUtils.java |
---|
222,7 → 222,7 |
if (lastString.length() == nbCharMaxLine) { |
int esp = lastString.lastIndexOf(" "); |
if (result.length() > 0) { |
if (result.length() > 0 && result.charAt(result.length() - 1) != '\n') { |
result.append("\n"); |
} |
if (esp > 0) { |
232,6 → 232,7 |
result.append(lastString.toString().trim()); |
lastString = new StringBuffer(); |
} |
result.append("\n"); |
} |
char charAt = s.charAt(i); |
240,12 → 241,11 |
result.append(lastString); |
lastString = new StringBuffer(); |
} else { |
lastString.append(charAt); |
} |
} |
if (result.length() > 0) { |
if (result.length() > 0 && result.charAt(result.length() - 1) != '\n') { |
result.append("\n"); |
} |
338,4 → 338,21 |
} |
} |
public static String rightAlign(String s, int width) { |
String r = s; |
int n = width - s.length(); |
for (int i = 0; i < n; i++) { |
r = ' ' + r; |
} |
return r; |
} |
public static String leftAlign(String s, int width) { |
String r = s; |
int n = width - s.length(); |
for (int i = 0; i < n; i++) { |
r += ' '; |
} |
return r; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/utils/ExceptionHandler.java |
---|
71,6 → 71,14 |
clipboard.setContents(data, data); |
} |
/** |
* Display the passed message. Note: this method doesn't block. |
* |
* @param comp the modal parent of the error window. |
* @param msg the message to display. |
* @param originalExn the cause, can be <code>null</code>. |
* @return an exception. |
*/ |
static public RuntimeException handle(Component comp, String msg, Throwable originalExn) { |
return new ExceptionHandler(comp, msg, originalExn, false); |
} |
83,6 → 91,14 |
return handle(msg, null); |
} |
/** |
* Display the passed message and quit. Note: this method blocks until the user closes the |
* window (then exits). |
* |
* @param msg the message to display. |
* @param originalExn the cause, can be <code>null</code>. |
* @return an exception. |
*/ |
static public RuntimeException die(String msg, Throwable originalExn) { |
return new ExceptionHandler(null, msg, originalExn); |
} |
115,14 → 131,25 |
if (!GraphicsEnvironment.isHeadless() || forceUI) { |
if (SwingUtilities.isEventDispatchThread()) { |
showMsg(msg, error); |
} else |
SwingUtilities.invokeLater(new Runnable() { |
} else { |
final Runnable run = new Runnable() { |
public void run() { |
showMsg(msg, error); |
} |
}); |
}; |
if (error) { |
try { |
SwingUtilities.invokeAndWait(run); |
} catch (Exception e) { |
e.printStackTrace(); |
System.exit(1); |
} |
} else { |
SwingUtilities.invokeLater(run); |
} |
} |
} |
} |
protected final void showMsg(final String msg, final boolean quit) { |
final JPanel p = new JPanel(); |
/trunk/OpenConcerto/src/org/openconcerto/task/TodoListPanel.java |
---|
236,8 → 236,9 |
} |
this.addButton = new JButton("Ajouter une tâche"); |
this.addButton.setOpaque(false); |
this.removeButton = new JButton("Effacer"); |
this.removeButton.setOpaque(false); |
this.removeButton.setEnabled(false); |
this.setLayout(new GridBagLayout()); |
GridBagConstraints c = new GridBagConstraints(); |
263,6 → 264,7 |
c.anchor = GridBagConstraints.EAST; |
c.gridx++; |
JMenuBar b = new JMenuBar(); |
b.setOpaque(false); |
b.setBorderPainted(false); |
b.add(this.comboUser); |
// Pour que le menu ne disparaisse pas quand on rapetisse trop la fenetre en bas |
273,6 → 275,7 |
c.gridx++; |
c.weightx = 1; |
this.detailCheckBox = new JCheckBox("Affichage détaillé"); |
this.detailCheckBox.setOpaque(false); |
this.detailCheckBox.setSelected(false); |
this.add(this.detailCheckBox, c); |
279,6 → 282,7 |
// |
c.gridx++; |
this.hideOldCheckBox = new JCheckBox("Masquer l'historique"); |
this.hideOldCheckBox.setOpaque(false); |
this.hideOldCheckBox.setSelected(true); |
this.add(this.hideOldCheckBox, c); |
286,6 → 290,7 |
c.weightx = 0; |
c.anchor = GridBagConstraints.EAST; |
this.reloadPanel.setOpaque(false); |
this.add(this.reloadPanel, c); |
// Table |
503,7 → 508,10 |
this.t.setBlockEventOnColumn(false); |
this.t.setBlockRepaint(false); |
this.t.getColumnModel().getColumn(1).setCellRenderer(this.iconRenderer); |
// Better look |
this.t.setShowHorizontalLines(false); |
this.t.setGridColor(new Color(230, 230, 230)); |
this.t.setRowHeight(this.t.getRowHeight() + 4); |
AlternateTableCellRenderer.UTILS.setAllColumns(this.t); |
this.t.repaint(); |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/DocumentGeneratorManager.java |
---|
New file |
0,0 → 1,66 |
/* |
* 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; |
import java.util.Set; |
public class DocumentGeneratorManager { |
private static DocumentGeneratorManager instance = new DocumentGeneratorManager(); |
private Map<String, DocumentGenerator> generators = new HashMap<String, DocumentGenerator>(); |
private DocumentGenerator defautGenerator; |
public static DocumentGeneratorManager getInstance() { |
return instance; |
} |
public void add(String templateId, DocumentGenerator generator) { |
this.generators.put(templateId, generator); |
} |
public void remove(DocumentGenerator generator) { |
final Set<String> keys = generators.keySet(); |
for (String key : keys) { |
if (generators.get(key).equals(generator)) { |
generators.remove(key); |
} |
} |
} |
public void setDefaultGenerator(DocumentGenerator generator) { |
this.defautGenerator = generator; |
} |
/** |
* Returns the document generator a specific templateId |
* */ |
public DocumentGenerator getGenerator(String templateId) { |
DocumentGenerator generator = this.generators.get(templateId); |
if (generator == null) { |
generator = defautGenerator; |
} |
return generator; |
} |
public void dump() { |
System.out.println(this.getClass().getCanonicalName()); |
System.out.println("Default generator:" + this.defautGenerator); |
Set<String> ids = generators.keySet(); |
for (String templateId : ids) { |
System.out.println("'" + templateId + "' : " + generators.get(templateId)); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractJOOReportsSheet.java |
---|
41,7 → 41,6 |
import javax.swing.JOptionPane; |
import javax.swing.SwingUtilities; |
public abstract class AbstractJOOReportsSheet { |
private static final String defaultLocationTemplate = SpreadSheetGenerator.defaultLocationTemplate; |
protected static final DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); |
49,8 → 48,7 |
protected static final DateFormat yearFormat = new SimpleDateFormat("yyyy"); |
private String year; |
protected String locationTemplate = TemplateNXProps.getInstance().getStringProperty("LocationTemplate"); |
private String locationOO, locationPDF; |
protected String templateFileName; |
protected String templateId; |
private String printer; |
protected boolean askOverwriting = false; |
61,11 → 59,9 |
abstract public String getFileName(); |
protected void init(String year, String templateFileName, String attributePrinter, Tuple2<String, String> t) { |
protected void init(String year, String templateId, String attributePrinter) { |
this.year = year; |
this.templateFileName = templateFileName; |
this.locationOO = SheetXml.getLocationForTuple(t, false) + File.separator + this.year; |
this.locationPDF = SheetXml.getLocationForTuple(t, true) + File.separator + this.year; |
this.templateId = templateId; |
this.printer = PrinterNXProps.getInstance().getStringProperty(attributePrinter); |
} |
88,27 → 84,23 |
try { |
String fileName = getFileName(); |
final InputStream fileTemplate = getStream(this.templateFileName, this.locationTemplate, defaultLocationTemplate); |
File fileOutOO = new File(this.locationOO, fileName + ".odt"); |
// File fileOutPDF = new File(locationPropositionPDF, fileName); |
final InputStream fileTemplate = TemplateManager.getInstance().getTemplate(this.templateId); |
File outputDir = DocumentLocalStorageManager.getInstance().getDocumentOutputDirectory(this.templateId); |
File fileOutOO = getDocumentFile(); |
if (fileOutOO.exists() && overwrite) { |
if (this.askOverwriting) { |
int answer = JOptionPane.showConfirmDialog(null, "Voulez vous écraser le document ?", "Remplacement d'un document", JOptionPane.YES_NO_OPTION); |
if (answer == JOptionPane.YES_OPTION) { |
SheetUtils.getInstance().convertToOldFile(fileName, new File(this.locationOO), fileOutOO, ".odt"); |
SheetUtils.convertToOldFile(fileName, outputDir, fileOutOO, ".odt"); |
} |
} else { |
SheetUtils.getInstance().convertToOldFile(fileName, new File(this.locationOO), fileOutOO, ".odt"); |
SheetUtils.convertToOldFile(fileName, outputDir, fileOutOO, ".odt"); |
} |
} |
if (!fileOutOO.exists()) { |
fileOutOO.getParentFile().mkdirs(); |
Template template; |
// try { |
template = new Template(new BufferedInputStream(fileTemplate)); |
Template template = new Template(new BufferedInputStream(fileTemplate)); |
// creation du document |
final Map createMap = createMap(); |
116,11 → 108,7 |
model.putAll(createMap); |
template.createDocument(model).saveAs(fileOutOO); |
// template.createDocument(model, new BufferedOutputStream(new |
// FileOutputStream(fileOutOO))); |
// } catch (JDOMException e) { |
// e.printStackTrace(); |
// } |
} |
// ouverture de OO |
133,9 → 121,10 |
} |
final Component doc = ooConnexion.loadDocument(fileOutOO, !show); |
if (this.savePDF()) |
doc.saveToPDF(new File(this.locationPDF, fileName + ".pdf"), "writer_pdf_Export"); |
if (this.savePDF()) { |
File pdfOutputDir = DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(templateId); |
doc.saveToPDF(new File(pdfOutputDir, fileName + ".pdf"), "writer_pdf_Export"); |
} |
if (print) { |
Map<String, Object> map = new HashMap<String, Object>(); |
map.put("Name", printer); |
164,7 → 153,7 |
} |
public void showDocument() { |
File fileOutOO = new File(this.locationOO, getFileName() + ".odt"); |
File fileOutOO = getDocumentFile(); |
if (fileOutOO.exists()) { |
try { |
final OOConnexion ooConnexion = ComptaPropsConfiguration.getOOConnexion(); |
183,8 → 172,13 |
} |
} |
private File getDocumentFile() { |
File outputDir = DocumentLocalStorageManager.getInstance().getDocumentOutputDirectory(templateId); |
return new File(outputDir, getFileName() + ".odt"); |
} |
public void printDocument() { |
File fileOutOO = new File(this.locationOO, getFileName() + ".odt"); |
File fileOutOO = getDocumentFile(); |
if (fileOutOO.exists()) { |
try { |
211,7 → 205,7 |
public void fastPrintDocument() { |
final File f = new File(this.locationOO, getFileName() + ".odt"); |
final File f = getDocumentFile(); |
if (!f.exists()) { |
generate(true, false, this.printer); |
239,13 → 233,6 |
} |
} |
public boolean exists() { |
String fileName = getFileName(); |
File fileOutOO = new File(this.locationOO, fileName + ".odt"); |
return fileOutOO.exists(); |
} |
protected String getInitiales(SQLRow row) { |
String init = ""; |
if (row != null) { |
264,9 → 251,10 |
public void exportToPdf() { |
// Export vers PDF |
String fileName = getFileName(); |
File fileOutOO = new File(this.locationOO, fileName + ".odt"); |
File fileOutPDF = new File(this.locationPDF, fileName); |
final String fileName = getFileName(); |
final File fileOutOO = getDocumentFile(); |
final File outputPDFDirectory = DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(this.templateId); |
final File fileOutPDF = new File(outputPDFDirectory, fileName + ".pdf"); |
if (!fileOutOO.exists()) { |
generate(false, false, ""); |
290,7 → 278,7 |
int result = JOptionPane.showOptionDialog(null, "Ouvrir le pdf ?", "Ouverture du PDF", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null); |
if (result == JOptionPane.YES_OPTION) { |
Gestion.openPDF(new File(fileOutPDF.getAbsolutePath() + ".pdf")); |
Gestion.openPDF(fileOutPDF); |
} else { |
try { |
FileUtils.openFile(fileOutPDF.getParentFile()); |
317,10 → 305,6 |
return ville.getName(); |
} |
public String getLocationOO() { |
return locationOO; |
} |
protected static String getVilleCP(String name) { |
Ville ville = Ville.getVilleFromVilleEtCode(name); |
if (ville == null) { |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/DocumentGenerator.java |
---|
New file |
0,0 → 1,27 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.erp.generationDoc; |
import java.util.Map; |
public interface DocumentGenerator { |
/** |
* Define the context for the creation of the document Keys of the context are defined in the |
* objects implementing the interface |
* */ |
public void setContext(Map<String, Object> context); |
public void createDocument(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractLocalTemplateProvider.java |
---|
New file |
0,0 → 1,73 |
/* |
* 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.io.File; |
import java.io.FileInputStream; |
import java.io.FileNotFoundException; |
import java.io.InputStream; |
public abstract class AbstractLocalTemplateProvider implements TemplateProvider { |
@Override |
public InputStream getTemplate(String templateId, String langage, String type) { |
try { |
final File templateFile = getTemplateFile(templateId, langage, type); |
if (templateFile == null || !templateFile.exists()) { |
return null; |
} |
return new FileInputStream(templateFile); |
} catch (FileNotFoundException e) { |
return null; |
} |
} |
@Override |
public InputStream getTemplatePrintConfiguration(String templateId, String langage, String type) { |
final File t = getTemplateFile(templateId, langage, type); |
final String name = t.getName(); |
if (name.toLowerCase().endsWith(".ods")) { |
final File file = new File(t.getParent(), name.substring(0, name.length() - 4) + ".odsp"); |
try { |
return new FileInputStream(file); |
} catch (FileNotFoundException e) { |
System.err.println("No print configuration " + file.getAbsolutePath() + " for template id: " + templateId); |
e.printStackTrace(); |
} |
} |
return null; |
} |
@Override |
public InputStream getTemplateConfiguration(String templateId, String langage, String type) { |
final File t = getTemplateFile(templateId, langage, type); |
final String name = t.getName(); |
if (name.toLowerCase().endsWith(".ods")) { |
final File file = new File(t.getParent(), name.substring(0, name.length() - 4) + ".xml"); |
try { |
return new FileInputStream(file); |
} catch (FileNotFoundException e) { |
System.err.println("No template configuration " + file.getAbsolutePath() + " for template id: " + templateId); |
e.printStackTrace(); |
} |
} |
return null; |
} |
public abstract File getTemplateFile(String templateId, String langage, String type); |
@Override |
public abstract String getTemplatePath(String templateId, String langage, String type); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/TemplateProvider.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; |
import java.io.InputStream; |
public interface TemplateProvider { |
/** |
* Path: ex ILM/Devis |
* */ |
public String getTemplatePath(String templateId, String language, String type); |
/** |
* Returns the content of template file (ex: the ODS file) |
* */ |
public InputStream getTemplate(String templateId, String language, String type); |
/** |
* Returns the content of template configuration file (ex: the odsp file) |
* */ |
public InputStream getTemplateConfiguration(String templateId, String language, String type); |
/** |
* Returns the content of template print configuration file (ex: the odsp file) |
* */ |
public InputStream getTemplatePrintConfiguration(String templateId, String language, String type); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetXml.java |
---|
17,7 → 17,8 |
import org.openconcerto.erp.core.common.ui.FastPrintAskFrame; |
import org.openconcerto.erp.core.common.ui.PreviewFrame; |
import org.openconcerto.erp.generationDoc.element.TypeModeleSQLElement; |
import org.openconcerto.erp.preferences.TemplateNXProps; |
import org.openconcerto.erp.storage.StorageEngine; |
import org.openconcerto.erp.storage.StorageEngines; |
import org.openconcerto.openoffice.OOUtils; |
import org.jopendocument.link.Component; |
import org.openconcerto.sql.Configuration; |
25,13 → 26,17 |
import org.openconcerto.sql.model.SQLBase; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.utils.ExceptionHandler; |
import org.openconcerto.utils.Tuple2; |
import java.io.BufferedInputStream; |
import java.io.File; |
import java.io.FileInputStream; |
import java.io.IOException; |
import java.lang.Thread.UncaughtExceptionHandler; |
import java.util.HashMap; |
import java.util.List; |
import java.util.Map; |
import java.util.concurrent.Callable; |
import java.util.concurrent.ExecutionException; |
import java.util.concurrent.ExecutorService; |
import java.util.concurrent.Future; |
import java.util.concurrent.LinkedBlockingQueue; |
46,6 → 51,23 |
public abstract class SheetXml { |
// return null to keep default value |
public interface StorageDirs { |
public File getDocumentOutputDirectory(SheetXml sheet); |
public File getPDFOutputDirectory(SheetXml sheet); |
public String getStoragePath(SheetXml sheet); |
} |
private static StorageDirs STORAGE_DIRS; |
// allow to redirect all documents |
public static void setStorageDirs(StorageDirs d) { |
STORAGE_DIRS = d; |
} |
public static final String DEFAULT_PROPERTY_NAME = "Default"; |
protected SQLElement elt; |
// nom de l'imprimante à utiliser |
57,16 → 79,6 |
// Language du document |
protected SQLRow rowLanguage; |
// emplacement du fichier OO généré |
protected String locationOO; |
// emplacement du fichier PDF généré |
protected String locationPDF; |
protected File f; |
public static final Tuple2<String, String> tupleDefault = Tuple2.create("Default", "Autres"); |
protected static final SQLBase base = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete(); |
// single threaded and kill its thread after 3 seconds (to allow the program to exit) |
79,62 → 91,98 |
} |
}; |
public void useOO(final File f, final boolean visu, final boolean impression, final String fileName) { |
useOO(f, visu, impression, fileName, true); |
public final SQLElement getElement() { |
return this.elt; |
} |
public void useOO(final File f, final boolean visu, final boolean impression, final String fileName, boolean exportPDF) { |
/** |
* Show, print and export the document to PDF. This method is asynchronous, but is executed in a |
* single threaded queue shared with createDocument |
* */ |
public Future<SheetXml> showPrintAndExportAsynchronous(final boolean showDocument, final boolean printDocument, final boolean exportToPDF) { |
final Callable<SheetXml> c = new Callable<SheetXml>() { |
@Override |
public SheetXml call() throws Exception { |
showPrintAndExport(showDocument, printDocument, exportToPDF); |
return SheetXml.this; |
} |
}; |
return runnableQueue.submit(c); |
if (f == null || fileName.trim().length() == 0) { |
ExceptionHandler.handle("Erreur lors de la génération du fichier " + fileName); |
} |
/** |
* Show, print and export the document to PDF. This method is synchronous |
* */ |
public void showPrintAndExport(final boolean showDocument, final boolean printDocument, boolean exportToPDF) { |
final File generatedFile = getGeneratedFile(); |
final File pdfFile = getGeneratedPDFFile(); |
if (generatedFile == null || !generatedFile.exists()) { |
ExceptionHandler.handle("Fichier généré manquant: " + generatedFile); |
return; |
} |
try { |
if (!Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) { |
final Component doc = ComptaPropsConfiguration.getOOConnexion().loadDocument(f, !visu); |
final Component doc = ComptaPropsConfiguration.getOOConnexion().loadDocument(generatedFile, !showDocument); |
if (exportPDF) { |
doc.saveToPDF(getFilePDF()).get(); |
} |
if (impression) { |
if (printDocument) { |
Map<String, Object> map = new HashMap<String, Object>(); |
map.put("Name", this.printer); |
doc.printDocument(map); |
} |
if (exportToPDF) { |
doc.saveToPDF(pdfFile).get(); |
} |
doc.close(); |
} else { |
final OpenDocument doc = new OpenDocument(f); |
final OpenDocument doc = new OpenDocument(generatedFile); |
if (exportPDF) { |
final Thread t = new Thread("PDF Export: " + fileName) { |
if (showDocument) { |
showPreviewDocument(); |
} |
if (printDocument) { |
// Print ! |
DefaultDocumentPrinter printer = new DefaultDocumentPrinter(); |
printer.print(doc); |
} |
if (exportToPDF) { |
try { |
SheetUtils.convert2PDF(doc, pdfFile); |
} catch (Throwable e) { |
ExceptionHandler.handle("Impossible de créer le PDF"); |
} |
Thread t = new Thread(new Runnable() { |
@Override |
public void run() { |
List<StorageEngine> engines = StorageEngines.getInstance().getActiveEngines(); |
for (StorageEngine storageEngine : engines) { |
if (storageEngine.isConfigured() && storageEngine.allowAutoStorage()) { |
try { |
SheetUtils.getInstance().convert2PDF(doc, f, fileName); |
} catch (Exception e) { |
// TODO Auto-generated catch block |
e.printStackTrace(); |
storageEngine.connect(); |
final BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(pdfFile)); |
final String path = getStoragePath(); |
storageEngine.store(inStream, path, pdfFile.getName(), true); |
inStream.close(); |
storageEngine.disconnect(); |
} catch (IOException e) { |
ExceptionHandler.handle("Impossible de sauvegarder le PDF"); |
} |
} |
}; |
t.setPriority(Thread.MIN_PRIORITY); |
t.start(); |
} |
if (visu) { |
showPreviewDocument(); |
} |
if (impression) { |
// Print ! |
DefaultDocumentPrinter printer = new DefaultDocumentPrinter(); |
printer.print(doc); |
} |
}); |
t.start(); |
} |
} |
} catch (Exception e) { |
e.printStackTrace(); |
142,19 → 190,61 |
} |
} |
public abstract String getDefaultModele(); |
public abstract String getDefaultTemplateId(); |
// nom du modele sans extension |
public String getModele() { |
if (this.row.getTable().getFieldsName().contains("ID_MODELE")) { |
/** |
* Path of the directory used for storage. Ex: Devis/2010 |
* */ |
public final String getStoragePath() { |
final String res = STORAGE_DIRS == null ? null : STORAGE_DIRS.getStoragePath(this); |
if (res != null) |
return res; |
else |
return this.getStoragePathP(); |
} |
public final File getDocumentOutputDirectory() { |
final File res = STORAGE_DIRS == null ? null : STORAGE_DIRS.getDocumentOutputDirectory(this); |
if (res != null) |
return res; |
else |
return this.getDocumentOutputDirectoryP(); |
} |
public final File getPDFOutputDirectory() { |
final File res = STORAGE_DIRS == null ? null : STORAGE_DIRS.getPDFOutputDirectory(this); |
if (res != null) |
return res; |
else |
return this.getPDFOutputDirectoryP(); |
} |
protected abstract String getStoragePathP(); |
protected abstract File getDocumentOutputDirectoryP(); |
protected abstract File getPDFOutputDirectoryP(); |
/** |
* Name of the generated document (without extension), do not rely on this name. |
* |
* Use getGeneratedFile().getName() to get the generated file name. |
* */ |
public abstract String getName(); |
/** |
* @return the template id for this template (ex: "sales.quote") |
* */ |
public String getTemplateId() { |
if (this.row != null && this.row.getTable().getFieldsName().contains("ID_MODELE")) { |
SQLRow rowModele = this.row.getForeignRow("ID_MODELE"); |
if (rowModele.isUndefined()) { |
TypeModeleSQLElement typeModele = Configuration.getInstance().getDirectory().getElement(TypeModeleSQLElement.class); |
String modele = typeModele.getTemplateMapping().get(this.row.getTable()); |
String modele = typeModele.getTemplateMapping().get(this.row.getTable().getName()); |
if (modele == null) { |
System.err.println("No default modele in table TYPE_MODELE for table " + this.row.getTable().getName()); |
Thread.dumpStack(); |
return getDefaultModele(); |
return getDefaultTemplateId(); |
} else { |
return modele; |
} |
162,23 → 252,24 |
return rowModele.getString("NOM"); |
} |
} |
return getDefaultModele(); |
return getDefaultTemplateId(); |
} |
public abstract Future<File> genere(final boolean visu, final boolean impression); |
public abstract Future<SheetXml> createDocumentAsynchronous(); |
public abstract String getFileName(); |
private String getOOName() { |
return getValidFileName(getFileName()) + ".ods"; |
public void createDocument() throws InterruptedException, ExecutionException { |
createDocumentAsynchronous().get(); |
} |
private String getPDFName() { |
return getValidFileName(getFileName()) + ".pdf"; |
} |
/** |
* get the File that is, or must be generated. |
* |
* @return a file (not null) |
* */ |
public abstract File getGeneratedFile(); |
private String getOO1Name() { |
return getValidFileName(getFileName()) + ".sxc"; |
public File getGeneratedPDFFile() { |
return SheetUtils.getFileWithExtension(getGeneratedFile(), ".pdf"); |
} |
public SQLRow getRowLanguage() { |
190,64 → 281,49 |
} |
/** |
* retourne l'emplacement de destination d'un Tuple<id (ex:LocationDevis), Nom (ex:Devis)> |
*/ |
public static String getLocationForTuple(Tuple2<String, String> t, boolean pdf) { |
final String stringProperty = TemplateNXProps.getInstance().getStringProperty(t.get0() + (pdf ? "PDF" : "OO")); |
if (stringProperty.equalsIgnoreCase(TemplateNXProps.getInstance().getDefaultStringValue())) { |
return stringProperty + File.separator + t.get1(); |
} else { |
return stringProperty; |
} |
} |
private File getFile() { |
if (this.f != null) { |
return f; |
} |
File f = new File(this.locationOO + File.separator + getOOName()); |
* Creates the document if needed and returns the generated file (OpenDocument) |
* */ |
public File getOrCreateDocumentFile() throws Exception { |
File f = getGeneratedFile(); |
if (!f.exists()) { |
File f2 = new File(this.locationOO + File.separator + getOO1Name()); |
if (f2.exists()) { |
return f2; |
return createDocumentAsynchronous().get().getGeneratedFile(); |
} else { |
return f; |
} |
} else { |
return f; |
} |
} |
public File getFilePDF() { |
File f = new File(this.locationPDF + File.separator + getPDFName()); |
return f; |
} |
/** |
* Open the document with the native application |
* |
* @param synchronous |
* */ |
public void openDocument(boolean synchronous) { |
Runnable r = new Runnable() { |
public File getFileWithoutExt() { |
File f = new File(this.locationPDF + File.separator + getValidFileName(getFileName())); |
return f; |
} |
public File getFileODS() { |
File f = new File(this.locationOO + File.separator + getOOName()); |
return f; |
} |
public void showDocument() { |
final File f = getFile(); |
@Override |
public void run() { |
File f; |
try { |
f = getOrCreateDocumentFile(); |
OOUtils.open(f); |
} catch (IOException e) { |
ExceptionHandler.handle("Impossible d'ouvrir " + f.getAbsolutePath(), e); |
} catch (Exception e) { |
ExceptionHandler.handle("Impossible d'ouvrir le document.", e); |
} |
} |
}; |
if (synchronous) { |
r.run(); |
} else { |
Thread thread = new Thread(r, "openDocument: " + getGeneratedFile().getAbsolutePath()); |
thread.setDaemon(true); |
thread.start(); |
} |
public void showPreviewDocument() { |
if (!isFileOOExist()) { |
genere(false, false); |
} |
final File f = getFile(); |
public void showPreviewDocument() throws Exception { |
File f = null; |
f = getOrCreateDocumentFile(); |
PreviewFrame.show(f); |
} |
257,9 → 333,10 |
} |
public void fastPrintDocument(short copies) { |
final File f = getFile(); |
try { |
final File f = getOrCreateDocumentFile(); |
if (!Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) { |
final Component doc = ComptaPropsConfiguration.getOOConnexion().loadDocument(f, true); |
295,9 → 372,9 |
} |
public void printDocument() { |
final File f = getFile(); |
try { |
final File f = getOrCreateDocumentFile(); |
if (!Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) { |
320,20 → 397,10 |
} |
} |
public boolean isFileOOExist() { |
final File f = getFile(); |
return f.exists(); |
} |
public SQLRow getSQLRow() { |
return this.row; |
} |
public boolean isFileODSExist() { |
final File f = getFileODS(); |
return f.exists(); |
} |
/** |
* Remplace tous les caracteres non alphanumeriques (seul le _ est autorisé) par un -. Cela |
* permet d'avoir toujours un nom de fichier valide. |
341,14 → 408,14 |
* @param fileName nom du fichier à créer ex:FACTURE_2007/03/001 |
* @return un nom fichier valide ex:FACTURE_2007-03-001 |
*/ |
public static String getValidFileName(String fileName) { |
StringBuffer result = new StringBuffer(fileName.length()); |
static String getValidFileName(String fileName) { |
final StringBuffer result = new StringBuffer(fileName.length()); |
for (int i = 0; i < fileName.length(); i++) { |
char c = fileName.charAt(i); |
char ch = fileName.charAt(i); |
// Si c'est un caractere alphanumerique |
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '_') || (c == ' ')) { |
result.append(c); |
if (Character.isLetterOrDigit(ch) || (ch == '_') || (ch == ' ')) { |
result.append(ch); |
} else { |
result.append('-'); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetUtils.java |
---|
13,6 → 13,8 |
package org.openconcerto.erp.generationDoc; |
import org.openconcerto.utils.ExceptionHandler; |
import java.awt.Graphics2D; |
import java.io.File; |
import java.io.FileOutputStream; |
36,16 → 38,8 |
public class SheetUtils { |
static SheetUtils instance; |
public static SheetUtils getInstance() { |
if (instance == null) { |
instance = new SheetUtils(); |
} |
return instance; |
} |
public File convertToOldFile(String fileName, File pathDest, File fDest) { |
public static File convertToOldFile(String fileName, File pathDest, File fDest) { |
// FIXME: !!!!!!!! |
return convertToOldFile(fileName, pathDest, fDest, ".ods"); |
} |
57,7 → 51,7 |
* @param fDest |
* @return |
*/ |
public File convertToOldFile(String fileName, File pathDest, File fDest, String extension) { |
public static File convertToOldFile(String fileName, File pathDest, File fDest, String extension) { |
if (fDest.exists()) { |
int i = 0; |
String destName = fileName; |
92,7 → 86,7 |
return fDest; |
} |
public List<File> getHistorique(final String fileName, File pathDest) { |
public static List<File> getHistorique(final String fileName, File pathDest) { |
File pathOld = new File(pathDest, "Historique"); |
File[] files = pathOld.listFiles(new FilenameFilter() { |
118,44 → 112,24 |
return result; |
} |
public static void main(String[] args) { |
final OpenDocument doc = new OpenDocument(new File("E:/Facture_FACT1108-5785.ods")); |
try { |
SheetUtils.getInstance().convert2PDF(doc, new File("E:/test"), "test"); |
} catch (Exception exn) { |
// TODO Bloc catch auto-généré |
exn.printStackTrace(); |
} |
} |
public static void convert2PDF(final OpenDocument doc, final File pdfFileToCreate) throws Exception { |
public void convert2PDF(final OpenDocument doc, final File f, final String fileName) throws Exception { |
SwingUtilities.invokeLater(new Runnable() { |
SwingUtilities.invokeAndWait(new Runnable() { |
@Override |
public void run() { |
// TODO Raccord de méthode auto-généré |
// Open the PDF document |
Document document = new Document(PageSize.A4, 50, 50, 50, 50); |
File outFile = new File(f.getParent(), fileName + ".pdf"); |
FileOutputStream fileOutputStream; |
try { |
fileOutputStream = new FileOutputStream(outFile); |
FileOutputStream fileOutputStream = new FileOutputStream(pdfFileToCreate); |
// Create the writer |
PdfWriter writer = PdfWriter.getInstance(document, fileOutputStream); |
writer.setPdfVersion(PdfWriter.VERSION_1_6); |
writer.setFullCompression(); |
// writer.setPageEmpty(true); |
document.open(); |
// System.out.println(writer.getPageNumber()); |
// // Create a template and a Graphics2D object |
// com.itextpdf.text.Rectangle pageSize = document.getPageSize(); |
// int w = (int) (pageSize.getWidth() * 0.9); |
// int h = (int) (pageSize.getHeight() * 0.95); |
PdfContentByte cb = writer.getDirectContent(); |
190,11 → 164,27 |
// writer.close(); |
fileOutputStream.close(); |
} catch (Exception exn) { |
// TODO Bloc catch auto-généré |
exn.printStackTrace(); |
} catch (Exception originalExn) { |
ExceptionHandler.handle("Impossible de créer le PDF " + pdfFileToCreate.getAbsolutePath(), originalExn); |
} |
} |
}); |
} |
/** |
* Get a new file with an other extension |
* |
* @param the file (ex: Test.ods) |
* @param the extension (ex: pdf) |
* */ |
static File getFileWithExtension(File file, String extension) { |
if (!extension.startsWith(".")) { |
extension = "." + extension; |
} |
String name = file.getName(); |
int i = name.lastIndexOf("."); |
name = name.substring(0, i) + extension; |
final File f = new File(file.getParent(), name); |
return f; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetInterface.java |
---|
18,11 → 18,12 |
import org.openconcerto.sql.model.SQLBase; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.utils.StringUtils; |
import java.io.File; |
import java.util.HashMap; |
import java.util.Map; |
public abstract class SheetInterface { |
// SQLRow de l'élément de la table qui est utilisé pour la génération |
46,12 → 47,6 |
// modele du document |
protected String modele; |
// emplacement du fichier OO généré |
protected String locationOO; |
// emplacement du fichier PDF généré |
protected String locationPDF; |
// nom du futur fichier |
protected String fileName; |
64,14 → 59,6 |
protected static final SQLBase base = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete(); |
public String getLocationOO() { |
return this.locationOO; |
} |
public String getLocationPDF() { |
return this.locationPDF; |
} |
public int getNbPage() { |
return this.nbPage; |
} |
114,6 → 101,17 |
return this.mCell; |
} |
protected abstract String getYear(); |
public File getDocumentOutputDirectory() { |
return new File(DocumentLocalStorageManager.getInstance().getDocumentOutputDirectory(this.getTemplateId()), getYear()); |
} |
public File getPDFOutputDirectory() { |
return new File(DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(this.getTemplateId()), getYear()); |
} |
protected abstract void createMap(); |
public abstract String getTemplateId(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/AvoirFournisseurXmlSheet.java |
---|
13,42 → 13,29 |
package org.openconcerto.erp.generationDoc.gestcomm; |
import org.openconcerto.erp.generationDoc.AbstractSheetXml; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.generationDoc.AbstractSheetXMLWithDate; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.utils.Tuple2; |
import java.io.File; |
import java.util.Calendar; |
import java.util.Date; |
public class AvoirFournisseurXmlSheet extends AbstractSheetXMLWithDate { |
public class AvoirFournisseurXmlSheet extends AbstractSheetXml { |
public static final String TEMPLATE_ID = "AvoirF"; |
public static final String TEMPLATE_PROPERTY_NAME = "LocationAvoirF"; |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationAvoirF", "Avoir Fournisseur"); |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
} |
public AvoirFournisseurXmlSheet(SQLRow row) { |
super(row); |
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter"); |
this.elt = Configuration.getInstance().getDirectory().getElement("AVOIR_FOURNISSEUR"); |
Calendar cal = Calendar.getInstance(); |
cal.setTime((Date) row.getObject("DATE")); |
this.locationOO = SheetXml.getLocationForTuple(tuple, false) + File.separator + cal.get(Calendar.YEAR); |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true) + File.separator + cal.get(Calendar.YEAR); |
} |
@Override |
public String getDefaultModele() { |
// TODO Raccord de méthode auto-généré |
return "AvoirF"; |
public String getDefaultTemplateId() { |
return TEMPLATE_ID; |
} |
public String getFileName() { |
return getValidFileName("AvoirF_" + this.row.getID()); |
@Override |
public String getName() { |
return "AvoirF_" + this.row.getID(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/PointageXmlSheet.java |
---|
14,7 → 14,6 |
package org.openconcerto.erp.generationDoc.gestcomm; |
import org.openconcerto.erp.generationDoc.AbstractListeSheetXml; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.SQLElement; |
36,16 → 35,18 |
public class PointageXmlSheet extends AbstractListeSheetXml { |
public static final String TEMPLATE_ID = "Pointage"; |
public static final String TEMPLATE_PROPERTY_NAME = DEFAULT_PROPERTY_NAME; |
private Map<Integer, List<Map<String, Object>>> listAllSheetValues; |
private Map<Integer, Map<Integer, String>> styleAllSheetValues; |
private Map<Integer, Map<String, Object>> mapAllSheetValues; |
private Calendar c = Calendar.getInstance(); |
private Date date = new Date(); |
private final long MILLIS_IN_HOUR = 3600000; |
public PointageXmlSheet(int mois, int year) { |
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter"); |
this.mapAllSheetValues = new HashMap<Integer, Map<String, Object>>(); |
this.locationOO = SheetXml.getLocationForTuple(tupleDefault, false); |
this.locationPDF = SheetXml.getLocationForTuple(tupleDefault, true); |
this.c.set(Calendar.DAY_OF_MONTH, 1); |
this.c.set(Calendar.YEAR, year); |
this.c.set(Calendar.MONTH, mois); |
57,11 → 58,14 |
} |
@Override |
public String getDefaultModele() { |
return "Pointage"; |
public String getName() { |
return "Pointage" + this.date; |
} |
private long oneHour = 3600000; |
@Override |
public String getDefaultTemplateId() { |
return TEMPLATE_ID; |
} |
protected void createListeValues() { |
SQLElement eltPointage = Configuration.getInstance().getDirectory().getElement("POINTAGE"); |
124,6 → 128,7 |
sel.setHaving(Where.createRaw("COUNT (\"POINTAGE\".\"ID_USER_COMMON\") > 0", tablePointage.getField("ID_USER_COMMON"))); |
sel.addFieldOrder(tableUser.getField("NOM")); |
System.err.println(sel.asString()); |
@SuppressWarnings("unchecked") |
List<SQLRow> listUser = (List<SQLRow>) Configuration.getInstance().getBase().getDataSource().execute(sel.asString(), SQLRowListRSH.createFromSelect(sel, tableUser)); |
String entete = "Horaires de travail du mois de " + formatMonth.format(d1); |
142,7 → 147,7 |
mapSheetValue.put("A1", userName); |
mapSheetValue.put("F1", entete); |
long tempsDePause = this.oneHour; |
long tempsDePause = this.MILLIS_IN_HOUR; |
// calcul du temps de pause si possible |
if (row.getObject("HEURE_MATIN_D") != null && row.getObject("MINUTE_MATIN_D") != null && row.getObject("HEURE_MIDI_A") != null && row.getObject("MINUTE_MIDI_A") != null) { |
173,8 → 178,8 |
// Temps travaillé dans la semaine |
if (semaine > 0 && semaine != this.c.get(Calendar.WEEK_OF_YEAR)) { |
Map<String, Object> mValues2 = new HashMap<String, Object>(); |
long hour = heureTotalSemaine / this.oneHour; |
long minute = (heureTotalSemaine % this.oneHour) / 60000; |
long hour = heureTotalSemaine / this.MILLIS_IN_HOUR; |
long minute = (heureTotalSemaine % this.MILLIS_IN_HOUR) / 60000; |
mValues2.put("HEURE_TOTAL", hour + "h" + minute); |
heureTotalSemaine = 0; |
listValues.add(mValues2); |
207,6 → 212,7 |
sel2.setWhere(wDay); |
sel2.addFieldOrder(table2.getField("DATE")); |
@SuppressWarnings("unchecked") |
List<SQLRow> list2 = (List<SQLRow>) Configuration.getInstance().getBase().getDataSource().execute(sel2.asString(), SQLRowListRSH.createFromSelect(sel2, table2)); |
if (list2.size() > 2) { |
258,8 → 264,8 |
System.err.println("time " + time + " Worked :" + timeWorked); |
heureTotalSemaine += timeWorked; |
heureTotalMois += timeWorked; |
long hour = timeWorked / this.oneHour; |
long minute = (timeWorked % this.oneHour) / 60000; |
long hour = timeWorked / this.MILLIS_IN_HOUR; |
long minute = (timeWorked % this.MILLIS_IN_HOUR) / 60000; |
mValues.put("HEURE_TOTAL", hour + "h" + minute); |
} else { |
278,8 → 284,8 |
// Heure de la derniere semaine |
Map<String, Object> mValues2 = new HashMap<String, Object>(); |
long hour = heureTotalSemaine / this.oneHour; |
long minute = (heureTotalSemaine % this.oneHour) / 60000; |
long hour = heureTotalSemaine / this.MILLIS_IN_HOUR; |
long minute = (heureTotalSemaine % this.MILLIS_IN_HOUR) / 60000; |
mValues2.put("HEURE_TOTAL", hour + "h" + minute); |
heureTotalSemaine = 0; |
listValues.add(mValues2); |
289,8 → 295,8 |
// Heure total du mois |
Map<String, Object> mValuesMois = new HashMap<String, Object>(); |
hour = heureTotalMois / this.oneHour; |
minute = (heureTotalMois % this.oneHour) / 60000; |
hour = heureTotalMois / this.MILLIS_IN_HOUR; |
minute = (heureTotalMois % this.MILLIS_IN_HOUR) / 60000; |
mValuesMois.put("HEURE_TOTAL", hour + "h" + minute); |
heureTotalMois = 0; |
315,9 → 321,4 |
} |
Date date = new Date(); |
public String getFileName() { |
return getValidFileName("Pointage" + this.date); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/FicheRelanceSheet.java |
---|
14,11 → 14,9 |
package org.openconcerto.erp.generationDoc.gestcomm; |
import org.openconcerto.erp.generationDoc.AbstractListeSheetXml; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.utils.GestionDevise; |
import org.openconcerto.utils.Tuple2; |
import java.text.DateFormat; |
import java.text.SimpleDateFormat; |
31,29 → 29,23 |
public class FicheRelanceSheet extends AbstractListeSheetXml { |
private static final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yy"); |
private SQLRow row; |
public static final String TEMPLATE_ID = "FicheRelance"; |
public static final String TEMPLATE_PROPERTY_NAME = DEFAULT_PROPERTY_NAME; |
public static Tuple2<String, String> getTuple2Location() { |
return tupleDefault; |
} |
public FicheRelanceSheet(SQLRow row) { |
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter"); |
this.row = row; |
this.locationOO = SheetXml.getLocationForTuple(tupleDefault, false); |
this.locationPDF = SheetXml.getLocationForTuple(tupleDefault, true); |
} |
@Override |
public String getDefaultModele() { |
return "FicheRelance"; |
public String getDefaultTemplateId() { |
return TEMPLATE_ID; |
} |
@Override |
protected void createListeValues() { |
// TODO Auto-generated method stub |
final Map<String, Object> values = new HashMap<String, Object>(); |
List<Map<String, Object>> listValues = new ArrayList<Map<String, Object>>(); |
final List<Map<String, Object>> listValues = new ArrayList<Map<String, Object>>(); |
final SQLRow clientRow = this.row.getForeignRow("ID_CLIENT"); |
final SQLRow factureRow = this.row.getForeignRow("ID_SAISIE_VENTE_FACTURE"); |
70,8 → 62,9 |
} |
public String getFileName() { |
return getValidFileName("FicheRelance" + new Date().getTime()); |
@Override |
public String getName() { |
return "FicheRelance" + new Date().getTime(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/CourrierClientSheet.java |
---|
15,12 → 15,10 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.generationDoc.AbstractJOOReportsSheet; |
import org.openconcerto.erp.generationDoc.AbstractSheetXml; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.utils.Tuple2; |
import java.util.Date; |
import java.util.HashMap; |
31,24 → 29,21 |
private SQLRow rowCourrier; |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationCourrier", "Courrier"); |
public static final String TEMPLATE_ID = "Courrier"; |
public static final String TEMPLATE_PROPERTY_NAME = "LocationCourrier"; |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
} |
public CourrierClientSheet(SQLRow row) { |
super(); |
this.rowCourrier = row; |
Date d = (Date) this.rowCourrier.getObject("DATE"); |
String year = yearFormat.format(d); |
init(year, "Courrier.odt", "CourrierPrinter", tuple); |
init(year, "Courrier.odt", "CourrierPrinter"); |
} |
/** |
* @return une Map contenant les valeurs à remplacer dans la template |
*/ |
protected Map createMap() { |
protected Map<String, Object> createMap() { |
Map<String, Object> m = new HashMap<String, Object>(); |
84,8 → 79,7 |
} |
public String getFileName() { |
String fileName = "Courrier_" + AbstractSheetXml.getValidFileName(this.rowCourrier.getString("NUMERO")); |
return fileName; |
return "Courrier_" + this.rowCourrier.getString("NUMERO"); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/RelanceSheet.java |
---|
16,13 → 16,11 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.finance.payment.element.ModeDeReglementSQLElement; |
import org.openconcerto.erp.generationDoc.AbstractJOOReportsSheet; |
import org.openconcerto.erp.generationDoc.AbstractSheetXml; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.utils.GestionDevise; |
import org.openconcerto.utils.Tuple2; |
import java.util.Date; |
import java.util.HashMap; |
33,11 → 31,9 |
private SQLRow rowRelance; |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationRelance", "Relance"); |
public static final String TEMPLATE_ID = "Relance"; |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
} |
public static final String TEMPLATE_PROPERTY_NAME = "LocationRelance"; |
/** |
* @return une Map contenant les valeurs à remplacer dans la template |
122,10 → 118,11 |
sel.addSelect(this.rowRelance.getTable().getKey()); |
sel.setWhere(new Where(this.rowRelance.getTable().getField("ID_SAISIE_VENTE_FACTURE"), "=", this.rowRelance.getInt("ID_SAISIE_VENTE_FACTURE"))); |
sel.addFieldOrder(this.rowRelance.getTable().getField("DATE").getFullName()); |
List<Map> listResult = Configuration.getInstance().getBase().getDataSource().execute(sel.asString()); |
@SuppressWarnings("unchecked") |
List<Map<String, Number>> listResult = Configuration.getInstance().getBase().getDataSource().execute(sel.asString()); |
if (listResult != null && listResult.size() > 0) { |
Map o = listResult.get(0); |
Number n = (Number) o.get(this.rowRelance.getTable().getKey().getName()); |
Map<String, Number> o = listResult.get(0); |
Number n = o.get(this.rowRelance.getTable().getKey().getName()); |
SQLRow rowOldRelance = this.rowRelance.getTable().getRow(n.intValue()); |
Date dOldRelance = (Date) rowOldRelance.getObject("DATE"); |
map.put("DatePremiereRelance", dateFormat2.format(dOldRelance)); |
144,7 → 141,7 |
final String string = rowLettre.getString("MODELE"); |
System.err.println(this.locationTemplate + "/" + string); |
init(year, string, "RelancePrinter", tuple); |
init(year, string, "RelancePrinter"); |
} |
protected boolean savePDF() { |
152,7 → 149,6 |
} |
public String getFileName() { |
String fileName = "Relance_" + AbstractSheetXml.getValidFileName(this.rowRelance.getString("NUMERO")); |
return fileName; |
return "Relance_" + this.rowRelance.getString("NUMERO"); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/ReleveChequeEmisSheet.java |
---|
41,19 → 41,23 |
createMap(); |
} |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationReleveCheque", "Relevé chéques émis"); |
public static final String TEMPLATE_ID = "ReleveChequeEmis"; |
public static final String TEMPLATE_PROPERTY_NAME = "LocationReleveCheque"; |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
} |
private void init() { |
this.modele = "ReleveChequeEmis.ods"; |
// this.printer = PrinterNXProps.getInstance().getStringProperty("FacturePrinter"); |
this.locationOO = SheetXml.getLocationForTuple(tuple, false); |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true); |
} |
@Override |
public String getTemplateId() { |
return TEMPLATE_ID; |
} |
@Override |
protected String getYear() { |
return ""; |
} |
protected void createMap() { |
long montantTotal = 0; |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/ReleveChequeSheet.java |
---|
15,13 → 15,11 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.generationDoc.AbstractListeSheetXml; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.utils.GestionDevise; |
import org.openconcerto.utils.Tuple2; |
import java.text.DateFormat; |
import java.text.SimpleDateFormat; |
39,7 → 37,7 |
private long total = 0; |
private long nb = 0; |
private boolean apercu = false; |
private static final SQLTable tableCheque = base.getTable("CHEQUE_A_ENCAISSER"); |
private List<Integer> listeIds; |
public ReleveChequeSheet(List<Integer> listeIds, Date date) { |
46,16 → 44,11 |
this(listeIds, date, false); |
} |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationReleveChequeCli", "Relevé chéques clients"); |
public static final String TEMPLATE_ID = "ReleveCheque"; |
public static final String TEMPLATE_PROPERTY_NAME = "LocationReleveChequeCli"; |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
} |
public ReleveChequeSheet(List<Integer> listeIds, Date date, boolean apercu) { |
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter"); |
this.locationOO = SheetXml.getLocationForTuple(tuple, false); |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true); |
this.date = date; |
this.apercu = apercu; |
this.listeIds = listeIds; |
62,11 → 55,14 |
} |
@Override |
public String getDefaultModele() { |
return "ReleveCheque"; |
public String getName() { |
return "ReleveCheque" + this.date.getTime(); |
} |
private static final SQLTable tableCheque = base.getTable("CHEQUE_A_ENCAISSER"); |
@Override |
public String getDefaultTemplateId() { |
return TEMPLATE_ID; |
} |
protected void createListeValues() { |
113,8 → 109,4 |
this.mapAllSheetValues.put(0, values); |
} |
public String getFileName() { |
return getValidFileName("ReleveCheque" + this.date.getTime()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/AvoirClientXmlSheet.java |
---|
14,27 → 14,16 |
package org.openconcerto.erp.generationDoc.gestcomm; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.generationDoc.AbstractSheetXml; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.generationDoc.AbstractSheetXMLWithDate; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.utils.Tuple2; |
import java.io.File; |
import java.util.Calendar; |
import java.util.Date; |
public class AvoirClientXmlSheet extends AbstractSheetXMLWithDate { |
public class AvoirClientXmlSheet extends AbstractSheetXml { |
public static final String TEMPLATE_ID = "Avoir"; |
public static final String TEMPLATE_PROPERTY_NAME = "LocationAvoir"; |
private String startName; |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationAvoir", "Avoir"); |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
} |
@Override |
public SQLRow getRowLanguage() { |
SQLRow rowClient = this.row.getForeignRow("ID_CLIENT"); |
49,24 → 38,16 |
super(row); |
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter"); |
this.elt = Configuration.getInstance().getDirectory().getElement("AVOIR_CLIENT"); |
} |
Calendar cal = Calendar.getInstance(); |
cal.setTime((Date) row.getObject("DATE")); |
this.locationOO = SheetXml.getLocationForTuple(tuple, false) + File.separator + cal.get(Calendar.YEAR); |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true) + File.separator + cal.get(Calendar.YEAR); |
this.startName = "Avoir_"; |
@Override |
public String getDefaultTemplateId() { |
return TEMPLATE_ID; |
} |
@Override |
public String getDefaultModele() { |
return "Avoir"; |
public String getName() { |
return "Avoir_" + this.row.getString("NUMERO"); |
} |
public String getFileName() { |
return getValidFileName(this.startName + this.row.getString("NUMERO")); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/EtatVentesXmlSheet.java |
---|
14,6 → 14,7 |
package org.openconcerto.erp.generationDoc.gestcomm; |
import org.openconcerto.erp.generationDoc.AbstractListeSheetXml; |
import org.openconcerto.erp.generationDoc.DocumentLocalStorageManager; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
25,6 → 26,7 |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.utils.Tuple2; |
import java.io.File; |
import java.sql.Timestamp; |
import java.text.DateFormat; |
import java.text.SimpleDateFormat; |
46,12 → 48,12 |
private static final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yy"); |
public static final String TEMPLATE_ID = "EtatVentes"; |
public static final String TEMPLATE_PROPERTY_NAME = DEFAULT_PROPERTY_NAME; |
private Timestamp du, au; |
public static Tuple2<String, String> getTuple2Location() { |
return tupleDefault; |
} |
public EtatVentesXmlSheet(Date du, Date au) { |
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter"); |
du.setHours(0); |
61,18 → 63,18 |
this.du = new Timestamp(du.getTime()); |
this.au = new Timestamp(au.getTime()); |
this.locationOO = SheetXml.getLocationForTuple(tupleDefault, false); |
this.locationPDF = SheetXml.getLocationForTuple(tupleDefault, true); |
} |
@Override |
public String getDefaultModele() { |
return "EtatVentes"; |
public String getDefaultTemplateId() { |
return TEMPLATE_ID; |
} |
public String getFileName() { |
return getValidFileName("EtatVentes" + new Date().getTime()); |
@Override |
public String getName() { |
return "EtatVentes" + new Date().getTime(); |
} |
protected void createListeValues() { |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/CommandeXmlSheet.java |
---|
13,25 → 13,16 |
package org.openconcerto.erp.generationDoc.gestcomm; |
import org.openconcerto.erp.generationDoc.AbstractSheetXml; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.generationDoc.AbstractSheetXMLWithDate; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.utils.Tuple2; |
import java.io.File; |
import java.util.Calendar; |
import java.util.Date; |
public class CommandeXmlSheet extends AbstractSheetXMLWithDate { |
public class CommandeXmlSheet extends AbstractSheetXml { |
public static final String TEMPLATE_ID = "Commande"; |
public static final String TEMPLATE_PROPERTY_NAME = "LocationCmd"; |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationCmd", "Commande fournisseur"); |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
} |
@Override |
public SQLRow getRowLanguage() { |
SQLRow rowFournisseur = this.row.getForeignRow("ID_FOURNISSEUR"); |
47,21 → 38,15 |
super(row); |
this.printer = PrinterNXProps.getInstance().getStringProperty("CmdPrinter"); |
this.elt = Configuration.getInstance().getDirectory().getElement("COMMANDE"); |
Calendar cal = Calendar.getInstance(); |
cal.setTime((Date) row.getObject("DATE")); |
this.locationOO = SheetXml.getLocationForTuple(tuple, false) + File.separator + cal.get(Calendar.YEAR); |
this.locationPDF = SheetXml.getLocationForTuple(tuple, false) + File.separator + cal.get(Calendar.YEAR); |
} |
@Override |
public String getDefaultModele() { |
return "Commande"; |
public String getDefaultTemplateId() { |
return TEMPLATE_ID; |
} |
public String getFileName() { |
return getValidFileName("Commande_" + row.getString("NUMERO")); |
@Override |
public String getName() { |
return "Commande_" + row.getString("NUMERO"); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLField.java |
---|
179,7 → 179,7 |
String condField = this.elt.getAttributeValue("conditionField"); |
String condValue = this.elt.getAttributeValue("conditionExpValue"); |
boolean bIsCondValid = condValue == null || this.row.getObject(condField).toString().equalsIgnoreCase(condValue); |
boolean bIsCondValid = condValue == null || !this.row.getObject(condField).toString().equalsIgnoreCase(condValue); |
if (condValue == null) { |
boolean bIsBooleanCondValid = false; |
if (condField == null) { |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/TemplateManager.java |
---|
New file |
0,0 → 1,165 |
/* |
* 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.io.InputStream; |
import java.util.ArrayList; |
import java.util.HashMap; |
import java.util.List; |
import java.util.Map; |
import java.util.Set; |
public class TemplateManager { |
private static TemplateManager instance = new TemplateManager(); |
private List<TemplateProvider> providers = new ArrayList<TemplateProvider>(); |
private Map<String, TemplateProvider> defaultMap = new HashMap<String, TemplateProvider>(); |
private TemplateProvider defautProvider; |
private List<String> knownTemplateIds = new ArrayList<String>(); |
public static TemplateManager getInstance() { |
return instance; |
} |
public void add(TemplateProvider provider) { |
this.providers.add(provider); |
} |
public void remove(TemplateProvider provider) { |
this.providers.remove(provider); |
final Set<String> keys = defaultMap.keySet(); |
for (String key : keys) { |
if (defaultMap.get(key).equals(provider)) { |
defaultMap.remove(key); |
} |
} |
} |
public void setDefaultProvider(String templateId, TemplateProvider provider) { |
defaultMap.put(templateId, provider); |
knownTemplateIds.add(templateId); |
} |
public void setDefaultProvider(TemplateProvider provider) { |
this.defautProvider = provider; |
} |
/** |
* Get the template using first the default template providers |
* |
* |
* @return the template file, IllegalStateException if no template is found |
* */ |
public InputStream getTemplate(String templateId, String language, String type) { |
TemplateProvider provider = defaultMap.get(templateId); |
if (provider == null) { |
for (TemplateProvider pr : providers) { |
InputStream stream = pr.getTemplate(templateId, language, type); |
if (stream != null) { |
return stream; |
} |
} |
if (defautProvider == null) { |
throw new IllegalStateException("Not default provider registered when using template id:" + templateId + " language:" + language + " type:" + type); |
} |
return defautProvider.getTemplate(templateId, language, type); |
} |
return provider.getTemplate(templateId, language, type); |
} |
/** |
* Get the template print configuration using first the default template providers |
* |
* |
* @return the template file, IllegalStateException if no template is found |
* */ |
public InputStream getTemplatePrintConfiguration(String templateId, String language, String type) { |
TemplateProvider provider = defaultMap.get(templateId); |
if (provider == null) { |
for (TemplateProvider pr : providers) { |
InputStream stream = pr.getTemplatePrintConfiguration(templateId, language, type); |
if (stream != null) { |
return stream; |
} |
} |
if (defautProvider == null) { |
throw new IllegalStateException("Not default provider registered when using template id:" + templateId + " langage:" + language + " type:" + type); |
} |
return defautProvider.getTemplatePrintConfiguration(templateId, language, type); |
} |
return provider.getTemplatePrintConfiguration(templateId, language, type); |
} |
/** |
* Get the template cofiguration using first the default template providers |
* |
* |
* @return the template file, IllegalStateException if no template is found |
* */ |
public InputStream getTemplateConfiguration(String templateId, String language, String type) { |
TemplateProvider provider = defaultMap.get(templateId); |
if (provider == null) { |
for (TemplateProvider pr : providers) { |
InputStream stream = pr.getTemplateConfiguration(templateId, language, type); |
if (stream != null) { |
return stream; |
} |
} |
if (defautProvider == null) { |
throw new IllegalStateException("Not default provider registered when using template id:" + templateId + " langage:" + language + " type:" + type); |
} |
return defautProvider.getTemplateConfiguration(templateId, language, type); |
} |
return provider.getTemplateConfiguration(templateId, language, type); |
} |
public InputStream getTemplate(String templateId) { |
return getTemplate(templateId, null, null); |
} |
public void register(String templateId) { |
knownTemplateIds.add(templateId); |
} |
public void dump() { |
System.out.println(this.getClass().getCanonicalName()); |
System.out.println("Default provider: " + this.defautProvider); |
System.out.println("Templates:"); |
for (String templateId : this.knownTemplateIds) { |
try { |
InputStream stream = this.getTemplate(templateId); |
if (stream == null) { |
System.out.println(rightAlign("'" + templateId + "'") + " : stream missing"); |
} else { |
System.out.println(rightAlign("'" + templateId + "'") + " : ok"); |
} |
} catch (Exception e) { |
System.out.println(rightAlign("'" + templateId + "'") + ": stream error"); |
} |
} |
} |
private String rightAlign(String s) { |
String r = s; |
int n = 20 - s.length(); |
for (int i = 0; i < n; i++) { |
r = ' ' + r; |
} |
return r; |
} |
public boolean isKnwonTemplate(String templateId) { |
return this.knownTemplateIds.contains(templateId); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/DefaultLocalTemplateProvider.java |
---|
New file |
0,0 → 1,66 |
/* |
* 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.io.File; |
public class DefaultLocalTemplateProvider extends AbstractLocalTemplateProvider { |
private File baseDirectory; |
public DefaultLocalTemplateProvider() { |
baseDirectory = new File("Configuration/Template/Default"); |
} |
public void setBaseDirectory(File dir) { |
this.baseDirectory = dir; |
} |
@Override |
public File getTemplateFile(String templateId, String langage, String type) { |
File file = getFile(templateId, langage, type); |
if (!file.exists()) { |
file = getFile(templateId + ".ods", langage, type); |
} |
return file; |
} |
private File getFile(String templateId, String langage, String type) { |
String path = templateId; |
if (type != null) { |
path += type; |
} |
if (langage != null) { |
path = langage + File.separatorChar + path; |
} |
File file = new File(baseDirectory, path); |
if (!file.exists()) { |
file = new File("Configuration/Template/Default", path); |
} |
return file; |
} |
@Override |
public String getTemplatePath(String templateId, String langage, String type) { |
String path = "Configuration/Template/Default"; |
if (type != null) { |
path += type; |
} |
if (langage != null) { |
path = langage + '/' + path; |
} |
return path; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractSheetXMLWithDate.java |
---|
New file |
0,0 → 1,47 |
/* |
* 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.SQLRow; |
import org.openconcerto.utils.StringUtils; |
import java.io.File; |
import java.util.Calendar; |
public abstract class AbstractSheetXMLWithDate extends AbstractSheetXml { |
public AbstractSheetXMLWithDate(SQLRow row) { |
super(row); |
} |
protected final String getYear() { |
final Calendar cal = this.row.getDate("DATE"); |
return cal == null ? "Date inconnue" : String.valueOf(cal.get(Calendar.YEAR)); |
} |
@Override |
public File getDocumentOutputDirectoryP() { |
return new File(DocumentLocalStorageManager.getInstance().getDocumentOutputDirectory(this.getTemplateId()), getYear()); |
} |
@Override |
public File getPDFOutputDirectoryP() { |
return new File(DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(this.getTemplateId()), getYear()); |
} |
@Override |
public String getStoragePathP() { |
return StringUtils.firstUp(this.elt.getPluralName() + File.separator + getYear()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/DocumentLocalStorageManager.java |
---|
New file |
0,0 → 1,160 |
/* |
* 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.io.File; |
import java.util.ArrayList; |
import java.util.HashMap; |
import java.util.List; |
import java.util.Map; |
public class DocumentLocalStorageManager { |
private static DocumentLocalStorageManager instance = new DocumentLocalStorageManager(); |
private Map<String, File> dirs = new HashMap<String, File>(); |
private Map<String, File> dirsPDF = new HashMap<String, File>(); |
private File documentDefaultDirectory; |
private File PDFDefaultDirectory; |
public static DocumentLocalStorageManager getInstance() { |
return instance; |
} |
/** |
* Returns the directory to store the document created from a template |
* |
* @param templateId : the id of the template used to create the document |
* */ |
public File getDocumentOutputDirectory(String templateId) { |
if (templateId == null) { |
throw new IllegalArgumentException("null template id"); |
} |
final File f = dirs.get(templateId); |
if (f != null) { |
return f; |
} |
return documentDefaultDirectory; |
} |
/** |
* Returns the directory to store the PDF document created from a template |
* |
* @param templateId : the id of the template used to create the document |
* */ |
public File getPDFOutputDirectory(String templateId) { |
if (templateId == null) { |
throw new IllegalArgumentException("null template id"); |
} |
final File f = dirsPDF.get(templateId); |
if (f != null) { |
return f; |
} |
return PDFDefaultDirectory; |
} |
public void addDocumentDirectory(String templateId, File directory) { |
if (templateId == null) { |
throw new IllegalArgumentException("null template id"); |
} |
this.dirs.put(templateId, directory); |
TemplateManager.getInstance().register(templateId); |
} |
public void removeDocumentDirectory(String templateId, File directory) { |
if (templateId == null) { |
throw new IllegalArgumentException("null template id"); |
} |
this.dirs.remove(templateId); |
} |
public void addPDFDirectory(String templateId, File directory) { |
if (templateId == null) { |
throw new IllegalArgumentException("null template id"); |
} |
this.dirsPDF.put(templateId, directory); |
TemplateManager.getInstance().register(templateId); |
} |
public void removePDFDirectory(String templateId, File directory) { |
if (templateId == null) { |
throw new IllegalArgumentException("null template id"); |
} |
this.dirsPDF.remove(templateId); |
} |
public void setDocumentDefaultDirectory(File directory) { |
this.documentDefaultDirectory = directory; |
} |
public void setPDFDefaultDirectory(File directory) { |
this.PDFDefaultDirectory = directory; |
} |
public List<File> getAllPDFDirectories() { |
List<File> list = new ArrayList<File>(); |
for (String id : this.dirsPDF.keySet()) { |
list.add(this.dirsPDF.get(id)); |
} |
return list; |
} |
public List<File> getAllDocumentDirectories() { |
List<File> list = new ArrayList<File>(); |
for (String id : this.dirs.keySet()) { |
list.add(this.dirs.get(id)); |
} |
return list; |
} |
public void dump() { |
System.out.println(this.getClass().getCanonicalName()); |
System.out.println("Default document directory: " + getAndTest(this.documentDefaultDirectory)); |
System.out.println("Default PFD directory : " + getAndTest(this.PDFDefaultDirectory)); |
System.out.println("Document directories:"); |
for (String key : this.dirs.keySet()) { |
System.out.println(rightAlign("'" + key + "'") + " : " + getAndTest(this.dirs.get(key))); |
} |
System.out.println("PDF directories:"); |
for (String key : this.dirsPDF.keySet()) { |
System.out.println(rightAlign("'" + key + "'") + " : " + getAndTest(this.dirsPDF.get(key))); |
} |
} |
private String rightAlign(String s) { |
String r = s; |
int n = 20 - s.length(); |
for (int i = 0; i < n; i++) { |
r = ' ' + r; |
} |
return r; |
} |
private String getAndTest(File dir) { |
if (dir == null) { |
return "null !!!!!!"; |
} |
String r = "'" + dir.getAbsolutePath() + "'"; |
if (dir.exists()) { |
if (!dir.isDirectory()) { |
r += " is not a directory!!"; |
} else if (!dir.canWrite()) { |
r += " is write protected!!"; |
} |
} else { |
r += " does not exist !!"; |
} |
return r; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationXML.java |
---|
73,8 → 73,8 |
private static int answer = JOptionPane.NO_OPTION; |
public static synchronized File genere(String modele, String pathDest, final String fileDest, SQLRow row, SQLRow rowLanguage) { |
public static synchronized File createDocument(String templateId, File outputDirectory, final String expectedFileName, SQLRow row, SQLRow rowLanguage) { |
final String langage = rowLanguage != null ? rowLanguage.getString("CHEMIN") : null; |
cacheStyle.clear(); |
OOXMLCache.clearCache(); |
rowsEltCache.clear(); |
81,7 → 81,7 |
taxe.clear(); |
cacheForeign.clear(); |
File fDest = new File(pathDest, fileDest + ".ods"); |
File fDest = new File(outputDirectory, expectedFileName); |
if (fDest.exists()) { |
112,20 → 112,20 |
SAXBuilder builder = new SAXBuilder(); |
try { |
if (needAnnexe(modele, row, rowLanguage)) { |
try { |
if (needAnnexe(templateId, row, rowLanguage)) { |
// check if it exists |
getOOTemplate(modele + "_annexe", rowLanguage); |
modele += "_annexe"; |
System.err.println("modele With annexe " + modele); |
} catch (FileNotFoundException e) { |
final String annexeTemplateId = templateId + "_annexe"; |
InputStream annexeStream = TemplateManager.getInstance().getTemplate(annexeTemplateId, langage, null); |
if (annexeStream != null) { |
templateId = annexeTemplateId; |
System.err.println("modele With annexe " + templateId); |
} |
} |
System.err.println("modele " + modele); |
System.err.println("Using template id: " + templateId); |
final InputStream xmlConfiguration = TemplateManager.getInstance().getTemplateConfiguration(templateId, langage, null); |
Document doc = builder.build(getXmlTemplate(modele, rowLanguage)); |
Document doc = builder.build(xmlConfiguration); |
// On initialise un nouvel élément racine avec l'élément racine du document. |
Element racine = doc.getRootElement(); |
134,7 → 134,9 |
List<Element> listElts = racine.getChildren("element"); |
// Création et génération du fichier OO |
SpreadSheet spreadSheet = SpreadSheet.create(new ODPackage(getOOTemplate(modele, rowLanguage))); |
final InputStream template = TemplateManager.getInstance().getTemplate(templateId, langage, null); |
final SpreadSheet spreadSheet = new ODPackage(template).getSpreadSheet(); |
try { |
// On remplit les cellules de la feuille |
parseElementsXML(listElts, row, spreadSheet); |
147,10 → 149,10 |
parseTableauXML(tableChild, row, spreadSheet, rowLanguage); |
} |
} catch (Exception e) { |
ExceptionHandler.handle("Impossible de remplir le document " + modele + " " + ((rowLanguage == null) ? "" : rowLanguage.getString("CHEMIN")), e); |
ExceptionHandler.handle("Impossible de remplir le document " + templateId + " " + ((rowLanguage == null) ? "" : rowLanguage.getString("CHEMIN")), e); |
} |
// Sauvegarde du fichier |
return saveSpreadSheet(spreadSheet, new File(pathDest), fileDest, modele, rowLanguage); |
return saveSpreadSheet(spreadSheet, outputDirectory, expectedFileName, templateId, rowLanguage); |
} catch (final JDOMException e) { |
157,7 → 159,7 |
e.printStackTrace(); |
SwingUtilities.invokeLater(new Runnable() { |
public void run() { |
ExceptionHandler.handle("Erreur lors de la génération du fichier " + fileDest, e); |
ExceptionHandler.handle("Erreur lors de la génération du fichier " + expectedFileName, e); |
} |
}); |
} catch (final IOException e) { |
165,7 → 167,7 |
e.printStackTrace(); |
SwingUtilities.invokeLater(new Runnable() { |
public void run() { |
ExceptionHandler.handle("Erreur lors de la création du fichier " + fileDest, e); |
ExceptionHandler.handle("Erreur lors de la création du fichier " + expectedFileName, e); |
} |
}); |
} |
706,8 → 708,9 |
* @return un File pointant sur le fichier créé |
* @throws IOException |
*/ |
private static File saveSpreadSheet(SpreadSheet ssheet, File pathDest, String fileName, String modele, SQLRow rowLanguage) throws IOException { |
private static File saveSpreadSheet(SpreadSheet ssheet, File pathDest, String fileName, String templateId, SQLRow rowLanguage) throws IOException { |
final String langage = rowLanguage != null ? rowLanguage.getString("CHEMIN") : null; |
// Test des arguments |
if (ssheet == null || pathDest == null || fileName.trim().length() == 0) { |
throw new IllegalArgumentException(); |
720,7 → 723,7 |
pathDest.mkdirs(); |
} |
fDest = SheetUtils.getInstance().convertToOldFile(fileName, pathDest, fDest); |
fDest = SheetUtils.convertToOldFile(fileName, pathDest, fDest); |
// Sauvegarde |
try { |
743,7 → 746,7 |
// Copie de l'odsp |
try { |
File odspOut = new File(pathDest, fileName + ".odsp"); |
InputStream odspIn = getTemplate(modele + ".odsp", rowLanguage); |
final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, langage, null); |
if (odspIn != null) { |
StreamUtils.copy(odspIn, odspOut); |
} |
753,18 → 756,6 |
return fDest; |
} |
public static InputStream getOOTemplate(String name, SQLRow language) throws FileNotFoundException { |
return OOgenerationListeXML.getOOTemplate(name, language); |
} |
public static InputStream getXmlTemplate(String name, SQLRow language) throws FileNotFoundException { |
return OOgenerationListeXML.getXmlTemplate(name, language); |
} |
public static InputStream getTemplate(String name, SQLRow language) throws FileNotFoundException { |
return OOgenerationListeXML.getTemplate(name, language); |
} |
/** |
* parcourt l'ensemble de la feuille pour trouver les style définit |
*/ |
827,15 → 818,16 |
return mapStyleDef; |
} |
public static boolean needAnnexe(String modele, SQLRow row, SQLRow rowLanguage) { |
SAXBuilder builder = new SAXBuilder(); |
public static boolean needAnnexe(String templateId, SQLRow row, SQLRow rowLanguage) { |
final String langage = rowLanguage != null ? rowLanguage.getString("CHEMIN") : null; |
final SAXBuilder builder = new SAXBuilder(); |
try { |
final InputStream xmlConfiguration = TemplateManager.getInstance().getTemplateConfiguration(templateId, langage, null); |
final Document doc = builder.build(xmlConfiguration); |
final InputStream template = TemplateManager.getInstance().getTemplate(templateId, langage, null); |
Document doc = builder.build(getXmlTemplate(modele, rowLanguage)); |
final SpreadSheet spreadSheet = new ODPackage(template).getSpreadSheet(); |
SpreadSheet spreadSheet = SpreadSheet.create(new ODPackage(getOOTemplate(modele, rowLanguage))); |
// On initialise un nouvel élément racine avec l'élément racine du document. |
Element racine = doc.getRootElement(); |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationListeXML.java |
---|
49,34 → 49,32 |
// Cache pour la recherche des styles |
private static Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<Sheet, Map<String, Map<Integer, String>>>(); |
public static File genere(String modele, String pathDest, String fileDest, Map<Integer, List<Map<String, Object>>> liste, Map<Integer, Map<String, Object>> values) { |
public static File genere(String modele, File pathDest, String fileDest, Map<Integer, List<Map<String, Object>>> liste, Map<Integer, Map<String, Object>> values) { |
return genere(modele, pathDest, fileDest, liste, values, new HashMap<Integer, Map<Integer, String>>(), null, null); |
} |
public static File genere(String modele, String pathDest, String fileDest, Map<Integer, List<Map<String, Object>>> liste, Map<Integer, Map<String, Object>> values, |
public static File genere(String templateId, File pathDest, String fileDest, Map<Integer, List<Map<String, Object>>> liste, Map<Integer, Map<String, Object>> values, |
Map<Integer, Map<Integer, String>> mapStyle, List<String> sheetName, SQLRow rowLanguage) { |
// SQLRow row = elt.getTable().getRow(id); |
cacheStyle.clear(); |
SAXBuilder builder = new SAXBuilder(); |
final SAXBuilder builder = new SAXBuilder(); |
try { |
Document doc = builder.build(getXmlTemplate(modele, rowLanguage)); |
InputStream xmlConfiguration = TemplateManager.getInstance().getTemplateConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null); |
Document doc = builder.build(xmlConfiguration); |
// On initialise un nouvel élément racine avec l'élément racine du |
// document. |
Element racine = doc.getRootElement(); |
final Element racine = doc.getRootElement(); |
// Création et génération du fichier OO |
SpreadSheet spreadSheet = SpreadSheet.create(new ODPackage(getOOTemplate(modele, rowLanguage))); |
final InputStream template = TemplateManager.getInstance().getTemplate(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null); |
final SpreadSheet spreadSheet = new ODPackage(template).getSpreadSheet(); |
Sheet sheet0 = spreadSheet.getSheet(0); |
if (sheetName != null && sheetName.size() > 0) { |
for (int i = 1; i < sheetName.size(); i++) { |
sheet0.copy(i, (sheetName != null) ? sheetName.get(i) : "Feuille " + i); |
} |
spreadSheet.getSheet(0).setName(sheetName.get(0)); |
System.err.println("add " + sheetName.size() + " sheet"); |
} |
for (Integer i : liste.keySet()) { |
86,7 → 84,6 |
children = racine.getChildren("element"); |
} |
parseElementsXML(children, sheet, values.get(i)); |
Element child = racine.getChild("table" + i); |
if (child == null) { |
child = racine.getChild("table"); |
94,15 → 91,11 |
parseListeXML(child, liste.get(i), sheet, mapStyle.get(i)); |
} |
// Sauvegarde du fichier |
return saveSpreadSheet(spreadSheet, new File(pathDest), fileDest, modele, rowLanguage); |
return saveSpreadSheet(spreadSheet, pathDest, fileDest, templateId, rowLanguage); |
} catch (JDOMException e) { |
e.printStackTrace(); |
ExceptionHandler.handle("Erreur lors de la génération du fichier " + fileDest, e); |
} catch (IOException e) { |
e.printStackTrace(); |
ExceptionHandler.handle("Erreur lors de la création du fichier " + fileDest, e); |
} |
return null; |
478,7 → 471,7 |
* @return un File pointant sur le fichier créé |
* @throws IOException |
*/ |
private static File saveSpreadSheet(SpreadSheet ssheet, File pathDest, String fileName, String modele, SQLRow rowLanguage) throws IOException { |
private static File saveSpreadSheet(SpreadSheet ssheet, File pathDest, String fileName, String templateId, SQLRow rowLanguage) throws IOException { |
// Test des arguments |
if (ssheet == null || pathDest == null || fileName.trim().length() == 0) { |
492,7 → 485,7 |
pathDest.mkdirs(); |
} |
SheetUtils.getInstance().convertToOldFile(fileName, pathDest, fDest); |
SheetUtils.convertToOldFile(fileName, pathDest, fDest); |
// Sauvegarde |
try { |
515,7 → 508,7 |
// Copie de l'odsp |
try { |
File odspOut = new File(pathDest, fileName + ".odsp"); |
InputStream odspIn = getTemplate(modele + ".odsp", rowLanguage); |
InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null); |
if (odspIn != null) { |
StreamUtils.copy(odspIn, odspOut); |
} |
526,34 → 519,7 |
return fDest; |
} |
public static InputStream getOOTemplate(String name, SQLRow rowLanguage) throws FileNotFoundException { |
return getTemplate(name + ".ods", rowLanguage); |
} |
public static InputStream getXmlTemplate(String name, SQLRow rowLanguage) throws FileNotFoundException { |
return getTemplate(name + ".xml", rowLanguage); |
} |
/** |
* Permet d'obtenir l'emplacement du modele passé en argument. Si le modéle ne se pas trouve |
* dans le répertoire spécifié dans les préférences alors on recherche dans le répertoire par |
* défaut des modéles. |
* |
* @param name nom du modéle à trouver |
* @return le modéle |
* @throws FileNotFoundException si le fichier est introuvable |
*/ |
public static InputStream getTemplate(String name, SQLRow rowLanguage) throws FileNotFoundException { |
String modelDir = TemplateNXProps.getInstance().getStringProperty("LocationTemplate"); |
if (rowLanguage != null) { |
return ComptaBasePropsConfiguration.getStream(name, modelDir + File.separator + rowLanguage.getString("CHEMIN"), modelDir, SpreadSheetGenerator.defaultLocationTemplate); |
} else { |
return ComptaBasePropsConfiguration.getStream(name, modelDir, SpreadSheetGenerator.defaultLocationTemplate); |
} |
} |
/** |
* 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) { |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractSheetXml.java |
---|
14,8 → 14,10 |
package org.openconcerto.erp.generationDoc; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.utils.StringUtils; |
import java.io.File; |
import java.io.InputStream; |
import java.util.concurrent.Callable; |
import java.util.concurrent.Future; |
23,35 → 25,36 |
import javax.swing.SwingUtilities; |
public abstract class AbstractSheetXml extends SheetXml { |
private File generatedOpenDocumentFile; |
public AbstractSheetXml(SQLRow row) { |
this.row = row; |
} |
public final Future<File> genere(final boolean visu, final boolean impression) { |
Callable<File> c = new Callable<File>() { |
@Override |
public File call() throws Exception { |
public final Future<SheetXml> createDocumentAsynchronous() { |
Callable<SheetXml> c = new Callable<SheetXml>() { |
@Override |
public SheetXml call() throws Exception { |
try { |
String modele = getModele(); |
final String modeleFinal = modele; |
try { |
OOgenerationXML.getOOTemplate(modele, getRowLanguage()); |
} catch (Exception e) { |
String templateId = getTemplateId(); |
final String modeleFinal = templateId; |
String langage = getRowLanguage() != null ? getRowLanguage().getString("CHEMIN") : null; |
InputStream templateStream = TemplateManager.getInstance().getTemplate(templateId, langage, getType()); |
if (templateStream == null) { |
SwingUtilities.invokeLater(new Runnable() { |
@Override |
public void run() { |
// TODO Raccord de méthode auto-généré |
JOptionPane.showMessageDialog(null, "Impossible de trouver le modele " + modeleFinal + ". \n Le modéle par défaut sera utilisé!"); |
} |
}); |
modele = getDefaultModele(); |
templateId = getDefaultTemplateId(); |
} |
File fGen = OOgenerationXML.genere(modele, AbstractSheetXml.this.locationOO, getFileName(), AbstractSheetXml.this.row, getRowLanguage()); |
AbstractSheetXml.this.f = fGen; |
useOO(fGen, visu, impression, getFileName()); |
return fGen; |
AbstractSheetXml.this.generatedOpenDocumentFile = OOgenerationXML.createDocument(templateId, getDocumentOutputDirectory(), getValidFileName(getName()), AbstractSheetXml.this.row, |
getRowLanguage()); |
} catch (Exception e) { |
DEFAULT_HANDLER.uncaughtException(null, e); |
// rethrow exception so that the unsuspecting caller can use this as the |
59,11 → 62,27 |
throw e; |
} catch (Throwable e) { |
DEFAULT_HANDLER.uncaughtException(null, e); |
return null; |
} |
} |
return AbstractSheetXml.this; |
} |
}; |
return runnableQueue.submit(c); |
} |
public String getType() { |
return null; |
} |
@Override |
public String getStoragePathP() { |
return StringUtils.firstUp(elt.getPluralName()); |
} |
@Override |
public File getGeneratedFile() { |
if (this.generatedOpenDocumentFile == null) |
this.generatedOpenDocumentFile = new File(getDocumentOutputDirectory(), getValidFileName(getName()) + ".ods"); |
return generatedOpenDocumentFile; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractListeSheetXml.java |
---|
13,6 → 13,9 |
package org.openconcerto.erp.generationDoc; |
import static org.openconcerto.erp.generationDoc.SheetXml.getValidFileName; |
import org.openconcerto.utils.StringUtils; |
import java.io.File; |
import java.util.ArrayList; |
import java.util.HashMap; |
35,16 → 38,21 |
// Nom des feuilles |
protected List<String> sheetNames = new ArrayList<String>(); |
public final Future<File> genere(final boolean visu, final boolean impression) { |
Callable<File> c = new Callable<File>() { |
private File generatedOpenDocumentFile; |
public AbstractListeSheetXml() { |
generatedOpenDocumentFile = new File(getDocumentOutputDirectory(), getValidFileName(getName()) + ".ods"); |
} |
public final Future<SheetXml> createDocumentAsynchronous() { |
Callable<SheetXml> c = new Callable<SheetXml>() { |
@Override |
public File call() throws Exception { |
public SheetXml call() throws Exception { |
try { |
createListeValues(); |
File fGen = OOgenerationListeXML.genere(getModele(), locationOO, getFileName(), listAllSheetValues, mapAllSheetValues, styleAllSheetValues, sheetNames, null); |
AbstractListeSheetXml.this.f = fGen; |
useOO(fGen, visu, impression, getFileName()); |
return fGen; |
generatedOpenDocumentFile = OOgenerationListeXML.genere(getTemplateId(), getDocumentOutputDirectory(), getValidFileName(getName()), listAllSheetValues, mapAllSheetValues, |
styleAllSheetValues, sheetNames, null); |
return AbstractListeSheetXml.this; |
} catch (Exception e) { |
DEFAULT_HANDLER.uncaughtException(null, e); |
// rethrow exception so that the unsuspecting caller can use this as the |
57,7 → 65,7 |
} |
}; |
return this.runnableQueue.submit(c); |
return runnableQueue.submit(c); |
} |
/** |
64,4 → 72,24 |
* To fill listAllSheetValues, styleAllSheetValues, mapAllSheetValues, sheetNames |
*/ |
protected abstract void createListeValues(); |
@Override |
public String getStoragePathP() { |
return StringUtils.firstUp(elt.getPluralName()); |
} |
@Override |
public File getGeneratedFile() { |
return generatedOpenDocumentFile; |
} |
@Override |
public File getDocumentOutputDirectoryP() { |
return DocumentLocalStorageManager.getInstance().getDocumentOutputDirectory(this.getTemplateId()); |
} |
@Override |
public File getPDFOutputDirectoryP() { |
return DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(this.getTemplateId()); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SpreadSheetGenerator.java |
---|
193,7 → 193,7 |
return null; |
} |
} |
final SpreadSheet res = SpreadSheet.create(new ODPackage(f)); |
final SpreadSheet res = new ODPackage(f).getSpreadSheet(); |
f.close(); |
return res; |
} |
250,9 → 250,9 |
this.modele = sheet.modele; |
this.mCell = sheet.mCell; |
this.destDirOO = new File(sheet.locationOO); |
this.destDirOO = sheet.getDocumentOutputDirectory(); |
this.destDirOO.mkdirs(); |
this.destDirPDF = new File(sheet.locationPDF); |
this.destDirPDF = sheet.getPDFOutputDirectory(); |
this.destDirPDF.mkdirs(); |
this.nbPage = sheet.nbPage; |
this.nbRowsPerPage = sheet.nbRowsPerPage; |
272,7 → 272,7 |
try { |
f = generateWithStyle(); |
final File pdfFileToCreate = new File(this.destDirPDF.getAbsolutePath(), this.destFileName + ".pdf"); |
try { |
if (!Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) { |
279,7 → 279,8 |
final Component doc = ComptaPropsConfiguration.getOOConnexion().loadDocument(f, !this.visu); |
if (this.exportPDF) { |
doc.saveToPDF(new File(this.destDirPDF.getAbsolutePath(), this.destFileName + ".pdf")); |
doc.saveToPDF(pdfFileToCreate); |
} |
if (this.impression) { |
295,7 → 296,7 |
PreviewFrame.show(f); |
} |
SheetUtils.getInstance().convert2PDF(doc, f, this.destFileName); |
SheetUtils.convert2PDF(doc, pdfFileToCreate); |
if (this.impression) { |
// Print ! |
DefaultNXDocumentPrinter printer = new DefaultNXDocumentPrinter(); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/customer/report/FicheClientXmlSheet.java |
---|
13,38 → 13,31 |
package org.openconcerto.erp.core.customerrelationship.customer.report; |
import org.openconcerto.erp.generationDoc.AbstractSheetXml; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.generationDoc.AbstractSheetXMLWithDate; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.utils.Tuple2; |
import java.io.File; |
import java.util.Calendar; |
import java.util.Date; |
public class FicheClientXmlSheet extends AbstractSheetXml { |
public class FicheClientXmlSheet extends AbstractSheetXMLWithDate { |
public static Tuple2<String, String> getTuple2Location() { |
return tupleDefault; |
} |
public static final String TEMPLATE_ID = "FicheClient"; |
public static final String TEMPLATE_PROPERTY_NAME = DEFAULT_PROPERTY_NAME; |
public FicheClientXmlSheet(SQLRow row) { |
super(row); |
this.printer = PrinterNXProps.getInstance().getStringProperty("DevisPrinter"); |
this.elt = Configuration.getInstance().getDirectory().getElement("CLIENT"); |
Calendar cal = Calendar.getInstance(); |
this.locationOO = SheetXml.getLocationForTuple(tupleDefault, false) + File.separator + cal.get(Calendar.YEAR); |
this.locationPDF = SheetXml.getLocationForTuple(tupleDefault, true) + File.separator + cal.get(Calendar.YEAR); |
} |
@Override |
public String getDefaultModele() { |
return "FicheClient"; |
public String getDefaultTemplateId() { |
return TEMPLATE_ID; |
} |
public String getFileName() { |
return getValidFileName("FicheClient_" + new Date().getTime()); |
@Override |
public String getName() { |
return "FicheClient_" + new Date().getTime(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/customer/element/ClientNormalSQLElement.java |
---|
44,6 → 44,7 |
import org.openconcerto.sql.sqlobject.JUniqueTextField; |
import org.openconcerto.sql.sqlobject.SQLTextCombo; |
import org.openconcerto.ui.DefaultGridBagConstraints; |
import org.openconcerto.ui.FormLayouter; |
import org.openconcerto.ui.TitledSeparator; |
import org.openconcerto.ui.component.ITextArea; |
86,8 → 87,11 |
protected List<String> getListFields() { |
final List<String> l = new ArrayList<String>(); |
l.add("CODE"); |
l.add("FORME_JURIDIQUE"); |
// l.add("FORME_JURIDIQUE"); |
l.add("NOM"); |
if (getTable().getFieldsName().contains("LOCALISATION")) { |
l.add("LOCALISATION"); |
} |
l.add("RESPONSABLE"); |
l.add("ID_ADRESSE"); |
l.add("TEL"); |
115,9 → 119,13 |
protected List<String> getComboFields() { |
final List<String> l = new ArrayList<String>(); |
l.add("FORME_JURIDIQUE"); |
// l.add("FORME_JURIDIQUE"); |
l.add("NOM"); |
if (getTable().getFieldsName().contains("LOCALISATION")) { |
l.add("LOCALISATION"); |
} else { |
l.add("CODE"); |
} |
return l; |
} |
234,7 → 242,20 |
this.add(boxPays, c); |
this.addView(boxPays, "ID_PAYS"); |
} |
if (getTable().getFieldsName().contains("LOCALISATION")) { |
c.gridy++; |
c.gridx = 0; |
c.weightx = 0; |
JLabel comp2 = new JLabel(getLabelFor("LOCALISATION")); |
comp2.setHorizontalAlignment(SwingConstants.RIGHT); |
this.add(comp2, c); |
JTextField loc = new JTextField(); |
c.gridx++; |
c.weightx = 1; |
// DefaultGridBagConstraints.lockMinimumSize(boxPays); |
this.add(loc, c); |
this.addView(loc, "LOCALISATION"); |
} |
// Numero intracomm |
JLabel labelIntraComm = new JLabel("N° TVA"); |
labelIntraComm.setHorizontalAlignment(SwingConstants.RIGHT); |
380,6 → 401,17 |
// Secteur activité |
final boolean customerIsKD; |
// Champ Module |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = GridBagConstraints.REMAINDER; |
final JPanel addP = new JPanel(); |
this.setAdditionalFieldsPanel(new FormLayouter(addP, 1)); |
this.add(addP, c); |
c.gridy++; |
c.gridwidth = 1; |
// Adresse |
c.gridx = 0; |
c.gridy++; |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/action/ListeDesRelancesAction.java |
---|
26,6 → 26,7 |
import org.openconcerto.sql.view.list.SQLTableModelColumn; |
import org.openconcerto.sql.view.list.SQLTableModelColumnPath; |
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline; |
import org.openconcerto.utils.ExceptionHandler; |
import java.awt.event.ActionEvent; |
import java.awt.event.MouseEvent; |
103,14 → 104,20 |
// Impression |
AbstractAction actionPrintFact = new AbstractAction("Imprimer la facture") { |
public void actionPerformed(ActionEvent e) { |
final Thread t = new Thread(new Runnable() { |
VenteFactureXmlSheet sheet = new VenteFactureXmlSheet(rowRelance.getForeignRow("ID_SAISIE_VENTE_FACTURE")); |
if (sheet.getFileODS().exists()) { |
sheet.fastPrintDocument(); |
} else { |
sheet.genere(false, true); |
@Override |
public void run() { |
try { |
printInvoice(rowRelance); |
} catch (Exception e) { |
ExceptionHandler.handle("Impression impossible", e); |
} |
} |
}); |
t.start(); |
} |
}; |
menu.add(actionPrintFact); |
118,14 → 125,19 |
AbstractAction actionPrintBoth = new AbstractAction("Imprimer la facture et la relance") { |
public void actionPerformed(ActionEvent e) { |
final Thread t = new Thread(new Runnable() { |
@Override |
public void run() { |
try { |
s.fastPrintDocument(); |
VenteFactureXmlSheet sheet = new VenteFactureXmlSheet(rowRelance.getForeignRow("ID_SAISIE_VENTE_FACTURE")); |
if (sheet.getFileODS().exists()) { |
sheet.fastPrintDocument(); |
} else { |
sheet.genere(false, true); |
printInvoice(rowRelance); |
} catch (Exception e) { |
ExceptionHandler.handle("Impression impossible", e); |
} |
} |
}); |
t.start(); |
} |
}; |
menu.add(actionPrintBoth); |
138,13 → 150,17 |
} |
}); |
// Générer |
// Créer la fiche de relance |
menu.add(new AbstractAction("Créer la fiche de relance") { |
public void actionPerformed(ActionEvent e) { |
try { |
FicheRelanceSheet sheet = new FicheRelanceSheet(rowRelance); |
sheet.genere(true, false); |
sheet.createDocumentAsynchronous(); |
sheet.showPrintAndExportAsynchronous(true, false, true); |
} catch (Exception ex) { |
ExceptionHandler.handle("Impression impossible", ex); |
} |
} |
}); |
menu.show(e.getComponent(), e.getPoint().x, e.getPoint().y); |
159,4 → 175,11 |
public void mouseExited(MouseEvent e) { |
} |
private void printInvoice(final SQLRow rowRelance) throws Exception { |
final VenteFactureXmlSheet sheet = new VenteFactureXmlSheet(rowRelance.getForeignRow("ID_SAISIE_VENTE_FACTURE")); |
sheet.getOrCreateDocumentFile(); |
sheet.fastPrintDocument(); |
sheet.showPrintAndExport(false, false, true); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/report/JournauxSheet.java |
---|
57,6 → 57,9 |
protected int lettrage; |
private String compteDeb, compteEnd; |
public static String TEMPLATE_ID = "Journaux"; |
public static String TEMPLATE_PROPERTY_NAME = "LocationJournaux"; |
public static void setSize(int debut, int fin) { |
debutFill = debut; |
endFill = fin; |
66,10 → 69,14 |
setSize(7, 68); |
} |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationJournaux", "Journaux"); |
@Override |
public String getTemplateId() { |
return TEMPLATE_ID; |
} |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
@Override |
protected String getYear() { |
return ""; |
} |
public JournauxSheet(int[] id, Date du, Date au, int lettrage, String compteDeb, String compteEnd) { |
78,8 → 85,6 |
cal.setTime(au); |
this.printer = PrinterNXProps.getInstance().getStringProperty("JournauxPrinter"); |
this.modele = "Journaux.ods"; |
this.locationOO = SheetXml.getLocationForTuple(tuple, false) + File.separator + cal.get(Calendar.YEAR); |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true) + File.separator + cal.get(Calendar.YEAR); |
this.dateAu = au; |
this.dateDu = du; |
this.idS = id; |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/report/GrandLivreSheet.java |
---|
16,7 → 16,6 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement; |
import org.openconcerto.erp.generationDoc.SheetInterface; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.erp.rights.ComptaUserRight; |
import org.openconcerto.sql.Configuration; |
28,10 → 27,8 |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.users.UserManager; |
import org.openconcerto.utils.GestionDevise; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.cc.ITransformer; |
import java.io.File; |
import java.text.DateFormat; |
import java.util.ArrayList; |
import java.util.Calendar; |
66,6 → 63,9 |
private boolean centralFourn = false; |
int idJrnlExclude = -1; |
public static String TEMPLATE_ID = "Grand Livre"; |
public static String TEMPLATE_PROPERTY_NAME = "LocationGrandLivre"; |
public static void setSize(int debut, int fin) { |
debutFill = debut; |
endFill = fin; |
75,10 → 75,9 |
setSize(7, 69); |
} |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationGrandLivre", "Grand Livre"); |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
@Override |
protected String getYear() { |
return ""; |
} |
public GrandLivreSheet(Date du, Date au, String compteDep, String compteEnd, int lettrage, boolean cumul, boolean excludeCptSolde, boolean centralClient, boolean centralFourn, int idJrnlExclude) { |
89,8 → 88,6 |
this.idJrnlExclude = idJrnlExclude; |
this.printer = PrinterNXProps.getInstance().getStringProperty("GrandLivrePrinter"); |
this.modele = "GrandLivre.ods"; |
this.locationOO = SheetXml.getLocationForTuple(tuple, false) + File.separator + cal.get(Calendar.YEAR); |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true) + File.separator + cal.get(Calendar.YEAR); |
this.dateAu = au; |
this.dateDu = du; |
this.compteDeb = compteDep.trim(); |
621,4 → 618,10 |
return map; |
} |
@Override |
public String getTemplateId() { |
// TODO Auto-generated method stub |
return TEMPLATE_ID; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/report/BalanceSheet.java |
---|
14,8 → 14,8 |
package org.openconcerto.erp.core.finance.accounting.report; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.generationDoc.DocumentLocalStorageManager; |
import org.openconcerto.erp.generationDoc.SheetInterface; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLRow; |
23,9 → 23,7 |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.utils.GestionDevise; |
import org.openconcerto.utils.Tuple2; |
import java.io.File; |
import java.text.DateFormat; |
import java.util.Calendar; |
import java.util.Date; |
42,7 → 40,8 |
private boolean centralClient, centralFourn; |
private final static DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM); |
private final static DateFormat dateFormatEcr = DateFormat.getDateInstance(DateFormat.SHORT); |
public static String TEMPLATE_ID = "Balance"; |
public static String TEMPLATE_PROPERTY_NAME = "LocationBalance"; |
private Date dateDu, dateAu; |
private String compteDeb, compteEnd; |
56,10 → 55,14 |
} |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationBalance", "Balance"); |
@Override |
protected String getYear() { |
return ""; |
} |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
@Override |
public String getTemplateId() { |
return TEMPLATE_ID; |
} |
public BalanceSheet(Date du, Date au, String compteDeb, String compteEnd, boolean centralClient, boolean centralFourn) { |
72,10 → 75,11 |
this.nbRowsPerPage = 72; |
this.printer = PrinterNXProps.getInstance().getStringProperty("BalancePrinter"); |
this.modele = "Balance.ods"; |
final String locationForTuple = SheetXml.getLocationForTuple(tuple, false); |
System.err.println("Emplacement balance :::: " + locationForTuple); |
this.locationOO = locationForTuple + File.separator + cal.get(Calendar.YEAR); |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true) + File.separator + cal.get(Calendar.YEAR); |
final DocumentLocalStorageManager storage = DocumentLocalStorageManager.getInstance(); |
// this.locationOO = storage.getDocumentOutputDirectory(TEMPLATE_ID); |
// this.locationPDF = storage.getPDFOutputDirectory(TEMPLATE_ID); |
this.dateAu = au; |
this.dateDu = du; |
this.compteDeb = compteDeb; |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/report/BalanceAgeeListeSheetXML.java |
---|
15,7 → 15,6 |
import org.openconcerto.erp.core.finance.payment.element.ModeDeReglementSQLElement; |
import org.openconcerto.erp.generationDoc.AbstractListeSheetXml; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.SQLElement; |
23,7 → 22,6 |
import org.openconcerto.sql.model.SQLRowListRSH; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.utils.Tuple2; |
import java.util.ArrayList; |
import java.util.Calendar; |
34,33 → 32,26 |
public class BalanceAgeeListeSheetXML extends AbstractListeSheetXml { |
// private final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yy"); |
private Date deb, fin; |
public static String TEMPLATE_ID = "Balance agée"; |
public static Tuple2<String, String> getTuple2Location() { |
return tupleDefault; |
} |
public BalanceAgeeListeSheetXML(Date deb, Date fin) { |
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter"); |
this.deb = deb; |
this.fin = fin; |
this.locationOO = SheetXml.getLocationForTuple(tupleDefault, false); |
this.locationPDF = SheetXml.getLocationForTuple(tupleDefault, true); |
} |
@Override |
public String getDefaultModele() { |
public String getDefaultTemplateId() { |
return "BalanceAgee"; |
} |
public String getFileName() { |
return getValidFileName("BalanceAgee" + new Date().getTime()); |
@Override |
public String getName() { |
return "BalanceAgee" + new Date().getTime(); |
} |
protected void createListeValues() { |
SQLElement ecr = Configuration.getInstance().getDirectory().getElement("ECRITURE"); |
SQLElement cpt = Configuration.getInstance().getDirectory().getElement("COMPTE_PCE"); |
SQLElement fact = Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_FACTURE"); |
106,7 → 97,6 |
long time = c.getTimeInMillis() - date; |
long day = time / 86400000; |
if (day < 0) { |
// System.err.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); |
continue; |
} |
final SQLRow rowCpt = sqlRow.getForeignRow("ID_COMPTE_PCE"); |
185,7 → 175,7 |
valuesTab.add(e); |
} |
} |
Map<String, Object> totalMap = new HashMap<String, Object>(); |
final Map<String, Object> totalMap = new HashMap<String, Object>(); |
totalMap.put("NOM", "TOTAL"); |
totalMap.put("30", total30 / 100.0); |
totalMap.put("60", total60 / 100.0); |
194,29 → 184,7 |
totalMap.put("TOTAL", totalFull / 100.0); |
valuesTab.add(totalMap); |
// Map<String, Object> values = this.mapAllSheetValues.get(0); |
// if (values == null) { |
// values = new HashMap<String, Object>(); |
// } |
// valuesHA.put("TOTAL", totalHA); |
// valuesE.put("TOTAL_HA", totalHA); |
// valuesE.put("TOTAL", totalE); |
// valuesE.put("TOTAL_VT", totalTPVTTC); |
// values.put("TOTAL", totalVC); |
// values.put("TOTAL_MARGE", totalTPVTTC - totalTPA); |
// |
// valuesE.put("TOTAL_GLOBAL", totalTPVTTC + totalHA); |
// values.put("TOTAL_PA", totalTPA); |
// values.put("TOTAL_PV_TTC", totalTPVTTC); |
// |
// String periode = "Période Du " + dateFormat.format(this.du) + " au " + |
// dateFormat.format(this.au); |
// values.put("DATE", periode); |
// valuesHA.put("DATE", periode); |
// valuesE.put("DATE", periode); |
this.listAllSheetValues.put(0, valuesTab); |
// this.mapAllSheetValues.put(0, values); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/BalanceAgeePanel.java |
---|
66,19 → 66,10 |
BalanceAgeeListeSheetXML l = new BalanceAgeeListeSheetXML(dateDeb.getDate(), dateFin.getDate()); |
try { |
l.genere(false, false).get(); |
// FIXME Probleme avec l'odsviewer |
if (!Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) { |
l.showDocument(); |
} else { |
l.showPreviewDocument(); |
} |
} catch (InterruptedException e1) { |
// TODO Auto-generated catch block |
l.createDocument(); |
l.openDocument(false); |
} catch (Exception e1) { |
e1.printStackTrace(); |
} catch (ExecutionException e1) { |
// TODO Auto-generated catch block |
e1.printStackTrace(); |
} |
} |
}); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/GenerationPointagePanel.java |
---|
13,7 → 13,6 |
package org.openconcerto.erp.core.finance.accounting.ui; |
import org.openconcerto.erp.generationDoc.gestcomm.PointageXmlSheet; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.SQLElement; |
69,7 → 68,6 |
this.add(this.spinYear, c); |
JPanel panelButton = new JPanel(); |
panelButton.add(this.gen); |
panelButton.add(this.close); |
100,7 → 98,8 |
int mois = this.combo.getValue() - 2; |
int year = Integer.valueOf(this.spinYear.getValue().toString()); |
PointageXmlSheet sheet = new PointageXmlSheet(mois, year); |
sheet.genere(true, false); |
sheet.createDocumentAsynchronous(); |
sheet.showPrintAndExportAsynchronous(true, false, true); |
} else { |
if (e.getSource() == this.close) { |
((JFrame) SwingUtilities.getRoot(this)).dispose(); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/element/ExerciceCommonSQLElement.java |
---|
123,6 → 123,9 |
@Override |
public synchronized ValidState getValidState() { |
if (this.dateDeb.getValue() == null || this.dateFin.getValue() == null) { |
return new ValidState(false, "Date de début ou de fin d'exercice non définie"); |
} |
return super.getValidState().and(ValidState.createCached(this.dateDeb.getValue().before(this.dateFin.getValue()), "Date de début après date de fin")); |
} |
}; |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/report/FichePayeSheet.java |
---|
14,8 → 14,8 |
package org.openconcerto.erp.core.humanresources.payroll.report; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.generationDoc.DocumentLocalStorageManager; |
import org.openconcerto.erp.generationDoc.SheetInterface; |
import org.openconcerto.erp.generationDoc.SheetXml; |
import org.openconcerto.erp.generationDoc.SpreadSheetGeneratorGestComm; |
import org.openconcerto.erp.preferences.PrinterNXProps; |
import org.openconcerto.map.model.Ville; |
26,7 → 26,6 |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.utils.ExceptionHandler; |
import org.openconcerto.utils.Tuple2; |
import java.io.File; |
import java.text.DateFormat; |
163,26 → 162,38 |
// Emplacement des fichiers générés |
public static String getLocation(int id, int type) { |
return getLocation(tableFiche.getRow(id), type); |
} |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationFichePaye", "Fiche de paye"); |
public static final String TEMPLATE_ID = "Fiche de paye"; |
public static final String TEMPLATE_PROPERTY_NAME = "LocationFichePaye"; |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
@Override |
public String getTemplateId() { |
return TEMPLATE_ID; |
} |
@Override |
protected String getYear() { |
// TODO Auto-generated method stub |
return this.row.getString("ANNEE"); |
} |
public static String getLocation(SQLRow r, int type) { |
DocumentLocalStorageManager storage = DocumentLocalStorageManager.getInstance(); |
String path; |
if (type == FichePayeSheet.typeOO) { |
path = storage.getDocumentOutputDirectory(TEMPLATE_ID).getAbsolutePath(); |
} else { |
path = storage.getPDFOutputDirectory(TEMPLATE_ID).getAbsolutePath(); |
} |
return SheetXml.getLocationForTuple(tuple, !(type == FichePayeSheet.typeOO)) + File.separator + r.getString("ANNEE"); |
return path + File.separator + r.getString("ANNEE"); |
} |
private void init() { |
this.modele = "FichePaye.ods"; |
this.printer = PrinterNXProps.getInstance().getStringProperty("FichePayePrinter"); |
this.locationOO = getLocation(this.row, typeOO); |
this.locationPDF = getLocation(this.row, typePDF); |
} |
protected void createMap() { |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/report/LivrePayeSheet.java |
---|
60,18 → 60,18 |
setSize(8, 65, 3); |
} |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationLivrePaye", "Livre de paye"); |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
@Override |
protected String getYear() { |
return ""; |
} |
public static final String TEMPLATE_ID = "Livre de paye"; |
public static final String TEMPLATE_PROPERTY_NAME = "LocationLivrePaye"; |
public LivrePayeSheet(int moisDu, int moisAu, String annee) { |
super(); |
this.printer = PrinterNXProps.getInstance().getStringProperty("LivrePayePrinter"); |
this.modele = "LivrePaye.ods"; |
this.locationOO = SheetXml.getLocationForTuple(tuple, false) + File.separator + annee; |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true) + File.separator + annee; |
this.moisAu = moisAu; |
this.moisDu = moisDu; |
this.annee = annee; |
96,6 → 96,11 |
this.mCell.put("A" + row, "Période de " + rowMoisDu.getString("NOM") + " à " + rowMoisAu.getString("NOM") + " " + this.annee); |
} |
@Override |
public String getTemplateId() { |
return TEMPLATE_ID; |
} |
protected void createMap() { |
this.mapReplace = new HashMap(); |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/report/EtatChargesPayeSheet.java |
---|
57,19 → 57,24 |
setSize(7, 66); |
} |
private static final Tuple2<String, String> tuple = Tuple2.create("LocationEtatChargesPaye", "Etat des charges"); |
public static String TEMPLATE_ID = "Etat des charges"; |
public static String TEMPLATE_PROPERTY_NAME = "LocationEtatChargesPaye"; |
public static Tuple2<String, String> getTuple2Location() { |
return tuple; |
@Override |
public String getTemplateId() { |
return TEMPLATE_ID; |
} |
@Override |
protected String getYear() { |
return ""; |
} |
public EtatChargesPayeSheet(int moisDu, int moisAu, String annee) { |
super(); |
this.printer = PrinterNXProps.getInstance().getStringProperty("EtatChargesPayePrinter"); |
this.modele = "EtatChargesPaye.ods"; |
this.locationOO = SheetXml.getLocationForTuple(tuple, false) + File.separator + annee; |
this.locationPDF = SheetXml.getLocationForTuple(tuple, true) + File.separator + annee; |
this.moisAu = moisAu; |
this.moisDu = moisDu; |
this.annee = annee; |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/employe/report/N4DS.java |
---|
New file |
0,0 → 1,458 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.erp.core.humanresources.employe.report; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.map.model.Ville; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowListRSH; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.Where; |
import java.io.File; |
import java.io.IOException; |
import java.io.PrintStream; |
import java.text.DateFormat; |
import java.text.Normalizer; |
import java.text.Normalizer.Form; |
import java.text.SimpleDateFormat; |
import java.util.Date; |
import java.util.List; |
public class N4DS { |
private static DateFormat format = new SimpleDateFormat("ddMMyyyy"); |
private ComptaPropsConfiguration conf = ((ComptaPropsConfiguration) Configuration.getInstance()); |
private long masseSalarialeBrute; |
private static final byte[] retour = "'\n".getBytes(); |
private PrintStream stream = null; |
// FIXME Salarie renvoye |
/** |
* Déclaration normale (type 51) |
* */ |
public N4DS() { |
} |
public void createDocument() { |
masseSalarialeBrute = 0; |
File f = new File("N4DS_" + format.format(new Date()) + ".txt"); |
try { |
stream = new PrintStream(f, "ISO-8859-1"); |
SQLElement eltSalarie = this.conf.getDirectory().getElement("SALARIE"); |
// Infos emetteur |
SQLRow rowSociete = this.conf.getRowSociete(); |
writeS10(stream, rowSociete); |
writeS20(stream, rowSociete); |
SQLSelect sel = new SQLSelect(this.conf.getBase()); |
sel.addSelect(eltSalarie.getTable().getKey()); |
@SuppressWarnings("unchecked") |
List<SQLRow> l = (List<SQLRow>) this.conf.getBase().getDataSource().execute(sel.asString(), new SQLRowListRSH(eltSalarie.getTable())); |
for (SQLRow row : l) { |
N4DSSalarie s = new N4DSSalarie(this); |
s.write(row, rowSociete); |
} |
writeS80(stream, rowSociete); |
writeS90(stream); |
} catch (IOException e) { |
e.printStackTrace(); |
} finally { |
if (stream != null) { |
stream.close(); |
} |
} |
} |
private void writeS80(PrintStream stream, SQLRow rowSociete) throws IOException { |
String siren = rowSociete.getString("NUM_SIRET").replaceAll(" ", "").substring(0, 9); |
String nic = rowSociete.getString("NUM_SIRET").replaceAll(" ", "").substring(9); |
// SIREN |
write("S80.G01.00.001.001", siren); |
// NIC |
write("S80.G01.00.001.002", nic); |
SQLRow rowAdr = rowSociete.getForeignRow("ID_ADRESSE_COMMON"); |
String voie = rowAdr.getString("RUE"); |
Ville ville = Ville.getVilleFromVilleEtCode(rowAdr.getString("VILLE")); |
// Complement adresse |
if (voie.contains("\n")) { |
String[] sVoies = voie.split("\n"); |
if (sVoies.length > 0) { |
voie = sVoies[0]; |
String complement = ""; |
for (int i = 1; i < sVoies.length; i++) { |
complement += sVoies[i].trim() + " "; |
} |
if (complement.length() > 0) { |
complement = complement.substring(0, complement.length() - 1); |
} |
write("S80.G01.00.003.001", complement); |
} |
} |
// Voie |
write("S80.G01.00.003.006", voie); |
// TODO Code INSEE, facultatif |
// stream.write("S80.G01.00.003.007",voie); |
// FIXME Service de distribution |
// stream.write("S80.G01.00.003.009",ville.getName()); |
// Code postal |
write("S80.G01.00.003.010", ville.getCodepostal()); |
// Localité |
write("S80.G01.00.003.012", ville.getName().toUpperCase()); |
// Code Pays, ne doit pas être renseigné pour une adresse en France |
// TODO support des autres pays |
// write("S80.G01.00.003.013", ""); |
// FIXME effectif déclaré |
write("S80.G01.00.004.001", String.valueOf(getEffectifDeclare())); |
// TODO Code établissement sans salarié |
// write( "S80.G01.00.004.001", "2"); |
// TODO Code assujettis taxe sur salaires |
write("S80.G01.00.005", "01"); |
// Code NAF etablissement |
write("S80.G01.00.006", rowSociete.getString("NUM_APE")); |
// FIXME Code section prud'homale |
write("S80.G01.00.007.001", "04"); |
// TODO stecion principale dérogatoire |
// write( "S80.G01.00.004.001", "2"); |
// TODO Institution Prevoyance sans salarie |
// write( "S80.G01.01.001", "P0012"); |
// write( "S80.G01.01.002", "0003"); |
// TODO Institution retraite sans salarie |
// write( "S80.G01.02.001", "G022"); |
// FIXME Code assujettissement taxe et contribution apprentissage |
write("S80.G62.05.001", "01"); |
long totalApprentissage = Math.round(this.masseSalarialeBrute * 0.0068); |
System.err.println(this.masseSalarialeBrute); |
write("S80.G62.05.002.001", String.valueOf(totalApprentissage)); |
write("S80.G62.05.003", "02"); |
// FIXME Code assujettissement formation professionnelle continue |
write("S80.G62.10.001", "01"); |
long totalFormation = Math.round(this.masseSalarialeBrute * 0.0055); |
write("S80.G62.10.003.001", String.valueOf(totalFormation)); |
} |
private void writeS90(PrintStream stream) throws IOException { |
// Nombre total de rubrique + S90 |
write("S90.G01.00.001", String.valueOf(this.nbRubrique + 2)); |
// Nombre total de rubrique S20 |
write("S90.G01.00.002", String.valueOf(1)); |
} |
private int nbRubrique = 0; |
public void write(String rubriqueName, String value) throws IOException { |
String tmp = rubriqueName + ",'"; |
stream.write(tmp.getBytes()); |
stream.write(value.getBytes()); |
stream.write(retour); |
// if (rubriqueName.startsWith("S20")) { |
// this.nbRubriqueS20++; |
// } |
this.nbRubrique++; |
} |
private int getEffectifDeclare() { |
// FIXME ne pas inclure les intérimaires |
SQLElement eltSalarie = this.conf.getDirectory().getElement("SALARIE"); |
SQLElement eltInfos = this.conf.getDirectory().getElement("INFOS_SALARIE_PAYE"); |
SQLSelect sel = new SQLSelect(eltSalarie.getTable().getBase()); |
sel.addSelect(eltSalarie.getTable().getKey()); |
Date d2 = new Date(110, 11, 31); |
Where w = new Where(eltSalarie.getTable().getField("ID_INFOS_SALARIE_PAYE"), "=", eltInfos.getTable().getKey()); |
w = w.and(new Where(eltInfos.getTable().getField("DATE_SORTIE"), "=", (Date) null).or(new Where(eltInfos.getTable().getField("DATE_SORTIE"), ">", d2))); |
sel.setWhere(w); |
System.err.println(sel.asString()); |
List<SQLRow> l = (List<SQLRow>) this.conf.getBase().getDataSource().execute(sel.asString(), new SQLRowListRSH(eltSalarie.getTable())); |
return (l == null ? 0 : l.size()); |
} |
public static String normalizeString2(String s) { |
s = s.toUpperCase(); |
String temp = Normalizer.normalize(s, Form.NFC); |
temp = temp.replaceAll("-", " "); |
return temp.replaceAll("[^\\p{ASCII}]", ""); |
} |
private void writeS20(PrintStream stream, SQLRow rowSociete) throws IOException { |
// Siren |
String siren = rowSociete.getString("NUM_SIRET").replaceAll(" ", "").substring(0, 9); |
String nic = rowSociete.getString("NUM_SIRET").replaceAll(" ", "").substring(9); |
write("S20.G01.00.001", siren); |
// Raison sociale |
write("S20.G01.00.002", rowSociete.getString("NOM")); |
// FIXME Debut periode |
write("S20.G01.00.003.001", "01012011"); |
// FIXME Fin periode |
write("S20.G01.00.003.002", "31122011"); |
// Code nature |
write("S20.G01.00.004.001", "01"); |
// FIXME Code type (complement, Rectificatif, ...) |
write("S20.G01.00.004.002", "51"); |
// fraction |
write("S20.G01.00.005", "11"); |
// TODO debut periode rattachement |
// stream.write("S20.G01.00.006.001,'","11"); |
// fin periode rattachement |
// stream.write("S20.G01.00.006.002,'","11"); |
// Code devise de la déclaration |
write("S20.G01.00.007", "01"); |
// NIC |
write("S20.G01.00.008", nic); |
SQLRow rowAdr = rowSociete.getForeignRow("ID_ADRESSE_COMMON"); |
String voie = rowAdr.getString("RUE"); |
Ville ville = Ville.getVilleFromVilleEtCode(rowAdr.getString("VILLE")); |
// Complement adresse |
if (voie.contains("\n")) { |
String[] sVoies = voie.split("\n"); |
if (sVoies.length > 0) { |
voie = sVoies[0]; |
String complement = ""; |
for (int i = 1; i < sVoies.length; i++) { |
complement += sVoies[i].trim() + " "; |
} |
if (complement.length() > 0) { |
complement = complement.substring(0, complement.length() - 1); |
} |
write("S20.G01.00.009.001", complement); |
} |
} |
// Voie |
write("S20.G01.00.009.006", voie); |
// TODO Code INSEE |
// stream.write("S20.G01.00.009.007",voie); |
// FIXME Service de distribution |
// stream.write("S20.G01.00.009.009",ville.getName()); |
// Code postal |
write("S20.G01.00.009.010", ville.getCodepostal()); |
// Localité |
write("S20.G01.00.009.012", ville.getName().toUpperCase()); |
// TODO Code Pays pour les autres pays que la France |
// write("S20.G01.00.009.013",""); |
// write("S20.G01.00.009.016",""); |
write("S20.G01.00.013.002", "1"); |
// Code periodicite |
// TODO déclaration autre que annuelle |
write("S20.G01.00.018", "A00"); |
} |
/** |
* Strucuture S10, N4DS |
* */ |
private void writeS10(PrintStream stream, SQLRow rowSociete) throws IOException { |
// Siren |
String siren = rowSociete.getString("NUM_SIRET").replaceAll(" ", "").substring(0, 9); |
String nic = rowSociete.getString("NUM_SIRET").replaceAll(" ", "").substring(9); |
write("S10.G01.00.001.001", siren); |
// NIC |
write("S10.G01.00.001.002", nic); |
// Raison sociale |
write("S10.G01.00.002", rowSociete.getString("NOM")); |
SQLRow rowAdr = rowSociete.getForeignRow("ID_ADRESSE_COMMON"); |
String voie = rowAdr.getString("RUE"); |
Ville ville = Ville.getVilleFromVilleEtCode(rowAdr.getString("VILLE")); |
// Complement adresse |
if (voie.contains("\n")) { |
String[] sVoies = voie.split("\n"); |
if (sVoies.length > 0) { |
voie = sVoies[0]; |
String complement = ""; |
for (int i = 1; i < sVoies.length; i++) { |
complement += sVoies[i] + " "; |
} |
if (complement.length() > 0) { |
complement = complement.substring(0, complement.length() - 1); |
} |
write("S10.G01.00.003.001", complement); |
} |
} |
// Voie |
write("S10.G01.00.003.006", voie); |
// TODO Code INSEE, facultatif |
// stream.write("S10.G01.00.003.007",voie); |
// TODO: Service de distribution |
write("S10.G01.00.003.009", ville.getName()); |
// Code postal |
write("S10.G01.00.003.010", ville.getCodepostal()); |
// Localité |
write("S10.G01.00.003.012", ville.getName().toUpperCase()); |
// Code Pays, ne doit pas être renseigné pour une adresse en France |
// TODO support des autres pays |
// write("S10.G01.00.003.013", ""); |
// FIXME Référence de l'envoi |
// Incrémenté le numéro |
write("S10.G01.00.004,'", "1"); |
// Nom du logiciel |
write("S10.G01.00.005", "OpenConcerto"); |
// Nom de l'éditeur |
write("S10.G01.00.006", "ILM Informatique"); |
// Numéro version |
// FIXME: utiliser le nuémro de version du logiciel |
write("S10.G01.00.007", "1.2"); |
// Code service choisi |
write("S10.G01.00.009", "40"); |
// Code envoi du fichier essai ou réel |
write("S10.G01.00.010", "02"); |
// Norme utilisée |
write("S10.G01.00.011", "V01X06"); |
// Code table char |
write("S10.G01.00.012", "01"); |
// TODO Contact pour DADS |
// Code civilite |
write("S10.G01.01.001.001", "01"); |
// Nom Contact |
// TODO Contact pour DADS |
write("S10.G01.01.001.002", "MAILLARD GUILLAUME"); |
// Code domaine |
// TODO Contact pour DADS |
write("S10.G01.01.002", "03"); |
// Adresse mail |
// TODO Contact pour DADS |
write("S10.G01.01.005", "contact@ilm-informatique.fr"); |
// Tel |
// TODO Contact pour DADS |
write("S10.G01.01.006", "0322194472"); |
// TODO Contact pour DADS |
// Fax |
write("S10.G01.01.007", "0322194408"); |
} |
private String getNumeroVoie(String voie) { |
String numero = ""; |
voie = voie.trim(); |
for (int i = 0; i < voie.trim().length(); i++) { |
char c = voie.charAt(i); |
if (c >= '0' && c <= '9') { |
numero += c; |
} else { |
break; |
} |
} |
return numero; |
} |
private String getVoieWithoutNumber(String voie) { |
voie = voie.trim(); |
String resultVoie = new String(voie); |
for (int i = 0; i < voie.trim().length(); i++) { |
char c = voie.charAt(i); |
if (c >= '0' && c <= '9') { |
resultVoie = resultVoie.substring(1); |
} else { |
break; |
} |
} |
return resultVoie.trim(); |
} |
public void addMasseSalarialeBrute(long baseBrute) { |
this.masseSalarialeBrute += baseBrute; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/employe/report/N4DSSalarie.java |
---|
New file |
0,0 → 1,508 |
/* |
* DO NOT ALTER OR |