OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 18 → Rev 19

/trunk/OpenConcerto/lib/poi-3.8-beta3-20110606.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/lib/poi-3.8-beta3-20110606.jar
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/Configuration/main.properties
1,9 → 1,7
server.ip=192.168.1.10:5432
log.level.ilm.sql=CONFIG
app.name=OpenConcerto1.1
#OpenConcerto
#Thu Aug 25 18:19:03 CEST 2011
server.ip=192.168.1.10\:5432
systemRoot=OpenConcerto
base.root=Common
customer=Gestion_Default
server.driver=postgresql
customer=Gestion_Default
systemRoot=OpenConcerto1.1
 
 
 
/trunk/OpenConcerto/src/org/jopendocument/link/OOInstallation.java
68,6 → 68,7
// cannot use \p{} since some names/values can be non-ASCII
private static final Pattern stringValuePattern = Pattern.compile("^\\s*(.+?)\\s+REG_SZ\\s+(.+?)$", Pattern.MULTILINE);
 
private static final String LOBundleID = "org.libreoffice.script";
private static final String OOBundleID = "org.openoffice.script";
 
// return the standard out (not the standard error)
88,7 → 89,8
 
// handle windows x64
private static String findRootPath() {
final String[] rootPaths = { "HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenOffice.org", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\OpenOffice.org" };
final String[] rootPaths = { "HKEY_LOCAL_MACHINE\\SOFTWARE\\LibreOffice", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LibreOffice", "HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenOffice.org",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\OpenOffice.org" };
for (final String p : rootPaths) {
if (DesktopEnvironment.test("reg", "query", p))
return p;
96,6 → 98,16
return null;
}
 
private static String findBundleURL() throws IOException {
for (final String bundleID : new String[] { LOBundleID, OOBundleID }) {
// if not found prints nothing to out and a cryptic error to the standard error stream
final String url = cmdSubstitution("osascript", "-e", "tell application id \"com.apple.Finder\" to URL of application file id \"" + bundleID + "\"").trim();
if (url.length() > 0)
return url;
}
return null;
}
 
// all string values for the passed registry path
private static Map<String, String> getStringValues(final String path, final String option) throws IOException {
final Map<String, String> values = new HashMap<String, String>();
154,6 → 166,7
// not installed
if (rootPath == null)
return null;
final boolean libreOffice = rootPath.contains("LibreOffice");
 
// Only the default value so pass '/ve'
final Map<String, String> unoValues = getStringValues(rootPath + "\\UNO\\InstallPath", "/ve");
166,12 → 179,11
exe = new File(unoPath, "soffice.exe");
 
// '/s' since variables are one level (the version) deeper
final Map<String, String> layersValues = getStringValues(rootPath + "\\Layers\\OpenOffice.org", "/s");
final Map<String, String> layersValues = getStringValues(rootPath + (libreOffice ? "\\Layers_\\LibreOffice" : "\\Layers\\OpenOffice.org"), "/s");
addPaths(cp, unoPath, layersValues.get("BASISINSTALLLOCATION"), layersValues.get("UREINSTALLLOCATION"));
} else if (os.startsWith("Mac OS")) {
// if not found prints nothing to out and a cryptic error to the standard error stream
final String url = cmdSubstitution("osascript", "-e", "tell application id \"com.apple.Finder\" to URL of application file id \"" + OOBundleID + "\"").trim();
if (url.length() == 0)
final String url = findBundleURL();
if (url == null)
return null;
try {
final File appPkg = new File(new URI(url).getPath());
/trunk/OpenConcerto/src/org/jopenchart/linechart/LineChart.java
118,10 → 118,6
int topHeight = left.getMaxLabelHeight(g) / 2;
int bottomHeight = 1 + bottom.getMaxLabelHeight(g) + bottom.getMarkerLenght() + bottom.getMarkerSpacing();
 
System.out.println("leftWidth:" + leftWidth);
System.out.println("rightWidth:" + rightWidth);
System.out.println("topHeight:" + topHeight);
System.out.println("bottomHeight:" + bottomHeight);
int graphWidth = this.getDimension().width - leftWidth - rightWidth;
int graphHeight = this.getDimension().height - topHeight - bottomHeight;
 
160,10 → 156,9
int graphHeight = this.getChartRectangle().height;
 
double dx = (double) graphWidth / (length - 1);
System.out.println("l:" + length);
 
double ratioy = (double) graphHeight / rangeXValue;
System.out.println("graphHeight:" + graphHeight + " " + rangeXValue);
System.out.println("graphWidth:" + graphWidth + " " + rangeXValue);
 
double x1 = graphPosX;
 
ArrayOfInt lx = new ArrayOfInt();
/trunk/OpenConcerto/src/org/jopenchart/DataModel.java
23,7 → 23,10
 
public void setChart(Chart chart) {
this.chart = chart;
}
 
public Chart getChart() {
return chart;
}
 
public synchronized int getState() {
/trunk/OpenConcerto/src/org/jopenchart/AreaRenderer.java
6,5 → 6,4
 
public abstract void render(Graphics2D g) ;
 
}
/trunk/OpenConcerto/src/org/jopenchart/sample/model/DataModel1DMorphing.java
67,7 → 67,7
}
synchronized (DataModel1DMorphing.this.src) {
try {
System.out.println("wait");
 
src.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
92,7 → 92,7
computeDy();
 
count += STEP;
System.out.println("notyfy");
 
synchronized (src) {
src.notifyAll();
}
/trunk/OpenConcerto/src/org/jopenchart/sample/devguide/GuidePanel.java
2,11 → 2,9
 
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
 
import javax.swing.BoxLayout;
14,13 → 12,11
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.LineBorder;
 
import org.jopenchart.Chart;
import org.jopenchart.ChartPanel;
import org.jopenchart.URLParser;
 
 
public class GuidePanel extends JPanel {
GuidePanel() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
68,15 → 64,11
Chart chart = parser.getChart();
if (chart != null) {
ChartPanel panel = new ChartPanel(chart);
p.add(panel, c);
c.gridy++;
URLPanel uPanle = new URLPanel(url);
uPanle.setPreferredSize(chart.getDimension());
uPanle.setMinimumSize(chart.getDimension());
System.out.println(uPanle.getSize());
p.add(uPanle, c);
}
return p;
/trunk/OpenConcerto/src/org/jopenchart/sample/devguide/URLPanel.java
5,7 → 5,6
import java.net.URL;
 
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
 
public class URLPanel extends JPanel {
15,17 → 14,13
URLPanel(final String surl) {
new Thread(new Runnable() {
public void run() {
 
try {
 
URL url = new URL(surl);
ImageIcon i = new ImageIcon(url);
im = i.getImage();
System.out.println("loaded:" + url);
repaint();
 
} catch (Exception e) {
 
e.printStackTrace();
}
 
34,10 → 29,7
}
 
protected void paintComponent(Graphics g) {
 
if (im != null && im.getHeight(null) > 0) {
System.out.println("paint:"+im.getWidth(null)+","+im.getWidth(null));
System.out.println(this.getSize());
g.drawImage(im, 0, 0, null);
}
}
/trunk/OpenConcerto/src/org/jopenchart/sample/devguide/GuideFrame.java
7,7 → 7,6
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
 
public class GuideFrame extends JFrame {
public GuideFrame() {
/trunk/OpenConcerto/src/org/jopenchart/Chart.java
39,13 → 39,11
 
public void setChartRectangle(Rectangle r) {
if (chartRectangle == null || !r.equals(chartRectangle)) {
System.err.println("Chart.setChartRectangle()" + r);
chartRectangle = r;
}
}
 
public Rectangle getChartRectangle() {
 
return chartRectangle;
}
 
99,14 → 97,10
renderBackground(g);
renderAxis(g);
renderPlot(g);
 
renderLabels(g);
// g.setColor(Color.PINK);
// g.drawLine(0, 0, this.getDimension().width, this.getDimension().height);
}
 
public void prepareRendering(Graphics2D g) {
 
}
 
public void renderBackground(Graphics2D g) {
/trunk/OpenConcerto/src/org/jopenchart/Axis.java
49,21 → 49,17
 
public void addLabels(List<AxisLabel> labels) {
this.labels.addAll(labels);
 
}
 
public int getWidth() {
 
return width;
}
 
public int getX() {
 
return x;
}
 
public int getY() {
 
return y;
}
 
74,12 → 70,11
public int getMaxLabelWidth(Graphics2D g) {
int max = 0;
for (AxisLabel label : this.labels) {
 
int w = (int) g.getFontMetrics().getStringBounds(label.getLabel(), g).getWidth();
if (w > max)
if (w > max) {
max = w;
}
 
}
return max;
}
 
86,12 → 81,10
public int getMaxLabelHeight(Graphics2D g) {
int max = 0;
for (AxisLabel label : this.labels) {
 
int h = (int) g.getFontMetrics().getStringBounds(label.getLabel(), g).getHeight();
if (h > max)
max = h;
}
 
return max;
}
 
134,8 → 127,9
}
 
public int getMarkerSpacing() {
if (labels.isEmpty())
if (labels.isEmpty()) {
return 0;
}
return 3;
}
 
/trunk/OpenConcerto/src/org/jopenchart/AxisLabel.java
9,9 → 9,6
super(label);
}
 
/*
* public AxisLabel(String label, int position) { super(label); this.position = position; }
*/
public AxisLabel(String label, Number value) {
super(label);
this.value = value;
/trunk/OpenConcerto/src/org/jopenchart/barchart/VerticalStackBarChart.java
37,10 → 37,10
 
double minXValue = lowerRange.doubleValue();
double rangeXValue = maxXValue - minXValue;
System.out.println("Range:" + rangeXValue);
 
double ratioy = (double) graphHeight / rangeXValue;
long x = graphPosX + this.getSpaceBetweenBars();
long height = (long) this.getDimension().getHeight();
 
for (int i = 0; i < nbBar; i++) {
long y = graphPosY + graphHeight;
 
50,7 → 50,7
final Number valueAt = model1.getValueAt(i);
if (valueAt != null) {
double h = valueAt.doubleValue() * ratioy;
System.out.print("y:" + (int) y + " h:" + (int) h + ",");
 
g.setColor(this.getColor(j));
y -= Math.ceil(h) - 1;
 
58,7 → 58,7
}
 
}
System.out.println();
 
x += this.getSpaceBetweenBars() + this.getBarWidth();
}
g.setColor(Color.pink);
/trunk/OpenConcerto/src/org/jopenchart/barchart/VerticalGroupBarChart.java
120,7 → 120,6
}
}
if (this.highlight != found) {
System.out.println(found);
this.highlight = found;
this.getDataModel().fireDataModelChanged();
}
/trunk/OpenConcerto/src/org/jopenchart/barchart/VerticalBarChart.java
51,8 → 51,6
double minYValue = Math.min(0, model1.getMinValue().doubleValue());
 
double rangeYValue = maxYValue - minYValue;
System.out.println("Range:" + rangeYValue);
System.out.println("GraphHeight:" + graphHeight);
double ratioy = ((double) graphHeight) / rangeYValue;
long x = graphPosX + this.getSpaceBetweenBars();
// long posY = Math.round(model1.getMinValue().doubleValue() * ratioy);
62,7 → 60,6
final Number valueAt = model1.getValueAt(i);
if (valueAt != null) {
double h = valueAt.doubleValue() * ratioy;
System.out.print("y:" + (int) y + " h:" + (int) h + ",");
g.setColor(this.getColor(0));
y -= Math.ceil(h) - 1;
 
69,12 → 66,10
g.fillRect((int) x, (int) y, this.getBarWidth(), (int) h);
}
 
System.out.println();
x += this.getSpaceBetweenBars() + this.getBarWidth();
}
g.setColor(Color.pink);
// g.drawRect(this.getChartRectangle().x, this.getChartRectangle().y,
// this.getChartRectangle().width, this.getChartRectangle().height);
 
}
 
@Override
/trunk/OpenConcerto/src/org/jopenchart/DataModelMultiple.java
26,7 → 26,6
}
 
public int getSize() {
 
return this.models.size();
}
 
46,7 → 45,6
 
public Number getMinValue() {
Number min = null;
 
for (DataModel1D model : models) {
Number b = model.getMinValue();
if (min == null) {
/trunk/OpenConcerto/src/org/jopenchart/ArrayOfInt.java
1,7 → 1,5
package org.jopenchart;
 
import com.sun.org.apache.bcel.internal.generic.GETSTATIC;
 
public class ArrayOfInt {
private int[] a = new int[5];
 
/trunk/OpenConcerto/src/org/jopenchart/piechart/PieChart.java
61,7 → 61,7
Color[] colors = new Color[stop];
double[] spaces = new double[stop];
Color origine = this.getColor(0);
System.out.println("PieColor:" + origine);
 
double mR = origine.getRed();
double mV = origine.getGreen();
double mB = origine.getBlue();
102,7 → 102,7
g.setColor(colors[i]);
g.setStroke(new BasicStroke(width2 - this.innerWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 12.0f, null, 10.0f));
g.drawArc(x, y, width2, height2, (int) Math.round(startAngle), -angle);
System.out.println("i:" + i + " moveAngle:" + moveAngle + " angle:" + angle + " x:" + x + " y:" + y);
 
g.setStroke(new BasicStroke());
if (i < labels.size()) {
final String label = labels.get(i).getLabel();
/trunk/OpenConcerto/src/org/jopenchart/DataModel1D.java
30,9 → 30,7
}
 
public void setValueAt(int index, Number value) {
 
ensureCapacity(index);
 
l.set(index, value);
}
 
44,13 → 42,11
 
public Number getValueAt(int index) {
ensureCapacity(index);
 
return l.get(index);
}
 
public Number getMaxValue() {
Number max = 0;
 
for (Number b : this.l) {
if (max == null) {
max = b;
63,7 → 59,6
 
public Number getMinValue() {
Number min = 0;
 
for (Number b : this.l) {
if (min == null) {
min = b;
/trunk/OpenConcerto/src/org/jopenchart/URLParser.java
42,7 → 42,6
if (c == '&') {
value = buff;
buff = "";
System.out.println(key + " " + value);
parameters.put(key, value);
 
} else if (c == '=') {
54,7 → 53,7
}
value = buff;
parameters.put(key, value);
System.out.println(key + " " + value);
 
}
 
/**
241,10 → 240,9
 
private List<Stroke> getStrokes(String string) {
List<Stroke> list = new ArrayList<Stroke>();
System.err.println("full:" + string);
 
final String[] params = splitPipe(string);
for (int i = 0; i < params.length; i++) {
System.err.println("f:" + params[i]);
list.add(getSroke(params[i]));
}
return list;
251,7 → 249,6
}
 
private Stroke getSroke(String string) {
System.err.println("s:" + string);
final String[] params = string.split(",");
float thickness = Float.parseFloat(params[0]);
float lineLength = Float.parseFloat(params[1]);
/trunk/OpenConcerto/src/org/jopenchart/ChartPanel.java
10,9 → 10,8
public class ChartPanel extends JPanel implements DataModelListener, MouseMotionListener {
private Chart chart;
 
public ChartPanel(Chart c) {
public ChartPanel(final Chart c) {
this.chart = c;
 
c.getDataModel().addDataModelListener(this);
this.setMinimumSize(c.getDimension());
this.setPreferredSize(c.getDimension());
22,22 → 21,18
 
@Override
protected void paintComponent(Graphics g) {
System.err.println("ChartPanel.paintComponent()");
super.paintComponent(g);
chart.render((Graphics2D) g);
}
 
public void dataChanged() {
System.err.println("ChartPanel.dataChanged()");
invalidate();
repaint();
 
}
 
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
 
// Nothing
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ql/QLPrinterExample.java
New file
0,0 → 1,32
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ql;
 
import java.io.File;
import java.io.IOException;
 
public class QLPrinterExample {
public static void main(String[] args) {
QLPrinter prt = new QLPrinter("192.168.1.103");
prt.setHighQuality(true);
try {
prt.print(new File("Hello_720x300.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/map/ui/ITextComboVilleViewer.java
48,7 → 48,6
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
 
 
import org.apache.commons.collections.Predicate;
 
public class ITextComboVilleViewer extends JPanel implements ValueWrapper<String>, DocumentComponent, TextComponent, EmptyObject {
174,6 → 173,11
this.supp.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.supp.removeValidListener(l);
}
 
public void addValueListener(final PropertyChangeListener l) {
this.supp.addValueListener(l);
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ContentTypeVersioned.java
126,24 → 126,27
/**
* Create a new minimal document using {@link RootElement#CONTENT}.
*
* @param version the version.
* @return the body of the created document.
* @see #createContent(boolean)
*/
public final Element createContent() {
return this.createContent(false);
public final Element createContent(final XMLFormatVersion version) {
return this.createContent(version, false);
}
 
/**
* Create a new minimal document.
*
* @param version the version.
* @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()
*/
public Element createContent(final boolean singleXML) {
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(), null);
final Document doc = rootElement.createDocument(getVersion(), version.getOfficeVersion());
final Namespace officeNS = getVersion().getOFFICE();
setType(doc, rootElement, officeNS);
// don't forget that, otherwise OO crash
161,6 → 164,11
return body;
}
 
private final void checkVersion(final XMLFormatVersion version) {
if (version.getXMLVersion() != getVersion())
throw new IllegalArgumentException("Version mismatch : " + version.getXMLVersion());
}
 
public void setType(final Document doc) {
this.setType(doc, RootElement.fromElementName(doc.getRootElement().getName()), getVersion().getOFFICE());
}
185,11 → 193,13
/**
* Create a new minimal document using {@link RootElement#STYLES}.
*
* @param version the version.
* @return the created document.
*/
public Document createStyles() {
public Document createStyles(final XMLFormatVersion version) {
checkVersion(version);
final Namespace officeNS = getVersion().getOFFICE();
final Document styles = RootElement.STYLES.createDocument(getVersion(), null);
final Document styles = RootElement.STYLES.createDocument(getVersion(), version.getOfficeVersion());
// 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;
198,12 → 208,13
/**
* Creates an empty package.
*
* @param version the version of the package.
* @return a new package with minimal {@link RootElement#CONTENT} and {@link RootElement#STYLES}
*/
public ODPackage createPackage() {
public ODPackage createPackage(final XMLFormatVersion version) {
final ODPackage res = new ODPackage();
res.putFile(RootElement.CONTENT.getZipEntry(), this.createContent(false).getDocument());
res.putFile(RootElement.STYLES.getZipEntry(), this.createStyles());
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;
/trunk/OpenConcerto/src/org/openconcerto/openoffice/OOXML.java
16,6 → 16,7
*/
package org.openconcerto.openoffice;
 
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.xml.JDOMUtils;
import org.openconcerto.xml.Validator;
 
25,6 → 26,8
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
32,8 → 35,6
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
 
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.LazyMap;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
48,80 → 49,138
* Various bits of OpenDocument XML.
*
* @author Sylvain CUAZ
* @see #get(XMLVersion)
* @see #get(XMLFormatVersion)
*/
public class OOXML {
public abstract class OOXML implements Comparable<OOXML> {
 
private static final Map instances = LazyMap.decorate(new HashMap(), new Transformer() {
public Object transform(Object input) {
return new OOXML((XMLVersion) input);
/**
* If this system property is set to <code>true</code> then {@link #get(XMLFormatVersion)} will
* never return <code>null</code>, allowing to support unknown versions.
*/
public static final String LAST_FOR_UNKNOWN_PROP = OOXML.class.getPackage().getName() + ".lastOOXMLForUnknownVersion";
private static final XML_OO instanceOO = new XML_OO();
private static final SortedMap<String, XML_OD> instancesODByDate = new TreeMap<String, XML_OD>();
private static final Map<String, XML_OD> instancesODByVersion = new HashMap<String, XML_OD>();
private static final List<OOXML> values;
private static OOXML defaultInstance;
 
static {
register(new XML_OD_1_0());
register(new XML_OD_1_1());
register(new XML_OD_1_2());
values = new ArrayList<OOXML>(instancesODByDate.size() + 1);
values.add(instanceOO);
values.addAll(instancesODByDate.values());
 
setDefault(getLast());
}
});
 
private static void register(XML_OD xml) {
assert xml.getVersion() == XMLVersion.OD;
instancesODByDate.put(xml.getDateString(), xml);
instancesODByVersion.put(xml.getFormatVersion().getOfficeVersion(), xml);
}
 
/**
* Returns the instance that match the requested version.
*
* @param version the version.
* @return the corresponding instance.
* @return the corresponding instance, <code>null</code> for unsupported versions.
* @see #LAST_FOR_UNKNOWN_PROP
*/
public static OOXML get(XMLVersion version) {
return (OOXML) instances.get(version);
public static OOXML get(XMLFormatVersion version) {
return get(version, Boolean.getBoolean(LAST_FOR_UNKNOWN_PROP));
}
 
static public final String getLineBreakS() {
return "<text:line-break/>";
public static OOXML get(XMLFormatVersion version, final boolean lastForUnknown) {
if (version.getXMLVersion() == XMLVersion.OOo) {
return instanceOO;
} else {
final XML_OD res = instancesODByVersion.get(version.getOfficeVersion());
if (res == null && lastForUnknown)
return getLast(version.getXMLVersion());
else
return res;
}
}
 
static private final String rt2oo(String content, String tagName, String styleName) {
return content.replaceAll("\\[" + tagName + "\\]", "<text:span text:style-name=\"" + styleName + "\">").replaceAll("\\[/" + tagName + "\\]", "</text:span>");
public static OOXML get(Element root) {
return XMLFormatVersion.get(root).getXML();
}
 
/**
* Encode spaces for OpenOffice 1, and escape characters for XML.
* Return all known instances in the order they were published.
*
* @param s a string to encode, eg "hi\n 3<4".
* @return the string encoded in XML, eg "hi<text:line-break/><text:s text:c="2"/>3&lt;4".
* @deprecated see {@link #encodeWS(String)}
* @return all known instances ordered.
* @see #compareTo(OOXML)
*/
static public final String encodeOOWS(final String s) {
String tmp = JDOMUtils.OUTPUTTER.escapeElementEntities(s).replaceAll("\n", getLineBreakS()).replaceAll("\t", OOXML.get(XMLVersion.OOo).getTabS());
static public final List<OOXML> values() {
return values;
}
 
String res = "";
// les séries de plus d'un espace consécutifs
final Pattern p = Pattern.compile(" +");
final Matcher m = p.matcher(tmp);
int lastEnd = 0;
while (m.find()) {
// c == le nombre d'espaces
res += tmp.substring(lastEnd, m.start()) + "<text:s text:c=\"" + (m.group().length()) + "\"/>";
lastEnd = m.end();
static public final OOXML getLast() {
return CollectionUtils.getLast(values);
}
res += tmp.substring(lastEnd);
 
return res;
static public final OOXML getLast(XMLVersion version) {
if (version == XMLVersion.OOo)
return instanceOO;
else
return instancesODByDate.get(instancesODByDate.lastKey());
}
 
public static void setDefault(OOXML ns) {
defaultInstance = ns;
}
 
public static OOXML getDefault() {
return defaultInstance;
}
 
static private final String rt2oo(String content, String tagName, String styleName) {
return content.replaceAll("\\[" + tagName + "\\]", "<text:span text:style-name=\"" + styleName + "\">").replaceAll("\\[/" + tagName + "\\]", "</text:span>");
}
 
// *** instances
 
private final XMLVersion version;
private Schema schema = null;
private final XMLFormatVersion version;
private final String dateString;
 
private OOXML(XMLVersion version) {
private OOXML(XMLFormatVersion version, final String dateString) {
this.version = version;
this.dateString = dateString;
}
 
public final XMLVersion getVersion() {
return this.version;
/**
* The date the specification was published.
*
* @return the date in "yyyyMMdd" format.
*/
public final String getDateString() {
return this.dateString;
}
 
private Schema getSchema() throws SAXException {
if (this.schema == null) {
this.schema = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI).newSchema(getClass().getResource("oofficeDTDs/OpenDocument-strict-schema-v1.1.rng"));
/**
* Compare the date the specification was published.
*
* @param o the object to be compared.
* @see #getDateString()
*/
@Override
public int compareTo(OOXML o) {
return this.dateString.compareTo(o.dateString);
}
assert this.schema != null;
return this.schema;
 
public final XMLVersion getVersion() {
return this.getFormatVersion().getXMLVersion();
}
 
public final XMLFormatVersion getFormatVersion() {
return this.version;
}
 
public abstract boolean canValidate();
 
/**
* Verify that the passed document is a valid OpenOffice.org 1 or ODF document.
*
128,23 → 187,7
* @param doc the xml to test.
* @return a validator on <code>doc</code>.
*/
public Validator getValidator(Document doc) {
if (this.getVersion() == XMLVersion.OD) {
final Schema schema;
try {
schema = this.getSchema();
} catch (SAXException e) {
throw new IllegalStateException("relaxNG schemas pb", e);
}
return new Validator.JAXPValidator(doc, schema);
} else {
// DTDs are stubborn, xmlns have to be exactly where they want
// in this case the root element
for (final Namespace n : getVersion().getALL())
doc.getRootElement().addNamespaceDeclaration(n);
return new Validator.DTDValidator(doc, OOUtils.getBuilderLoadDTD());
}
}
public abstract Validator getValidator(Document doc);
 
/**
* Return the names of font face declarations.
152,37 → 195,22
* @return at index 0 the name of the container element, at 1 the qualified name of its
* children.
*/
public String[] getFontDecls() {
if (this.getVersion() == XMLVersion.OOo)
return new String[] { "font-decls", "style:font-decl" };
else
return new String[] { "font-face-decls", "style:font-face" };
}
public abstract String[] getFontDecls();
 
public final Element getLineBreak() {
return new Element("line-break", getVersion().getTEXT());
}
 
public final Element getTab() {
return new Element(this.getVersion().equals(XMLVersion.OD) ? "tab" : "tab-stop", getVersion().getTEXT());
}
public abstract Element getTab();
 
/**
* How to encode a tab.
*
* @return the xml string to encode a tab.
* @deprecated use {@link #getTab()}
*/
public final String getTabS() {
return this.getVersion().equals(XMLVersion.OD) ? "<text:tab/>" : "<text:tab-stop/>";
}
public abstract String getFrameQName();
 
protected final List encodeRT_L(String content, Map styles) {
public abstract Element createFormattingProperties(final String family);
 
protected final List encodeRT_L(String content, Map<String, String> styles) {
String res = JDOMUtils.OUTPUTTER.escapeElementEntities(content);
final Iterator iter = styles.entrySet().iterator();
while (iter.hasNext()) {
final Entry e = (Entry) iter.next();
res = rt2oo(res, (String) e.getKey(), (String) e.getValue());
for (final Entry<String, String> e : styles.entrySet()) {
res = rt2oo(res, e.getKey(), e.getValue());
}
try {
return JDOMUtils.parseString(res, getVersion().getALL());
201,7 → 229,7
* "Gras").
* @return the corresponding element.
*/
public final Element encodeRT(String content, Map styles) {
public final Element encodeRT(String content, Map<String, String> styles) {
return new Element("span", getVersion().getTEXT()).addContent(encodeRT_L(content, styles));
}
 
264,7 → 292,7
public final Element encodeWS(final Element elem) {
final XPath path;
try {
path = OOUtils.getXPath(".//text()", XMLVersion.getVersion(elem));
path = OOUtils.getXPath(".//text()", getVersion());
} catch (JDOMException e) {
// static path, hence always valid
throw new IllegalStateException("cannot create XPath", e);
281,4 → 309,114
return elem;
}
 
private static final class XML_OO extends OOXML {
public XML_OO() {
super(XMLFormatVersion.getOOo(), "20020501");
}
 
@Override
public boolean canValidate() {
return true;
}
 
@Override
public Validator getValidator(Document doc) {
// DTDs are stubborn, xmlns have to be exactly where they want
// in this case the root element
for (final Namespace n : getVersion().getALL())
doc.getRootElement().addNamespaceDeclaration(n);
return new Validator.DTDValidator(doc, OOUtils.getBuilderLoadDTD());
}
 
@Override
public String[] getFontDecls() {
return new String[] { "font-decls", "style:font-decl" };
}
 
@Override
public final Element getTab() {
return new Element("tab-stop", getVersion().getTEXT());
}
 
@Override
public String getFrameQName() {
return "draw:text-box";
}
 
@Override
public Element createFormattingProperties(String family) {
return new Element("properties", this.getVersion().getSTYLE());
}
}
 
private static class XML_OD extends OOXML {
private final String schemaFile;
private Schema schema = null;
 
public XML_OD(final String dateString, final String versionString, final String schemaFile) {
super(XMLFormatVersion.get(XMLVersion.OD, versionString), dateString);
this.schemaFile = schemaFile;
}
 
@Override
public boolean canValidate() {
return this.schemaFile != null;
}
 
private Schema getSchema() throws SAXException {
if (this.schema == null && this.schemaFile != null) {
this.schema = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI).newSchema(getClass().getResource("oofficeDTDs/" + this.schemaFile));
}
return this.schema;
}
 
@Override
public Validator getValidator(Document doc) {
final Schema schema;
try {
schema = this.getSchema();
} catch (SAXException e) {
throw new IllegalStateException("relaxNG schemas pb", e);
}
return schema == null ? null : new Validator.JAXPValidator(doc, schema);
}
 
@Override
public final String[] getFontDecls() {
return new String[] { "font-face-decls", "style:font-face" };
}
 
@Override
public final Element getTab() {
return new Element("tab", getVersion().getTEXT());
}
 
@Override
public String getFrameQName() {
return "draw:frame";
}
 
@Override
public Element createFormattingProperties(String family) {
return new Element(family + "-properties", this.getVersion().getSTYLE());
}
}
 
private static final class XML_OD_1_0 extends XML_OD {
public XML_OD_1_0() {
super("20061130", "1.0", null);
}
}
 
private static final class XML_OD_1_1 extends XML_OD {
public XML_OD_1_1() {
super("20070201", "1.1", "OpenDocument-strict-schema-v1.1.rng");
}
}
 
private static final class XML_OD_1_2 extends XML_OD {
public XML_OD_1_2() {
super("20110317", "1.2", "OpenDocument-v1.2-cs01-schema.rng");
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/Style.java
249,19 → 249,19
private final StyleDesc<?> desc;
private final ODPackage pkg;
private final String name;
private final XMLVersion ns;
private final XMLFormatVersion ns;
 
public Style(final ODPackage pkg, final Element styleElem) {
super(styleElem);
this.pkg = pkg;
this.name = this.getElement().getAttributeValue("name", this.getSTYLE());
this.ns = this.pkg.getVersion();
this.desc = getNonNullStyleDesc(this.getClass(), this.ns, styleElem, getName());
this.ns = this.pkg.getFormatVersion();
this.desc = getNonNullStyleDesc(this.getClass(), this.ns.getXMLVersion(), styleElem, getName());
if (!this.desc.getElementName().equals(this.getElement().getName()))
throw new IllegalArgumentException("expected " + this.desc.getElementName() + " but got " + this.getElement().getName() + " for " + styleElem);
// assert that styleElem is in pkg (and thus have the same version)
assert this.pkg.getXMLFile(getElement().getDocument()) != null;
assert this.pkg.getVersion() == XMLVersion.getVersion(getElement());
assert this.pkg.getFormatVersion().equals(XMLFormatVersion.get(getElement().getDocument()));
}
 
protected final Namespace getSTYLE() {
269,7 → 269,7
}
 
public final XMLVersion getNS() {
return this.ns;
return this.ns.getXMLVersion();
}
 
public final String getName() {
291,14 → 291,10
* @return the matching properties, eg &lt;text-properties&gt;.
*/
public final Element getFormattingProperties(final String family) {
final String childName;
if (this.getNS() == XMLVersion.OD)
childName = family + "-properties";
else
childName = "properties";
Element res = this.getElement().getChild(childName, this.getSTYLE());
final Element elem = this.ns.getXML().createFormattingProperties(family);
Element res = this.getElement().getChild(elem.getName(), elem.getNamespace());
if (res == null) {
res = new Element(childName, this.getSTYLE());
res = elem;
this.getElement().addContent(res);
}
return res;
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODDocument.java
21,5 → 21,7
public interface ODDocument {
public XMLVersion getVersion();
 
public XMLFormatVersion getFormatVersion();
 
public ODPackage getPackage();
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODPackage.java
24,6 → 24,7
import org.openconcerto.utils.StringInputStream;
import org.openconcerto.utils.Zip;
import org.openconcerto.utils.ZippedFilesProcessor;
import org.openconcerto.xml.Validator;
 
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
97,8 → 98,8
}
 
static final Document createSingle(final Document from) {
final XMLVersion version = XMLVersion.getVersion(from);
return SINGLE_CONTENT.createDocument(version, from.getRootElement().getAttributeValue("version", version.getOFFICE()));
final XMLFormatVersion version = XMLFormatVersion.get(from);
return SINGLE_CONTENT.createDocument(version.getXMLVersion(), version.getOfficeVersion());
}
 
private final String nsPrefix;
268,11 → 269,16
* @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();
}
 
public final XMLFormatVersion getFormatVersion() {
final ODXMLDocument content = this.getContent();
if (content == null)
return null;
else
return content.getVersion();
return content.getFormatVersion();
}
 
/**
301,12 → 307,15
}
 
/**
* Call {@link OOXML#isValid(Document)} on each XML subdocuments.
* Call {@link Validator#isValid()} on each XML subdocuments.
*
* @return all problems indexed by subdocuments names, ie empty if all ok.
* @return all problems indexed by subdocuments names, i.e. empty if all OK, <code>null</code>
* if validation couldn't occur.
*/
public final Map<String, String> validateSubDocuments() {
final OOXML ooxml = OOXML.get(getVersion());
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)) {
497,7 → 506,7
final Map<RootElement, Document> split = ((ODSingleXMLDocument) this.getContent()).split();
// from 22.2.1 (D1.1.2) of OpenDocument-v1.2-part1-cd04
assert (split.containsKey(RootElement.CONTENT) || split.containsKey(RootElement.STYLES)) && RootElement.getPackageElements().containsAll(split.keySet()) : "wrong elements " + split;
final XMLVersion version = getVersion();
final XMLFormatVersion version = getFormatVersion();
for (final Entry<RootElement, Document> e : split.entrySet()) {
this.putFile(e.getKey().getZipEntry(), new ODXMLDocument(e.getValue(), version));
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODXMLDocument.java
61,7 → 61,7
res.add(new Element("meta", ns));
res.add(new Element("settings", ns));
res.add(new Element(ins == XMLVersion.OOo ? "script" : "scripts", ns));
res.add(new Element(OOXML.get(ins).getFontDecls()[0], ns));
res.add(new Element(OOXML.getLast(ins).getFontDecls()[0], ns));
res.add(new Element("styles", ns));
res.add(new Element("automatic-styles", ns));
res.add(new Element("master-styles", ns));
91,12 → 91,12
}
 
private final Document content;
private final XMLVersion version;
private final XMLFormatVersion version;
private final ChildCreator childCreator;
 
// before making it public, assure that content is really of version "version"
// eg by checking some namespace
protected ODXMLDocument(final Document content, final XMLVersion version) {
protected ODXMLDocument(final Document content, final XMLFormatVersion version) {
if (content == null)
throw new NullPointerException("null document");
this.content = content;
105,7 → 105,7
}
 
public ODXMLDocument(Document content) {
this(content, XMLVersion.getVersion(content.getRootElement()));
this(content, XMLFormatVersion.get(content.getRootElement()));
}
 
public ODXMLDocument(ODXMLDocument doc) {
117,13 → 117,21
}
 
public Validator getValidator() {
return OOXML.get(this.getVersion()).getValidator(this.getDocument());
return getXML().getValidator(this.getDocument());
}
 
public final XMLVersion getVersion() {
public final OOXML getXML() {
return this.getFormatVersion().getXML();
}
 
public final XMLFormatVersion getFormatVersion() {
return this.version;
}
 
public final XMLVersion getVersion() {
return this.getFormatVersion().getXMLVersion();
}
 
// *** children
 
public final Element getChild(String childName) {
363,9 → 371,9
listToAdd = cloned;
} else {
listToAdd = new ArrayList<Content>(cloned.size());
final Iterator iter = cloned.iterator();
final Iterator<Content> iter = cloned.iterator();
while (iter.hasNext()) {
final Content c = (Content) iter.next();
final Content c = iter.next();
if (c instanceof Element) {
final Element transformedElem = addTransf.transform((Element) c);
if (transformedElem != null)
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODSingleXMLDocument.java
406,7 → 406,7
}
 
private String[] getFontDecls() {
return OOXML.get(getVersion()).getFontDecls();
return getXML().getFontDecls();
}
 
// merge everything under office:styles
822,7 → 822,7
final Map<RootElement, Document> res = new HashMap<RootElement, Document>();
final XMLVersion version = getVersion();
final Element root = this.getDocument().getRootElement();
final String officeVersion = root.getAttributeValue("version", version.getOFFICE());
final String officeVersion = getFormatVersion().getOfficeVersion();
 
// meta
{
924,6 → 924,6
}
 
private final Element getPProps() {
return new Element(this.getVersion().equals(XMLVersion.OD) ? "paragraph-properties" : "properties", this.getVersion().getSTYLE());
return this.getXML().createFormattingProperties("paragraph");
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Cell.java
18,6 → 18,7
 
import org.openconcerto.openoffice.ODDocument;
import org.openconcerto.openoffice.ODValueType;
import org.openconcerto.openoffice.XMLFormatVersion;
import org.openconcerto.openoffice.XMLVersion;
import org.openconcerto.utils.CollectionUtils;
 
43,6 → 44,11
private static final Pattern multiSpacePattern = Pattern.compile("[\t\r\n ]+");
private static boolean OO_MODE = true;
 
// from §5.12 of OpenDocument-v1.2-cs01-part2
// Error ::= '#' [A-Z0-9]+ ([!?] | ('/' ([A-Z] | ([0-9] [!?]))))
// we added an optional space before the marks to support OpenOffice/LibreOffice (at least until 3.4)
private static final Pattern ErrorPattern = Pattern.compile("#[A-Z0-9]+( ?[!?]|(/([A-Z]|([0-9] ?[!?]))))");
 
/**
* Set whether {@link #getTextValue()} parses strings using the standard way or using the
* OpenOffice.org way.
197,6 → 203,29
return sb.toString();
}
 
public final String getFormula() {
return this.getElement().getAttributeValue("formula", getTABLE());
}
 
/**
* Tries to find out if this cell computation resulted in an error. This method cannot be robust
* since there's no error attribute in OpenDocument, we must match the value of the cell against
* a pattern. E.g. whether a cell has '=A0' for formula or '= "#N" & "/A"', this method will
* return a non-null error.
*
* @return the error or <code>null</code>.
*/
public String getError() {
// to differentiate between the result of a computation and the user having typed '#N/A'
// (this is because per §4.6 of OpenDocument-v1.2-cs01-part2 : if an error value is the
// result of a cell computation it shall be stored as if it was a string.)
if (getFormula() == null)
return null;
final String textValue = getTextValue();
// OpenDocument 1.1 didn't specify errors
return (XMLFormatVersion.get(XMLVersion.OD, "1.1").equals(getODDocument().getFormatVersion()) && textValue.equals("#NA")) || ErrorPattern.matcher(textValue).matches() ? textValue : null;
}
 
public boolean isValid() {
return !this.getElement().getName().equals("covered-table-cell");
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/SpreadSheet.java
20,6 → 20,7
import org.openconcerto.openoffice.ODDocument;
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;
 
57,13 → 58,13
}
 
public static SpreadSheet createEmpty(TableModel t) throws IOException {
return createEmpty(t, XMLVersion.getOD());
return createEmpty(t, XMLFormatVersion.getDefault());
}
 
public static SpreadSheet createEmpty(TableModel t, XMLVersion ns) throws IOException {
final ContentTypeVersioned ct = ContentType.SPREADSHEET.getVersioned(ns);
final SpreadSheet spreadSheet = create(ct.createPackage());
spreadSheet.getBody().addContent(Sheet.createEmpty(ns));
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));
spreadSheet.getBody().addContent(Sheet.createEmpty(ns.getXMLVersion()));
spreadSheet.getSheet(0).merge(t, 0, 0, true);
return spreadSheet;
}
78,7 → 79,7
* @return the saved file, eg "dir/data.ods".
* @throws IOException if the file can't be saved.
*/
public static File export(TableModel t, File f, XMLVersion ns) throws IOException {
public static File export(TableModel t, File f, XMLFormatVersion ns) throws IOException {
return SpreadSheet.createEmpty(t, ns).saveAs(f);
}
 
113,6 → 114,11
return this.getPackage().getVersion();
}
 
@Override
public XMLFormatVersion getFormatVersion() {
return this.getPackage().getFormatVersion();
}
 
private Element getBody() {
return ContentType.SPREADSHEET.getVersioned(getVersion()).getBody(getContent());
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Table.java
27,6 → 27,7
import java.util.ListIterator;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import javax.swing.table.TableModel;
 
175,6 → 176,8
this.duplicateRows(rowDuplicated, 1, nbDuplicate);
}
 
private static Pattern regexp = Pattern.compile("((^.*)\\.(\\D*))((\\d*)$)");
 
/**
* Clone a range of rows. Eg if you want to copy once rows 2 through 5, you call
* <code>duplicateRows(2, 4, 1)</code>.
183,6 → 186,7
* @param count the number of rows after <code>start</code> to clone.
* @param copies the number of copies of the range to make.
*/
 
public final synchronized void duplicateRows(int start, int count, int copies) {
final int stop = start + count;
// clone xml elements and add them to our tree
190,15 → 194,66
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());
Element c = (Element) r.clone();
List<Element> children = (List<Element>) c.getChildren("table-cell", c.getNamespace());
for (Element element : children) {
System.err.println("--------get table cell");
List<Element> lChild = (List<Element>) element.getChildren("frame", element.getNamespace("frame"));
for (Element element2 : lChild) {
System.err.println("---------get frame");
Attribute attribute = element2.getAttribute("end-cell-address", c.getNamespace());
final String value = attribute.getValue();
System.err.println(value);
final Matcher matcher = regexp.matcher(value);
if (matcher.matches() && matcher.groupCount() == 5) {
String result = matcher.group(1);
int val = Integer.parseInt(matcher.group(4));
val = val + (count * (i + 1));
result += val;
 
attribute.setValue(result);
System.err.println(attribute.getValue());
}
}
}
clones.add(c);
}
}
// works anywhere its XML element is
JDOMUtils.insertAfter(this.rows.get(stop - 1).getElement(), clones);
 
// synchronize our rows with our new tree
this.readRows();
 
// Fix image if after
for (int i = (start + (count * (copies + 1))); i < this.rows.size(); i++) {
final Element r = this.rows.get(i).getElement();
 
List<Element> children = (List<Element>) r.getChildren("table-cell", r.getNamespace());
for (Element element : children) {
System.err.println("--------get table cell");
List<Element> lChild = (List<Element>) element.getChildren("frame", element.getNamespace("frame"));
for (Element element2 : lChild) {
System.err.println("---------get frame");
Attribute attribute = element2.getAttribute("end-cell-address", r.getNamespace());
final String value = attribute.getValue();
System.err.println(value);
final Matcher matcher = regexp.matcher(value);
if (matcher.matches() && matcher.groupCount() == 5) {
String result = matcher.group(1);
int val = Integer.parseInt(matcher.group(4));
val = val + (count * copies);
result += val;
 
attribute.setValue(result);
System.err.println(attribute.getValue());
}
}
}
}
// synchronize our rows with our new tree
this.readRows();
}
 
private synchronized void addRow(Element child) {
this.rows.add(new Row<D>(this, child, this.rows.size()));
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/MutableCell.java
107,7 → 107,13
// setValue(Object o, final ODValueType vt)
if (obj instanceof Number)
// 5.2
// FIXME voir avec Sylvain : probleme avec le viewer si Integer ou Long le textp ne doit
// avoir de décimal
if (obj instanceof Integer || obj instanceof Long) {
this.setValue(ODValueType.FLOAT, obj, (obj == null) ? "" : obj.toString());
} else {
this.setValue(ODValueType.FLOAT, obj, TextPFloatFormat.format(obj));
}
else if (obj instanceof Date)
this.setValue(ODValueType.DATE, obj, TextPDateFormat.format(obj));
else
/trunk/OpenConcerto/src/org/openconcerto/openoffice/XMLVersion.java
76,8 → 76,6
private static final String DRAW_2 = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0";
private static final String FO_2 = "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0";
 
private static XMLVersion defaultNS = OD;
 
private final String name;
private final Map<String, Namespace> nss;
private final Namespace manifest;
189,11 → 187,7
return parent;
}
 
public static void setDefault(XMLVersion ns) {
defaultNS = ns;
}
 
public static XMLVersion getDefault() {
return defaultNS;
return OOXML.getDefault().getVersion();
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/GenerationCommon.java
16,6 → 16,7
*/
package org.openconcerto.openoffice.generation;
 
import org.openconcerto.openoffice.ODPackage;
import org.openconcerto.openoffice.ODSingleXMLDocument;
import org.openconcerto.openoffice.OOXML;
import org.openconcerto.openoffice.XMLVersion;
24,6 → 25,7
import org.openconcerto.openoffice.generation.generator.ExtractGenerator;
 
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.HashMap;
38,25 → 40,33
*
* @param <R> type of generation
*/
public class GenerationCommon<R extends ReportGeneration> {
public class GenerationCommon<R extends ReportGeneration<?>> {
 
private static final NumberFormat FLOAT_FMT = new DecimalFormat("#.###");
 
/** Notre génération */
private final R rg;
private OOXML xml;
 
public GenerationCommon(R rg) {
this.rg = rg;
this.xml = null;
}
 
public final XMLVersion getOOVersion() {
// MAYBE more formal, but ATTN costly to unzip
return this.getRg().getReportType().getTemplate().getName().endsWith(".sxw") ? XMLVersion.OOo : XMLVersion.OD;
return this.getOOXML().getVersion();
}
 
public final OOXML getOOXML() {
return OOXML.get(getOOVersion());
if (this.xml == null) {
try {
this.xml = new ODPackage(this.getRg().getReportType().getTemplate()).getFormatVersion().getXML();
} catch (IOException e) {
throw new IllegalStateException("Couldn't read template", e);
}
}
return this.xml;
}
 
/**
* Encode s as rich text. Ie with embedded [] to indicate styles.
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/ReportGeneration.java
422,7 → 422,6
try {
res.put("join", Ognl.getValue(":[@org.openconcerto.utils.CollectionUtils@join( #this, #sep == null ? ', ' : #sep )]", null));
res.put("silentFirst", Ognl.getValue(":[#this.size == 0 ? null : #this[0]]", null));
res.put("escape", Ognl.getValue(":[#s = #this, @org.openconcerto.openoffice.OOXML@encodeOOWS(#s)]", null));
} catch (OgnlException exn) {
// n'arrive jamais, la syntaxe est correcte
exn.printStackTrace();
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/desc/ParamsHelper.java
117,7 → 117,7
}
}
 
private static Object evaluteOgnl(final String exprAttr, IFactory<?> data) {
static Object evaluteOgnl(final String exprAttr, IFactory<?> data) {
try {
return Ognl.getValue(exprAttr, data.createChecked());
} catch (OgnlException e) {
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/desc/part/SubReportPart.java
40,6 → 40,10
}
 
public final String getDocumentID() {
return this.elem.getAttributeValue("documentID");
final String attr = this.elem.getAttributeValue("documentID");
if (attr == null)
return null;
final Object res = this.evaluateOgnl(attr);
return res == null ? null : res.toString();
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/desc/XMLItem.java
65,6 → 65,10
return this.getType() == null ? null : this.dataFactory;
}
 
protected final Object evaluateOgnl(final String s) {
return ParamsHelper.evaluteOgnl(s, getData());
}
 
public String getParam(String paramName) {
return ParamsHelper.getParam(this.elem, paramName, getData());
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODFrame.java
26,15 → 26,6
*/
public class ODFrame<D extends ODDocument> extends ImmutableDocStyledNode<GraphicStyle, D> {
 
static public String getQualifiedName(final XMLVersion version) {
if (version == XMLVersion.OOo)
return "draw:text-box";
else if (version == XMLVersion.OD)
return "draw:frame";
else
throw new IllegalArgumentException("Unsupported version : " + version);
}
 
/**
* Parse SVG and OD length.
*
/trunk/OpenConcerto/src/org/openconcerto/openoffice/XMLFormatVersion.java
New file
0,0 → 1,122
/*
* 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.CompareUtils;
 
import java.util.HashMap;
import java.util.Map;
 
import org.jdom.Document;
import org.jdom.Element;
 
/**
* Encapsulate a {@link XMLVersion version of xml} and its office version.
*
* @author Sylvain CUAZ
*/
public final class XMLFormatVersion {
// not an enum to support any version (be forward compatible)
 
static private Map<XMLFormatVersion, XMLFormatVersion> instances = new HashMap<XMLFormatVersion, XMLFormatVersion>();
static private final XMLFormatVersion OOo = get(XMLVersion.OOo, "1.0");
 
public static XMLFormatVersion getOOo() {
return OOo;
}
 
/**
* The default version.
*
* @return the default version.
* @see OOXML#setDefault(OOXML)
*/
public static XMLFormatVersion getDefault() {
return OOXML.getDefault().getFormatVersion();
}
 
public static XMLFormatVersion get(Document doc) {
return get(doc.getRootElement());
}
 
public static XMLFormatVersion get(Element root) {
final XMLVersion version = XMLVersion.getVersion(root);
return get(version, root.getAttributeValue("version", version.getOFFICE()));
}
 
public static XMLFormatVersion get(XMLVersion xmlVersion, String officeVersion) {
final XMLFormatVersion key = new XMLFormatVersion(xmlVersion, officeVersion);
XMLFormatVersion res = instances.get(key);
if (res == null) {
res = key;
instances.put(res, res);
}
return res;
}
 
private final XMLVersion xmlVersion;
private final String officeVersion;
private OOXML xml;
 
private XMLFormatVersion(XMLVersion xmlVersion, String officeVersion) {
if (xmlVersion == null)
throw new NullPointerException("Null XMLVersion");
this.xmlVersion = xmlVersion;
this.officeVersion = officeVersion;
// ATTN cannot set this.xml now since OOXML depends on us and is not yet fully functional
// ATTN cannot set this.xml in OOXML constructor since OOo generates faulty documents (even
// for XMLVersion.OOo documents it sets the office:version to the ODF one)
this.xml = null;
}
 
public final XMLVersion getXMLVersion() {
return this.xmlVersion;
}
 
public final String getOfficeVersion() {
return this.officeVersion;
}
 
public final OOXML getXML() {
if (this.xml == null)
this.xml = OOXML.get(this);
return this.xml;
}
 
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.officeVersion == null) ? 0 : this.officeVersion.hashCode());
result = prime * result + this.xmlVersion.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 XMLFormatVersion other = (XMLFormatVersion) obj;
return this.xmlVersion == other.xmlVersion && CompareUtils.equals(this.officeVersion, other.officeVersion);
}
 
@Override
public String toString() {
return super.toString() + " " + this.getXMLVersion() + " version " + this.getOfficeVersion();
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/JDate.java
102,6 → 102,11
// nothing to do
}
 
@Override
public void removeValidListener(ValidListener l) {
// nothing to do
}
 
public String getValidationText() {
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/BaseValueWrapper.java
48,8 → 48,8
this.supp.addValidListener(l);
}
 
public void rmValidListener(ValidListener l) {
this.supp.rmValidListener(l);
public void removeValidListener(ValidListener l) {
this.supp.removeValidListener(l);
}
 
public String getValidationText() {
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/format/FormatValueWrapper.java
26,6 → 26,8
import java.beans.PropertyChangeListener;
import java.text.Format;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.JComponent;
import javax.swing.text.AbstractDocument;
66,16 → 68,33
 
// this validObject is the combination of comp & this format
this.comb = ValidObjectCombiner.create(this, this.comp, new ValidObject() {
public void addValidListener(final ValidListener l) {
final ValidObject me = this;
 
private final List<ValidListener> listeners = new ArrayList<ValidListener>();
 
{
// isValidated() depends on getText(), ie the value
FormatValueWrapper.this.addValueListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
l.validChange(me, isValidated());
fireValidChange();
}
});
}
 
private void fireValidChange() {
for (final ValidListener l : this.listeners)
l.validChange(this, this.isValidated());
}
 
@Override
public void addValidListener(final ValidListener l) {
this.listeners.add(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.listeners.remove(l);
}
 
public String getValidationText() {
return f.getValidationText(getText());
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/EmptyValueWrapper.java
49,6 → 49,10
this.vw.addValidListener(l);
}
 
public void removeValidListener(final ValidListener l) {
this.vw.removeValidListener(l);
}
 
public void addValueListener(final PropertyChangeListener l) {
this.vw.addValueListener(l);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/ConvertorValueWrapper.java
43,6 → 43,11
this.delegate.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.delegate.removeValidListener(l);
}
 
public String getValidationText() {
return this.delegate.getValidationText();
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/ValueChangeSupport.java
87,7 → 87,7
this.validListeners.add(l);
}
 
public void rmValidListener(ValidListener l) {
public void removeValidListener(ValidListener l) {
this.validListeners.remove(l);
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/PreferencePanel.java
13,29 → 13,32
package org.openconcerto.ui.preferences;
 
public interface PreferencePanel {
import org.openconcerto.utils.checks.ValidObject;
 
public interface PreferencePanel extends ValidObject {
 
// nom figurant comme titre
public String getTitleName();
 
/**
* Called once before being displayed.
*/
public void uiInit();
 
/**
* Persist UI values.
*/
public void apply();
 
public void storeValues();
 
/**
* Reset UI to the default values.
*/
public void restoreToDefaults();
 
public void addModifyChangeListener(PreferencePanelListener l);
 
/**
* fire if the modify state of panel change
*
* @param b
*/
public void fireModifyChange(boolean b);
 
/**
* @return true if any changes occured on the values
*/
public boolean isModified();
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/DefaultPreferencePanel.java
13,6 → 13,7
package org.openconcerto.ui.preferences;
 
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import java.awt.Component;
57,6 → 58,10
fireModifyChange(false);
}
 
@Override
public void uiInit() {
}
 
public final void apply() {
storeValues();
fireModifyChange(false);
86,7 → 91,6
fireModifyChange(this.hasBeenModified);
}
 
@Override
public void fireModifyChange(boolean b) {
long time = Calendar.getInstance().getTimeInMillis();
 
183,4 → 187,26
public void actionPerformed(ActionEvent e) {
fireModifyChange(true);
}
 
// * ValidObject
 
@Override
public boolean isValidated() {
return true;
}
 
@Override
public String getValidationText() {
return null;
}
 
@Override
public void addValidListener(ValidListener l) {
// nothing to do
}
 
@Override
public void removeValidListener(ValidListener l) {
// nothing to do
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/JavaPrefPreferencePanel.java
New file
0,0 → 1,192
/*
* 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.preferences;
 
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.AutoLayouter;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.checks.ValidChangeSupport;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
 
import javax.swing.JPanel;
 
/**
* A {@link PreferencePanel} using java {@link Preferences}.
*
* @author Sylvain CUAZ
*/
public abstract class JavaPrefPreferencePanel extends JPanel implements PreferencePanel {
 
private final String title;
private Preferences prefs;
private final AutoLayouter layouter;
private final Set<PrefView<?>> views;
private boolean modified;
private final ValidChangeSupport validSupp;
private String invalidityCause;
 
public JavaPrefPreferencePanel(final String title, final Preferences prefs) {
this.title = title;
this.prefs = prefs;
this.layouter = new AutoLayouter(this);
this.views = new HashSet<PrefView<?>>();
this.modified = false;
this.validSupp = new ValidChangeSupport(this);
this.invalidityCause = null;
}
 
public final void setPrefs(Preferences prefs) {
if (this.prefs != null)
throw new IllegalStateException("Already set : " + this.prefs);
this.prefs = prefs;
}
 
@Override
public final String getTitleName() {
return this.title;
}
 
public final String getPrefPath() {
return this.prefs.absolutePath();
}
 
@Override
public void uiInit() {
if (this.prefs == null)
throw new NullPointerException("prefs wasn't set");
this.addViews();
this.reset();
}
 
protected abstract void addViews();
 
protected final void addView(final PrefView<?> view) {
final ValueWrapper<?> vw = view.getVW();
this.layouter.add(view.getName(), vw.getComp());
this.views.add(view);
view.init(this);
 
vw.addValueListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// needed since some components are not synchronous (e.g. ITextCombo)
if (!view.equalsToPrefValue(JavaPrefPreferencePanel.this.prefs))
setModified(true);
}
});
vw.addValidListener(new ValidListener() {
@Override
public void validChange(ValidObject src, boolean newValue) {
JavaPrefPreferencePanel.this.validSupp.fireValidChange(isValidated());
}
});
}
 
/**
* Reset UI to the stored values.
*/
public final void reset() {
for (final PrefView<?> v : this.views) {
v.setViewValue(this.prefs);
}
this.setModified(false);
}
 
@Override
public final void apply() {
if (this.isModified()) {
try {
// only set preferences in apply() and not when UI changes since some implementation
// flush preferences automatically (e.g. the default implementation)
for (final PrefView<?> v : this.views) {
v.setPrefValue(this.prefs);
}
this.prefs.sync();
// preferences were reloaded and another VM might have also changed them
this.reset();
} catch (BackingStoreException e) {
throw new IllegalStateException("Couldn't store values", e);
}
}
}
 
@Override
public final void restoreToDefaults() {
for (final PrefView<?> v : this.views) {
v.resetViewValue();
}
}
 
@Override
public final void addModifyChangeListener(PreferencePanelListener l) {
// TODO
throw new UnsupportedOperationException();
}
 
private final void setModified(boolean modified) {
if (this.modified != modified) {
this.modified = modified;
}
}
 
@Override
public final boolean isModified() {
return this.modified;
}
 
// ValidObject
 
@Override
public final boolean isValidated() {
boolean res = true;
final List<String> pbs = new ArrayList<String>();
for (final PrefView<?> v : this.views) {
if (!v.getVW().isValidated()) {
String explanation = "'" + v.getName() + "' n'est pas valide";
final String txt = v.getVW().getValidationText();
if (txt != null)
explanation += " (" + txt + ")";
pbs.add(explanation);
res = false;
}
}
this.invalidityCause = res ? null : CollectionUtils.join(pbs, "\n");
return res;
}
 
@Override
public final String getValidationText() {
return this.invalidityCause;
}
 
@Override
public final void addValidListener(ValidListener l) {
this.validSupp.addValidListener(l);
}
 
@Override
public final void removeValidListener(ValidListener l) {
this.validSupp.removeValidListener(l);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/MainPrefPanel.java
14,6 → 14,8
package org.openconcerto.ui.preferences;
 
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
 
import java.awt.Component;
import java.awt.Font;
57,6 → 59,13
private PrefTree tree;
private PrefTreeNode currentNode;
private final JButton buttonApply = new JButton("Appliquer");
private final ValidListener validListener = new ValidListener() {
@Override
public void validChange(ValidObject src, boolean newValue) {
MainPrefPanel.this.buttonApply.setEnabled(newValue);
MainPrefPanel.this.buttonApply.setToolTipText(src.getValidationText());
}
};
 
public MainPrefPanel(PrefTree tree) {
this.tree = tree;
187,7 → 196,7
public void setPanelFromTreeNode(PrefTreeNode n) {
this.currentNode = n;
 
PreferencePanel p = n.getPanel();
PreferencePanel p = n.createPanel();
if (p != null) {
this.titleLabel.setText(p.getTitleName());
 
198,7 → 207,7
// MainPrefPanel.this.buttonApply.setEnabled(b);
// }
// });
 
p.uiInit();
replacePanel(p);
this.addToHistory(n);
}
219,18 → 228,24
if (JOptionPane.showConfirmDialog(this, "Appliquer les modifications?", "Modifications", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
this.currentPanel.apply();
} else {
this.currentPanel.fireModifyChange(false);
// no need to reset the panel, it will be discarded (the node is kept in history
// to be able to recreate a brand new panel)
}
}
 
this.currentPanel.removeValidListener(this.validListener);
}
 
this.remove((JComponent) this.currentPanel);
this.currentPanel = null;
 
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
if (p instanceof JComponent) {
 
this.currentPanel = p;
this.currentPanel.addValidListener(this.validListener);
// initial value
this.validListener.validChange(this.currentPanel, this.currentPanel.isValidated());
this.add((JComponent) this.currentPanel, c);
this.revalidate();
this.repaint();
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/PrefTreeNode.java
29,14 → 29,11
public PrefTreeNode(Class<? extends PreferencePanel> c, String name, String[] keywords, boolean bold) {
this.name = name;
this.keywords = keywords;
 
// if (!PreferencePanel.class.isAssignableFrom(c))
// throw new IllegalArgumentException();
this.bold = bold;
this.c = c;
}
 
public PreferencePanel getPanel() {
public PreferencePanel createPanel() {
try {
return this.c.newInstance();
} catch (Exception e) {
56,7 → 53,6
for (int j = 0; j < this.keywords.length; j++) {
String key = this.keywords[j].toLowerCase();
if (key.indexOf(inValue) >= 0) {
System.out.println("--- match " + this.name);
return true;
}
}
72,6 → 68,7
return this.name;
}
 
@Override
public String toString() {
return getName();
}
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/PrefView.java
New file
0,0 → 1,159
/*
* 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.preferences;
 
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.component.ITextArea;
import org.openconcerto.ui.component.text.TextComponentUtils;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.ui.valuewrapper.ValueWrapperFactory;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.PrefType;
import org.openconcerto.utils.text.DocumentFilterList;
import org.openconcerto.utils.text.DocumentFilterList.FilterType;
import org.openconcerto.utils.text.LimitedSizeDocumentFilter;
 
import java.util.Date;
import java.util.prefs.Preferences;
 
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.text.AbstractDocument;
import javax.swing.text.Document;
 
/**
* A view for one preference value in {@link JavaPrefPreferencePanel}.
*
* @author Sylvain CUAZ
*
* @param <T> type of value
* @see #setDefaultValue(Object)
*/
public class PrefView<T> {
 
private final PrefType<T> type;
private final int length;
private final ValueWrapper<T> vw;
private T defaultValue;
private final String name, prefKey;
 
public PrefView(PrefType<T> type, String name, String prefKey) {
this(type, -1, name, prefKey);
}
 
public PrefView(PrefType<T> type, int length, String name, String prefKey) {
super();
this.type = type;
this.length = length;
this.name = name;
this.prefKey = prefKey;
this.vw = this.createVW();
this.setDefaultValue(this.type.getDefaultValue());
}
 
public final PrefType<T> getType() {
return this.type;
}
 
public final Class<T> getViewClass() {
return this.getType().getTypeClass();
}
 
public final int getLength() {
return this.length;
}
 
public final String getName() {
return this.name;
}
 
public final String getPrefKey() {
return this.prefKey;
}
 
protected JComponent createComponent() {
final JComponent comp;
if (Boolean.class.isAssignableFrom(this.getViewClass())) {
// ATTN hack to view the focus (should try to paint around the button)
comp = new JCheckBox(" ");
} else if (Date.class.isAssignableFrom(this.getViewClass())) {
comp = new JDate();
} else if (String.class.isAssignableFrom(this.getViewClass()) && this.getLength() >= 512) {
comp = new ITextArea();
} else {
comp = new JTextField();
}
return comp;
}
 
protected ValueWrapper<T> createVW() {
final JComponent comp = createComponent();
if (this.getLength() > 0) {
final Document doc = TextComponentUtils.getDocument(comp);
if (doc instanceof AbstractDocument)
DocumentFilterList.add((AbstractDocument) doc, new LimitedSizeDocumentFilter(this.getLength()), FilterType.SIMPLE_FILTER);
}
return ValueWrapperFactory.create(comp, this.getViewClass());
}
 
public final ValueWrapper<T> getVW() {
return this.vw;
}
 
public void init(final JavaPrefPreferencePanel prefPanel) {
}
 
/**
* Set the default value for this preference. Initially this is set to
* {@link PrefType#getDefaultValue()}.
*
* @param defaultValue the new default value.
* @return this.
*/
public final PrefView<T> setDefaultValue(T defaultValue) {
this.defaultValue = defaultValue;
return this;
}
 
public final T getDefaultValue() {
return this.defaultValue;
}
 
final void resetViewValue() {
this.getVW().setValue(this.getDefaultValue());
}
 
final void setViewValue(final Preferences prefs) {
this.getVW().setValue(getPrefValue(prefs));
}
 
private final T getPrefValue(final Preferences prefs) {
return this.getType().get(prefs, getPrefKey(), this.getDefaultValue());
}
 
final boolean equalsToPrefValue(final Preferences prefs) {
return CompareUtils.equals(getPrefValue(prefs), this.getVW().getValue());
}
 
final void setPrefValue(final Preferences prefs) {
final T val = this.getVW().getValue();
// e.g. empty text field
if (val == null)
prefs.remove(getPrefKey());
else
this.getType().put(prefs, getPrefKey(), val);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/AbstractProps.java
75,10 → 75,26
return property;
}
 
/**
* Return Boolean.TRUE only if the property is defined and equals to "true". If the property is
* not defined or not equals to "true", return Boolean.FALSE
* */
public final Boolean getBooleanValue(String name) {
return Boolean.valueOf(this.getProperty(name));
final String property = this.getProperty(name);
if (property == null) {
return Boolean.FALSE;
}
return Boolean.valueOf(property);
}
 
public final boolean getBooleanValue(String name, boolean defaultValue) {
final String property = this.getProperty(name);
if (property == null) {
return defaultValue;
}
return Boolean.valueOf(property);
}
 
public String getDefaultStringValue() {
return "";
}
/trunk/OpenConcerto/src/org/openconcerto/ui/MenuUtils.java
New file
0,0 → 1,178
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ui;
 
import java.awt.Component;
import java.awt.Container;
import java.util.Arrays;
import java.util.List;
 
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSeparator;
import javax.swing.MenuElement;
 
public class MenuUtils {
 
private static final String GROUPNAME_PROPNAME = "GROUPNAME";
private static final String DEFAULT_GROUPNAME = "defaultGroupName";
 
static public <C extends JComponent & MenuElement> JMenuItem addMenuItem(final Action action, final C topLevelMenu) throws IllegalArgumentException {
return addMenuItem(action, topLevelMenu, (String) null);
}
 
static public <C extends JComponent & MenuElement> JMenuItem addMenuItem(final Action action, final C topLevelMenu, final String... path) throws IllegalArgumentException {
return addMenuItem(action, topLevelMenu, Arrays.asList(path));
}
 
/**
* Adds a menu item to the passed menu. The path should be an alternation of group and menu
* within that menu. All items within the same group will be grouped together inside separators.
* Menus will be created as needed and groups' names can be <code>null</code>. NOTE: items added
* with this method (even with null groups) will always be separated from items added directly.
*
* @param action the action to perform.
* @param topLevelMenu where to add the menu item.
* @param path where to add the menu item.
* @return the newly created item.
* @throws IllegalArgumentException if path length is not odd.
*/
static public <C extends JComponent & MenuElement> JMenuItem addMenuItem(final Action action, final C topLevelMenu, final List<String> path) throws IllegalArgumentException {
if (path.size() == 0 || path.size() % 2 == 0)
throw new IllegalArgumentException("Path should be of the form group/menu/group/... : " + path);
JComponent menu = topLevelMenu;
for (int i = 0; i < path.size() - 1; i += 2) {
final String groupName = path.get(i);
final String menuName = path.get(i + 1);
menu = addChild(menu, groupName, new JMenu(menuName), JMenu.class, false);
}
final String actionGroupName = path.get(path.size() - 1);
return addChild(menu, actionGroupName, new JMenuItem(action), JMenuItem.class, true);
}
 
static private Component[] getChildren(final Container c) {
return c instanceof JMenu ? ((JMenu) c).getMenuComponents() : c.getComponents();
}
 
// finds a child like created in the passed group or adds created to the passed group in menu
static private <T extends JMenuItem> T addChild(final Container c, String groupName, final T created, final Class<T> clazz, final boolean alwaysAdd) {
if (groupName == null)
groupName = DEFAULT_GROUPNAME;
final Component[] children = getChildren(c);
final int[] groupRange = getRange(children, groupName);
final T res;
if (groupRange == null) {
if (children.length > 0)
c.add(new JSeparator());
res = created;
c.add(res);
} else {
final T existingChild = alwaysAdd ? null : findChild(children, groupRange, created.getText(), clazz);
if (existingChild != null) {
res = existingChild;
} else {
res = created;
// add after the last of the group (groupRange[1] is exclusive)
// from Container.addImpl() index can be equal to count() to add at the end
c.add(res, groupRange[1]);
}
}
res.putClientProperty(GROUPNAME_PROPNAME, groupName);
return res;
}
 
// search for the range (inclusive, exclusive) of children that are in the passed group
static private int[] getRange(final Component[] children, String groupName) {
int min = -1;
int max = -1;
for (int i = 0; i < children.length; i++) {
if (groupName.equals(((JComponent) children[i]).getClientProperty(GROUPNAME_PROPNAME))) {
if (min < 0)
min = i;
if (max < i)
max = i;
}
}
// inclusive, exclusive
return min == -1 ? null : new int[] { min, max + 1 };
}
 
/**
* Find a child with the passed class and text.
*
* @param <T> type of child
* @param c the parent.
* @param name the text of the child.
* @param clazz the class of the child.
* @return the child found or <code>null</code>.
*/
static public <T extends JMenuItem> T findChild(final Container c, final String name, Class<T> clazz) {
return findChild(getChildren(c), null, name, clazz);
}
 
static private <T extends JMenuItem> T findChild(final Component[] children, int[] range, final String name, Class<T> clazz) {
if (range == null)
range = new int[] { 0, children.length };
for (int groupIndex = range[0]; groupIndex < range[1]; groupIndex++) {
final Component child = children[groupIndex];
if (clazz == child.getClass()) {
final T casted = clazz.cast(child);
if (name.equals(casted.getText())) {
return casted;
}
}
}
return null;
}
 
/**
* Remove the passed item from its menu. This method handles the cleanup of separator and empty
* menus.
*
* @param item the item to remove.
*/
static public void removeMenuItem(final JMenuItem item) {
Container parent = detachItem(item);
// have to use getAncestorOrSelf() since there are JPopupMenu everywhere
JMenu menu = SwingThreadUtils.getAncestorOrSelf(JMenu.class, parent);
while (menu != null && menu.getMenuComponentCount() == 0) {
parent = detachItem(menu);
menu = SwingThreadUtils.getAncestorOrSelf(JMenu.class, parent);
}
}
 
// remove item from its parent and cleanup separator
static private Container detachItem(final JComponent item) {
Container parent = item.getParent();
final Component[] siblings = parent.getComponents();
final int index = Arrays.asList(siblings).indexOf(item);
final boolean sepBefore = index > 0 && siblings[index - 1] instanceof JSeparator;
final boolean sepAfter = index < siblings.length - 1 && siblings[index + 1] instanceof JSeparator;
parent.remove(index);
// ATTN siblings.length is before removing item
if (siblings.length > 1) {
if ((sepBefore && sepAfter) || (sepAfter && index == 0)) {
parent.remove(index);
} else if (sepBefore && index == siblings.length - 1) {
parent.remove(index - 1);
}
}
((JComponent) parent).revalidate();
// needed at least when removing the last menu of a menu bar
parent.repaint();
return parent;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/ISpinner.java
43,6 → 43,12
}
 
@Override
public void removeValidListener(ValidListener l) {
// TODO Auto-generated method stub
}
 
@Override
public String getValidationText() {
// TODO Auto-generated method stub
return null;
/trunk/OpenConcerto/src/org/openconcerto/ui/TextAreaTableCellEditor.java
17,6 → 17,7
import org.openconcerto.utils.text.LimitedSizeDocumentFilter;
import org.openconcerto.utils.text.DocumentFilterList.FilterType;
 
import java.awt.Color;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
31,6 → 32,7
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.TableCellEditor;
43,7 → 45,8
final JTextArea textArea = new JTextArea();
 
public TextAreaTableCellEditor(final JTable t) {
 
// Mimic JTable.GenericEditor behavior
this.textArea.setBorder(new LineBorder(Color.black));
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
/trunk/OpenConcerto/src/org/openconcerto/ui/JDateTime.java
148,6 → 148,11
}
 
@Override
public void removeValidListener(ValidListener l) {
// nothing to do
}
 
@Override
public String getValidationText() {
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/table/AlternateTableCellRenderer.java
33,7 → 33,7
*
* @author Sylvain
*/
public class AlternateTableCellRenderer implements TableCellRenderer {
public class AlternateTableCellRenderer extends TableCellRendererDecorator {
 
public static final Color COLOR_LIGHT_GRAY = new Color(243, 243, 243);
public static final Color DEFAULT_BG_COLOR = Color.WHITE;
118,23 → 118,13
}
};
 
/**
* Set the cell renderer of all the columns of <code>jTable</code> to an
* AlternateTableCellRenderer.
*
* @param jTable the wannabe iTunes jTable.
*/
static public void setAllColumns(final JTable jTable) {
for (int i = 0; i < jTable.getColumnModel().getColumnCount(); i++) {
setRenderer(jTable.getColumnModel().getColumn(i));
}
}
static public final TableCellRendererDecoratorUtils<AlternateTableCellRenderer> UTILS = createUtils(AlternateTableCellRenderer.class);
 
private static final PropertyChangeListener RENDERER_L = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("cellRenderer".equals(evt.getPropertyName())) {
setRenderer((TableColumn) evt.getSource());
UTILS.setRenderer((TableColumn) evt.getSource());
}
}
};
147,35 → 137,24
}
 
static public final void setRenderer(final TableColumn col) {
final TableCellRenderer currentRenderer = col.getCellRenderer();
if (!(currentRenderer instanceof AlternateTableCellRenderer))
col.setCellRenderer(new AlternateTableCellRenderer(currentRenderer));
UTILS.setRenderer(col);
}
 
static public void clearColumns(JTable jTable) {
for (int i = 0; i < jTable.getColumnModel().getColumnCount(); i++) {
final TableColumn tc = jTable.getColumnModel().getColumn(i);
tc.setCellRenderer(null);
}
}
 
static public AlternateTableCellRenderer createDefault() {
return new AlternateTableCellRenderer(new DefaultTableCellRenderer());
}
 
private final TableCellRenderer renderer;
 
public AlternateTableCellRenderer() {
this(null);
}
 
public AlternateTableCellRenderer(TableCellRenderer renderer) {
this.renderer = renderer;
super(renderer);
}
 
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
TableCellRenderer tableRenderer = this.getRenderer(table, row, column);
TableCellRenderer tableRenderer = this.getRenderer(table, column);
if (tableRenderer instanceof IAlternateTableCellRenderer) {
return ((IAlternateTableCellRenderer) tableRenderer).getAlternateTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
} else {
187,8 → 166,4
}
}
}
 
private TableCellRenderer getRenderer(JTable table, int row, int column) {
return this.renderer == null ? table.getDefaultRenderer(table.getColumnClass(column)) : this.renderer;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/table/TableCellRendererDecorator.java
New file
0,0 → 1,191
/*
* 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.table;
 
import org.openconcerto.utils.cc.IPredicate;
import org.openconcerto.utils.cc.ITransformer;
 
import java.lang.reflect.Constructor;
 
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
 
/**
* A renderer that decorates another one.
*
* @author Sylvain
*/
public abstract class TableCellRendererDecorator implements TableCellRenderer {
 
static private final <T extends TableCellRendererDecorator> ITransformer<TableCellRenderer, T> getTransf(final Class<T> clazz) {
final Constructor<T> ctor;
try {
ctor = clazz.getConstructor(TableCellRenderer.class);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Missing TableCellRenderer constructor in " + clazz);
}
return new ITransformer<TableCellRenderer, T>() {
@Override
public T transformChecked(TableCellRenderer input) {
try {
return ctor.newInstance(input);
} catch (Exception e) {
throw new IllegalStateException("Couldn't create a " + clazz + " with " + input);
}
}
};
}
 
// syntactic sugar
static protected final <T extends TableCellRendererDecorator> TableCellRendererDecoratorUtils<T> createUtils(final Class<T> clazz) {
return new TableCellRendererDecoratorUtils<T>(clazz);
}
 
static public class TableCellRendererDecoratorUtils<T extends TableCellRendererDecorator> {
 
private final Class<T> clazz;
private final ITransformer<TableCellRenderer, T> transf;
private final T nullRenderer;
 
protected TableCellRendererDecoratorUtils(final Class<T> clazz) {
this(clazz, getTransf(clazz));
}
 
protected TableCellRendererDecoratorUtils(final Class<T> clazz, final ITransformer<TableCellRenderer, T> transf) {
super();
this.clazz = clazz;
this.transf = transf;
this.nullRenderer = transf.transformChecked(null);
}
 
protected final T getDecoratedRenderer(final TableCellRenderer currentRenderer) {
final T res = currentRenderer == null ? this.nullRenderer : this.transf.transformChecked(currentRenderer);
assert res != null;
return res;
}
 
/**
* Set the cell renderer of all the columns of <code>jTable</code> to an instance of
* <code>T</code>.
*
* @param jTable the jTable which will have its columns changed.
* @see #setRenderer(TableColumn)
*/
public final void setAllColumns(final JTable jTable) {
for (int i = 0; i < jTable.getColumnModel().getColumnCount(); i++) {
setRenderer(jTable.getColumnModel().getColumn(i));
}
}
 
/**
* Change the renderer of <code>col</code> if it doesn't already use a
* TableCellRendererDecorator of this class.
*
* @param col the column to change.
*/
public final void setRenderer(final TableColumn col) {
final TableCellRenderer currentRenderer = col.getCellRenderer();
final TableCellRenderer newR = getRenderer(currentRenderer);
if (currentRenderer != newR)
col.setCellRenderer(newR);
}
 
public final TableCellRenderer getRenderer(final TableCellRenderer currentRenderer) {
return getRenderer(currentRenderer, new IPredicate<TableCellRenderer>() {
@Override
public boolean evaluateChecked(TableCellRenderer input) {
return replaces(input);
}
});
}
 
public final boolean alreadyDecorates(final TableCellRenderer currentRenderer) {
TableCellRenderer r = currentRenderer;
boolean decorates = false;
while (!decorates && r != null) {
if (doesTheSame(r))
decorates = true;
r = r instanceof TableCellRendererDecorator ? ((TableCellRendererDecorator) r).renderer : null;
}
return decorates;
}
 
// walk through the decorators of currentRenderer adding this renderer if necessary
private final TableCellRenderer getRenderer(final TableCellRenderer currentRenderer, final IPredicate<? super TableCellRenderer> toReplace) {
TableCellRenderer res = currentRenderer;
TableCellRenderer r = currentRenderer;
TableCellRendererDecorator previousR = null;
boolean needToCreate = true;
// create only one renderer
while (needToCreate && r != null) {
final TableCellRendererDecorator decorator = r instanceof TableCellRendererDecorator ? (TableCellRendererDecorator) r : null;
final TableCellRenderer next = decorator != null ? decorator.renderer : null;
if (doesTheSame(r)) {
needToCreate = false;
} else if (toReplace.evaluateChecked(r)) {
final T created = getDecoratedRenderer(next);
if (previousR == null)
res = created;
else
previousR.setRenderer(created);
needToCreate = false;
}
previousR = decorator;
r = next;
}
return needToCreate ? getDecoratedRenderer(res) : res;
}
 
// if true a new TableCellRendererDecorator won't be created
protected boolean doesTheSame(final TableCellRenderer r) {
return r.getClass() == this.clazz;
}
 
// if true r will be replaced by a new instance of this decorator
protected boolean replaces(final TableCellRenderer r) {
return false;
}
}
 
static public void clearColumns(JTable jTable) {
for (int i = 0; i < jTable.getColumnModel().getColumnCount(); i++) {
final TableColumn tc = jTable.getColumnModel().getColumn(i);
tc.setCellRenderer(null);
}
}
 
private TableCellRenderer renderer;
 
public TableCellRendererDecorator() {
this(null);
}
 
public TableCellRendererDecorator(TableCellRenderer renderer) {
this.renderer = renderer;
}
 
protected final TableCellRenderer getRenderer(JTable table, int column) {
return this.renderer == null ? table.getDefaultRenderer(table.getColumnClass(column)) : this.renderer;
}
 
protected final void setRenderer(TableCellRenderer renderer) {
this.renderer = renderer;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " on <" + this.renderer + ">";
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/JTime.java
169,6 → 169,11
}
 
@Override
public void removeValidListener(ValidListener l) {
// nothing to do
}
 
@Override
public String getValidationText() {
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/EnhancedTable.java
13,6 → 13,7
package org.openconcerto.ui;
 
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
83,7 → 84,8
*/
private void initUI() {
setUI(new EnhancedTableUI());
 
// Fix for Nimbus L&F http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6594663
this.setIntercellSpacing(new Dimension(1, 1));
};
 
public int rowAtPoint(Point point) {
402,23 → 404,19
 
@Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
resizeAndRepaint();
// If call resizeAndRepaint(); infinite repaints on OpenSuse...
}
 
@Override
public void paintComponents(Graphics g) {
// TODO Auto-generated method stub
super.paintComponents(g);
resizeAndRepaint();
}
 
public void repaint() {
 
if (!blockRepaint) {
// System.out.println("--------------- EnhancedTable.repaint()");
;
// Thread.dumpStack();
super.repaint();
}
480,4 → 478,16
super.resizeAndRepaint();
// System.out.println("*- EnhancedTable.resizeAndRepaint()" + this.getSize() + " done");
}
 
@Override
public boolean getShowHorizontalLines() {
// Fix for Nimbus L&F http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6594663
return true;
}
 
@Override
public boolean getShowVerticalLines() {
// Fix for Nimbus L&F http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6594663
return true;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextSelector.java
372,10 → 372,14
}
 
public void addValidListener(final ValidListener l) {
// nothing to do
this.supp.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.supp.removeValidListener(l);
}
 
// document
public Document getDocument() {
if (this.isLocked())
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextCombo.java
46,8 → 46,8
import javax.swing.event.DocumentEvent;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter.FilterBypass;
import javax.swing.text.JTextComponent;
import javax.swing.text.DocumentFilter.FilterBypass;
 
/**
* A comboBox that can be editable or not, and whose values are taken from a ITextComboCache.
404,6 → 404,11
// nothing to do
}
 
@Override
public void removeValidListener(ValidListener l) {
// nothing to do
}
 
public String getValidationText() {
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/component/combo/ISearchableCombo.java
1077,6 → 1077,11
this.supp.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.supp.removeValidListener(l);
}
 
// document
 
public Document getDocument() {
/trunk/OpenConcerto/src/org/openconcerto/ui/tips/TipsFrame.java
122,9 → 122,8
 
this.setContentPane(panel);
 
pack();
this.setResizable(false);
this.pack();
checkBox.addActionListener(new ActionListener() {
 
@Override
134,9 → 133,6
}
});
}
 
protected void checkBoxModified(boolean selected) {
153,7 → 149,7
}
currentIndex = i % this.tips.size();
// Le panel du tips doit faire 640,480;
 
synchronized (getTreeLock()) {
this.remove(currentPanel);
this.invalidate();
currentPanel = this.tips.get(i).getPanel();
161,6 → 157,7
currentPanel.setPreferredSize(new Dimension(480, H));
this.add(currentPanel, constraintPanel);
this.validateTree();
}
this.repaint();
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/TextAreaRenderer.java
20,6 → 20,7
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumnModel;
 
33,11 → 34,27
public final static Color couleurBonMore = new Color(243, 233, 194);
public final static Color couleurBonDark = couleurBon.darker();
 
JTextArea area = new JTextArea();
final JTextArea area;
private JTable currentTable;
private int currentRow;
 
public TextAreaRenderer() {
if (UIManager.getLookAndFeel().getName().equalsIgnoreCase("nimbus")) {
this.area = new JTextArea() {
// remplace le bord blanc des JTextArea de Nimbus
protected void paintComponent(java.awt.Graphics g) {
final Color c = g.getColor();
final Color background = getBackground();
g.setColor(background);
g.fillRect(0, 0, TextAreaRenderer.this.area.getWidth(), TextAreaRenderer.this.area.getHeight());
g.setColor(c);
super.paintComponent(g);
};
 
};
} else {
this.area = new JTextArea();
}
this.area.setLineWrap(true);
this.area.setWrapStyleWord(true);
}
/trunk/OpenConcerto/src/org/openconcerto/odtemplate/engine/Material.java
13,9 → 13,9
package org.openconcerto.odtemplate.engine;
 
import org.openconcerto.openoffice.XMLVersion;
import org.openconcerto.openoffice.ODPackage;
import org.openconcerto.openoffice.ODXMLDocument;
import org.openconcerto.openoffice.OOXML;
import org.openconcerto.utils.CopyUtils;
 
import java.io.File;
84,8 → 84,8
return this.whole;
}
 
public XMLVersion getNS() {
return XMLVersion.getVersion(this.getRoot());
public OOXML getNS() {
return OOXML.get(this.getRoot());
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/odtemplate/engine/Processor.java
15,7 → 15,6
 
import org.openconcerto.odtemplate.TemplateException;
import org.openconcerto.odtemplate.statements.Statement;
import org.openconcerto.openoffice.XMLVersion;
import org.openconcerto.openoffice.OOUtils;
import org.openconcerto.openoffice.OOXML;
import org.openconcerto.utils.ExceptionUtils;
64,7 → 63,7
private static Logger logger = Logger.getLogger(Processor.class.getName());
 
private final Parsed<E> parsed;
private final XMLVersion ns;
private final OOXML ns;
// to workaround OO, see getChildren()
private final XPath xp;
private final DataModel model;
76,7 → 75,7
this.model = model;
this.ns = this.parsed.getSource().getNS();
try {
this.xp = OOUtils.getXPath(".//text:span", this.ns);
this.xp = OOUtils.getXPath(".//text:span", this.ns.getVersion());
} catch (JDOMException e) {
throw ExceptionUtils.createExn(TemplateException.class, "xpath error", e);
}
148,7 → 147,7
* @throws TemplateException if the field cannot be evaluated.
*/
private void replaceField(Element field) throws TemplateException {
String expression = field.getAttributeValue("description", this.ns.getTEXT());
String expression = field.getAttributeValue("description", this.ns.getVersion().getTEXT());
 
final boolean asString = expression.startsWith(AS_STR);
if (asString)
161,11 → 160,11
expression = expression.substring(ENCODE.length());
 
field.setName("span");
field.setNamespace(this.ns.getTEXT());
field.setNamespace(this.ns.getVersion().getTEXT());
Object value = this.model.eval(expression);
if (value != null) {
if (encode)
value = OOXML.get(this.ns).encodeWS(value.toString());
value = this.ns.encodeWS(value.toString());
else if (isOOXML) {
try {
value = this.parse(value.toString());
220,7 → 219,7
}
 
private Element parse(String ooxml) throws JDOMException {
return JDOMUtils.parseElementString("<dummy>" + ooxml + "</dummy>", this.ns.getALL());
return JDOMUtils.parseElementString("<dummy>" + ooxml + "</dummy>", this.ns.getVersion().getALL());
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ShowAs.java
59,7 → 59,7
this.clearCache();
}
 
public List getFieldExpand(SQLTable table) {
public List<SQLField> getFieldExpand(SQLTable table) {
return this.byTables.get(table);
}
 
84,7 → 84,7
}
}
 
private final List<SQLField> namesToFields(final List<String> names, final SQLTable table) {
static private final List<SQLField> namesToFields(final List<String> names, final SQLTable table) {
final List<SQLField> res = new ArrayList<SQLField>(names.size());
for (final String fieldName : names) {
res.add(table.getField(fieldName));
92,6 → 92,21
return res;
}
 
// TODO a listener to remove tables and fields as they are dropped
public final void removeTable(SQLTable t) {
this.byTables.remove(t);
for (final SQLField f : t.getFields())
this.byFields.remove(f);
this.clearCache();
}
 
public final void clear() {
this.setRoot(null);
this.byTables.clear();
this.byFields.clear();
this.clearCache();
}
 
// *** byTables
 
public void show(String tableName, String... fields) {
143,6 → 158,7
 
// *** expand
 
@Override
protected List<SQLField> expandOnce(SQLField field) {
// c'est une clef externe, donc elle pointe sur une table
final SQLTable foreignTable = field.getTable().getBase().getGraph().getForeignTable(field);
168,6 → 184,7
return this.simpleExpand(getField(fieldName));
}
 
@Override
public String toString() {
return super.toString() + " byTables: " + this.byTables + " byFields: " + this.byFields;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextWithCompletion.java
149,7 → 149,11
private boolean consume;
 
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (e.getKeyCode() == KeyEvent.VK_TAB) {
// Complete si exactement la valeur souhaitée
updateAutoCompletion(true);
e.consume();
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (ITextWithCompletion.this.popup.isShowing()) {
ITextWithCompletion.this.popup.selectNext();
e.consume();
181,13 → 185,12
ITextWithCompletion.this.popup.selectPreviousPage();
e.consume();
}
} else {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if (ITextWithCompletion.this.popup.isShowing()) {
hidePopup();
}
 
}
}
 
// else {
// if (e.getKeyCode() != KeyEvent.VK_RIGHT && e.getKeyCode() !=
265,8 → 268,6
}
final SwingWorker worker = new SwingWorker<Object, Object>() {
 
 
// Runs on the event-dispatching thread.
@Override
public void done() {
296,7 → 297,9
*/
List<IComboSelectionItem> getPossibleValues(String aText) {
List<IComboSelectionItem> result = new Vector<IComboSelectionItem>();
 
if (aText.isEmpty()) {
return result;
}
Map<String, IComboSelectionItem> map = new HashMap<String, IComboSelectionItem>();
 
aText = aText.trim().toLowerCase();
353,19 → 356,16
}
 
private List<String> cut(String value) {
Vector<String> v = new Vector<String>();
StringTokenizer tokenizer = new StringTokenizer(value);
final Vector<String> v = new Vector<String>();
final StringTokenizer tokenizer = new StringTokenizer(value);
while (tokenizer.hasMoreElements()) {
String element = (String) tokenizer.nextElement();
 
final String element = (String) tokenizer.nextElement();
v.add(element.toLowerCase());
 
}
 
return v;
}
 
private void updateAutoCompletion() {
private void updateAutoCompletion(boolean autoselectIfMatch) {
if (!this.isCompletionEnabled() || this.isLoading) {
return;
}
389,14 → 389,12
hidePopup();
}
// Le texte dans la case n'est pas celui d'un id
// boolean isInCombo=false;
// this.selectedId = -1;
 
int newId = this.selectedId;
boolean found = false;
for (Iterator<IComboSelectionItem> iter = l.iterator(); iter.hasNext();) {
IComboSelectionItem element = iter.next();
if (element.getLabel().equalsIgnoreCase(t) && l.size() == 1) {
 
if (element.getLabel().equalsIgnoreCase(t) && autoselectIfMatch) {
newId = element.getId();
hidePopup();
found = true;
409,10 → 407,8
public void run() {
ITextWithCompletion.this.fireSelectionId(ITextWithCompletion.this.getSelectedId());
}
});
}
 
);
}
if (!found) {
this.selectedId = -1;
fireSelectionId(-1);
431,17 → 427,17
}
 
public void changedUpdate(DocumentEvent e) {
updateAutoCompletion();
updateAutoCompletion(false);
this.supp.firePropertyChange("value", null, this.getText());
}
 
public void insertUpdate(DocumentEvent e) {
updateAutoCompletion();
updateAutoCompletion(false);
this.supp.firePropertyChange("value", null, this.getText());
}
 
public void removeUpdate(DocumentEvent e) {
updateAutoCompletion();
updateAutoCompletion(false);
this.supp.firePropertyChange("value", null, this.getText());
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/SQLTextCombo.java
14,7 → 14,7
package org.openconcerto.sql.sqlobject;
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowValues;
57,16 → 57,20
this.initCache(cache);
}
 
static class ITextComboCacheSQL implements ITextComboCache {
static public class ITextComboCacheSQL implements ITextComboCache {
 
private final SQLField field;
private final String field;
private final SQLTable t;
private final List<String> cache;
private boolean loadedOnce;
 
public ITextComboCacheSQL(final SQLField f) {
this.field = f;
this.t = this.field.getDBRoot().findTable("COMPLETION");
this(f.getDBRoot(), f.getFullName());
}
 
public ITextComboCacheSQL(final DBRoot r, final String id) {
this.field = id;
this.t = r.findTable("COMPLETION");
if (!this.isValid())
Log.get().warning("no completion found for " + this.field);
this.cache = new ArrayList<String>();
85,7 → 89,7
public List<String> loadCache() {
final SQLSelect sel = new SQLSelect(this.t.getBase());
sel.addSelect(this.t.getField("LABEL"));
sel.setWhere(new Where(this.t.getField("CHAMP"), "=", this.field.getFullName()));
sel.setWhere(new Where(this.t.getField("CHAMP"), "=", this.field));
this.cache.clear();
this.cache.addAll(this.getDS().executeCol(sel.asString()));
 
103,7 → 107,7
public void addToCache(String string) {
if (!this.cache.contains(string)) {
final Map<String, Object> m = new HashMap<String, Object>();
m.put("CHAMP", this.field.getFullName());
m.put("CHAMP", this.field);
m.put("LABEL", string);
try {
// the primary key is not generated so don't let SQLRowValues remove it.
116,8 → 120,8
}
 
public void deleteFromCache(String string) {
String req = "DELETE FROM \"COMPLETION\" WHERE \"CHAMP\"= " + SQLBase.quoteStringStd(this.field.getFullName()) + " AND \"LABEL\"=" + SQLBase.quoteStringStd(string);
this.getDS().executeScalar(req);
final Where w = new Where(this.t.getField("CHAMP"), "=", this.field).and(new Where(this.t.getField("LABEL"), "=", string));
this.getDS().executeScalar("DELETE FROM " + this.t.getSQLName().quote() + " WHERE " + w.getClause());
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/JUniqueTextField.java
442,6 → 442,11
this.supp.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.supp.removeValidListener(l);
}
 
public void rmValueListener(PropertyChangeListener l) {
this.supp.rmValueListener(l);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/SQLSearchableTextCombo.java
63,7 → 63,16
 
public void init(SQLRowItemView v) {
// after uiInit since our superclass add listeners to our UI
final ISQLListModel cache = new ISQLListModel(v.getField());
this.initCacheLater(new ISQLListModel(v.getField()));
}
 
/**
* Load <code>cache</code> and only afterwards call
* {@link #initCache(org.openconcerto.utils.model.IListModel)}.
*
* @param cache the cache to set.
*/
public void initCacheLater(final ISQLListModel cache) {
cache.load(new Runnable() {
@Override
public void run() {
72,13 → 81,17
});
}
 
private static class ISQLListModel extends DefaultIMutableListModel<String> {
public static class ISQLListModel extends DefaultIMutableListModel<String> {
 
private final ITextComboCacheSQL cache;
private final ListDataListener l;
 
public ISQLListModel(final SQLField f) {
this.cache = new ITextComboCacheSQL(f);
this(new ITextComboCacheSQL(f));
}
 
public ISQLListModel(final ITextComboCacheSQL c) {
this.cache = c;
this.l = new ListDataListener() {
 
@SuppressWarnings("unchecked")
135,6 → 148,7
e1.printStackTrace();
}
addListDataListener(ISQLListModel.this.l);
if (r != null)
r.run();
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/SQLRequestComboBox.java
466,6 → 466,11
this.supp.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.supp.removeValidListener(l);
}
 
public String getValidationText() {
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextWithCompletionPopUp.java
93,16 → 93,12
 
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
System.out.println("Largeur:" + d.width);
int width = d.width;
if (width > 500)
width = 500;
System.out.println(this.getBounds());
width = Math.max(width, this.minWitdh) + 2;
int height = 2 + 17 * Math.min(listModel.getSize(), MAXROW);
Dimension newD = new Dimension(width, height);
System.out.println("ITextWithCompletionPopUp.getPreferredSize()");
System.out.println("->taille du model:" + listModel.getSize() + " -> Dimension:" + newD);
return newD;
}
 
138,7 → 134,6
index = listModel.getSize() - 1;
}
if (this.list.getSelectedIndex() != index) {
System.out.println("->" + index);
this.list.setSelectedIndex(index);
if (shouldScroll)
this.list.ensureIndexIsVisible(index);
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/itemview/VWRowItemView.java
64,7 → 64,7
 
/**
* The predicate testing whether the value is empty or not. This implementation returns
* {@link EmptyObjFromVO#DEFAULT_PREDICATE}}
* {@link EmptyObjFromVO#DEFAULT_PREDICATE}
*
* @return the predicate testing whether the value is empty.
*/
115,6 → 115,11
this.getWrapper().addValidListener(new ChainValidListener(this, l));
}
 
@Override
public void removeValidListener(ValidListener l) {
this.getWrapper().removeValidListener(new ChainValidListener(this, l));
}
 
public String getValidationText() {
return this.getWrapper().getValidationText();
}
/trunk/OpenConcerto/src/org/openconcerto/sql/request/BaseFillSQLRequest.java
117,10 → 117,10
protected final SQLRowValuesListFetcher getFetcher(final Where w) {
final String tableName = getPrimaryTable().getName();
final SQLRowValuesListFetcher fetcher = new SQLRowValuesListFetcher(getGraphToFetch(), true);
// ignore LOCAL in archived BATIMENT, since IListe always expect a BATIMENT
// works for now because LOCAL w/o OBS point to OBS[1]
fetcher.setFullOnly(true);
fetcher.setIncludeForeignUndef(true);
// include rows having NULL (not undefined ID) foreign keys
fetcher.setFullOnly(false);
// treat the same way tables with or without undefined ID
fetcher.setIncludeForeignUndef(false);
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect sel) {
/trunk/OpenConcerto/src/org/openconcerto/sql/request/ComboSQLRequest.java
33,6 → 33,7
import org.openconcerto.utils.Tuple3;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.IPredicate;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
208,13 → 209,14
else
desc = CollectionUtils.join(this.exp.expandGroupBy(this.getFields()), SEP_CHILD, new ITransformer<Tuple2<Path, List<FieldPath>>, Object>() {
public Object transformChecked(Tuple2<Path, List<FieldPath>> ancestorFields) {
return CollectionUtils.join(ancestorFields.get1(), ComboSQLRequest.this.fieldSeparator, new ITransformer<FieldPath, String>() {
final List<String> filtered = CollectionUtils.transformAndFilter(ancestorFields.get1(), new ITransformer<FieldPath, String>() {
// no need to keep this Transformer in an attribute
// even when creating one per line it's the same speed
public String transformChecked(FieldPath input) {
return getFinalValueOf(input, rs);
}
});
}, IPredicate.notNullPredicate(), new ArrayList<String>());
return CollectionUtils.join(filtered, ComboSQLRequest.this.fieldSeparator);
}
});
final IComboSelectionItem res = new IComboSelectionItem(rs.getID(), desc);
236,8 → 238,7
* @return la valeur du champ en String.
*/
protected static String getFinalValueOf(FieldPath element, SQLRowValues rs) {
String result = "";
result = rs.followPath(element.getPath()).getString(element.getFieldName());
String result = element.getString(rs);
// TODO
// if (element.getType() == "FLOAT") {
// result = result.replace('.', ',');
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
25,14 → 25,18
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.graph.DatabaseGraph;
import org.openconcerto.sql.model.graph.Link;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.request.SQLCache;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.RowActionFactory;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelColumnPath;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
44,8 → 48,11
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.change.ListChangeIndex;
import org.openconcerto.utils.change.ListChangeRecorder;
 
import java.awt.Component;
import java.awt.Container;
import java.lang.reflect.Constructor;
import java.sql.SQLException;
import java.util.ArrayList;
61,7 → 68,9
import java.util.SortedMap;
import java.util.logging.Level;
 
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.text.JTextComponent;
 
import org.apache.commons.collections.MapIterator;
import org.apache.commons.collections.MultiMap;
96,7 → 105,8
private ComboSQLRequest combo;
private ListSQLRequest list;
private SQLTableModelSourceOnline tableSrc;
 
private final ListChangeRecorder<RowAction> rowActions;
private final List<RowActionFactory> rowActionFactories;
// foreign fields
private Set<String> normalFF;
private String parentFF;
110,6 → 120,8
// lazy creation
private SQLCache<SQLRowAccessor, Object> modelCache;
 
private final Map<String, JComponent> additionalFields;
 
public SQLElement(String singular, String plural, SQLTable primaryTable) {
super();
this.singular = singular;
120,18 → 132,29
this.primaryTable = primaryTable;
this.combo = null;
this.list = null;
this.rowActions = new ListChangeRecorder<RowAction>(new ArrayList<RowAction>());
this.rowActionFactories = new ArrayList<RowActionFactory>();
this.actions = new HashMap<String, ReferenceAction>();
this.resetRelationships();
 
this.modelCache = null;
 
this.additionalFields = new HashMap<String, JComponent>();
}
 
/**
* Must be called if foreign/referent keys are added or removed.
*/
public synchronized void resetRelationships() {
this.privateFF = null;
this.parentFF = null;
this.normalFF = null;
this.sharedFF = null;
this.actions = new HashMap<String, ReferenceAction>();
this.actions.clear();
 
this.childRF = null;
this.privateParentRF = null;
this.otherRF = null;
 
this.modelCache = null;
}
 
private void checkSelfCall(boolean check, final String methodName) {
246,7 → 269,7
return;
this.childRF = computingRF;
 
final Set children = this.computeChildrenRF();
final Set<SQLField> children = this.computeChildrenRF();
 
final Set<SQLField> tmpChildRF = new HashSet<SQLField>();
for (final SQLField refField : this.getTable().getBase().getGraph().getReferentKeys(this.getTable())) {
524,8 → 547,8
final MapIterator refIter = new EntrySetMapIterator(externReferences);
while (refIter.hasNext()) {
final SQLField refKey = (SQLField) refIter.next();
final Collection refList = (Collection) refIter.getValue();
final Iterator listIter = refList.iterator();
final Collection<?> refList = (Collection<?>) refIter.getValue();
final Iterator<?> listIter = refList.iterator();
while (listIter.hasNext()) {
final SQLRow ref = (SQLRow) listIter.next();
ref.createEmptyUpdateRow().putEmptyLink(refKey.getName()).update();
730,8 → 753,7
}
 
/**
* Specify an action for a normal foreign field. Should be called from {@link #ffInited()} to
* avoid infinite loop.
* Specify an action for a normal foreign field.
*
* @param ff the foreign field name.
* @param action what to do if a referenced row must be archived.
815,13 → 837,17
 
abstract protected List<String> getComboFields();
 
public synchronized ListSQLRequest getListRequest() {
public final synchronized ListSQLRequest getListRequest() {
if (this.list == null) {
this.list = new ListSQLRequest(this.getTable(), this.getListFields());
this.list = createListRequest();
}
return this.list;
}
 
protected ListSQLRequest createListRequest() {
return new ListSQLRequest(this.getTable(), this.getListFields());
}
 
public final SQLTableModelSourceOnline getTableSource() {
return this.getTableSource(!cacheTableSource());
}
843,8 → 869,27
return this.createAndInitTableSource();
}
 
public final SQLTableModelSourceOnline createTableSource(final List<String> fields) {
return initTableSource(new SQLTableModelSourceOnline(new ListSQLRequest(this.getTable(), fields)));
}
 
public final SQLTableModelSourceOnline createTableSource(final Where w) {
final SQLTableModelSourceOnline res = this.getTableSource(true);
res.getReq().setWhere(w);
return res;
}
 
private final SQLTableModelSourceOnline createAndInitTableSource() {
final SQLTableModelSourceOnline res = this.createTableSource();
return initTableSource(res);
}
 
protected synchronized void _initTableSource(final SQLTableModelSourceOnline res) {
}
 
public final synchronized SQLTableModelSourceOnline initTableSource(final SQLTableModelSourceOnline res) {
// do init first since it can modify the columns
this._initTableSource(res);
// setEditable(false) on read only fields
// MAYBE setReadOnlyFields() on SQLTableModelSource, so that SQLTableModelLinesSource can
// check in commit()
857,7 → 902,9
}
 
protected SQLTableModelSourceOnline createTableSource() {
return new SQLTableModelSourceOnline(this.getListRequest());
// also create a new ListSQLRequest, otherwise it's a backdoor to change the behaviour of
// the new TableModelSource
return new SQLTableModelSourceOnline(this.createListRequest());
}
 
/**
872,6 → 919,22
 
abstract protected List<String> getListFields();
 
public final Collection<RowAction> getRowActions() {
return this.rowActions;
}
 
public List<RowActionFactory> getRowActionFactories() {
return this.rowActionFactories;
}
 
public final void addRowActionsListener(final IClosure<ListChangeIndex<RowAction>> listener) {
this.rowActions.getRecipe().addListener(listener);
}
 
public final void removeRowActionsListener(final IClosure<ListChangeIndex<RowAction>> listener) {
this.rowActions.getRecipe().rmListener(listener);
}
 
public String getDescription(SQLRow fromRow) {
return fromRow.toString();
}
1076,9 → 1139,7
final SQLRowValues copy = new SQLRowValues(this.getTable());
copy.loadAllSafe(row);
 
final Iterator iter = this.getPrivateForeignFields().iterator();
while (iter.hasNext()) {
final String privateName = (String) iter.next();
for (final String privateName : this.getPrivateForeignFields()) {
final SQLElement privateElement = this.getPrivateElement(privateName);
if (!privateElement.dontDeepCopy() && !row.isForeignEmpty(privateName)) {
final SQLRowValues child = privateElement.createCopy(row.getInt(privateName));
1202,10 → 1263,10
private Map<String, SQLRow> getNormalForeigns(SQLRow row, final SQLRowMode mode) {
check(row);
final Map<String, SQLRow> mm = new HashMap<String, SQLRow>();
final Iterator iter = this.getNormalForeignFields().iterator();
final Iterator<String> iter = this.getNormalForeignFields().iterator();
while (iter.hasNext()) {
// eg SOURCE.ID_CPI
final String ff = (String) iter.next();
final String ff = iter.next();
// eg CPI[12]
final SQLRow foreignRow = row.getForeignRow(ff, mode);
if (foreignRow != null)
1246,7 → 1307,7
private final Object createModelObject(SQLRowAccessor row) {
if (!RowBacked.class.isAssignableFrom(this.getModelClass()))
throw new IllegalStateException("modelClass must inherit from RowBacked: " + this.getModelClass());
final Constructor ctor;
final Constructor<? extends RowBacked> ctor;
try {
ctor = this.getModelClass().getConstructor(new Class[] { SQLRowAccessor.class });
} catch (Exception e) {
1283,9 → 1344,7
}
 
// les private equals
final Iterator privateIter = this.getPrivateForeignFields().iterator();
while (privateIter.hasNext()) {
final String prvt = (String) privateIter.next();
for (final String prvt : this.getPrivateForeignFields()) {
final SQLElement foreignElement = this.getForeignElement(prvt);
// ne pas tester
if (!foreignElement.dontDeepCopy() && !foreignElement.equals(row.getForeignRow(prvt), row2.getForeignRow(prvt)))
1331,6 → 1390,42
*/
public abstract SQLComponent createComponent();
 
/**
* Allows a module to add a view for a field to this element.
*
* @param field the field of the component.
* @return <code>true</code> if no view existed.
*/
public final boolean putAdditionalField(final String field) {
return this.putAdditionalField(field, (JComponent) null);
}
 
public final boolean putAdditionalField(final String field, final JTextComponent comp) {
return this.putAdditionalField(field, (JComponent) comp);
}
 
public final boolean putAdditionalField(final String field, final SQLTextCombo comp) {
return this.putAdditionalField(field, (JComponent) comp);
}
 
// private as only a few JComponent are OK
private final boolean putAdditionalField(final String field, final JComponent comp) {
if (this.additionalFields.containsKey(field)) {
return false;
} else {
this.additionalFields.put(field, comp);
return true;
}
}
 
public final Map<String, JComponent> getAdditionalFields() {
return Collections.unmodifiableMap(this.additionalFields);
}
 
public final void removeAdditionalField(final String field) {
this.additionalFields.remove(field);
}
 
public final boolean askArchive(final Component comp, final Number ids) {
return this.askArchive(comp, Collections.singleton(ids));
}
1393,6 → 1488,7
}
}
 
@SuppressWarnings("rawtypes")
private final String toString(MultiMap descs) {
final List<String> l = new ArrayList<String>();
final Iterator iter = descs.keySet().iterator();
1431,4 → 1527,5
private final int askSerious(Component comp, String msg, String title) {
return JOptionPane.showConfirmDialog(comp, msg, title + " (" + this.getPluralName() + ")", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java
17,6 → 17,7
package org.openconcerto.sql.element;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.Log;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
33,6 → 34,7
import org.openconcerto.sql.sqlobject.itemview.SimpleRowItemView;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.ui.DisplayabilityListener;
import org.openconcerto.ui.FormLayouter;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.component.ComboLockedMode;
import org.openconcerto.ui.component.text.TextBehaviour;
58,6 → 60,7
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
 
import javax.swing.JCheckBox;
93,6 → 96,7
private boolean alwaysEditable;
private final Set<SQLField> hide;
private String invalidityCause;
private FormLayouter additionalFieldsPanel;
 
public BaseSQLComponent(SQLElement element) {
super(element);
134,18 → 138,18
return this.addViewJComponent(field, spec);
}
 
private Component addViewJComponent(String field, String spec) {
private Component addViewJComponent(String field, Object spec) {
if (getElement().getPrivateElement(field) != null) {
// private
final SQLComponent comp = this.getElement().getPrivateElement(field).createComponent();
 
// TODO add a callback so that RowItemView is notified when added to a SQLComponent
// avoid parsing twice spec, and the 'if instanceof ElementSQLObject'
final SpecParser parser = new SpecParser(spec);
// avoiding the 'if instanceof ElementSQLObject' in addInitedView()
final SpecParser parser = SpecParser.create(spec);
DefaultElementSQLObject dobj = new DefaultElementSQLObject(this, comp);
dobj.setDecorated(parser.isDecorated());
dobj.showSeparator(parser.showSeparator());
return this.addView((MutableRowItemView) dobj, field, spec);
return this.addView((MutableRowItemView) dobj, field, parser);
} else if (getField(field).isKey()) {
// foreign
return this.addView(new ElementComboBox(), field, spec);
227,11 → 231,7
// if (obj == null)
// throw new IllegalArgumentException("obj is null");
 
final Spec spec;
if (specObj == null || specObj instanceof String) {
spec = new SpecParser((String) specObj);
} else
spec = (SpecParser) specObj;
final Spec spec = SpecParser.create(specObj);
 
// ParentForeignField is always required
final String fieldName = v.getField().getName();
243,8 → 243,15
this.getRequest().add(v);
 
if (!this.hide.contains(v.getField())) {
if (spec.isAdditional()) {
if (this.additionalFieldsPanel == null)
Log.get().warning("No additionalFieldsPanel for " + v.getField() + " : " + v);
else
this.additionalFieldsPanel.add(getDesc(v), v.getComp());
} else {
this.addToUI(v, spec.getWhere());
}
}
if (dontEdit(v))
v.setEditable(false);
 
261,6 → 268,16
}
 
protected final void inited() {
super.inited();
for (final Entry<String, JComponent> e : this.getElement().getAdditionalFields().entrySet()) {
final SpecParser spec = new SpecParser(null, true);
final JComponent comp = e.getValue();
if (comp == null)
// infer component
this.addViewJComponent(e.getKey(), spec);
else
this.addView(comp, e.getKey(), spec);
}
// assure that added views are consistent with our editable status
this.setChildrenEditable(this.isEditable());
for (final SQLRowItemView v : this.getRequest().getViews()) {
306,6 → 323,10
// implement it to do nothing since subclass may choose not to use it
}
 
protected final void setAdditionalFieldsPanel(FormLayouter panel) {
this.additionalFieldsPanel = panel;
}
 
public final SQLRowItemView getView(String name) {
return this.getRequest().getView(name);
}
327,6 → 348,11
this.listeners.add(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.listeners.remove(l);
}
 
protected synchronized final void fireValidChange() {
// ATTN called very often during a select() (for each SQLObject empty & value change)
final boolean validated = this.isValidated();
562,16 → 588,34
boolean isRequired();
 
String getWhere();
 
boolean isAdditional();
}
 
private static final class SpecParser implements Spec {
 
static public SpecParser create(Object specObj) {
final SpecParser spec;
if (specObj == null || specObj instanceof String) {
spec = new SpecParser((String) specObj);
} else {
spec = (SpecParser) specObj;
}
return spec;
}
 
private boolean isRequired;
private String where;
private boolean showSeparator = true;
private boolean isDecorated = true;
private final boolean isAdditional;
 
public SpecParser(String spec) {
this(spec, false);
}
 
public SpecParser(String spec, final boolean isAdditional) {
this.isAdditional = isAdditional;
// empty string treated as null
if (spec == null || spec.length() == 0) {
this.isRequired = false;
612,7 → 656,12
public final String getWhere() {
return this.where;
}
 
@Override
public final boolean isAdditional() {
return this.isAdditional;
}
}
 
// *** scrollable
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/UISQLComponent.java
159,6 → 159,7
 
private void setLayouter(int w, int d) {
this.autoLayouter = new FormLayouter(this.currentPanel, w, d);
this.setAdditionalFieldsPanel(this.autoLayouter);
}
 
protected final FormLayouter getLayouter() {
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java
22,9 → 22,12
import org.openconcerto.utils.cc.ITransformer;
 
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
38,6 → 41,7
private final Map<SQLTable, SQLElement> elements;
private final CollectionMap<String, SQLTable> tableNames;
private final CollectionMap<Class<? extends SQLElement>, SQLTable> byClass;
private final List<DirectoryListener> listeners;
 
public SQLElementDirectory() {
this.elements = new HashMap<SQLTable, SQLElement>();
45,6 → 49,8
// the second one should replace the first one
this.tableNames = new CollectionMap<String, SQLTable>(HashSet.class);
this.byClass = new CollectionMap<Class<? extends SQLElement>, SQLTable>(HashSet.class);
 
this.listeners = new ArrayList<DirectoryListener>();
}
 
private static <K> SQLTable getSoleTable(CollectionMap<K, SQLTable> m, K key) throws IllegalArgumentException {
95,7 → 101,10
this.elements.put(elem.getTable(), elem);
this.tableNames.put(elem.getTable().getName(), elem.getTable());
this.byClass.put(elem.getClass(), elem.getTable());
for (final DirectoryListener dl : this.listeners) {
dl.elementAdded(elem);
}
}
 
public synchronized final boolean contains(SQLTable t) {
return this.elements.containsKey(t);
113,7 → 122,7
* <code>tableName</code>.
* @throws IllegalArgumentException if more than one table match.
*/
public final SQLElement getElement(String tableName) {
public synchronized final SQLElement getElement(String tableName) {
return this.getElement(getSoleTable(this.tableNames, tableName));
}
 
125,15 → 134,66
* @return the corresponding SQLElement, or <code>null</code> if none can be found.
* @throws IllegalArgumentException if there's more than one match.
*/
public final <S extends SQLElement> S getElement(Class<S> clazz) {
public synchronized final <S extends SQLElement> S getElement(Class<S> clazz) {
return clazz.cast(this.getElement(getSoleTable(this.byClass, clazz)));
}
 
public synchronized final Set<SQLTable> getTables() {
return this.elements.keySet();
return this.getElementsMap().keySet();
}
 
public synchronized final Collection<SQLElement> getElements() {
return this.elements.values();
return this.getElementsMap().values();
}
 
public final Map<SQLTable, SQLElement> getElementsMap() {
return Collections.unmodifiableMap(this.elements);
}
 
/**
* Remove the passed instance. NOTE: this method only remove the specific instance passed, so
* it's a conditional <code>removeSQLElement(elem.getTable())</code>.
*
* @param elem the instance to remove.
* @see #removeSQLElement(SQLTable)
*/
public synchronized void removeSQLElement(SQLElement elem) {
if (this.getElement(elem.getTable()) == elem)
this.removeSQLElement(elem.getTable());
}
 
/**
* Remove the element for the passed table.
*
* @param t the table to remove.
* @return the removed element, can be <code>null</code>.
*/
public synchronized SQLElement removeSQLElement(SQLTable t) {
final SQLElement elem = this.elements.remove(t);
if (elem != null) {
this.tableNames.remove(elem.getTable().getName(), elem.getTable());
this.byClass.remove(elem.getClass(), elem.getTable());
// MAYBE only reset neighbours.
for (final SQLElement otherElem : this.elements.values())
otherElem.resetRelationships();
for (final DirectoryListener dl : this.listeners) {
dl.elementRemoved(elem);
}
}
return elem;
}
 
public synchronized final void addListener(DirectoryListener dl) {
this.listeners.add(dl);
}
 
public synchronized final void removeListener(DirectoryListener dl) {
this.listeners.remove(dl);
}
 
static public interface DirectoryListener {
void elementAdded(SQLElement elem);
 
void elementRemoved(SQLElement elem);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/ElementSQLObject.java
290,6 → 290,11
this.validSupp.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.validSupp.removeValidListener(l);
}
 
private void fireValidChange() {
this.validSupp.fireValidChange(isValidated());
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/TreesOfSQLRows.java
149,7 → 149,9
final SQLElement refElem = this.elem.getElementLenient(link.getSource());
// play it safe
final ReferenceAction action = refElem != null ? refElem.getActions().get(ffName) : ReferenceAction.RESTRICT;
 
if (action == null) {
throw new IllegalStateException("Null action for " + refElem + " " + ffName);
}
final Map<Integer, SQLRowValues> next = new HashMap<Integer, SQLRowValues>();
final SQLRowValuesListFetcher fetcher = new SQLRowValuesListFetcher(new SQLRowValues(link.getSource()).put(ffName, null));
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
/trunk/OpenConcerto/src/org/openconcerto/sql/navigator/VerticalTextColumn.java
100,7 → 100,6
newImage = this.createImage(this.getWidth(), this.getHeight());
Graphics g = newImage.getGraphics();
Rectangle r = this.getBounds();
System.out.println("paint Tile:" + r);
 
// super.paint(g);
 
137,7 → 136,7
 
AffineTransform at = new AffineTransform();
at.rotate(Math.toRadians(-90), 0, 0);
System.out.println(at);
 
g2.setTransform(at);
g2.drawString(title, x, y);
 
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ReOrder.java
14,6 → 14,7
package org.openconcerto.sql.utils;
 
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSyntax;
23,6 → 24,7
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
 
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
36,6 → 38,11
*/
public abstract class ReOrder {
 
// must be zero so that we can work on negative numbers without breaking the unique constraint
public static final BigDecimal MIN_ORDER = BigDecimal.ZERO;
// preferred distance
public static final BigDecimal DISTANCE = BigDecimal.ONE;
 
static public ReOrder create(final SQLTable t) {
return create(t, ALL);
}
70,7 → 77,11
return this.spec == ALL;
}
 
protected final int getFirst() {
protected final BigDecimal getFirstToReorder() {
return this.spec.getFirstToReorder();
}
 
protected final BigDecimal getFirstOrderValue() {
return this.spec.getFirst();
}
 
92,7 → 103,7
// MAYBE return affected IDs
public final void exec() throws SQLException {
final Connection conn = this.t.getBase().getDataSource().getConnection();
final UpdateBuilder updateUndef = new UpdateBuilder(this.t).set(this.t.getOrderField().getName(), "0");
final UpdateBuilder updateUndef = new UpdateBuilder(this.t).set(this.t.getOrderField().getName(), MIN_ORDER.toPlainString());
updateUndef.setWhere(new Where(this.t.getKey(), "=", this.t.getUndefinedID()));
SQLUtils.executeAtomic(conn, new SQLFactory<Object>() {
@Override
117,25 → 128,49
static private class Some implements Spec {
 
private final SQLTable t;
private final int first;
private final int count;
private final BigDecimal firstToReorder;
private final BigDecimal first;
private final BigDecimal lastToReorder;
 
public Some(final SQLTable t, final int first, final int count) {
this.t = t;
if (first <= 0)
throw new IllegalArgumentException();
this.first = first;
if (count <= 0)
throw new IllegalArgumentException();
this.count = count;
throw new IllegalArgumentException("Negative Count : " + count);
// the row with MIN_ORDER cannot be displayed since no row can be moved before it
// so don't change it
if (BigDecimal.valueOf(first).compareTo(MIN_ORDER) <= 0) {
this.firstToReorder = MIN_ORDER.add(t.getOrderULP());
// make some room before the first non MIN_ORDER row so that another on can came
// before it
this.first = MIN_ORDER.add(DISTANCE);
} else {
this.firstToReorder = BigDecimal.valueOf(first);
this.first = this.firstToReorder;
}
final BigDecimal simpleLastToReorder = this.firstToReorder.add(BigDecimal.valueOf(count));
// needed since first can be different than firstToReorder
this.lastToReorder = simpleLastToReorder.compareTo(this.first) > 0 ? simpleLastToReorder : this.first.add(DISTANCE.movePointRight(1));
// OK since DISTANCE is a lot greater than the ULP of ORDRE
assert this.getFirstToReorder().compareTo(this.getFirst()) <= 0 && this.getFirst().compareTo(this.getLast()) < 0 && this.getLast().compareTo(this.getLastToReorder()) <= 0;
}
 
@Override
public final String getInc() {
final SQLField oF = this.t.getOrderField();
final SQLSyntax syntax = SQLSyntax.get(this.t.getServer().getSQLSystem());
 
// last order of the whole table
final SQLSelect selTableLast = new SQLSelect(this.t.getBase(), true);
selTableLast.addSelect(oF, "MAX");
 
// cast inc to order type to avoid truncation error
return SQLSelect.quote(" cast( ( max( %n ) - min( %n ) ) / ( count(*) -1) as " + syntax.getOrderType() + ") FROM %f where " + this.getWhere(null).getClause(), oF, oF, this.t);
final String avgDistance = " cast( ( " + getLast() + " - " + this.getFirst() + " ) / ( count(*) -1) as " + syntax.getOrderType() + ")";
// if the last order of this Spec is the last order of the table, we can use whatever
// increment we want, we won't span over existing rows. This can be useful when
// reordering densely packed rows, but this means that lastOrderValue won't be equal to
// getLastToReorder().
final String res = "CASE WHEN max(" + SQLBase.quoteIdentifier(oF.getName()) + ") = (" + selTableLast.asString() + ") then " + ALL.getInc() + " else " + avgDistance + " end";
return res + " FROM " + this.t.getSQLName().quote() + " where " + this.getWhere(null).getClause();
}
 
@Override
144,20 → 179,32
order = this.t.getOrderField();
else if (order.getField() != this.t.getOrderField())
throw new IllegalArgumentException();
return new Where(order, this.first, this.first + this.count);
return new Where(order, this.getFirstToReorder(), this.getLastToReorder());
}
 
@Override
public int getFirst() {
public final BigDecimal getFirstToReorder() {
return this.firstToReorder;
}
 
private final BigDecimal getLastToReorder() {
return this.lastToReorder;
}
 
@Override
public BigDecimal getFirst() {
return this.first;
}
 
public final BigDecimal getLast() {
return this.getLastToReorder();
}
}
 
static private Spec ALL = new Spec() {
@Override
public String getInc() {
return "1";
return String.valueOf(DISTANCE);
}
 
@Override
166,9 → 213,14
}
 
@Override
public int getFirst() {
return 0;
public BigDecimal getFirstToReorder() {
return MIN_ORDER;
}
 
@Override
public BigDecimal getFirst() {
return getFirstToReorder();
}
};
 
static interface Spec {
176,6 → 228,10
 
Where getWhere(final FieldRef order);
 
int getFirst();
// before reorder
BigDecimal getFirstToReorder();
 
// the first order value after reorder
BigDecimal getFirst();
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/Diff.java
115,12 → 115,19
return "-- To change " + getDesc(this.a) + t + "\n-- into " + getDesc(this.b) + t + "\n-- \n";
}
 
private Set<String> getTablesUnion() {
return CollectionUtils.union(this.a.getChildrenNames(), this.b.getChildrenNames());
}
 
public final String compute() {
final Set<String> tables = CollectionUtils.union(this.a.getChildrenNames(), this.b.getChildrenNames());
return this.getHeader(null) + this.computeBody(tables);
return this.getHeader(null) + this.computeBody(getTablesUnion());
}
 
private final String computeBody(final Collection<String> tables) {
public final List<ChangeTable<?>> getChangeTables() {
return this.getChangeTables(getTablesUnion());
}
 
public final List<ChangeTable<?>> getChangeTables(final Collection<String> tables) {
final List<ChangeTable<?>> l = new ArrayList<ChangeTable<?>>();
for (final String table : tables) {
final ChangeTable<?> compute = this.computeP(table);
128,6 → 135,11
l.add(compute);
}
}
return l;
}
 
private final String computeBody(final Collection<String> tables) {
final List<ChangeTable<?>> l = getChangeTables(tables);
if (Boolean.getBoolean(SIMPLE_SEQ)) {
final StringBuilder sb = new StringBuilder();
for (final ChangeTable<?> compute : l) {
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/Copy.java
18,6 → 18,7
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBSystemRoot;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLSchema;
85,7 → 86,7
LogUtils.setUpConsoleHandler();
Log.get().setLevel(Level.INFO);
 
System.setProperty("org.openconcerto.sql.identifier.allowRemoval", "true");
System.setProperty(SQLBase.ALLOW_OBJECT_REMOVAL, "true");
// we're backup/restore tool: don't touch the data at all
System.setProperty(SQLSchema.NOAUTO_CREATE_METADATA, "true");
 
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/AlterTable.java
13,17 → 13,19
package org.openconcerto.sql.utils;
 
import org.openconcerto.sql.model.Constraint;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLField.Properties;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLField.Properties;
import org.openconcerto.sql.model.graph.Link;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
58,6 → 60,57
return this.addClause("DROP COLUMN " + SQLBase.quoteIdentifier(name), ClauseType.DROP_COL);
}
 
public final AlterTable dropColumnCascade(String name) {
return this.dropColumnsCascade(Collections.singleton(name));
}
 
/**
* Drop the passed columns and all constraints that depends on them. Note: this can thus drop
* constraints that use other fields.
*
* @param columns the names of the columns to drop.
* @return this.
*/
public final AlterTable dropColumnsCascade(Collection<String> columns) {
for (final Link l : this.t.getDBSystemRoot().getGraph().getForeignLinks(this.t))
if (CollectionUtils.containsAny(l.getCols(), columns))
this.dropForeignConstraint(l.getName());
for (final Constraint c : this.t.getConstraints())
if (CollectionUtils.containsAny(c.getCols(), columns))
this.dropConstraint(c.getName());
for (final String name : columns)
this.dropColumn(name);
return thisAsT();
 
}
 
public final AlterTable dropForeignColumn(String name) {
return dropForeignColumns(Collections.singletonList(name));
}
 
/**
* Drop the passed columns and their constraint.
*
* @param columns the columns of a single foreign key.
* @return this.
* @throws IllegalArgumentException if no foreign key with <code>columns</code> exists.
*/
public final AlterTable dropForeignColumns(List<String> columns) throws IllegalArgumentException {
final Link foreignLink = this.t.getDBSystemRoot().getGraph().getForeignLink(this.t, columns);
if (foreignLink == null)
throw new IllegalArgumentException("No foreign key in " + this.t + " with : " + columns);
return dropForeignColumns(foreignLink);
}
 
public final AlterTable dropForeignColumns(final Link foreignLink) throws IllegalArgumentException {
if (foreignLink.getSource() != this.t)
throw new IllegalArgumentException("Not in " + this.t + " : " + foreignLink);
this.dropForeignConstraint(foreignLink.getName());
for (final String name : foreignLink.getCols())
this.dropColumn(name);
return thisAsT();
}
 
public final AlterTable alterColumn(String fname, SQLField from) {
return this.alterColumn(fname, from, EnumSet.allOf(Properties.class));
}
138,7 → 191,10
 
@Override
public String asString(String rootName) {
return this.asString(rootName, EnumSet.allOf(ClauseType.class));
// even for a single instance of AlterTable we need to order types since
// supportMultiAlterClause() might return false, in which case we might return several SQL
// statements
return this.asString(rootName, ChangeTable.ORDERED_TYPES);
}
 
private final String asString(final String rootName, final Set<ClauseType> types) {
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ModelCreator.java
18,6 → 18,7
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.DefaultListModel;
import org.openconcerto.utils.ClipboardUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.LogUtils;
 
168,15 → 169,39
}
}
 
private final JEditTextArea createTA(final String text) {
private final JPanel createTA(final String text) {
JPanel p = new JPanel();
p.setOpaque(false);
p.setLayout(new GridBagLayout());
GridBagConstraints c = new DefaultGridBagConstraints();
 
c.weightx = 1;
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
final JEditTextArea res = new JEditTextArea();
res.setEditable(false);
res.setTokenMarker(new JavaTokenMarker());
res.setText(text);
res.setCaretPosition(0);
return res;
p.add(res, c);
 
JButton b = new JButton("Copy to clipboard");
b.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
ClipboardUtils.setClipboardContents(res.getText());
 
}
});
c.gridy++;
c.fill = GridBagConstraints.NONE;
c.weighty = 0;
p.add(b, c);
 
return p;
}
 
private void connect(final DefaultListModel model, final String textUrl) {
ModelCreator.this.pref.put("url", textUrl);
 
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ReOrderPostgreSQL.java
66,7 → 66,7
final UpdateBuilder update = new UpdateBuilder(this.t);
update.addTable("REORDER", "M");
update.addTable("inc", null);
update.set(oF.getName(), "M.index * inc.val + " + getFirst());
update.set(oF.getName(), "M.index * inc.val + " + getFirstOrderValue());
res.add(update.asString() + " where M.\"ID\" = " + this.t.getKey().getFieldRef() + ";");
 
// drop tables so we can reorder more than once in the same transaction
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ReOrderMySQL.java
39,8 → 39,8
res.add("SELECT " + getInc() + " into @inc");
res.add(this.t.getBase().quote("UPDATE %f SET %n = -%n " + this.getWhere(), this.t, oF, oF));
// on commence à 0
res.add("SET @o := " + this.getFirst() + "- @inc");
res.add(getLoop(oF, "<= -" + this.getFirst(), oF, "DESC"));
res.add("SET @o := " + this.getFirstOrderValue() + "- @inc");
res.add(getLoop(oF, "<= -" + this.getFirstToReorder(), oF, "DESC"));
if (this.isAll()) {
res.add(getLoop(oF, "is null", this.t.getKey(), "ASC"));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ReOrderH2.java
48,7 → 48,7
idsToReorder.addFrom(this.t, alias);
idsToReorder.addSelect(tID);
final Where updateNulls = this.isAll() ? new Where(tOrder, "is", (Object) null) : null;
final Where w = new Where(tOrder, "<=", -this.getFirst()).or(updateNulls);
final Where w = new Where(tOrder, "<=", this.getFirstToReorder().negate()).or(updateNulls);
idsToReorder.setWhere(w);
idsToReorder.addRawOrder(tOrder.getFieldRef() + " DESC NULLS LAST");
idsToReorder.addRawOrder(tID.getFieldRef() + " ASC");
55,7 → 55,7
// REORDER: ID => ORDRE
res.add("DROP TABLE IF EXISTS REORDER ;");
final String idName = this.t.getKey().getName();
res.add("CREATE LOCAL TEMPORARY TABLE REORDER as select M.ID, " + this.getFirst() + " +(M.ind - 1) * @inc as ORDRE from (\n" + "SELECT rownum() as ind, " + new SQLName(idName).quote()
res.add("CREATE LOCAL TEMPORARY TABLE REORDER as select M.ID, " + this.getFirstOrderValue() + " +(M.ind - 1) * @inc as ORDRE from (\n" + "SELECT rownum() as ind, " + new SQLName(idName).quote()
+ " as ID from (" + idsToReorder.asString() + ") ) M;");
 
res.add(this.t.getBase().quote("UPDATE %f %i SET ( %n ) = (\n" +
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ChangeTable.java
31,7 → 31,9
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
72,6 → 74,16
}
}
 
public static final Set<ClauseType> ORDERED_TYPES;
 
static {
final Set<ClauseType> tmp = new LinkedHashSet<ClauseType>(ClauseType.values().length);
for (final ConcatStep step : ConcatStep.values())
tmp.addAll(step.getTypes());
assert tmp.equals(EnumSet.allOf(ClauseType.class)) : "ConcatStep is missing some types : " + tmp;
ORDERED_TYPES = Collections.unmodifiableSet(tmp);
}
 
/**
* Compute the SQL needed to create all passed tables, handling foreign key cycles.
*
79,11 → 91,11
* @param r where to create them.
* @return the SQL needed.
*/
public static List<String> cat(List<? extends ChangeTable> cts, final String r) {
public static List<String> cat(List<? extends ChangeTable<?>> cts, final String r) {
return cat(cts, r, false);
}
 
private static List<String> cat(List<? extends ChangeTable> cts, final String r, final boolean forceCat) {
private static List<String> cat(List<? extends ChangeTable<?>> cts, final String r, final boolean forceCat) {
final List<String> res = new ArrayList<String>();
for (final ConcatStep step : ConcatStep.values()) {
for (final ChangeTable<?> ct : cts) {
93,15 → 105,17
}
}
}
// don't return [""] because the caller might test the size of the result and assume that
// the DB was changed
// MySQL needs to have its "alter table add/drop fk" in separate execute()
// (multiple add would work in 5.0)
if (!forceCat && cts.size() > 0 && cts.get(0).getSyntax().getSystem() == SQLSystem.MYSQL)
if (!forceCat && (cts.size() == 0 || cts.get(0).getSyntax().getSystem() == SQLSystem.MYSQL))
return res;
else
return Collections.singletonList(CollectionUtils.join(res, "\n"));
}
 
public static String catToString(List<? extends ChangeTable> cts, final String r) {
public static String catToString(List<? extends ChangeTable<?>> cts, final String r) {
return cat(cts, r, true).get(0);
}
 
191,9 → 205,13
public abstract T addColumn(String name, String definition);
 
public final T addColumn(SQLField f) {
return this.addColumn(f.getName(), this.getSyntax().getFieldDecl(f));
return this.addColumn(f.getName(), f);
}
 
public final T addColumn(final String name, SQLField f) {
return this.addColumn(name, this.getSyntax().getFieldDecl(f));
}
 
public final T addIndex(final Index index) {
return this.addOutsideClause(getSyntax().getCreateIndex(index));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java
664,7 → 664,7
* @return this.
*/
public SQLRowValues setOrder(SQLRow r, boolean after) {
return this.setOrder(r, after, 100, 0);
return this.setOrder(r, after, ReOrder.DISTANCE.movePointRight(2).intValue(), 0);
}
 
private SQLRowValues setOrder(SQLRow r, boolean after, int nbToReOrder, int nbReOrdered) {
677,7 → 677,7
} else {
// make room
try {
ReOrder.create(this.getTable(), r.getOrder().intValue() - 1, nbToReOrder).exec();
ReOrder.create(this.getTable(), r.getOrder().intValue() - (nbToReOrder / 2), nbToReOrder).exec();
} catch (SQLException e) {
throw ExceptionUtils.createExn(IllegalStateException.class, "reorder failed for " + this.getTable() + " at " + r.getOrder(), e);
}
1336,7 → 1336,8
req += questionMarks;
if (values.size() > 0)
req += ", ";
req += "MAX(" + SQLBase.quoteIdentifier(order.getName()) + ") + 1 FROM " + tableQuoted;
// COALESCE for empty tables, MIN_ORDER + 1 since MIN_ORDER cannot be moved
req += "COALESCE(MAX(" + SQLBase.quoteIdentifier(order.getName()) + "), " + ReOrder.MIN_ORDER + ") + 1 FROM " + tableQuoted;
} else {
req += " VALUES (";
req += questionMarks;
1539,9 → 1540,9
// if scalar is null primary keys aren't fetched
private static final Insertion<?> insert(final SQLTable t, final String sql, final Boolean scalar) throws SQLException {
final SQLSystem sys = t.getServer().getSQLSystem();
if (sys == SQLSystem.H2)
if (scalar != null && sys == SQLSystem.H2)
throw new IllegalArgumentException("H2 use IDENTITY() which only returns the last ID: " + t.getSQLName());
if (sys == SQLSystem.MSSQL)
if (scalar != null && sys == SQLSystem.MSSQL)
throw new IllegalArgumentException("In MS getUpdateCount() is correct but getGeneratedKeys() only returns the last ID: " + t.getSQLName());
return SQLUtils.executeAtomic(t.getDBSystemRoot().getDataSource(), new ConnectionHandlerNoSetup<Insertion<?>, SQLException>() {
@Override
1568,9 → 1569,10
// null if no returning
rs = stmt.getResultSet();
} else {
stmt.execute(insertInto, Statement.RETURN_GENERATED_KEYS);
// MySQL always return an empty resultSet for anything else than 1 pk
rs = t.getPrimaryKeys().size() != 1 ? null : stmt.getGeneratedKeys();
final boolean dontGetGK = scalar == null || (sys == SQLSystem.MYSQL && t.getPrimaryKeys().size() != 1);
stmt.execute(insertInto, dontGetGK ? Statement.NO_GENERATED_KEYS : Statement.RETURN_GENERATED_KEYS);
rs = dontGetGK ? null : stmt.getGeneratedKeys();
}
final List<?> list;
final int count;
1611,7 → 1613,42
return res;
}
 
// MAYBE add insertFromSelect(SQLTable, SQLSelect) if aliases are kept in SQLSelect (so that we
// can map arbitray expressions to fields in the destination table)
public static final int insertFromTable(final SQLTable dest, final SQLTable src) throws SQLException {
return insertFromTable(dest, src, src.getChildrenNames());
}
 
/**
* Copy all rows from <code>src</code> to <code>dest</code>.
*
* @param dest the table where rows will be inserted.
* @param src the table where rows will be selected.
* @param fieldsNames the fields to use.
* @return the insertion count.
* @throws SQLException if an error occurs while inserting.
*/
public static final int insertFromTable(final SQLTable dest, final SQLTable src, final Set<String> fieldsNames) throws SQLException {
if (dest.getDBSystemRoot() != src.getDBSystemRoot())
throw new IllegalArgumentException("Tables are not on the same system root : " + dest.getSQLName() + " / " + src.getSQLName());
if (!dest.getChildrenNames().containsAll(fieldsNames))
throw new IllegalArgumentException("Destination table " + dest.getSQLName() + " doesn't contain all fields of the source " + src + " : " + fieldsNames);
 
final List<SQLField> fields = new ArrayList<SQLField>(fieldsNames.size());
for (final String fName : fieldsNames)
fields.add(src.getField(fName));
final SQLSelect sel = new SQLSelect(src.getBase(), true);
sel.addAllSelect(fields);
final String colNames = "(" + CollectionUtils.join(fields, ",", new ITransformer<SQLField, String>() {
@Override
public String transformChecked(SQLField input) {
return SQLBase.quoteIdentifier(input.getName());
}
}) + ") ";
return insertCount(dest, colNames + sel.asString());
}
 
/**
* Trim a collection of SQLRowValues.
*
* @param graphs the rowValues to trim.
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLImmutableRowValues.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.model;
 
import java.util.Collection;
import java.util.Map;
import java.util.Set;
 
public class SQLImmutableRowValues extends SQLRowAccessor {
 
private final SQLRowValues delegate;
 
public SQLImmutableRowValues(SQLRowValues delegate) {
super(delegate.getTable());
this.delegate = delegate;
}
 
@Override
public SQLRowValues createEmptyUpdateRow() {
return this.delegate.createEmptyUpdateRow();
}
 
@Override
public Collection<SQLRowValues> getReferentRows() {
return this.delegate.getReferentRows();
}
 
@Override
public Set<SQLRowValues> getReferentRows(SQLField refField) {
return this.delegate.getReferentRows(refField);
}
 
@Override
public Collection<SQLRowValues> getReferentRows(SQLTable refTable) {
return this.delegate.getReferentRows(refTable);
}
 
public int size() {
return this.delegate.size();
}
 
@Override
public final int getID() {
return this.delegate.getID();
}
 
@Override
public final Number getIDNumber() {
return this.delegate.getIDNumber();
}
 
@Override
public final Object getObject(String fieldName) {
return this.delegate.getObject(fieldName);
}
 
@Override
public Map<String, Object> getAbsolutelyAll() {
return this.delegate.getAbsolutelyAll();
}
 
@Override
public final SQLRowAccessor getForeign(String fieldName) {
return this.delegate.getForeign(fieldName);
}
 
@Override
public boolean isForeignEmpty(String fieldName) {
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);
}
 
@Override
public Set<String> getFields() {
return this.delegate.getFields();
}
 
@Override
public final SQLRow asRow() {
return this.delegate.asRow();
}
 
@Override
public final SQLRowValues asRowValues() {
return this.delegate.deepCopy();
}
 
public final String printTree() {
return this.delegate.printTree();
}
 
public final String printGraph() {
return this.delegate.printGraph();
}
 
public final boolean equalsGraph(SQLRowValues other) {
return this.delegate.equalsGraph(other);
}
 
@Override
public SQLTableListener createTableListener(SQLDataListener l) {
return this.delegate.createTableListener(l);
}
 
@Override
public boolean equals(Object obj) {
return this.delegate.equals(obj);
}
 
@Override
public int hashCode() {
return this.delegate.hashCode();
}
 
@Override
public String toString() {
return super.toString() + " on <" + this.delegate.toString() + ">";
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/graph/DatabaseGraph.java
505,22 → 505,28
return res;
}
 
public SQLTable findReferentTable(SQLTable table, final String refTable, final List<String> refKeys) {
public Set<SQLTable> findReferentTables(SQLTable table, final String refTable, final List<String> refKeys) {
final Set<SQLTable> res = new HashSet<SQLTable>();
for (final Link l : this.getReferentLinks(table)) {
if (l.getSource().getName().equals(refTable) && (refKeys.isEmpty() || l.getCols().equals(refKeys)))
return l.getSource();
res.add(l.getSource());
}
return null;
return res;
}
 
public SQLTable findReferentTable(SQLTable table, final String refTable, final List<String> refKeys) {
return org.openconcerto.utils.CollectionUtils.getSole(this.findReferentTables(table, refTable, refKeys));
}
 
/**
* Find the first referent table named <code>refTable</code>.
* Find the only referent table named <code>refTable</code>.
*
* @param table a table.
* @param refTable a table name that should point to <code>table</code>.
* @param refKeys the names of the fields from <code>refTable</code>, empty meaning don't use
* them to filter.
* @return the first matching table or <code>null</code>.
* @return the only matching table or <code>null</code> (i.e. if there's none or more than one).
* @see #findReferentTables(SQLTable, String, List)
*/
public SQLTable findReferentTable(SQLTable table, final String refTable, final String... refKeys) {
return this.findReferentTable(table, refTable, Arrays.asList(refKeys));
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBSystemRoot.java
166,8 → 166,13
}
 
void descendantsChanged() {
this.descendantsChanged(true);
}
 
void descendantsChanged(final boolean tableListChange) {
this.clearGraph();
// the dataSource must always have all tables, to listen to them for its cache
if (tableListChange)
this.getDataSource().setTables(getDescs(SQLTable.class));
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/model/XMLStructureSource.java
38,7 → 38,7
/**
* Date format used in xml files.
*/
public static final DateFormat XMLDATE_FMT = new SimpleDateFormat("yyyyMMdd-HHmm");
public static final DateFormat XMLDATE_FMT = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ");
public static final String version = "20100917-1546";
 
private final Map<String, Element> xmlSchemas;
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java
303,6 → 303,10
e.printStackTrace();
this.addConstraint((Constraint) null);
}
 
// we might have added/dropped a foreign key but the set of tables hasn't changed
this.getDBSystemRoot().descendantsChanged(false);
 
this.save();
}
 
589,6 → 593,10
return this.getDBSystemRoot().getGraph().getForeignTable(this.getField(foreignField));
}
 
public SQLTable findReferentTable(String tableName) {
return this.getDBSystemRoot().getGraph().findReferentTable(this, tableName);
}
 
/**
* Renvoie toutes les clefs de cette table. C'est à dire les clefs primaires plus les clefs
* externes.
618,8 → 626,9
*/
public SQLField getField(String fieldName) {
SQLField res = this.getFieldRaw(fieldName);
if (res == null)
throw new IllegalArgumentException("unknown field " + fieldName + " in " + this);
if (res == null) {
throw new IllegalArgumentException("unknown field " + fieldName + " in " + this.getName() + ". The table " + this.getName() + " contains the followins fields: " + this.fields.asList());
}
return res;
}
 
873,6 → 882,19
return this.getFieldRaw(orderField);
}
 
/**
* The number of fractional digits of the order field.
*
* @return the number of fractional digits of the order field.
*/
public final int getOrderDecimalDigits() {
return this.getOrderField().getType().getDecimalDigits().intValue();
}
 
public final BigDecimal getOrderULP() {
return BigDecimal.ONE.scaleByPowerOfTen(-this.getOrderDecimalDigits());
}
 
public boolean isArchivable() {
return this.getArchiveField() != null;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxH2.java
103,11 → 103,13
final boolean newNullable = toAlter.contains(Properties.NULLABLE) ? nullable : getNullable(f);
res.add(SQLSelect.quote("ALTER COLUMN %n " + type + getDefaultClause(newDef) + getNullableClause(newNullable), f));
} else {
if (toAlter.contains(Properties.NULLABLE))
res.add(this.setNullable(f, nullable));
if (toAlter.contains(Properties.DEFAULT))
res.add(this.setDefault(f, defaultVal));
}
// Contrary to the documentation "alter column type" doesn't change the nullable
// e.g. ALTER COLUMN "VARCHAR" varchar(150) DEFAULT 'testAllProps' NULL
if (toAlter.contains(Properties.NULLABLE))
res.add(this.setNullable(f, nullable));
return res;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/model/FieldPath.java
61,33 → 61,21
return this.fieldName;
}
 
public Object getObject(final SQLRowAccessor r) {
return this.getObject(r, true);
}
 
/**
* Return the value of the field at the end of this path from <code>r</code>.
* <code>getForeign</code> controls whether the safer but slower getForeign() is used.
*
* @param r the row to use.
* @param getForeign <code>true</code> to use {@link SQLRowAccessor#getForeign(String)},
* <code>false</code> for {@link SQLRowAccessor#getObject(String)}.
* @return the value.
*/
public Object getObject(final SQLRowValues r, final boolean getForeign) {
return this.getObject((SQLRowAccessor) r, getForeign);
public Object getObject(final SQLRowValues r) {
final SQLRowValues vals = r.followPath(getPath());
return vals == null ? null : vals.getObject(getFieldName());
}
 
private Object getObject(final SQLRowAccessor r, final boolean getForeign) {
SQLRowAccessor current = r;
final Path p2 = this.p;
final int length = p2.length();
for (int i = 0; i < length; i++) {
final SQLField step = p2.getSingleStep(i);
current = getForeign ? current.getForeign(step.getName()) : (SQLRowAccessor) current.getObject(step.getName());
public String getString(final SQLRowValues r) {
final SQLRowValues vals = r.followPath(getPath());
return vals == null ? null : vals.getString(getFieldName());
}
return current.getObject(this.fieldName);
}
 
@Override
public SQLField getField() {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSchema.java
311,6 → 311,14
return this.getFwkMetadata(VERSION_MDKEY);
}
 
// TODO assure that the updated version is different that current one and unique
// For now the resolution is the millisecond, this poses 2 problems :
// 1/ if we have a fast in-memory DB, some additions might get lost
// 2/ if not everyone's time is correct ; if client1 calls updateVersion(), then client2 makes
// some changes and calls updateVersion(), his clock might be returning the same time than
// client1 had when he called updateVersion().
// Perhaps something like VERSION = date seconds || '_' || (select cast( substring(indexof '_')
// as int ) + 1 from VERSION) ; e.g. 20110701-1021_01352
public final String updateVersion() throws SQLException {
final String res = XMLStructureSource.XMLDATE_FMT.format(new Date());
this.setFwkMetadata(SQLSchema.VERSION_MDKEY, res);
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBStructureItem.java
288,6 → 288,14
}
}
 
public final <T extends DBStructureItemJDBC> T getDescLenient(SQLName name, Class<T> clazz) {
try {
return this.getDesc(name, clazz);
} catch (DBStructureItemNotFound e) {
return null;
}
}
 
@SuppressWarnings("unchecked")
public final <T extends DBStructureItem> Set<T> getDescs(Class<T> clazz) {
// getDescendants() stays in the same tree, so start from the desired one.
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBase.java
57,6 → 57,11
* will be loaded from XML instead of JDBC.
*/
public static final String STRUCTURE_USE_XML = "org.openconcerto.sql.structure.useXML";
/**
* Boolean system property, if <code>true</code> then schemas and tables can be dropped,
* otherwise {@link #fetchTables()} will throw an exception.
*/
public static final String ALLOW_OBJECT_REMOVAL = "org.openconcerto.sql.identifier.allowRemoval";
 
// null is a valid name (MySQL doesn't support schemas)
private final Map<String, SQLSchema> schemas;
271,7 → 276,7
}
 
static <T> void mustContain(final DBStructureItemJDBC c, final Set<T> newC, final Set<T> oldC, final String name) {
if (Boolean.getBoolean("org.openconcerto.sql.identifier.allowRemoval"))
if (Boolean.getBoolean(ALLOW_OBJECT_REMOVAL))
return;
 
final Set<T> diff = CollectionUtils.contains(newC, oldC);
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRow.java
20,6 → 20,7
import org.openconcerto.sql.model.SQLSelect.ArchiveMode;
import org.openconcerto.sql.model.graph.Link;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.utils.ReOrder;
import org.openconcerto.utils.CollectionMap;
import org.openconcerto.utils.DecimalUtils;
 
206,13 → 207,13
* @param values les valeurs de la lignes.
* @throws IllegalArgumentException si values ne contient pas la clef de la table.
*/
public SQLRow(SQLTable table, Map<String, Object> values) {
public SQLRow(SQLTable table, Map<String, ?> values) {
this(table, getID(values, table));
// faire une copie, sinon backdoor pour changer les valeurs sans qu'on s'en aperçoive
this.setValues(new HashMap<String, Object>(values));
}
 
private static Number getID(Map<String, Object> values, final SQLTable table) {
private static Number getID(Map<String, ?> values, final SQLTable table) {
final String keyName = table.getKey().getName();
if (!values.keySet().contains(keyName))
throw new IllegalArgumentException(values + " does not contain the key of " + table);
364,8 → 365,8
final int diff = (!after) ? -1 : 1;
 
final SQLSelect sel = new SQLSelect(t.getBase());
// pouvoir passer le deuxième en premier: le mettre entre indéfini (0) et le premier
sel.setExcludeUndefined(false);
// undefined must not move
sel.setExcludeUndefined(true);
// unique index prend aussi en compte les archivés
sel.setArchivedPolicy(SQLSelect.BOTH);
sel.addSelect(t.getKey());
372,25 → 373,29
sel.addSelect(t.getOrderField());
sel.setWhere(new Where(t.getOrderField(), diff < 0 ? "<" : ">", destOrder));
sel.addRawOrder(t.getOrderField().getFieldRef() + (diff < 0 ? "DESC" : "ASC"));
sel.setLimit(1);
 
final BigDecimal otherOrder;
final SQLDataSource ds = t.getBase().getDataSource();
final Map<String, Object> otherMap = ds.execute1(sel.asString() + " LIMIT 1");
if (otherMap == null) {
final Map<String, Object> otherMap = ds.execute1(sel.asString());
if (otherMap != null) {
final SQLRow otherRow = new SQLRow(t, otherMap);
otherOrder = otherRow.getOrder();
} else if (after) {
// dernière ligne de la table
otherOrder = destOrder.add(BigDecimal.ONE);
otherOrder = destOrder.add(ReOrder.DISTANCE);
} else {
final SQLRow otherRow = new SQLRow(t, otherMap);
otherOrder = otherRow.getOrder();
// première ligne
otherOrder = ReOrder.MIN_ORDER;
}
 
final int decDigits = this.getTable().getOrderField().getType().getDecimalDigits().intValue();
final int decDigits = this.getTable().getOrderDecimalDigits();
final BigDecimal least = BigDecimal.ONE.scaleByPowerOfTen(-decDigits);
final BigDecimal distance = destOrder.subtract(otherOrder).abs();
if (distance.compareTo(least) <= 0)
return null;
else {
final BigDecimal mean = destOrder.add(otherOrder).divide(new BigDecimal(2));
final BigDecimal mean = destOrder.add(otherOrder).divide(BigDecimal.valueOf(2));
return DecimalUtils.round(mean, decDigits);
}
}
532,7 → 537,7
* @see #getDistantRows(List)
*/
public SQLRow getDistantRow(List<String> path) {
Set rows = this.getDistantRows(path);
final Set<SQLRow> rows = this.getDistantRows(path);
if (rows.size() != 1)
throw new IllegalStateException("the path " + path + " does not lead to a unique row (" + rows.size() + ")");
return (SQLRow) rows.iterator().next();
547,7 → 552,7
*/
public Set<SQLRow> getDistantRows(List<String> path) {
// on veut tous les champs de la derniere table et rien d'autre
final List<List> fields = new ArrayList<List>(Collections.nCopies(path.size() - 1, Collections.EMPTY_LIST));
final List<List<SQLField>> fields = new ArrayList<List<SQLField>>(Collections.nCopies(path.size() - 1, Collections.<SQLField> emptyList()));
fields.add(null);
final Set<List<SQLRow>> s = this.getRowsOnPath(path, fields);
final Set<SQLRow> res = new LinkedHashSet<SQLRow>(s.size());
845,7 → 850,7
public Map<String, Object> getAllValues() {
// commence par tout copier
final Map<String, Object> res = new HashMap<String, Object>(this.getValues());
final Set keys = this.getTable().getKeys();
final Set<SQLField> keys = this.getTable().getKeys();
// puis on enlève les clefs, l'ordre et l'archive
CollectionUtils.filter(res.keySet(), new Predicate() {
public boolean evaluate(Object object) {
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/UserRightsManager.java
27,6 → 27,7
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.utils.CollectionMap;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Tuple3;
import org.openconcerto.utils.cc.IFactory;
232,6 → 233,7
* @return the user's rights by CODE.
*/
private final CollectionMap<String, Tuple2<String, Boolean>> loadRightsForUser(final int userID) {
try {
final SQLRow userRow = this.getTable().getForeignTable("ID_USER_COMMON").getRow(userID);
if (userRow != null && userRow.getBoolean("SUPERUSER"))
return SUPERUSER_RIGHTS;
283,7 → 285,11
}
 
return res;
} catch (Exception e) {
ExceptionHandler.handle("Erreur lors du chargement des droits utilisateurs pour l'utilisateur (Id:" + userID + ")", e);
return SUPERUSER_RIGHTS;
}
}
 
private final void expand(final CollectionMap<String, Tuple2<String, Boolean>> res, final Set<Tuple2<String, String>> unicity, final RightTuple t) {
this.expand(res, unicity, t.get0(), t.get1(), t.get2());
/trunk/OpenConcerto/src/org/openconcerto/sql/preferences/SQLPreferences.java
New file
0,0 → 1,320
/*
* 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.preferences;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.IResultSetHandler;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
import org.openconcerto.utils.CollectionUtils;
 
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
 
import org.apache.commons.dbutils.ResultSetHandler;
 
/**
* Preferences backed by SQL tables.
*
* @author Sylvain CUAZ
*/
public class SQLPreferences extends AbstractPreferences {
 
private static final String PREF_NODE_TABLENAME = "PREF_NODE";
private static final String PREF_VALUE_TABLENAME = "PREF_VALUE";
 
static public SQLTable getPrefTable(final DBRoot root) throws SQLException {
if (!root.contains(PREF_VALUE_TABLENAME)) {
final SQLDataSource ds = root.getDBSystemRoot().getDataSource();
SQLUtils.executeAtomic(ds, new SQLFactory<Object>() {
@Override
public Object create() throws SQLException {
final SQLCreateTable createNodeT = new SQLCreateTable(root, PREF_NODE_TABLENAME);
// don't need ORDER and ARCHIVE
createNodeT.setPlain(true);
createNodeT.addColumn(SQLSyntax.ID_NAME, createNodeT.getSyntax().getPrimaryIDDefinition());
// cannot use addForeignColumn() since it's a self-reference
createNodeT.addColumn("ID_PARENT", createNodeT.getSyntax().getIDType() + " NULL");
createNodeT.addVarCharColumn("NAME", Preferences.MAX_NAME_LENGTH);
 
createNodeT.addForeignConstraint("ID_PARENT", new SQLName(createNodeT.getName()), SQLSyntax.ID_NAME);
createNodeT.addUniqueConstraint("uniqNamePerParent", Arrays.asList("ID_PARENT", "NAME"));
 
final SQLCreateTable createValueT = new SQLCreateTable(root, PREF_VALUE_TABLENAME);
createValueT.setPlain(true);
createValueT.addColumn("ID_NODE", createValueT.getSyntax().getIDType() + " NOT NULL");
createValueT.addVarCharColumn("NAME", Preferences.MAX_KEY_LENGTH);
createValueT.addVarCharColumn("VALUE", Preferences.MAX_VALUE_LENGTH);
// unique name per node
createValueT.setPrimaryKey("ID_NODE", "NAME");
createValueT.addForeignConstraint("ID_NODE", new SQLName(createNodeT.getName()), SQLSyntax.ID_NAME);
 
for (final SQLCreateTable ct : new SQLCreateTable[] { createNodeT, createValueT }) {
ds.execute(ct.asString());
SQLTable.setUndefID(root.getSchema(), ct.getName(), null);
}
root.getSchema().updateVersion();
return null;
}
});
root.refetch();
}
return root.getTable(PREF_VALUE_TABLENAME);
}
 
private final SQLTable prefT;
private final SQLTable nodeT;
// values from the DB
private Map<String, String> values;
// values changed in-memory (not yet committed)
private final Map<String, String> changedValues;
// values removed in-memory (not yet committed)
private final Set<String> removedKeys;
private SQLRow node;
 
// root node
public SQLPreferences(DBRoot db) {
this(null, "", db);
}
 
private SQLPreferences(SQLPreferences parent, String name, DBRoot db) {
super(parent, name);
if (db == null)
throw new IllegalArgumentException("Missing DBRoot");
 
this.prefT = db.getTable(PREF_VALUE_TABLENAME);
this.nodeT = this.prefT.getForeignTable("ID_NODE");
 
this.values = null;
this.changedValues = new HashMap<String, String>();
this.removedKeys = new HashSet<String>();
this.node = null;
}
 
private final SQLDataSource getDS() {
return this.prefT.getDBSystemRoot().getDataSource();
}
 
private Object execute(final String sel, ResultSetHandler rsh) {
// don't use the cache, our superclass and us have already a cache system
// plus this would require to fire when modifying the table
return getDS().execute(sel, new IResultSetHandler(rsh, false));
}
 
public final SQLRow getNode() {
try {
return this.getNode(false);
} catch (SQLException e) {
// shouldn't happen since we don't want to access the DB
throw new IllegalStateException(e);
}
}
 
public final SQLRow getNode(final boolean create) throws SQLException {
if (this.node == null) {
final SQLPreferences parent = (SQLPreferences) parent();
final Where parentW;
if (parent == null) {
parentW = Where.isNull(this.nodeT.getField("ID_PARENT"));
} else {
final SQLRow parentNode = parent.getNode(create);
parentW = parentNode == null ? null : new Where(this.nodeT.getField("ID_PARENT"), "=", parentNode.getID());
}
if (parentW == null) {
// our parent is not in the DB, we can't
this.node = null;
} else {
final SQLSelect sel = new SQLSelect(this.nodeT.getBase()).addSelectStar(this.nodeT);
sel.setWhere(parentW.and(new Where(this.nodeT.getField("NAME"), "=", name())));
 
@SuppressWarnings("unchecked")
final Map<String, ?> m = (Map<String, ?>) execute(sel.asString(), SQLDataSource.MAP_HANDLER);
this.node = m == null ? null : new SQLRow(this.nodeT, m);
}
if (this.node == null && create) {
final SQLRowValues insVals = new SQLRowValues(this.nodeT);
insVals.put("ID_PARENT", parent == null ? null : parent.getNode(create).getID());
insVals.put("NAME", name());
this.node = insVals.insert();
}
}
return this.node;
}
 
public final Map<String, String> getValues() {
if (this.values == null) {
this.values = new HashMap<String, String>();
final SQLRow node = getNode();
if (node != null) {
final SQLSelect sel = new SQLSelect(this.prefT.getBase()).addSelectStar(this.prefT);
sel.setWhere(new Where(this.prefT.getField("ID_NODE"), "=", node.getID()));
 
@SuppressWarnings("unchecked")
final List<Map<String, Object>> l = (List<Map<String, Object>>) execute(sel.asString(), SQLDataSource.MAP_LIST_HANDLER);
for (final Map<String, Object> r : l) {
this.values.put(r.get("NAME").toString(), r.get("VALUE").toString());
}
}
}
return this.values;
}
 
@Override
protected void putSpi(String key, String value) {
this.changedValues.put(key, value);
this.removedKeys.remove(key);
}
 
@Override
protected void removeSpi(String key) {
this.removedKeys.add(key);
this.changedValues.remove(key);
}
 
@Override
protected String getSpi(String key) {
if (this.removedKeys.contains(key))
return null;
else if (this.changedValues.containsKey(key))
return this.changedValues.get(key);
else
return this.getValues().get(key);
}
 
// null means delete all
private void deleteValues(final Set<String> keys) {
final SQLRow node = this.getNode();
if (node != null) {
final String keysW;
if (keys == null)
keysW = "";
else
keysW = " and " + new Where(this.prefT.getField("NAME"), keys).getClause();
 
getDS().execute("DELETE FROM " + this.prefT.getSQLName().quote() + " where \"ID_NODE\" = " + node.getID() + keysW);
}
}
 
@Override
protected void removeNodeSpi() throws BackingStoreException {
try {
final SQLRow node = this.getNode();
if (node != null) {
deleteValues(null);
getDS().execute("DELETE FROM " + this.nodeT.getSQLName().quote() + " where \"ID\" = " + node.getID());
this.node = null;
}
} catch (Exception e) {
throw new BackingStoreException(e);
}
assert this.node == null;
this.values = null;
this.removedKeys.clear();
this.changedValues.clear();
}
 
@Override
protected String[] keysSpi() throws BackingStoreException {
try {
final Set<String> committedKeys = this.getValues().keySet();
final Set<String> res;
if (this.removedKeys.isEmpty() && this.changedValues.isEmpty()) {
res = committedKeys;
} else {
res = new HashSet<String>(committedKeys);
res.removeAll(this.removedKeys);
res.addAll(this.changedValues.keySet());
}
return res.toArray(new String[res.size()]);
} catch (Exception e) {
throw new BackingStoreException(e);
}
}
 
@Override
protected String[] childrenNamesSpi() throws BackingStoreException {
try {
final SQLRow node = this.getNode();
if (node == null) {
// OK since "This method need not return the names of any nodes already cached"
// so if we call pref.node("a/b/c") with no existing nodes this still works
return new String[0];
}
 
final int nodeID = node.getID();
final SQLSelect sel = new SQLSelect(this.nodeT.getBase()).addSelect(this.nodeT.getField("NAME"));
final Where w = new Where(this.nodeT.getField("ID_PARENT"), "=", nodeID);
sel.setWhere(w);
@SuppressWarnings("unchecked")
final List<String> names = (List<String>) execute(sel.asString(), SQLDataSource.COLUMN_LIST_HANDLER);
return names.toArray(new String[names.size()]);
} catch (Exception e) {
throw new BackingStoreException(e);
}
}
 
@Override
protected SQLPreferences childSpi(String name) {
return new SQLPreferences(this, name, this.prefT.getDBRoot());
}
 
@Override
protected void syncSpi() throws BackingStoreException {
this.flushSpi();
this.values = null;
}
 
@Override
protected void flushSpi() throws BackingStoreException {
if (this.removedKeys.size() > 0 || this.changedValues.size() > 0) {
try {
// also delete changed, so we can insert afterwards
this.deleteValues(CollectionUtils.union(this.removedKeys, this.changedValues.keySet()));
this.removedKeys.clear();
 
if (this.changedValues.size() > 0) {
final int nodeID = getNode(true).getID();
final List<String> insValues = new ArrayList<String>(this.changedValues.size());
for (final Entry<String, String> e : this.changedValues.entrySet()) {
insValues.add("(" + nodeID + ", " + this.prefT.getBase().quoteString(e.getKey()) + ", " + this.prefT.getBase().quoteString(e.getValue()) + ")");
}
 
SQLRowValues.insertCount(this.prefT, "(\"ID_NODE\", \"NAME\", \"VALUE\") VALUES" + CollectionUtils.join(insValues, ", "));
this.changedValues.clear();
}
} catch (Exception e) {
throw new BackingStoreException(e);
}
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/ListSQLView.java
13,7 → 13,6
/*
* Créé le 2 mai 2005
*
*/
package org.openconcerto.sql.view.listview;
 
57,8 → 56,7
private final SQLComponent parent;
private final String name;
private final ItemPool pool;
// [ListItemSQLView]
private final List items;
private final List<ListItemSQLView> items;
 
private final PropertyChangeSupport supp;
private final EmptyObjectHelper helper;
76,7 → 74,7
this.pool = factory.create(this);
 
this.supp = new PropertyChangeSupport(this);
this.items = new ArrayList();
this.items = new ArrayList<ListItemSQLView>();
 
this.addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
210,7 → 208,7
}
}
 
public List getExistantViews() {
public List<ListItemSQLView> getExistantViews() {
return this.items;
}
 
264,6 → 262,11
this.getPool().addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.getPool().removeValidListener(l);
}
 
public String getValidationText() {
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/ItemPool.java
37,12 → 37,12
 
private final ItemPoolFactory creator;
private final ListSQLView panel;
private final Set validListeners;
private final Set<ValidListener> validListeners;
 
public ItemPool(ItemPoolFactory parent, ListSQLView panel) {
this.creator = parent;
this.panel = panel;
this.validListeners = new HashSet();
this.validListeners = new HashSet<ValidListener>();
}
 
public abstract void reset();
68,7 → 68,7
*
* @return a List of SQLRowItemView.
*/
public abstract List getItems();
public abstract List<SQLRowItemView> getItems();
 
/**
* Get the items that will be added to the DB on the next update/insert.
75,7 → 75,7
*
* @return a List of SQLRowItemView.
*/
public abstract List getAddedItems();
public abstract List<SQLRowItemView> getAddedItems();
 
/**
* Get the items that will be deleted from the DB on the next update/insert.
82,7 → 82,7
*
* @return a List of SQLRowItemView.
*/
public abstract List getRemovedItems();
public abstract List<SQLRowItemView> getRemovedItems();
 
protected final ItemPoolFactory getCreator() {
return this.creator;
116,12 → 116,14
this.validListeners.add(l);
}
 
public void removeValidListener(ValidListener l) {
this.validListeners.remove(l);
}
 
protected synchronized final void fireValidChange() {
// ATTN called very often during a select() (for each SQLObject empty & value change)
final boolean validated = this.isValidated();
final Iterator iter = this.validListeners.iterator();
while (iter.hasNext()) {
final ValidListener l = (ValidListener) iter.next();
for (final ValidListener l : this.validListeners) {
l.validChange(this.getPanel(), validated);
}
}
129,9 → 131,9
final boolean isValidated() {
// si la liste est vide, elle est valide
boolean res = true;
final Iterator iter = this.getItems().iterator();
final Iterator<SQLRowItemView> iter = this.getItems().iterator();
while (iter.hasNext() && res) {
final SQLRowItemView v = (SQLRowItemView) iter.next();
final SQLRowItemView v = iter.next();
res = v.isValidated();
}
return res;
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/PrivateFFPoolFactory.java
24,7 → 24,7
super(t, foreignT, count, firstSuffixed);
}
 
public PrivateFFPoolFactory(SQLTable t, String foreignT, List fields) {
public PrivateFFPoolFactory(SQLTable t, String foreignT, List<String> fields) {
super(t, foreignT, fields);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/FFPoolFactory.java
19,7 → 19,6
import org.openconcerto.sql.model.graph.DatabaseGraph;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
// ID_ARTICLE_1,_2,_3 or ID_OBSERVATION,_2,_3
27,8 → 26,7
 
private final SQLTable t;
private final SQLTable foreignT;
// [SQLField]
private final List fields;
private final List<SQLField> fields;
 
public FFPoolFactory(SQLTable t, String foreignT) {
this(t, foreignT, null);
38,17 → 36,15
this(t, foreignT, computeFF(foreignT, count, firstSuffixed));
}
 
public FFPoolFactory(SQLTable t, String foreignT, List fields) {
public FFPoolFactory(SQLTable t, String foreignT, List<String> fields) {
this.t = t;
this.foreignT = t.getBase().getTable(foreignT);
this.foreignT = t.getDBRoot().getTable(foreignT);
 
this.fields = new ArrayList();
final DatabaseGraph g = this.t.getBase().getGraph();
this.fields = new ArrayList<SQLField>();
final DatabaseGraph g = this.t.getDBSystemRoot().getGraph();
if (fields == null)
fields = new ArrayList(g.getForeignFields(this.t, this.foreignT));
final Iterator iter = fields.iterator();
while (iter.hasNext()) {
final String fieldName = (String) iter.next();
fields = DatabaseGraph.getNames(g.getForeignLinks(this.t, this.foreignT), new ArrayList<String>());
for (final String fieldName : fields) {
final SQLField f = this.t.getField(fieldName);
if (this.foreignT.equals(g.getForeignTable(f))) {
this.fields.add(f);
58,7 → 54,7
}
}
 
protected final List getFields() {
protected final List<SQLField> getFields() {
return this.fields;
}
 
72,11 → 68,9
 
public abstract ItemPool create(ListSQLView panel);
 
public final List getItems(SQLRowAccessor r) {
final List res = new ArrayList();
final Iterator iter = this.getFields().iterator();
while (iter.hasNext()) {
final SQLField f = (SQLField) iter.next();
public final List<SQLRowAccessor> getItems(SQLRowAccessor r) {
final List<SQLRowAccessor> res = new ArrayList<SQLRowAccessor>();
for (final SQLField f : this.getFields()) {
if (!r.isForeignEmpty(f.getName()))
res.add(r.getForeign(f.getName()));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/ItemPoolFactory.java
28,8 → 28,8
public abstract class ItemPoolFactory {
 
// computeFF("ARTICLE", 3, false) => {"ID_ARTICLE", "ID_ARTICLE_2", "ID_ARTICLE_3"}
protected static final List computeFF(String foreignT, int count, boolean firstSuffixed) {
final List res = new ArrayList(count);
protected static final List<String> computeFF(String foreignT, int count, boolean firstSuffixed) {
final List<String> res = new ArrayList<String>(count);
if (!firstSuffixed)
res.add("ID_" + foreignT);
for (int i = (firstSuffixed ? 1 : 2); i <= count; i++)
43,7 → 43,7
* @param r the row, eg MACHINE[123].
* @return a list of SQLRowAccessor, eg [OBSERVATION[142], OBSERVATION[221]].
*/
public abstract List getItems(SQLRowAccessor r);
public abstract List<SQLRowAccessor> getItems(SQLRowAccessor r);
 
/**
* Creates an ItemPool who can handle a list of this kind.
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/FFItemPool.java
20,29 → 20,27
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
 
// gère les créés, effacés, inchangés
public abstract class FFItemPool extends ItemPool {
 
// [SQLRowItemView]
// items that have been neither added nor removed since show()
// but they may have been changed (ie change the CONSTATATION of an observation)
protected final List stills;
protected final List<SQLRowItemView> stills;
// items that have been added since show()
protected final List added;
protected final List<SQLRowItemView> added;
// items that have been removed since show()
protected final List removed;
// free items, [SQLField]
protected final List availables;
protected final List<SQLRowItemView> removed;
// free items
protected final List<SQLField> availables;
 
public FFItemPool(ItemPoolFactory parent, ListSQLView panel) {
super(parent, panel);
this.stills = new ArrayList();
this.added = new ArrayList();
this.removed = new ArrayList();
this.availables = new ArrayList();
this.stills = new ArrayList<SQLRowItemView>();
this.added = new ArrayList<SQLRowItemView>();
this.removed = new ArrayList<SQLRowItemView>();
this.availables = new ArrayList<SQLField>();
 
this.reset();
}
58,12 → 56,10
public final void show(SQLRowAccessor r) {
this.reset();
 
final List availableViews = new ArrayList(this.getPanel().getExistantViews());
final List<ListItemSQLView> availableViews = new ArrayList<ListItemSQLView>(this.getPanel().getExistantViews());
// eg ARTICLE[12], ARTICLE[25]
final List items = this.getCreator().getItems(r);
final Iterator iter = items.iterator();
while (iter.hasNext()) {
final SQLRowAccessor foreignRow = (SQLRowAccessor) iter.next();
final List<SQLRowAccessor> items = this.getCreator().getItems(r);
for (final SQLRowAccessor foreignRow : items) {
// reuse existant views and create necessary ones
final ListItemSQLView v;
if (availableViews.isEmpty()) {
107,17 → 103,17
 
//
 
public List getItems() {
final List res = new ArrayList(this.stills);
public List<SQLRowItemView> getItems() {
final List<SQLRowItemView> res = new ArrayList<SQLRowItemView>(this.stills);
res.addAll(this.added);
return res;
}
 
public List getAddedItems() {
public List<SQLRowItemView> getAddedItems() {
return Collections.unmodifiableList(this.added);
}
 
public List getRemovedItems() {
public List<SQLRowItemView> getRemovedItems() {
return Collections.unmodifiableList(this.removed);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/SharedFFPoolFactory.java
24,7 → 24,7
super(t, foreignT, count, firstSuffixed);
}
 
public SharedFFPoolFactory(SQLTable t, String foreignT, List fields) {
public SharedFFPoolFactory(SQLTable t, String foreignT, List<String> fields) {
super(t, foreignT, fields);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableModelColumnPath.java
96,7 → 96,7
}
 
@Override
protected Class getValueClass_() {
protected Class<?> getValueClass_() {
return this.getField().getType().getJavaType();
}
 
112,8 → 112,7
 
@Override
protected Object show_(final SQLRowAccessor r) {
// to speed things up, suppose that r is correct (avoid getForeignTable())
return this.p.getObject((SQLRowValues) r, false);
return this.p.getObject(r.asRowValues());
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java
13,7 → 13,7
package org.openconcerto.sql.view.list;
 
import org.openconcerto.openoffice.XMLVersion;
import org.openconcerto.openoffice.XMLFormatVersion;
import org.openconcerto.openoffice.spreadsheet.SpreadSheet;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.Log;
20,6 → 20,7
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLImmutableRowValues;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
26,11 → 27,15
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.view.FileTransfertHandler;
import org.openconcerto.sql.view.IListener;
import org.openconcerto.sql.view.list.RowAction.LimitedSizeRowAction;
import org.openconcerto.sql.view.search.ColumnSearchSpec;
import org.openconcerto.sql.view.search.SearchList;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.FormatEditor;
import org.openconcerto.ui.MenuUtils;
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.ui.list.selection.ListSelection;
import org.openconcerto.ui.list.selection.ListSelectionState;
import org.openconcerto.ui.state.JTableStateManager;
49,6 → 54,8
import org.openconcerto.utils.convertor.StringClobConvertor;
 
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
65,7 → 72,6
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.sql.Clob;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
75,6 → 81,7
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
82,8 → 89,10
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
90,6 → 99,7
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.AncestorEvent;
141,6 → 151,10
FORCE_ALT_CELL_RENDERER = force;
}
 
public static final IListe get(ActionEvent evt) {
return SwingThreadUtils.getAncestorOrSelf(IListe.class, (Component) evt.getSource());
}
 
// *** instance
 
private final JTable jTable;
155,6 → 169,11
private boolean adjustVisible;
private ColumnSizeAdjustor tcsa;
 
private final Map<RowAction, JButton> rowActions;
// double-click
private RowAction defaultRowAction;
private final JPanel btnPanel;
 
// * selection
private final List<IListener> listeners;
private final List<IListener> naListeners;
170,6 → 189,7
 
private final ListSelectionState state;
private final JTableStateManager tableStateManager;
private List<RowActionFactory> rowActionFactories = new ArrayList<RowActionFactory>(0);
 
public IListe(final ListSQLRequest req) {
this(req, null);
191,6 → 211,7
if (req == null)
throw new NullPointerException("Création d'une IListe avec une requete null");
 
this.rowActions = new LinkedHashMap<RowAction, JButton>();
this.supp = new PropertyChangeSupport(this);
this.listeners = new ArrayList<IListener>();
this.naListeners = new ArrayList<IListener>();
218,7 → 239,7
infoL.add(original);
}
 
final SQLRowValues row = IListe.this.getModel().getRow(rowIndex).getRow();
final SQLRowValues row = ITableModel.getLine(this.getModel(), rowIndex).getRow();
 
final String create = getLine("Créée", row, getSource().getPrimaryTable().getCreationUserField(), getSource().getPrimaryTable().getCreationDateField());
if (create != null)
278,15 → 299,22
TablePopupMouseListener.add(this.jTable, new ITransformer<MouseEvent, JPopupMenu>() {
@Override
public JPopupMenu transformChecked(MouseEvent input) {
// afficher un menu que si selection
return hasSelection() ? IListe.this.popup : null;
return updatePopupMenu();
}
});
this.jTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2)
performDefaultAction(e);
}
});
 
this.selectionListener = new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
fireNASelectionId();
updateButtons();
}
}
};
330,6 → 358,8
// car les updates du ITableModel se font de manière synchrone dans la EDT
// donc on ne peut faire aucune action pendant les maj
 
this.btnPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
 
uiInit();
}
 
342,10 → 372,115
return FORMATS;
}
 
public final void addRowAction(Action action) {
this.popup.add(action);
public final RowAction addRowAction(Action action) {
// for backward compatibility don't put in header
final RowAction res = new LimitedSizeRowAction(action, false, true);
this.addRowAction(res);
return res;
}
 
public final void addRowActions(Collection<RowAction> actions) {
for (final RowAction a : actions)
this.addRowAction(a);
}
 
public void addRowActionFactories(List<RowActionFactory> rowActionFactories) {
this.rowActionFactories.addAll(rowActionFactories);
}
 
public final void addRowAction(RowAction action) {
final JButton headerBtn = action.inHeader() ? new JButton(action.getAction()) : null;
this.rowActions.put(action, headerBtn);
if (headerBtn != null) {
this.updateButton(action, getSelectedRows());
this.btnPanel.add(headerBtn);
this.btnPanel.setVisible(true);
}
}
 
public final void removeRowActions(Collection<RowAction> actions) {
for (final RowAction a : actions)
this.removeRowAction(a);
}
 
public final void removeRowAction(RowAction action) {
final JButton headerBtn = this.rowActions.remove(action);
if (headerBtn != null) {
this.btnPanel.remove(headerBtn);
if (this.btnPanel.getComponentCount() == 0)
this.btnPanel.setVisible(false);
this.btnPanel.revalidate();
}
if (action.equals(this.defaultRowAction))
this.defaultRowAction = null;
}
 
public void removeRowActionFactories(List<RowActionFactory> rowActionFactories2) {
// TODO Auto-generated method stub
}
 
private void updateButtons() {
final List<SQLRowAccessor> selectedRows = getSelectedRows();
for (final RowAction action : this.rowActions.keySet()) {
this.updateButton(action, selectedRows);
}
}
 
private JButton updateButton(final RowAction action, List<SQLRowAccessor> selectedRows) {
final JButton btn = this.rowActions.get(action);
if (btn != null) {
btn.setEnabled(action.enabledFor(selectedRows));
}
return btn;
}
 
private JPopupMenu updatePopupMenu() {
this.popup.removeAll();
final List<SQLRowAccessor> selectedRows = getSelectedRows();
List<RowAction> actions = new ArrayList<RowAction>();
actions.addAll(this.rowActions.keySet());
final int size = this.rowActionFactories.size();
for (int i = 0; i < size; i++) {
RowActionFactory f = this.rowActionFactories.get(i);
List<RowAction> l = f.createActions(selectedRows);
if (l != null) {
actions.addAll(l);
}
}
 
for (final RowAction a : actions) {
if (a.inPopupMenu()) {
final JMenuItem menuItem = MenuUtils.addMenuItem(a.getAction(), this.popup, a.getPath());
if (a.equals(this.defaultRowAction))
menuItem.setFont(menuItem.getFont().deriveFont(Font.BOLD));
menuItem.setEnabled(a.enabledFor(selectedRows));
}
}
 
return this.popup;
}
 
/**
* Set the action performed when double-clicking a row. This method calls
* {@link #addRowAction(Action)} and the popup display this action distinctively.
*
* @param action the default action.
*/
public final void setDefaultRowAction(final RowAction action) {
if (action != null && !this.rowActions.containsKey(action))
this.addRowAction(action);
this.defaultRowAction = action;
}
 
public final RowAction getDefaultRowAction() {
return this.defaultRowAction;
}
 
private void performDefaultAction(MouseEvent e) {
if (this.defaultRowAction != null && this.defaultRowAction.enabledFor(getSelectedRows()))
this.defaultRowAction.getAction().actionPerformed(new ActionEvent(e.getSource(), e.getID(), null, e.getWhen(), e.getModifiers()));
}
 
private void uiInit() {
// * filter
this.filter.addMouseListener(new MouseAdapter() {
451,6 → 586,11
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0);
this.add(this.filter, c);
 
c.gridy++;
this.btnPanel.setVisible(false);
this.add(this.btnPanel, c);
 
c.weighty = 1;
c.gridy++;
this.add(scrollPane, c);
462,6 → 602,8
dispChanged();
}
});
 
this.setTransferHandler(new FileTransfertHandler(getSource().getPrimaryTable()));
}
 
protected synchronized final void invertDebug() {
537,31 → 679,15
 
// Export en tableau OpenOffice
public void exporter(File file) throws IOException {
exporter(file, false, XMLVersion.getDefault());
exporter(file, false, XMLFormatVersion.getDefault());
}
 
public File exporter(File file, final boolean onlySelection, final XMLVersion version) throws IOException {
public File exporter(File file, final boolean onlySelection, final XMLFormatVersion version) throws IOException {
return SpreadSheet.export(getExportModel(onlySelection), file, version);
}
 
protected TableModel getExportModel(final boolean onlySelection) {
final ViewTableModel res;
final String appName = Configuration.getInstance() == null ? null : Configuration.getInstance().getAppName();
final boolean isGestioNX = appName != null && appName.startsWith("OpenConcerto");
if (isGestioNX) {
res = new ViewTableModel(this.jTable) {
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
final Object value = super.getValueAt(rowIndex, columnIndex);
if (value instanceof Long || value instanceof BigInteger) {
return new Double(((Number) value).longValue() / 100.0);
} else {
return value;
}
}
};
} else
res = new ViewTableModel(this.jTable);
final ViewTableModel res = new ViewTableModel(this.jTable);
return onlySelection ? new TableModelSelectionAdapter(res, this.jTable.getSelectedRows()) : res;
}
 
675,6 → 801,21
return this.getRow(this.getSelection().getUserSelectedID());
}
 
public final List<SQLRowAccessor> getSelectedRows() {
final ListSelectionModel selectionModel = this.getJTable().getSelectionModel();
if (selectionModel.isSelectionEmpty())
return Collections.emptyList();
 
final int start = selectionModel.getMinSelectionIndex();
final int stop = selectionModel.getMaxSelectionIndex();
final List<SQLRowAccessor> res = new ArrayList<SQLRowAccessor>();
for (int i = start; i <= stop; i++) {
if (selectionModel.isSelectedIndex(i))
res.add(new SQLImmutableRowValues(this.getLine(i).getRow()));
}
return res;
}
 
public final void setAdjustVisible(boolean b) {
this.adjustVisible = b;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableModelSource.java
26,7 → 26,6
import org.openconcerto.utils.change.ListChangeIndex;
import org.openconcerto.utils.change.ListChangeRecorder;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.ref.WeakReference;
135,19 → 134,15
}
 
private void listenToCols() {
this.cols.getRecipe().clear();
// keep allCols in sync with cols, and listen to any change
this.cols.getRecipe().bind(this.allCols);
this.cols.getRecipe().addListener(new PropertyChangeListener() {
this.cols.getRecipe().addListener(new IClosure<ListChangeIndex<SQLTableModelColumn>>() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
final ListChangeIndex change = (ListChangeIndex) evt.getNewValue();
for (final Object o : change.getItemsRemoved()) {
final SQLTableModelColumn col = (SQLTableModelColumn) o;
public void executeChecked(ListChangeIndex<SQLTableModelColumn> change) {
for (final SQLTableModelColumn col : change.getItemsRemoved()) {
SQLTableModelSource.this.colsByName.remove(col.getName());
}
for (final Object o : change.getItemsAdded()) {
final SQLTableModelColumn col = (SQLTableModelColumn) o;
for (final SQLTableModelColumn col : change.getItemsAdded()) {
SQLTableModelSource.this.colsByName.put(col.getName(), col);
}
colsChanged(change);
156,7 → 151,7
});
}
 
protected void colsChanged(final ListChangeIndex change) {
protected void colsChanged(final ListChangeIndex<SQLTableModelColumn> change) {
}
 
private void fireColsChanged() {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTablePanel.java
New file
0,0 → 1,84
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.view.list;
 
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.ui.DefaultGridBagConstraints;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
 
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ToolTipManager;
 
public abstract class RowValuesTablePanel extends JPanel {
protected RowValuesTableModel model;
protected RowValuesTable table;
protected SQLRowValues defaultRowVals;
 
/**
* TableModel and Table initialization
* */
protected abstract void init();
 
public abstract SQLElement getSQLElement();
 
/**
* User interface initialization
*/
protected void uiInit() {
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new DefaultGridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
this.add(new JScrollPane(this.table), c);
this.table.setDefaultRenderer(Long.class, new RowValuesTableRenderer());
ToolTipManager.sharedInstance().unregisterComponent(this.table);
ToolTipManager.sharedInstance().unregisterComponent(this.table.getTableHeader());
}
 
public void updateField(String field, int id) {
this.table.updateField(field, id);
}
 
public RowValuesTable getRowValuesTable() {
return this.table;
}
 
public void insertFrom(String field, int id) {
this.table.insertFrom(field, id);
}
 
public RowValuesTableModel getModel() {
return this.table.getRowValuesTableModel();
}
 
public void refreshTable() {
this.table.repaint();
}
 
public SQLRowValues getDefaultRowValues() {
return this.defaultRowVals;
}
 
public void removeSelectedRow() {
int index = this.table.getSelectedRow();
if (index >= 0 && index < model.getRowCount()) {
this.model.removeRowAt(index);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/TextTableCellEditorWithCompletion.java
29,7 → 29,7
// FIXME replace by requestcombobox
t.setPopupInvoker(getTextArea());
t.setTextEditor(getTextArea());
textWithCompl.setSelectionAutoEnabled(false);
textWithCompl.setSelectionAutoEnabled(true);
}
 
public void setSelectionAutoEnabled(boolean b) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowActionFactory.java
New file
0,0 → 1,32
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.view.list;
 
import org.openconcerto.sql.model.SQLRowAccessor;
 
import java.util.List;
 
public abstract class RowActionFactory {
private String tableName;
 
public RowActionFactory(String tableName) {
this.tableName = tableName;
}
 
public String getTableName() {
return tableName;
}
 
public abstract List<RowAction> createActions(List<SQLRowAccessor> rows);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/AutoCompletionManager.java
15,7 → 15,7
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.ITextWithCompletion;
169,8 → 169,9
}
new Thread(new Runnable() {
public void run() {
final SQLRowValues rowV = new SQLRowValues(AutoCompletionManager.this.fillFrom.getTable());
rowV.loadAllSafe(AutoCompletionManager.this.fillFrom.getTable().getRow(id));
// final SQLRowValues rowV = new
// SQLRowValues(AutoCompletionManager.this.fillFrom.getTable());
final SQLRow rowV = AutoCompletionManager.this.fillFrom.getTable().getRow(id);
final Set<String> keys = AutoCompletionManager.this.fillBy.keySet();
// Fill the table model rowvalue with the selected item using the fields defined
// with 'fill'
180,7 → 181,7
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
String from = iter.next();
String to = AutoCompletionManager.this.fillBy.get(from);
Object fromV = rowV.getObject(from);
Object fromV = getValueFrom(rowV, from);
int column = AutoCompletionManager.this.tableModel.getColumnForField(to);
if (column >= 0) {
 
213,6 → 214,10
}
}
 
protected Object getValueFrom(SQLRow row, String field) {
return row.getObject(field);
}
 
public void setWhere(Where w) {
this.t.setWhere(w);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTable.java
30,6 → 30,9
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
37,7 → 40,10
import java.util.List;
import java.util.Set;
 
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.TableModelEvent;
109,10 → 115,20
this.getModel().addTableModelListener(this);
 
this.getTableHeader().setReorderingAllowed(false);
 
this.addAncestorListener(this);
this.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
 
// ALT ENTER pour ajouter une nouvelle ligne
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.ALT_DOWN_MASK), "addLine");
this.getActionMap().put("addLine", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
getRowValuesTableModel().addNewRow();
}
});
 
}
 
@Override
public void paint(Graphics g) {
updateEditorAndRenderer();
180,12 → 196,15
 
public void loadState(String filename) {
this.stateManager.loadState(new File(filename));
 
}
 
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
// Scroll à la ligne insérée
if (e.getType() == TableModelEvent.INSERT) {
scrollRectToVisible(new Rectangle(getCellRect(e.getFirstRow(), 0, true)));
}
}
 
public RowValuesTableModel getRowValuesTableModel() {
return this.model;
207,7 → 226,6
 
public void updateField(String field, int id, String fieldCondition) {
this.model.updateField(field, id, fieldCondition);
 
// Clear pour fixer le probleme avec les editframe et ne pas fermer la fenetre
// sinon les elements pointront sur la nouveau devis et l'ancien les perdra
clear();
215,7 → 233,6
 
public void updateField(String field, SQLRowValues rowVals, String fieldCondition) {
this.model.updateField(field, rowVals, fieldCondition);
 
// Clear pour fixer le probleme avec les editframe et ne pas fermer la fenetre
// sinon les elements pointront sur la nouveau devis et l'ancien les perdra
clear();
251,14 → 268,11
 
@Override
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
 
super.changeSelection(rowIndex, columnIndex, toggle, extend);
if (editCellAt(rowIndex, columnIndex)) {
// System.out.println("editCellAt called");
getEditorComponent().requestFocusInWindow();
getEditorComponent().requestFocus();
} else {
// System.out.println("editCellAt called but failed");
}
}
 
267,7 → 281,6
TableColumn tableColumn = getColumnModel().getColumn(column);
TableCellEditor editor = tableColumn.getCellEditor();
if (editor == null) {
 
editor = getDefaultEditor(getColumnClass(column));
}
return editor;
292,7 → 305,6
try {
this.stateManager.saveState();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
303,12 → 315,10
}
 
public void ancestorMoved(AncestorEvent event) {
// TODO Auto-generated method stub
 
}
 
public void ancestorRemoved(AncestorEvent event) {
// TODO Auto-generated method stub
 
}
 
322,19 → 332,16
 
@Override
public void addValueListener(PropertyChangeListener l) {
// TODO Auto-generated method stub
 
}
 
@Override
public Component getComp() {
// TODO Auto-generated method stub
return this;
}
 
@Override
public String getDescription() {
// TODO Auto-generated method stub
return this.model.getSQLElement().getPluralName();
}
 
343,7 → 350,6
 
@Override
public SQLField getField() {
 
return this.field;
}
 
354,68 → 360,62
 
@Override
public void insert(SQLRowValues vals) {
// TODO Auto-generated method stub
System.err.println("Insert");
}
 
@Override
public void resetValue() {
// TODO Auto-generated method stub
 
}
 
@Override
public void setEditable(boolean b) {
// TODO Auto-generated method stub
this.model.setEditable(b);
}
 
@Override
public void show(SQLRowAccessor r) {
// TODO Auto-generated method stub
 
}
 
@Override
public void update(SQLRowValues vals) {
// TODO Auto-generated method stub
 
}
 
@Override
public void addEmptyListener(EmptyListener l) {
// TODO Auto-generated method stub
 
}
 
@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return false;
}
 
@Override
public void addValidListener(ValidListener l) {
// TODO Auto-generated method stub
 
}
 
@Override
public void removeValidListener(ValidListener l) {
 
}
 
@Override
public String getValidationText() {
// TODO Auto-generated method stub
SQLFieldTranslator trans = Configuration.getInstance().getTranslator();
final SQLFieldTranslator trans = Configuration.getInstance().getTranslator();
return "au moins " + this.model.getSQLElement().getSingularName() + " n'a pas le champ requis \"" + trans.getLabelFor(this.model.getRequiredField()) + "\" rempli";
}
 
@Override
public boolean isValidated() {
// TODO Auto-generated method stub
return this.model.isValidated();
}
 
@Override
public void init(String sqlName, Set<SQLField> fields) {
// TODO Auto-generated method stub
final Object[] array = fields.toArray();
if (array.length > 0) {
this.field = (SQLField) array[0];
427,7 → 427,6
 
@Override
public void setDescription(String s) {
// TODO Auto-generated method stub
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTextComboTableCellEditor.java
18,6 → 18,7
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
 
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
26,7 → 27,10
 
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.table.TableCellEditor;
 
public class SQLTextComboTableCellEditor extends AbstractCellEditor implements TableCellEditor {
43,6 → 47,11
this.addUndefined = addUndefined;
 
this.comboBox = new SQLRequestComboBox(addUndefined);
// Mimic JTable.GenericEditor behavior
this.comboBox.getTextComp().setBorder(new EmptyBorder(0, 0, 0, 18));
this.comboBox.setBorder(new LineBorder(Color.black));
((JComponent) this.comboBox.getPulseComponent()).setBorder(null);
 
ComboSQLRequest c = new ComboSQLRequest(elt.getComboRequest());
this.comboBox.uiInit(c);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowAction.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.sql.view.list;
 
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.utils.cc.IClosure;
 
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
 
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
 
/**
* An action that act on rows of a {@link IListe}.
*
* @author Sylvain CUAZ
* @see IListe#addRowAction(RowAction)
*/
public abstract class RowAction {
 
public static Action createAction(String name, Icon icon, final IClosure<List<SQLRowAccessor>> action) {
return new AbstractAction(name, icon) {
@Override
public void actionPerformed(ActionEvent e) {
action.executeChecked(IListe.get(e).getSelectedRows());
}
};
}
 
public static class LimitedSizeRowAction extends RowAction {
private int minSize = 1;
private int maxSize = Integer.MAX_VALUE;
 
public LimitedSizeRowAction(Action action, boolean header) {
super(action, header);
}
 
public LimitedSizeRowAction(Action action, boolean header, boolean popupMenu) {
super(action, header, popupMenu);
}
 
public final int getMinSize() {
return this.minSize;
}
 
public final LimitedSizeRowAction setMinSize(int minSize) {
this.minSize = minSize;
return this;
}
 
public final int getMaxSize() {
return this.maxSize;
}
 
public final LimitedSizeRowAction setMaxSize(int maxSize) {
this.maxSize = maxSize;
return this;
}
 
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return selection.size() >= this.minSize && selection.size() <= this.maxSize;
}
}
 
private final Action action;
private final boolean header, popupMenu;
private List<String> path;
 
public RowAction(Action action, boolean header) {
this(action, header, true);
}
 
public RowAction(Action action, boolean header, boolean popupMenu) {
super();
this.action = action;
this.header = header;
this.popupMenu = popupMenu;
this.setGroup(null);
}
 
public final Action getAction() {
return this.action;
}
 
public final boolean inHeader() {
return this.header;
}
 
public final boolean inPopupMenu() {
return this.popupMenu;
}
 
public final RowAction setGroup(String groupName) {
this.path = Arrays.asList(groupName);
return this;
}
 
public final RowAction setPath(List<String> path) {
this.path = Collections.unmodifiableList(new ArrayList<String>(path));
return this;
}
 
public final List<String> getPath() {
return this.path;
}
 
public abstract boolean enabledFor(List<SQLRowAccessor> selection);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableModelSourceOnline.java
43,11 → 43,10
}
 
@Override
protected void colsChanged(ListChangeIndex change) {
protected void colsChanged(ListChangeIndex<SQLTableModelColumn> change) {
super.colsChanged(change);
// add needed fields for each new column
for (final Object o : change.getItemsAdded()) {
final SQLTableModelColumn col = (SQLTableModelColumn) o;
for (final SQLTableModelColumn col : change.getItemsAdded()) {
for (final FieldPath p : col.getPaths()) {
final SQLRowValues assurePath = this.getReq().getGraphToFetch().assurePath(p.getPath());
if (!assurePath.getFields().contains(p.getFieldName()))
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableElement.java
230,6 → 230,10
return this.rowField;
}
 
protected Object getDefaultNullValue() {
return null;
}
 
public Object convertEditorValueToModel(final Object value, final SQLRowValues row) {
 
// if (value instanceof IComboSelectionItem) {
241,8 → 245,12
return v;
}
// }
if (value == null && getDefaultNullValue() != null) {
return getDefaultNullValue();
} else {
return value;
}
}
 
public void fireModification(final SQLRowValues row) {
// System.out.println("FireModification: from:" + this.name);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/DropManager.java
New file
0,0 → 1,54
/*
* 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.model.SQLTable;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class DropManager {
private static final DropManager instance = new DropManager();
private final Map<SQLTable, List<FileDropHandler>> handlers = new HashMap<SQLTable, List<FileDropHandler>>();
 
private DropManager() {
}
 
public static DropManager getInstance() {
return instance;
}
 
public void add(SQLTable table, FileDropHandler handler) {
List<FileDropHandler> l = handlers.get(table);
if (l == null) {
l = new ArrayList<FileDropHandler>();
handlers.put(table, l);
}
if (l.contains(handler)) {
throw new IllegalArgumentException("Handler already defined for table " + table);
}
l.add(handler);
}
 
public List<FileDropHandler> getHandlerForTable(SQLTable tableName) {
List<FileDropHandler> l = handlers.get(tableName);
if (l == null) {
l = new ArrayList<FileDropHandler>(0);
}
return l;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/EditFrame.java
21,6 → 21,7
import org.openconcerto.utils.doc.Documented;
 
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
98,8 → 99,15
this.setContentPane(this.panel);
this.initTitle(comp.getElement(), mode);
this.setLocation(0, 50);
 
// The minimum size of the frame must be the size when packed
this.pack();
this.setMinimumSize(new Dimension(this.getMinimumSize()));
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int w = Math.min(d.width - 100, getWidth());
int h = Math.min(d.height - 100, getHeight());
setMinimumSize(new Dimension(w, h));
 
// View resized
this.viewResized();
addEditPanelListener(this);
if (mode == CREATION) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/FileDropHandler.java
New file
0,0 → 1,29
/*
* 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 java.awt.Component;
import java.io.File;
 
public interface FileDropHandler {
/**
* not called in the AWT event dispatching thread
* */
public boolean canHandle(File f);
 
/**
* called in the AWT event dispatching thread
* */
public boolean handle(File f, Component source);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/SQLMenuItemHelper.java
15,17 → 15,15
 
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.IFactory;
 
import java.awt.event.ActionEvent;
 
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
 
import org.apache.commons.collections.Factory;
 
/**
* Allow to easily create JMenuItem from an SQLElement (for creating and listing). If you want
* custom behaviour you can overload postProcessFrame(), createEditFrame() and createListFrame().
94,13 → 92,18
 
public final JMenuItem createEditMenuItem(final SQLElement elem) {
this.menuItemCreated(elem);
final SQLMenuItemAction menuItemAction = new SQLMenuItemAction(elem, "Créer " + elem.getSingularName(), new Factory() {
public Object create() {
return new JMenuItem(createEditAction(elem));
}
 
public final SQLMenuItemAction createEditAction(final SQLElement elem) {
final SQLMenuItemAction menuItemAction = new SQLMenuItemAction(elem, "Créer " + elem.getSingularName(), new IFactory<JFrame>() {
@Override
public JFrame createChecked() {
return ppFrame(createEditFrame(elem), null);
}
});
this.actionCreated(menuItemAction);
return new JMenuItem(menuItemAction);
return menuItemAction;
}
 
public final JMenuItem createListMenuItem(final SQLElement elem) {
109,13 → 112,22
 
public final JMenuItem createListMenuItem(final SQLElement elem, final IClosure<IListFrame> initFrame) {
this.menuItemCreated(elem);
final SQLMenuItemAction menuItemAction = new SQLMenuItemAction(elem, "Gérer les " + elem.getPluralName(), new Factory() {
public Object create() {
return new JMenuItem(createListAction(elem, initFrame));
}
 
public final SQLMenuItemAction createListAction(final SQLElement elem) {
return this.createListAction(elem, null);
}
 
public final SQLMenuItemAction createListAction(final SQLElement elem, final IClosure<IListFrame> initFrame) {
final SQLMenuItemAction menuItemAction = new SQLMenuItemAction(elem, "Gérer les " + elem.getPluralName(), new IFactory<JFrame>() {
@Override
public JFrame createChecked() {
return ppFrame(createListFrame(elem), initFrame);
}
});
this.actionCreated(menuItemAction);
return new JMenuItem(menuItemAction);
return menuItemAction;
}
 
public static abstract class AbstractSQLMenuItemAction extends AbstractAction {
122,24 → 134,37
 
private final SQLElement elem;
private JFrame frame;
private boolean cacheFrame;
 
public AbstractSQLMenuItemAction(SQLElement elem, String name) {
super(name);
this.elem = elem;
this.putValue(Action.NAME, name);
this.frame = null;
this.cacheFrame = true;
}
 
public final void setCacheFrame(boolean cacheFrame) {
if (this.cacheFrame != cacheFrame) {
this.cacheFrame = cacheFrame;
this.frame = null;
}
}
 
/**
* La frame que doit afficher cet élément de menu.
*
* @return la frame de cet élément de menu.
*/
public synchronized final JFrame getFrame() {
public final JFrame getFrame() {
if (this.cacheFrame) {
if (this.frame == null) {
this.frame = this.createFrame();
}
return this.frame;
} else {
return this.createFrame();
}
}
 
protected abstract JFrame createFrame();
 
147,6 → 172,7
return this.elem;
}
 
@Override
public void actionPerformed(ActionEvent e) {
this.getFrame().setVisible(true);
}
154,15 → 180,16
 
public static class SQLMenuItemAction extends AbstractSQLMenuItemAction {
 
private final Factory frameFactory;
private final IFactory<? extends JFrame> frameFactory;
 
public SQLMenuItemAction(SQLElement elem, String name, Factory frameFactory) {
public SQLMenuItemAction(SQLElement elem, String name, IFactory<? extends JFrame> frameFactory) {
super(elem, name);
this.frameFactory = frameFactory;
}
 
@Override
protected JFrame createFrame() {
return (JFrame) this.frameFactory.create();
return this.frameFactory.createChecked();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/IListPanel.java
17,7 → 17,7
import static javax.swing.JOptionPane.QUESTION_MESSAGE;
import org.openconcerto.openoffice.ContentType;
import org.openconcerto.openoffice.OOUtils;
import org.openconcerto.openoffice.XMLVersion;
import org.openconcerto.openoffice.XMLFormatVersion;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
29,6 → 29,7
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.search.SearchListComponent;
import org.openconcerto.ui.ContinuousButtonModel;
import org.openconcerto.ui.FrameUtil;
35,7 → 36,9
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.change.ListChangeIndex;
 
import java.awt.Container;
import java.awt.Dimension;
46,6 → 49,8
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
150,6 → 155,31
list.setConfigFile(config);
}
this.liste = list;
final IClosure<ListChangeIndex<RowAction>> l = new IClosure<ListChangeIndex<RowAction>>() {
@Override
public void executeChecked(ListChangeIndex<RowAction> input) {
for (final RowAction rm : input.getItemsRemoved())
getListe().removeRowAction(rm);
for (final RowAction added : input.getItemsAdded())
getListe().addRowAction(added);
}
};
// remove listener if non displayable since getElement() never dies
this.addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0)
if (isDisplayable()) {
getListe().addRowActions(getElement().getRowActions());
getListe().addRowActionFactories(getElement().getRowActionFactories());
getElement().addRowActionsListener(l);
} else {
getElement().removeRowActionsListener(l);
getListe().removeRowActions(getElement().getRowActions());
getListe().removeRowActionFactories(getElement().getRowActionFactories());
}
}
});
 
this.init();
}
 
450,8 → 480,8
options, options[0]);
if (answer == 0 || answer == 1) {
final FileDialog fd = new FileDialog(SwingThreadUtils.getAncestorOrSelf(Frame.class, this), "Sauver la liste", FileDialog.SAVE);
final XMLVersion version = XMLVersion.getDefault();
fd.setFile(this.element.getPluralName().replace('/', '-') + "." + ContentType.SPREADSHEET.getVersioned(version).getExtension());
final XMLFormatVersion version = XMLFormatVersion.getDefault();
fd.setFile(this.element.getPluralName().replace('/', '-') + "." + ContentType.SPREADSHEET.getVersioned(version.getXMLVersion()).getExtension());
fd.setVisible(true);
if (fd.getFile() != null) {
final File f = this.liste.exporter(new File(fd.getDirectory(), fd.getFile()), answer == 1, version);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/FileTransfertHandler.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.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 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) {
this.tableName = table;
}
 
@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 {
 
Thread thread = new Thread("FileTransfertHandler " + this.tableName) {
 
@Override
public void run() {
List<FileDropHandler> handlers = getHandlers();
for (File realFile : list) {
Log.get().info("Searching handler for file:" + realFile.getAbsolutePath());
for (FileDropHandler handler : handlers) {
if (handler.canHandle(realFile)) {
Log.get().config("Importing file:" + realFile.getAbsolutePath() + " with " + handler);
handler.handle(realFile, c);
break;
}
}
}
 
}
};
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 (getHandlers().isEmpty()) {
Log.get().config("No drop handler for table " + this.tableName);
return false;
}
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;
}
 
protected List<FileDropHandler> getHandlers() {
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
15,6 → 15,7
 
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.element.SQLElementDirectory.DirectoryListener;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBStructureItem;
import org.openconcerto.sql.model.DBSystemRoot;
152,6 → 153,7
private SQLFilter filter;
private SQLFieldTranslator translator;
private SQLElementDirectory directory;
private DirectoryListener directoryListener;
private File wd;
// split sql tree and the rest since creating the tree is costly
// and nodes are inter-dependant, while the rest is mostly fast
202,6 → 204,8
if (this.server != null) {
this.server.destroy();
}
if (this.directoryListener != null)
this.directory.removeListener(this.directoryListener);
}
 
public final String getProperty(String name) {
517,6 → 521,13
FileUtils.mkdir_p(homeLogDir);
logDir = homeLogDir;
}
System.out.println("Log directory: " + logDir.getAbsolutePath());
if (!logDir.exists()) {
System.err.println("Log directory: " + logDir.getAbsolutePath() + " DOEST NOT EXISTS!!!");
}
if (!logDir.canWrite()) {
System.err.println("Log directory: " + logDir.getAbsolutePath() + " is NOT WRITABLE");
}
} catch (IOException e) {
throw new IllegalStateException("unable to create log dir", e);
}
527,6 → 538,7
final File logFile = new File(logDir, (logNameBase + ".txt"));
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);
545,6 → 557,8
}
}
}).start();
} else {
System.out.println("Log not redirected to file");
}
 
// removes default
555,6 → 569,7
try {
final File logFile = new File(logDir, this.getAppName() + "-%u-age%g.log");
logFile.getParentFile().mkdirs();
System.out.println("Logger logs: " + logFile.getAbsolutePath());
// 2 files of at most 5M, each new launch append
// if multiple concurrent launches %u is used
final FileHandler fh = new FileHandler(logFile.getPath(), 5 * 1024 * 1024, 2, true);
561,7 → 576,7
fh.setFormatter(new SimpleFormatter());
Logger.getLogger("").addHandler(fh);
} catch (IOException e) {
ExceptionHandler.handle("Enregistrement du log désactivé", e);
ExceptionHandler.handle("Enregistrement du Logger désactivé", e);
}
 
this.setLoggersLevel();
581,7 → 596,15
 
protected ShowAs createShowAs() {
final ShowAs res = new ShowAs(this.getRoot());
for (final SQLElement elem : this.getDirectory().getElements()) {
assert this.directoryListener == null;
this.directoryListener = new DirectoryListener() {
@Override
public void elementRemoved(SQLElement elem) {
res.removeTable(elem.getTable());
}
 
@Override
public void elementAdded(SQLElement elem) {
final CollectionMap<String, String> sa = elem.getShowAs();
if (sa != null) {
for (final Entry<String, Collection<String>> e : sa.entrySet()) {
592,6 → 615,13
}
}
}
};
synchronized (this.getDirectory()) {
for (final SQLElement elem : this.getDirectory().getElements()) {
this.directoryListener.elementAdded(elem);
}
this.getDirectory().addListener(this.directoryListener);
}
return res;
}
 
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ValidChangeSupport.java
49,4 → 49,7
this.listeners.add(l);
}
 
public void removeValidListener(ValidListener l) {
this.listeners.remove(l);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ValidObjectCombiner.java
82,4 → 82,7
this.supp.addValidListener(l);
}
 
public void removeValidListener(ValidListener l) {
this.supp.removeValidListener(l);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ValidObject.java
28,6 → 28,8
 
public void addValidListener(ValidListener l);
 
public void removeValidListener(ValidListener l);
 
/**
* Why isValidated() returns its value.
*
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ChainValidListener.java
25,6 → 25,8
private final ValidObject target;
 
public ChainValidListener(ValidObject target, ValidListener delegate) {
if (target == null || delegate == null)
throw new NullPointerException();
this.target = target;
this.delegate = delegate;
}
33,4 → 35,25
this.delegate.validChange(this.target, newValue);
}
 
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + this.delegate.hashCode();
result = prime * result + this.target.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 ChainValidListener other = (ChainValidListener) obj;
return this.delegate.equals(other.delegate) && this.target.equals(other.target);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/shortcut.vbs
New file
0,0 → 1,30
if Wscript.Arguments.count = 0 then
Wscript.Echo "Usage: " & WScript.ScriptName & " shortcutPath [absoluteTarget]"
Wscript.Quit
end if
 
linkPath = Wscript.Arguments.item(0)
' a shortcut must always end with .LNK
if UCase(Right(linkPath, 4)) <> ".LNK" then
linkPath = linkPath & ".LNK"
end if
 
Set oWS = WScript.CreateObject("WScript.Shell")
Set oLink = oWS.CreateShortcut(linkPath)
 
if Wscript.Arguments.count = 1 then
' means readlink
Wscript.Echo oLink.TargetPath
else
' means ln
targetPath = Wscript.Arguments.item(1)
oLink.TargetPath = targetPath
'oWS.CurrentDirectory & "\" &
' oLink.Arguments = ""
' oLink.Description = "MyProgram"
' oLink.HotKey = "ALT+CTRL+F"
' oLink.IconLocation = "C:\Program Files\MyApp\MyProgram.EXE, 2"
' oLink.WindowStyle = "1"
' oLink.WorkingDirectory = "C:\Program Files\MyApp"
oLink.Save
end if
/trunk/OpenConcerto/src/org/openconcerto/utils/StringUtils.java
16,6 → 16,7
*/
package org.openconcerto.utils;
 
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
30,6 → 31,8
*/
public class StringUtils {
 
private static final Charset UTF8 = Charset.forName("UTF8");
 
/**
* Retourne la chaine avec la première lettre en majuscule et le reste en minuscule.
*
56,6 → 59,128
return s.substring(0, 1).toUpperCase() + s.substring(1);
}
 
static public abstract class Shortener {
 
private final int hashSize;
private final int hashPartSize;
private final String prefix;
private final String suffix;
private final int minStringLength;
 
protected Shortener(int hashSize, String prefix, String suffix, int minCharsBeforeAndAfter) {
super();
this.hashSize = hashSize;
this.prefix = prefix;
this.suffix = suffix;
this.hashPartSize = this.hashSize + this.prefix.length() + this.suffix.length();
if (minCharsBeforeAndAfter < 1)
throw new IllegalArgumentException("minCharsBeforeAndAfter must be at least 1: " + minCharsBeforeAndAfter);
this.minStringLength = this.hashPartSize + minCharsBeforeAndAfter * 2;
}
 
public final int getMinStringLength() {
return this.minStringLength;
}
 
public final String getBoundedLengthString(final String s, final int maxLength) {
// don't test first for s.length, it's more predictable
// (otherwise boundedString("a", 2) would succeed)
if (maxLength < this.getMinStringLength())
throw new IllegalArgumentException("Maximum too low : " + maxLength + "<" + getMinStringLength());
if (s.length() <= maxLength)
return s;
else
return this.shorten(s, maxLength);
}
 
final String shorten(final String s, final int maxLength) {
assert s.length() >= this.getMinStringLength();
final int toRemoveLength = s.length() - maxLength + this.hashPartSize;
// remove the middle part of encoded
final int toRemoveStartIndex = s.length() / 2 - toRemoveLength / 2;
final String toHash = s.substring(toRemoveStartIndex, toRemoveStartIndex + toRemoveLength);
 
final String hash = shorten(toHash);
assert this.hashSize == hash.length();
 
final String res = s.substring(0, toRemoveStartIndex) + this.prefix + hash + this.suffix + s.substring(toRemoveStartIndex + toRemoveLength);
assert res.length() == maxLength;
return res;
}
 
protected abstract String shorten(String s);
 
static public final Shortener Ellipsis = new Shortener(1, "", "", 1) {
@Override
protected String shorten(String s) {
return "…";
}
};
 
// String.hashCode() is an int written in hex
static public final Shortener JavaHashCode = new Shortener(Integer.SIZE / 8 * 2, "#", "#", 3) {
@Override
protected String shorten(String s) {
return MessageDigestUtils.asHex(MessageDigestUtils.int2bytes(s.hashCode()));
}
};
 
// 128 bits written in hex
static public final Shortener MD5 = new Shortener(128 / 8 * 2, "#", "#", 11) {
@Override
protected String shorten(String s) {
return MessageDigestUtils.getHashString(MessageDigestUtils.getMD5(), s.getBytes(UTF8));
}
};
 
// order descendant by getMinStringLength()
static final Shortener[] ORDERED = new Shortener[] { MD5, JavaHashCode, Ellipsis };
}
 
/**
* The minimum value for {@link #getBoundedLengthString(String, int)}.
*
* @return the minimum value for <code>maxLength</code>.
*/
public static final int getLeastMaximum() {
return Shortener.ORDERED[Shortener.ORDERED.length - 1].getMinStringLength();
}
 
private static final Shortener getShortener(final int l) {
for (final Shortener sh : Shortener.ORDERED) {
if (l >= sh.getMinStringLength())
return sh;
}
return null;
}
 
/**
* Return a string built from <code>s</code> that is at most <code>maxLength</code> long.
*
* @param s the string to bound.
* @param maxLength the maximum length the result must have.
* @return a string built from <code>s</code>.
* @throws IllegalArgumentException if <code>maxLength</code> is too small.
* @see #getLeastMaximum()
* @see Shortener#getBoundedLengthString(String, int)
*/
public static final String getBoundedLengthString(final String s, final int maxLength) throws IllegalArgumentException {
// don't test first for s.length, it's more predictable
// (otherwise boundedString("a", 2) would succeed)
if (maxLength < getLeastMaximum())
throw new IllegalArgumentException("Maximum too low : " + maxLength + "<" + getLeastMaximum());
 
final String res;
if (s.length() <= maxLength) {
res = s;
} else {
// use maxLength to choose the shortener since it's generally a constant
// and thus the strings returned by this method have the same pattern
res = getShortener(maxLength).shorten(s, maxLength);
}
return res;
}
 
public static final List<String> fastSplit(final String string, final char sep) {
final List<String> l = new ArrayList<String>();
final int length = string.length();
75,6 → 200,60
return l;
}
 
/**
* Split une string s tous les nbCharMaxLine
*
* @param s
* @param nbCharMaxLine
* @return
*/
public static String splitString(String s, int nbCharMaxLine) {
 
if (s == null) {
return s;
}
 
if (s.trim().length() < nbCharMaxLine) {
return s;
}
StringBuffer lastString = new StringBuffer();
StringBuffer result = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
 
if (lastString.length() == nbCharMaxLine) {
int esp = lastString.lastIndexOf(" ");
if (result.length() > 0) {
result.append("\n");
}
if (esp > 0) {
result.append(lastString.substring(0, esp).toString().trim());
lastString = new StringBuffer(lastString.substring(esp, lastString.length()));
} else {
result.append(lastString.toString().trim());
lastString = new StringBuffer();
}
}
 
char charAt = s.charAt(i);
if (charAt == '\n') {
lastString.append(charAt);
result.append(charAt);
lastString = new StringBuffer();
} else {
 
lastString.append(charAt);
}
}
 
if (result.length() > 0) {
result.append("\n");
}
 
result.append(lastString.toString().trim());
 
return result.toString();
}
 
public static final class Escaper {
 
// eg '
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/PropertyDialog.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/Bean.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/PropertySelector.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/DottedPropertyDescriptor.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/PropertyController.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/PropertyText.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/PropertySheet.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/PropertyView.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/PropertyCanvas.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/list/BeanMutableListModelAdapter.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/list/CBeanTableModel.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/list/BeanListModelAdapter.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/list/CBeanList.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/beans/list/CBeanListEdit.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/PrefType.java
New file
0,0 → 1,153
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils;
 
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.prefs.Preferences;
 
/**
* Types supported by {@link Preferences}.
*
* @author Sylvain CUAZ
*
* @param <T> java type.
*/
public abstract class PrefType<T> {
// don't use enum since they don't support type parameters
 
public static final PrefType<String> STRING_TYPE = new PrefType<String>(String.class, null, null) {
@Override
public void put(Preferences prefs, String prefKey, Object val) {
prefs.put(prefKey, String.valueOf(val));
}
 
public String get(Preferences prefs, String prefKey, String def) {
return prefs.get(prefKey, def);
}
};
public static final PrefType<Boolean> BOOLEAN_TYPE = new PrefType<Boolean>(Boolean.class, Boolean.TYPE, java.lang.Boolean.FALSE) {
@Override
public void put(Preferences prefs, String prefKey, Object val) {
prefs.putBoolean(prefKey, (Boolean) val);
}
 
public Boolean get(Preferences prefs, String prefKey, Boolean def) {
return prefs.getBoolean(prefKey, def);
}
};
public static final PrefType<Float> FLOAT_TYPE = new PrefType<Float>(Float.class, Float.TYPE, 0f) {
@Override
public void put(Preferences prefs, String prefKey, Object val) {
prefs.putFloat(prefKey, ((Number) val).floatValue());
}
 
public Float get(Preferences prefs, String prefKey, Float def) {
return prefs.getFloat(prefKey, def);
}
};
public static final PrefType<Double> DOUBLE_TYPE = new PrefType<Double>(Double.class, Double.TYPE, 0d) {
@Override
public void put(Preferences prefs, String prefKey, Object val) {
prefs.putDouble(prefKey, ((Number) val).doubleValue());
}
 
public Double get(Preferences prefs, String prefKey, Double def) {
return prefs.getDouble(prefKey, def);
}
};
public static final PrefType<Integer> INT_TYPE = new PrefType<Integer>(Integer.class, Integer.TYPE, 0) {
@Override
public void put(Preferences prefs, String prefKey, Object val) {
prefs.putInt(prefKey, ((Number) val).intValue());
}
 
public Integer get(Preferences prefs, String prefKey, Integer def) {
return prefs.getInt(prefKey, def);
}
};
public static final PrefType<Long> LONG_TYPE = new PrefType<Long>(Long.class, Long.TYPE, 0l) {
@Override
public void put(Preferences prefs, String prefKey, Object val) {
prefs.putLong(prefKey, ((Number) val).longValue());
}
 
public Long get(Preferences prefs, String prefKey, Long def) {
return prefs.getLong(prefKey, def);
}
};
 
public static final PrefType<byte[]> BYTE_ARRAY_TYPE = new PrefType<byte[]>(byte[].class, null, null) {
@Override
public void put(Preferences prefs, String prefKey, Object val) {
prefs.putByteArray(prefKey, (byte[]) val);
}
 
public byte[] get(Preferences prefs, String prefKey, byte[] def) {
return prefs.getByteArray(prefKey, def);
}
};
 
public static final PrefType<?>[] VALUES = { STRING_TYPE, BOOLEAN_TYPE, FLOAT_TYPE, DOUBLE_TYPE, INT_TYPE, LONG_TYPE, BYTE_ARRAY_TYPE };
public static final Set<PrefType<?>> VALUES_COLLECTION = Collections.unmodifiableSet(new HashSet<PrefType<?>>(Arrays.asList(VALUES)));
 
private final Class<T> clazz, primitiveClass;
private final T defaultValue;
 
private PrefType(Class<T> clazz, Class<T> primitiveClass, T defaultValue) {
this.clazz = clazz;
if(this.clazz == null)
throw new IllegalArgumentException();
this.primitiveClass = primitiveClass;
this.defaultValue = defaultValue;
}
 
/**
* The non primitive type.
*
* @return the non primitive type, never <code>null</code>.
*/
public final Class<T> getTypeClass() {
return this.clazz;
}
 
/**
* The primitive type.
*
* @return the primitive type or <code>null</code>.
*/
public final Class<T> getPrimitiveTypeClass() {
return this.primitiveClass;
}
 
/**
* The default value for this type as specified by the JLS.
*
* @return the default value, e.g. 0.
* @see http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.12.5
*/
public final T getDefaultValue() {
return this.defaultValue;
}
 
public abstract void put(final Preferences prefs, final String prefKey, final Object val);
 
public abstract T get(final Preferences prefs, final String prefKey, final T def);
 
public final T get(final Preferences prefs, final String prefKey) {
return this.get(prefs, prefKey, getDefaultValue());
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/text/CSVParser.java
New file
0,0 → 1,335
/*
* 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.text;
 
/**
* Copyright 2005 Bytecode Pty Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
 
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
 
/**
* A very simple CSV parser released under a commercial-friendly license. This just implements
* splitting a single line into fields.
*
* @author Glen Smith
* @author Rainer Pruy
*/
public class CSVParser {
 
private final char separator;
 
private final char quotechar;
 
private final char escape;
 
private final boolean strictQuotes;
 
private String pending;
private boolean inField = false;
 
private final boolean ignoreLeadingWhiteSpace;
 
/**
* The default separator to use if none is supplied to the constructor.
*/
public static final char DEFAULT_SEPARATOR = ',';
 
public static final int INITIAL_READ_SIZE = 128;
 
/**
* The default quote character to use if none is supplied to the constructor.
*/
public static final char DEFAULT_QUOTE_CHARACTER = '"';
 
/**
* The default escape character to use if none is supplied to the constructor.
*/
public static final char DEFAULT_ESCAPE_CHARACTER = '\\';
 
/**
* The default strict quote behavior to use if none is supplied to the constructor
*/
public static final boolean DEFAULT_STRICT_QUOTES = false;
 
/**
* The default leading whitespace behavior to use if none is supplied to the constructor
*/
public static final boolean DEFAULT_IGNORE_LEADING_WHITESPACE = true;
 
/**
* This is the "null" character - if a value is set to this then it is ignored. I.E. if the
* quote character is set to null then there is no quote character.
*/
public static final char NULL_CHARACTER = '\0';
 
/**
* Constructs CSVParser using a comma for the separator.
*/
public CSVParser() {
this(DEFAULT_SEPARATOR, DEFAULT_QUOTE_CHARACTER, DEFAULT_ESCAPE_CHARACTER);
}
 
/**
* Constructs CSVParser with supplied separator.
*
* @param separator the delimiter to use for separating entries.
*/
public CSVParser(char separator) {
this(separator, DEFAULT_QUOTE_CHARACTER, DEFAULT_ESCAPE_CHARACTER);
}
 
/**
* Constructs CSVParser with supplied separator and quote char.
*
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
*/
public CSVParser(char separator, char quotechar) {
this(separator, quotechar, DEFAULT_ESCAPE_CHARACTER);
}
 
/**
* Constructs CSVReader with supplied separator and quote char.
*
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escape the character to use for escaping a separator or quote
*/
public CSVParser(char separator, char quotechar, char escape) {
this(separator, quotechar, escape, DEFAULT_STRICT_QUOTES);
}
 
/**
* Constructs CSVReader with supplied separator and quote char. Allows setting the
* "strict quotes" flag
*
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escape the character to use for escaping a separator or quote
* @param strictQuotes if true, characters outside the quotes are ignored
*/
public CSVParser(char separator, char quotechar, char escape, boolean strictQuotes) {
this(separator, quotechar, escape, strictQuotes, DEFAULT_IGNORE_LEADING_WHITESPACE);
}
 
/**
* Constructs CSVReader with supplied separator and quote char. Allows setting the
* "strict quotes" and "ignore leading whitespace" flags
*
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escape the character to use for escaping a separator or quote
* @param strictQuotes if true, characters outside the quotes are ignored
* @param ignoreLeadingWhiteSpace if true, white space in front of a quote in a field is ignored
*/
public CSVParser(char separator, char quotechar, char escape, boolean strictQuotes, boolean ignoreLeadingWhiteSpace) {
if (anyCharactersAreTheSame(separator, quotechar, escape)) {
throw new UnsupportedOperationException("The separator, quote, and escape characters must be different!");
}
if (separator == NULL_CHARACTER) {
throw new UnsupportedOperationException("The separator character must be defined!");
}
this.separator = separator;
this.quotechar = quotechar;
this.escape = escape;
this.strictQuotes = strictQuotes;
this.ignoreLeadingWhiteSpace = ignoreLeadingWhiteSpace;
}
 
private boolean anyCharactersAreTheSame(char separator, char quotechar, char escape) {
return isSameCharacter(separator, quotechar) || isSameCharacter(separator, escape) || isSameCharacter(quotechar, escape);
}
 
private boolean isSameCharacter(char c1, char c2) {
return c1 != NULL_CHARACTER && c1 == c2;
}
 
/**
* @return true if something was left over from last call(s)
*/
public boolean isPending() {
return pending != null;
}
 
public String[] parseLineMulti(String nextLine) throws IOException {
return parseLine(nextLine, true);
}
 
public String[] parseLine(String nextLine) throws IOException {
return parseLine(nextLine, false);
}
 
/**
* Parses an incoming String and returns an array of elements.
*
* @param nextLine the string to parse
* @param multi
* @return the comma-tokenized list of elements, or null if nextLine is null
* @throws IOException if bad things happen during the read
*/
private String[] parseLine(String nextLine, boolean multi) throws IOException {
 
if (!multi && pending != null) {
pending = null;
}
 
if (nextLine == null) {
if (pending != null) {
String s = pending;
pending = null;
return new String[] { s };
} else {
return null;
}
}
 
List<String> tokensOnThisLine = new ArrayList<String>();
StringBuilder sb = new StringBuilder(INITIAL_READ_SIZE);
boolean inQuotes = false;
if (pending != null) {
sb.append(pending);
pending = null;
inQuotes = true;
}
for (int i = 0; i < nextLine.length(); i++) {
 
char c = nextLine.charAt(i);
if (c == this.escape) {
if (isNextCharacterEscapable(nextLine, inQuotes || inField, i)) {
sb.append(nextLine.charAt(i + 1));
i++;
}
} else if (c == quotechar) {
if (isNextCharacterEscapedQuote(nextLine, inQuotes || inField, i)) {
sb.append(nextLine.charAt(i + 1));
i++;
} else {
// inQuotes = !inQuotes;
 
// the tricky case of an embedded quote in the middle: a,bc"d"ef,g
if (!strictQuotes) {
if (i > 2 // not on the beginning of the line
&& nextLine.charAt(i - 1) != this.separator // not at the beginning
// of an escape sequence
&& nextLine.length() > (i + 1) && nextLine.charAt(i + 1) != this.separator // not
// at
// the
// end
// of
// an
// escape
// sequence
) {
 
if (ignoreLeadingWhiteSpace && sb.length() > 0 && isAllWhiteSpace(sb)) {
sb.setLength(0); // discard white space leading up to quote
} else {
sb.append(c);
// continue;
}
 
}
}
 
inQuotes = !inQuotes;
}
inField = !inField;
} else if (c == separator && !inQuotes) {
tokensOnThisLine.add(sb.toString());
sb.setLength(0); // start work on next token
inField = false;
} else {
if (!strictQuotes || inQuotes) {
sb.append(c);
inField = true;
}
}
}
// line is done - check status
if (inQuotes) {
if (multi) {
// continuing a quoted section, re-append newline
sb.append("\n");
pending = sb.toString();
sb = null; // this partial content is not to be added to field list yet
} else {
throw new IOException("Un-terminated quoted field at end of CSV line");
}
}
if (sb != null) {
tokensOnThisLine.add(sb.toString());
}
return tokensOnThisLine.toArray(new String[tokensOnThisLine.size()]);
 
}
 
/**
* precondition: the current character is a quote or an escape
*
* @param nextLine the current line
* @param inQuotes true if the current context is quoted
* @param i current index in line
* @return true if the following character is a quote
*/
private boolean isNextCharacterEscapedQuote(String nextLine, boolean inQuotes, int i) {
return inQuotes // we are in quotes, therefore there can be escaped quotes in here.
&& nextLine.length() > (i + 1) // there is indeed another character to check.
&& nextLine.charAt(i + 1) == quotechar;
}
 
/**
* precondition: the current character is an escape
*
* @param nextLine the current line
* @param inQuotes true if the current context is quoted
* @param i current index in line
* @return true if the following character is a quote
*/
protected boolean isNextCharacterEscapable(String nextLine, boolean inQuotes, int i) {
return inQuotes // we are in quotes, therefore there can be escaped quotes in here.
&& nextLine.length() > (i + 1) // there is indeed another character to check.
&& (nextLine.charAt(i + 1) == quotechar || nextLine.charAt(i + 1) == this.escape);
}
 
/**
* precondition: sb.length() > 0
*
* @param sb A sequence of characters to examine
* @return true if every character in the sequence is whitespace
*/
protected boolean isAllWhiteSpace(CharSequence sb) {
boolean result = true;
for (int i = 0; i < sb.length(); i++) {
char c = sb.charAt(i);
 
if (!Character.isWhitespace(c)) {
return false;
}
}
return result;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/text/CSVWriter.java
New file
0,0 → 1,245
/*
* 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.text;
 
/**
* Copyright 2005 Bytecode Pty Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
 
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.List;
 
/**
* A very simple CSV writer released under a commercial-friendly license.
*
* @author Glen Smith
*
*/
public class CSVWriter implements Closeable {
 
public static final int INITIAL_STRING_SIZE = 128;
 
private Writer rawWriter;
 
private PrintWriter pw;
 
private char separator;
 
private char quotechar;
 
private char escapechar;
 
private String lineEnd;
 
/** The character used for escaping quotes. */
public static final char DEFAULT_ESCAPE_CHARACTER = '"';
 
/** The default separator to use if none is supplied to the constructor. */
public static final char DEFAULT_SEPARATOR = ',';
 
/**
* The default quote character to use if none is supplied to the constructor.
*/
public static final char DEFAULT_QUOTE_CHARACTER = '"';
 
/** The quote constant to use when you wish to suppress all quoting. */
public static final char NO_QUOTE_CHARACTER = '\u0000';
 
/** The escape constant to use when you wish to suppress all escaping. */
public static final char NO_ESCAPE_CHARACTER = '\u0000';
 
/** Default line terminator uses platform encoding. */
public static final String DEFAULT_LINE_END = "\n";
 
/**
* Constructs CSVWriter using a comma for the separator.
*
* @param writer the writer to an underlying CSV source.
*/
public CSVWriter(Writer writer) {
this(writer, DEFAULT_SEPARATOR);
}
 
/**
* Constructs CSVWriter with supplied separator.
*
* @param writer the writer to an underlying CSV source.
* @param separator the delimiter to use for separating entries.
*/
public CSVWriter(Writer writer, char separator) {
this(writer, separator, DEFAULT_QUOTE_CHARACTER);
}
 
/**
* Constructs CSVWriter with supplied separator and quote char.
*
* @param writer the writer to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
*/
public CSVWriter(Writer writer, char separator, char quotechar) {
this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER);
}
 
/**
* Constructs CSVWriter with supplied separator and quote char.
*
* @param writer the writer to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escapechar the character to use for escaping quotechars or escapechars
*/
public CSVWriter(Writer writer, char separator, char quotechar, char escapechar) {
this(writer, separator, quotechar, escapechar, DEFAULT_LINE_END);
}
 
/**
* Constructs CSVWriter with supplied separator and quote char.
*
* @param writer the writer to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param lineEnd the line feed terminator to use
*/
public CSVWriter(Writer writer, char separator, char quotechar, String lineEnd) {
this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd);
}
 
/**
* Constructs CSVWriter with supplied separator, quote char, escape char and line ending.
*
* @param writer the writer to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escapechar the character to use for escaping quotechars or escapechars
* @param lineEnd the line feed terminator to use
*/
public CSVWriter(Writer writer, char separator, char quotechar, char escapechar, String lineEnd) {
this.rawWriter = writer;
this.pw = new PrintWriter(writer);
this.separator = separator;
this.quotechar = quotechar;
this.escapechar = escapechar;
this.lineEnd = lineEnd;
}
 
/**
* Writes the entire list to a CSV file. The list is assumed to be a String[]
*
* @param allLines a List of String[], with each String[] representing a line of the file.
*/
public void writeAll(List<String[]> allLines) {
for (String[] line : allLines) {
writeNext(line);
}
}
 
/**
* Writes the next line to the file.
*
* @param nextLine a string array with each comma-separated element as a separate entry.
*/
public void writeNext(String[] nextLine) {
 
if (nextLine == null)
return;
 
StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
for (int i = 0; i < nextLine.length; i++) {
 
if (i != 0) {
sb.append(separator);
}
 
String nextElement = nextLine[i];
if (nextElement == null)
continue;
if (quotechar != NO_QUOTE_CHARACTER)
sb.append(quotechar);
 
sb.append(stringContainsSpecialCharacters(nextElement) ? processLine(nextElement) : nextElement);
 
if (quotechar != NO_QUOTE_CHARACTER)
sb.append(quotechar);
}
 
sb.append(lineEnd);
pw.write(sb.toString());
 
}
 
private boolean stringContainsSpecialCharacters(String line) {
return line.indexOf(quotechar) != -1 || line.indexOf(escapechar) != -1;
}
 
protected StringBuilder processLine(String nextElement) {
StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
for (int j = 0; j < nextElement.length(); j++) {
char nextChar = nextElement.charAt(j);
if (escapechar != NO_ESCAPE_CHARACTER && nextChar == quotechar) {
sb.append(escapechar).append(nextChar);
} else if (escapechar != NO_ESCAPE_CHARACTER && nextChar == escapechar) {
sb.append(escapechar).append(nextChar);
} else {
sb.append(nextChar);
}
}
 
return sb;
}
 
/**
* Flush underlying stream to writer.
*
* @throws IOException if bad things happen
*/
public void flush() throws IOException {
 
pw.flush();
 
}
 
/**
* Close the underlying stream writer flushing any buffered content.
*
* @throws IOException if bad things happen
*
*/
public void close() throws IOException {
flush();
pw.close();
rawWriter.close();
}
 
/**
* Checks to see if the there has been an error in the printstream.
*/
public boolean checkError() {
return pw.checkError();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/text/CharsetHelper.java
New file
0,0 → 1,192
/*
* 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.text;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Collection;
 
public class CharsetHelper {
private byte buffer[];
private Charset defaultCharset;
private boolean enforce8Bit;
 
public CharsetHelper(byte buffer[]) {
enforce8Bit = false;
this.buffer = buffer;
defaultCharset = getDefaultSystemCharset();
}
 
public CharsetHelper(byte buffer[], Charset defaultCharset) {
enforce8Bit = false;
this.buffer = buffer;
setDefaultCharset(defaultCharset);
}
 
public void setDefaultCharset(Charset defaultCharset) {
if (defaultCharset != null)
this.defaultCharset = defaultCharset;
else
this.defaultCharset = getDefaultSystemCharset();
}
 
public void setEnforce8Bit(boolean enforce) {
enforce8Bit = enforce;
}
 
public boolean getEnforce8Bit() {
return enforce8Bit;
}
 
public Charset getDefaultCharset() {
return defaultCharset;
}
 
public Charset guessEncoding() {
if (hasUTF8Bom(buffer))
return Charset.forName("UTF-8");
if (hasUTF16LEBom(buffer))
return Charset.forName("UTF-16LE");
if (hasUTF16BEBom(buffer))
return Charset.forName("UTF-16BE");
boolean highOrderBit = false;
boolean validU8Char = true;
int length = buffer.length;
int i = 0;
do {
if (i >= length - 6)
break;
byte b0 = buffer[i];
byte b1 = buffer[i + 1];
byte b2 = buffer[i + 2];
byte b3 = buffer[i + 3];
byte b4 = buffer[i + 4];
byte b5 = buffer[i + 5];
if (b0 < 0) {
highOrderBit = true;
if (isTwoBytesSequence(b0)) {
if (!isContinuationChar(b1))
validU8Char = false;
else
i++;
} else if (isThreeBytesSequence(b0)) {
if (!isContinuationChar(b1) || !isContinuationChar(b2))
validU8Char = false;
else
i += 2;
} else if (isFourBytesSequence(b0)) {
if (!isContinuationChar(b1) || !isContinuationChar(b2) || !isContinuationChar(b3))
validU8Char = false;
else
i += 3;
} else if (isFiveBytesSequence(b0)) {
if (!isContinuationChar(b1) || !isContinuationChar(b2) || !isContinuationChar(b3) || !isContinuationChar(b4))
validU8Char = false;
else
i += 4;
} else if (isSixBytesSequence(b0)) {
if (!isContinuationChar(b1) || !isContinuationChar(b2) || !isContinuationChar(b3) || !isContinuationChar(b4) || !isContinuationChar(b5))
validU8Char = false;
else
i += 5;
} else {
validU8Char = false;
}
}
if (!validU8Char)
break;
i++;
} while (true);
if (!highOrderBit)
if (enforce8Bit)
return defaultCharset;
else
return Charset.forName("US-ASCII");
if (validU8Char)
return Charset.forName("UTF-8");
else
return defaultCharset;
}
 
public int getBomSize() {
if (hasUTF8Bom(buffer))
return 3;
return !hasUTF16LEBom(buffer) && !hasUTF16BEBom(buffer) ? 0 : 2;
}
 
public static Charset guessEncoding(File f, int bufferLength) throws FileNotFoundException, IOException {
return guessEncoding(f, bufferLength, null);
}
 
public static Charset guessEncoding(File f, int bufferLength, Charset defaultCharset) throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream(f);
byte buffer[] = new byte[bufferLength];
fis.read(buffer);
fis.close();
CharsetHelper toolkit = new CharsetHelper(buffer);
if (defaultCharset != null) {
toolkit.setDefaultCharset(defaultCharset);
}
return toolkit.guessEncoding();
}
 
private static boolean isContinuationChar(byte b) {
return -128 <= b && b <= -65;
}
 
private static boolean isTwoBytesSequence(byte b) {
return -64 <= b && b <= -33;
}
 
private static boolean isThreeBytesSequence(byte b) {
return -32 <= b && b <= -17;
}
 
private static boolean isFourBytesSequence(byte b) {
return -16 <= b && b <= -9;
}
 
private static boolean isFiveBytesSequence(byte b) {
return -8 <= b && b <= -5;
}
 
private static boolean isSixBytesSequence(byte b) {
return -4 <= b && b <= -3;
}
 
public static Charset getDefaultSystemCharset() {
return Charset.forName(System.getProperty("file.encoding"));
}
 
private static boolean hasUTF8Bom(byte bom[]) {
return bom[0] == -17 && bom[1] == -69 && bom[2] == -65;
}
 
private static boolean hasUTF16LEBom(byte bom[]) {
return bom[0] == -1 && bom[1] == -2;
}
 
private static boolean hasUTF16BEBom(byte bom[]) {
return bom[0] == -2 && bom[1] == -1;
}
 
public static Charset[] getAvailableCharsets() {
final Collection<Charset> collection = Charset.availableCharsets().values();
return collection.toArray(new Charset[collection.size()]);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/text/CSVReader.java
New file
0,0 → 1,250
/*
* 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.text;
 
/**
* Copyright 2005 Bytecode Pty Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
 
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
 
/**
* A very simple CSV reader released under a commercial-friendly license.
*
* @author Glen Smith
*
*/
public class CSVReader implements Closeable {
 
private BufferedReader br;
 
private boolean hasNext = true;
 
private CSVParser parser;
 
private int skipLines;
 
private boolean linesSkiped;
 
/**
* The default line to start reading.
*/
public static final int DEFAULT_SKIP_LINES = 0;
 
/**
* Constructs CSVReader using a comma for the separator.
*
* @param reader the reader to an underlying CSV source.
*/
public CSVReader(Reader reader) {
this(reader, CSVParser.DEFAULT_SEPARATOR, CSVParser.DEFAULT_QUOTE_CHARACTER, CSVParser.DEFAULT_ESCAPE_CHARACTER);
}
 
/**
* Constructs CSVReader with supplied separator.
*
* @param reader the reader to an underlying CSV source.
* @param separator the delimiter to use for separating entries.
*/
public CSVReader(Reader reader, char separator) {
this(reader, separator, CSVParser.DEFAULT_QUOTE_CHARACTER, CSVParser.DEFAULT_ESCAPE_CHARACTER);
}
 
/**
* Constructs CSVReader with supplied separator and quote char.
*
* @param reader the reader to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
*/
public CSVReader(Reader reader, char separator, char quotechar) {
this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, DEFAULT_SKIP_LINES, CSVParser.DEFAULT_STRICT_QUOTES);
}
 
/**
* Constructs CSVReader with supplied separator, quote char and quote handling behavior.
*
* @param reader the reader to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param strictQuotes sets if characters outside the quotes are ignored
*/
public CSVReader(Reader reader, char separator, char quotechar, boolean strictQuotes) {
this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, DEFAULT_SKIP_LINES, strictQuotes);
}
 
/**
* Constructs CSVReader with supplied separator and quote char.
*
* @param reader the reader to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escape the character to use for escaping a separator or quote
*/
 
public CSVReader(Reader reader, char separator, char quotechar, char escape) {
this(reader, separator, quotechar, escape, DEFAULT_SKIP_LINES, CSVParser.DEFAULT_STRICT_QUOTES);
}
 
/**
* Constructs CSVReader with supplied separator and quote char.
*
* @param reader the reader to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param line the line number to skip for start reading
*/
public CSVReader(Reader reader, char separator, char quotechar, int line) {
this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, line, CSVParser.DEFAULT_STRICT_QUOTES);
}
 
/**
* Constructs CSVReader with supplied separator and quote char.
*
* @param reader the reader to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escape the character to use for escaping a separator or quote
* @param line the line number to skip for start reading
*/
public CSVReader(Reader reader, char separator, char quotechar, char escape, int line) {
this(reader, separator, quotechar, escape, line, CSVParser.DEFAULT_STRICT_QUOTES);
}
 
/**
* Constructs CSVReader with supplied separator and quote char.
*
* @param reader the reader to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escape the character to use for escaping a separator or quote
* @param line the line number to skip for start reading
* @param strictQuotes sets if characters outside the quotes are ignored
*/
public CSVReader(Reader reader, char separator, char quotechar, char escape, int line, boolean strictQuotes) {
this(reader, separator, quotechar, escape, line, strictQuotes, CSVParser.DEFAULT_IGNORE_LEADING_WHITESPACE);
}
 
/**
* Constructs CSVReader with supplied separator and quote char.
*
* @param reader the reader to an underlying CSV source.
* @param separator the delimiter to use for separating entries
* @param quotechar the character to use for quoted elements
* @param escape the character to use for escaping a separator or quote
* @param line the line number to skip for start reading
* @param strictQuotes sets if characters outside the quotes are ignored
* @param ignoreLeadingWhiteSpace it true, parser should ignore white space before a quote in a
* field
*/
public CSVReader(Reader reader, char separator, char quotechar, char escape, int line, boolean strictQuotes, boolean ignoreLeadingWhiteSpace) {
this.br = new BufferedReader(reader);
this.parser = new CSVParser(separator, quotechar, escape, strictQuotes, ignoreLeadingWhiteSpace);
this.skipLines = line;
}
 
/**
* Reads the entire file into a List with each element being a String[] of tokens.
*
* @return a List of String[], with each String[] representing a line of the file.
*
* @throws IOException if bad things happen during the read
*/
public List<String[]> readAll() throws IOException {
 
List<String[]> allElements = new ArrayList<String[]>();
while (hasNext) {
String[] nextLineAsTokens = readNext();
if (nextLineAsTokens != null)
allElements.add(nextLineAsTokens);
}
return allElements;
 
}
 
/**
* Reads the next line from the buffer and converts to a string array.
*
* @return a string array with each comma-separated element as a separate entry.
*
* @throws IOException if bad things happen during the read
*/
public String[] readNext() throws IOException {
 
String[] result = null;
do {
String nextLine = getNextLine();
if (!hasNext) {
return result; // should throw if still pending?
}
String[] r = parser.parseLineMulti(nextLine);
if (r.length > 0) {
if (result == null) {
result = r;
} else {
String[] t = new String[result.length + r.length];
System.arraycopy(result, 0, t, 0, result.length);
System.arraycopy(r, 0, t, result.length, r.length);
result = t;
}
}
} while (parser.isPending());
return result;
}
 
/**
* Reads the next line from the file.
*
* @return the next line from the file without trailing newline
* @throws IOException if bad things happen during the read
*/
private String getNextLine() throws IOException {
if (!this.linesSkiped) {
for (int i = 0; i < skipLines; i++) {
br.readLine();
}
this.linesSkiped = true;
}
String nextLine = br.readLine();
if (nextLine == null) {
hasNext = false;
}
return hasNext ? nextLine : null;
}
 
/**
* Closes the underlying reader.
*
* @throws IOException if the close fails
*/
public void close() throws IOException {
br.close();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/MessageDigestUtils.java
87,12 → 87,15
 
public static String getHashString(String algo, byte[] data) throws NoSuchAlgorithmException {
final MessageDigest md = MessageDigest.getInstance(algo);
return getHashString(md, data);
}
 
public static String getHashString(MessageDigest md, byte[] data) {
md.update(data);
return getHashString(md);
}
 
public static String getHashString(String algo, final InputStream ins) throws IOException, NoSuchAlgorithmException {
final MessageDigest md = MessageDigest.getInstance(algo);
public static String getHashString(MessageDigest md, final InputStream ins) throws IOException {
final DigestOutputStream out = new DigestOutputStream(StreamUtils.NULL_OS, md);
StreamUtils.copy(ins, out);
out.close();
102,14 → 105,20
public static String getMD5(File f) throws IOException {
final InputStream ins = new FileInputStream(f);
try {
return getHashString("MD5", ins);
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 is part of the standard vm", e);
return getHashString(getMD5(), ins);
} finally {
ins.close();
}
}
 
public static MessageDigest getMD5() {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 is part of the standard vm", e);
}
}
 
private MessageDigestUtils() {
}
 
/trunk/OpenConcerto/src/org/openconcerto/utils/change/ListChangeRecorder.java
20,7 → 20,7
import java.util.List;
 
/**
* A class that wraps a list, to recored every change made to it. The changes are available with
* A class that wraps a list, to detect every change made to it. The changes are available with
* {@link #getRecipe()}.
*
* @author Sylvain
33,9 → 33,13
private final ListChangeRecipe<E> recipe;
 
public ListChangeRecorder(List<E> delegate) {
this(delegate, false);
}
 
public ListChangeRecorder(List<E> delegate, final boolean keepHistory) {
super();
this.delegate = delegate;
this.recipe = new ListChangeRecipe<E>();
this.recipe = new ListChangeRecipe<E>(keepHistory);
}
 
public ListChangeRecipe<E> getRecipe() {
/trunk/OpenConcerto/src/org/openconcerto/utils/change/ListChangeRecipe.java
13,11 → 13,10
package org.openconcerto.utils.change;
 
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.cc.Transformer;
 
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
25,37 → 24,54
import java.util.Map;
 
/**
* A list of ListChange.
* Allow to propagate ListChange to listeners and bound lists. Can also store all changes that it
* was notified and replay them with {@link #apply(List, ITransformer)}.
*
* @author Sylvain
*
* @param <T> type of items.
* @see #bind(List, ITransformer)
* @see #addListener(IClosure)
*/
public class ListChangeRecipe<T> implements ListChange<T> {
 
private final List<ListChange<T>> changes;
private final PropertyChangeSupport supp;
private final Map<List<?>, Pair> boundedLists;
private final List<ListChangeIndex<T>> changes;
// don't use PropertyChangeSupport since it isn't type safe and we're only interested in the
// last change (and not the whole property, i.e. the whole list)
private final List<IClosure<? super ListChangeIndex<T>>> listeners;
private final Map<List<?>, Pair<?>> boundLists;
 
public ListChangeRecipe() {
/**
* Create a new instance. Recording is only necessary for {@link #apply(List, ITransformer)}.
*
* @param record <code>true</code> if all changes should be kept (this will leak memory until
* {@link #clear()} is called).
*/
public ListChangeRecipe(final boolean record) {
super();
this.changes = new ArrayList<ListChange<T>>();
this.supp = new PropertyChangeSupport(this);
this.changes = record ? new ArrayList<ListChangeIndex<T>>() : null;
this.listeners = new ArrayList<IClosure<? super ListChangeIndex<T>>>();
// need IdentityHashMap since List.equals() depend on its items
// which will change
this.boundedLists = new IdentityHashMap<List<?>, Pair>();
this.boundLists = new IdentityHashMap<List<?>, Pair<?>>();
}
 
public List<ListChange<T>> getChanges() {
public final boolean recordChanges() {
return this.changes != null;
}
 
public final List<ListChangeIndex<T>> getChanges() {
if (!this.recordChanges())
throw new IllegalStateException("This instance wasn't created to record changes");
return this.changes;
}
 
public void addListener(PropertyChangeListener l) {
this.supp.addPropertyChangeListener("changes", l);
public void addListener(IClosure<? super ListChangeIndex<T>> l) {
this.listeners.add(l);
}
 
public void rmListener(PropertyChangeListener l) {
this.supp.removePropertyChangeListener("changes", l);
public void rmListener(IClosure<? super ListChangeIndex<T>> l) {
this.listeners.remove(l);
}
 
public void bind(List<T> l) {
70,20 → 86,22
* @param transf the transformer.
*/
public <U> void bind(List<U> l, ITransformer<T, U> transf) {
this.boundedLists.put(l, new Pair<U>(l, transf));
this.boundLists.put(l, new Pair<U>(l, transf));
}
 
public <U> void unbind(List<U> l) {
this.boundedLists.remove(l);
this.boundLists.remove(l);
}
 
private final void add(ListChange<T> change) {
private final void add(ListChangeIndex<T> change) {
if (this.recordChanges())
this.changes.add(change);
// must change bounded lists first, otherwise listeners couldn't access them
for (final Pair<?> p : this.boundedLists.values()) {
for (final Pair<?> p : this.boundLists.values()) {
p.apply(change);
}
this.supp.firePropertyChange("changes", null, change);
for (final IClosure<? super ListChangeIndex<T>> l : this.listeners)
l.executeChecked(change);
}
 
public void add(int index0, Collection<? extends T> c) {
98,12 → 116,26
this.add(new ListChangeIndex.Set<T>(index0, old, newItem));
}
 
/**
* Clear all recorded changes. In general should be called after
* {@link #apply(List, ITransformer)}.
*/
public final void clear() {
this.changes.clear();
this.getChanges().clear();
}
 
public <U> void apply(List<U> l, ITransformer<T, U> transf) {
for (final ListChange<T> change : this.changes) {
/**
* Apply all changes since the last {@link #clear()}.
*
* @param <U> type of list
* @param l the list to change.
* @param transf transform items between this and <code>l</code>.
* @throws IllegalStateException if this instance doesn't {@link #recordChanges() record
* changes}.
*/
@Override
public <U> void apply(List<U> l, ITransformer<T, U> transf) throws IllegalStateException {
for (final ListChange<T> change : this.getChanges()) {
change.apply(l, transf);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/GestionDevise.java
13,9 → 13,13
package org.openconcerto.utils;
 
import java.math.BigDecimal;
import java.text.DecimalFormat;
 
public class GestionDevise {
 
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat(",##0.00");
 
/**
* parse une String representant un decimal avec 2 chiffres apres la virgule en un long.
*
132,6 → 136,10
return currencyToString(cents, true);
}
 
public final static String currencyToString(BigDecimal currency) {
return DECIMAL_FORMAT.format(currency);
}
 
/**
*
* @param cents long representant des cents
/trunk/OpenConcerto/src/org/openconcerto/utils/JImage.java
13,9 → 13,14
package org.openconcerto.utils;
 
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URI;
import java.net.URL;
 
import javax.swing.ImageIcon;
32,6 → 37,7
private ImageIcon icon;
 
private boolean centered;
private String hyperlink;
 
/**
* Cree une JImage a partir d'un nom de fichier.
54,8 → 60,32
public JImage(Image img) {
this.image = img;
this.icon = null;
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (hyperlink != null) {
try {
URI uri = new URI(hyperlink);
Desktop.getDesktop().browse(uri);
} catch (Exception ex) {
ExceptionHandler.handle("Impossible d'ouvir l'URL " + hyperlink, ex);
}
e.consume();
}
}
 
@Override
public void mouseEntered(MouseEvent e) {
setCursor(new Cursor(Cursor.HAND_CURSOR));
}
 
@Override
public void mouseExited(MouseEvent e) {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
});
}
 
public void check() {
if (this.image == null || this.image.getHeight(null) <= 0) {
throw new IllegalStateException();
98,4 → 128,8
public void setImage(Image image) {
this.image = image;
}
 
public void setHyperLink(String url) {
this.hyperlink = url;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/IPredicate.java
23,6 → 23,12
return true;
}
};
private static final IPredicate<Object> NotNullPred = new IPredicate<Object>() {
@Override
public boolean evaluateChecked(Object input) {
return input != null;
}
};
 
@SuppressWarnings("unchecked")
public static final <N> IPredicate<N> truePredicate() {
30,6 → 36,11
}
 
@SuppressWarnings("unchecked")
public static final <N> IPredicate<N> notNullPredicate() {
return (IPredicate<N>) NotNullPred;
}
 
@SuppressWarnings("unchecked")
public boolean evaluate(Object object) {
return this.evaluateChecked((E) object);
}
/trunk/OpenConcerto/src/org/openconcerto/utils/CollectionUtils.java
13,6 → 13,8
package org.openconcerto.utils;
 
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.IPredicate;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
55,19 → 57,18
* @return la chaine composée de chacun des éléments séparés par <code>sep</code>.
*/
static public final <E> String join(final Collection<E> c, final String sep, final ITransformer<? super E, ?> tf) {
if (c.size() == 0)
final int size = c.size();
if (size == 0)
return "";
 
final StringBuffer res = new StringBuffer(c.size() * 4);
final StringBuffer res = new StringBuffer(size * 4);
if (c instanceof RandomAccess && c instanceof List) {
final List<E> list = (List<E>) c;
final int stop = c.size() - 1;
for (int i = 0; i < stop; i++) {
for (int i = 0; i < size; i++) {
res.append(tf.transformChecked(list.get(i)));
if (i < size - 1)
res.append(sep);
 
}
res.append(tf.transformChecked(list.get(stop)));
} else {
final Iterator<E> iter = c.iterator();
while (iter.hasNext()) {
93,8 → 94,33
return join(c, sep, org.openconcerto.utils.cc.Transformer.<T> nopTransformer());
}
 
// *** split
static public <T, U, C extends Collection<? super U>> C transformAndFilter(final Collection<T> c, final ITransformer<? super T, U> transf, final IPredicate<? super U> filter, final C res) {
iterate(c, new IClosure<T>() {
@Override
public void executeChecked(T input) {
final U item = transf.transformChecked(input);
if (filter.evaluateChecked(item))
res.add(item);
}
});
return res;
}
 
static public <T> void iterate(final Collection<T> c, final IClosure<T> cl) {
if (c instanceof RandomAccess && c instanceof List) {
final List<T> list = (List<T>) c;
final int size = c.size();
for (int i = 0; i < size; i++) {
cl.executeChecked(list.get(i));
}
} else {
final Iterator<T> iter = c.iterator();
while (iter.hasNext()) {
cl.executeChecked(iter.next());
}
}
}
 
private static final Pattern COMMA = Pattern.compile("\\p{Space}*,\\p{Space}*");
 
static public List<String> split(String s) {
165,6 → 191,11
delete(l, from, -1);
}
 
public static <T, C extends Collection<? super T>> C select(Collection<T> inputCollection, IPredicate<? super T> predicate, C outputCollection) {
org.apache.commons.collections.CollectionUtils.select(inputCollection, predicate, outputCollection);
return outputCollection;
}
 
/**
* Permet d'organiser une collection en une hiérarchie à l'aide de Map. Avec <code>
* Col = [
/trunk/OpenConcerto/src/org/openconcerto/utils/OutlookEmail.vbs
New file
0,0 → 1,63
' http://msdn.microsoft.com/en-us/library/aa210946(office.11).aspx
 
if Wscript.Arguments.count = 0 or Wscript.Arguments.Named.count > 3 then
Wscript.Echo "Usage: " & WScript.ScriptName & " /to:addr /subject:Re [ /body:""Hi, dear friend"" | /unicodeStdIn:[0|1] ] attachment..." & vbNewLine &_
vbTab & "Named parameters should be percent-encoded since certain characters like double quote cannot be passed." &_
" If unicodeStdIn is defined the body will be read from stdin (avoiding arguments size limitation), 1 will parse the stream as UTF16, " &_
"0 will parse as the platform default. If calling from cmd.exe you might need to change the codepage, e.g. chcp 1252 (from 850)"
Wscript.Quit 1
end if
 
toAddr = getNamedArg("to")
subject = getNamedArg("subject")
' Cannot always call StdIn.ReadAll since it blocks
If Wscript.Arguments.Named.Exists("unicodeStdIn") then
isUnicode = CBool(Wscript.Arguments.Named.item("unicodeStdIn"))
Set fso = CreateObject ("Scripting.FileSystemObject")
piped = fso.GetStandardStream (StdIn, isUnicode).ReadAll
else
body = getNamedArg("body")
End If
 
' Enable error handling
On Error Resume Next
 
'Create a mail object and send the mail
Dim objMail
Dim objclient
 
Set objMail = CreateObject("Outlook.application")
quitIfErr()
Set objclient = objMail.createitem(olMailItem)
quitIfErr()
 
With objclient
.Subject = subject
.To = toAddr
'.CC = "cc@email.com"
.Body = body & piped
For each attachmentPath in Wscript.Arguments.Unnamed
.Attachments.Add attachmentPath
Next
.Display
End With
quitIfErr()
 
Function getNamedArg(n)
getNamedArg = Unescape(Wscript.Arguments.Named.item(n))
End Function
 
Function getNoExn(i)
if Wscript.Arguments.Unnamed.count > i then
getNoExn = Wscript.Arguments.Unnamed.item(i)
else
getNoExn = ""
end if
End Function
 
Function quitIfErr()
If Err.number <> 0 Then
Wscript.Echo "Error # " & CStr(Err.Number) & " " & Err.Description & " Source: " & Err.Source
Wscript.Quit Err.Number
End If
End Function
/trunk/OpenConcerto/src/org/openconcerto/utils/Nombre.java
26,8 → 26,23
 
static int[] puissanceMille = { 0, 1000, 1000000, 1000000000 };
 
static final String[] ref0Eng = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
"seventeen", "eighteen", "nineteen", "twenty" };
static final String[] ref10Eng = { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety", "hundred" };
 
static final String[] refmultEng = { "thousand", "million", "billion", "billion", "trillion" };// 3,6,9,12,15
 
public static int FR = 0;
public static int EN = 1;
private int language = FR;
 
public Nombre(int i) {
this(i, FR);
}
 
public Nombre(int i, int language) {
this.nb = i;
this.language = language;
}
 
public String getText() {
36,26 → 51,26
result.append("moins ");
 
if (this.nb <= 20) {
result.append(ref0[this.nb]);
result.append(language == FR ? ref0[this.nb] : ref0Eng[this.nb]);
} else if (this.nb < 100) {
 
int decimal = this.nb / 10;
int unit = this.nb % 10;
 
result.append(ref10[decimal]);
result.append(language == FR ? ref10[decimal] : ref10Eng[decimal]);
 
if (decimal != 7 && decimal != 9) {
if (this.language == EN || (decimal != 7 && decimal != 9)) {
if (unit > 0) { // trente, quarante..
if (unit == 1) {
result.append(" et");
result.append(language == FR ? " et" : " and");
}
result.append(" " + ref0[unit]);
result.append(" " + (language == FR ? ref0[unit] : ref0Eng[unit]));
}
} else {
if (unit == 1) {
result.append(" et");
result.append(language == FR ? " et" : " and");
}
result.append(" " + ref0[unit + 10]);
result.append(" " + (language == FR ? ref0[unit + 10] : ref0Eng[unit + 10]));
}
 
} else {
65,13 → 80,13
int cent = this.nb / 100;
 
if (cent == 1) {
result.append("cent");
result.append(language == FR ? "cent" : "one hundred");
} else {
result.append(ref0[cent] + " cent");
result.append((language == FR ? ref0[cent] : ref0Eng[cent]) + (language == FR ? " cent" : " hundred"));
}
int reste = this.nb - (cent * 100);
if (reste > 0) {
Nombre d = new Nombre(reste);
Nombre d = new Nombre(reste, language);
result.append(" " + d.getText());
}
} else {
85,9 → 100,9
if (val > 0) {
if (val > 1 && (i - 1) > 0) {
 
result.append(new Nombre(val).getText() + " " + refmult[i - 1] + "s ");
result.append(new Nombre(val, this.language).getText() + " " + (language == FR ? refmult[i - 1] : refmultEng[i - 1]) + "s ");
} else {
result.append(new Nombre(val).getText() + " " + refmult[i - 1] + " ");
result.append(new Nombre(val, this.language).getText() + " " + (language == FR ? refmult[i - 1] : refmultEng[i - 1]) + " ");
}
}
cumul += val * puissancei;
95,7 → 110,7
 
int val = this.nb % 1000;
if (val > 0) {
result.append(new Nombre(val).getText());
result.append(new Nombre(val, this.language).getText());
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/task/TodoListPanel.java
90,7 → 90,7
 
import org.apache.commons.dbutils.ResultSetHandler;
 
import sun.swing.table.DefaultTableCellHeaderRenderer;
import javax.swing.table.DefaultTableCellRenderer;
 
public class TodoListPanel extends JPanel implements ModelStateListener {
 
504,7 → 504,7
this.t.setBlockRepaint(false);
this.t.getColumnModel().getColumn(1).setCellRenderer(this.iconRenderer);
 
AlternateTableCellRenderer.setAllColumns(this.t);
AlternateTableCellRenderer.UTILS.setAllColumns(this.t);
this.t.repaint();
 
}
659,7 → 659,7
}
}
 
class JComponentTableCellRenderer extends DefaultTableCellHeaderRenderer {
class JComponentTableCellRenderer extends DefaultTableCellRenderer {
Icon icon;
TableCellRenderer renderer;
 
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/ITreeSelection.java
272,6 → 272,11
// TODO Auto-generated method stub
}
 
@Override
public void removeValidListener(ValidListener l) {
// TODO Auto-generated method stub
}
 
public boolean isValidated() {
 
return true;
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/ITreeSelectionNode.java
13,12 → 13,12
package org.openconcerto.erp.panel;
 
import java.util.List;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
 
import java.util.List;
 
import javax.swing.tree.DefaultMutableTreeNode;
 
public class ITreeSelectionNode extends DefaultMutableTreeNode {
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/ChargementCreationSocietePanel.java
20,7 → 20,6
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSchema;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSystem;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.ui.JLabelBold;
95,13 → 94,8
 
System.err.println("Création de la base");
 
final SQLSystem dbSystem = Configuration.getInstance().getBase().getServer().getSQLSystem();
ActionDB.dupliqueDB("Default", "OpenConcerto" + id, this);
 
if (dbSystem == SQLSystem.MYSQL) {
ActionDB.dupliqueMySQLDB("Default", "OpenConcerto" + id, this);
} else {
ActionDB.dupliquePGSqlDB("Default", "OpenConcerto" + id, this);
}
statusChanged("Mise à jour des sociétés");
SQLRowValues rowVals = new SQLRowValues(Configuration.getInstance().getBase().getTable("SOCIETE_COMMON"));
rowVals.put("DATABASE_NAME", "OpenConcerto" + id);
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/SauvegardeBasePanel.java
20,7 → 20,6
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
 
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
/trunk/OpenConcerto/src/org/openconcerto/erp/model/MouseSheetXmlListeListener.java
20,13 → 20,13
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
 
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.ui.EmailComposer;
import org.openconcerto.utils.ExceptionHandler;
 
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
34,13 → 34,13
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
 
public class MouseSheetXmlListeListener implements MouseListener {
 
52,8 → 52,8
private String previewString = "Voir le document";
private String showString = "Modifier le document avec OpenOffice";
private String generateString = "Générer le document";
private String mailPDFString = "Envoyé le document PDF par email";
private String mailString = "Envoyé le document par email";
private String mailPDFString = "Envoyer le document PDF par email";
private String mailString = "Envoyer le document par email";
 
private boolean previewIsVisible = true;
private boolean showIsVisible = true;
74,14 → 74,21
this.generateIsVisible = generate;
}
 
private static Map<SQLRow, AbstractSheetXml> cache = new HashMap<SQLRow, AbstractSheetXml>();
 
protected Class<? extends AbstractSheetXml> getSheetClass() {
return this.clazz;
}
 
protected AbstractSheetXml createAbstractSheet(SQLRow row) {
if (cache.get(row) != null) {
return cache.get(row);
} else {
try {
Constructor<? extends AbstractSheetXml> ctor = getSheetClass().getConstructor(SQLRow.class);
return ctor.newInstance(row);
AbstractSheetXml sheet = ctor.newInstance(row);
cache.put(row, sheet);
return sheet;
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InstantiationException e) {
97,6 → 104,7
}
return null;
}
}
 
public void mouseClicked(MouseEvent e) {
}
117,128 → 125,10
final AbstractSheetXml bSheet = createAbstractSheet(this.liste.getSelectedRow());
if (bSheet != null) {
 
if (!Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) {
if (this.showIsVisible) {
AbstractAction actionShow = new AbstractAction(this.showString) {
public void actionPerformed(ActionEvent ev) {
bSheet.showDocument();
for (RowAction action : getRowActions()) {
menuDroit.add(action.getAction());
}
};
JMenuItem item = new JMenuItem(actionShow);
 
if (bSheet.isFileOOExist()) {
item.setFont(item.getFont().deriveFont(Font.BOLD));
}
actionShow.setEnabled(bSheet.isFileOOExist());
menuDroit.add(item);
 
}
} else {
if (this.previewIsVisible && bSheet.isFileODSExist()) {
AbstractAction actionPreview = new AbstractAction(this.previewString) {
public void actionPerformed(ActionEvent ev) {
bSheet.showPreviewDocument();
}
};
JMenuItem item = new JMenuItem(actionPreview);
if (bSheet.isFileOOExist()) {
item.setFont(item.getFont().deriveFont(Font.BOLD));
}
menuDroit.add(item);
}
}
List<AbstractAction> list = addToMenu();
if (list != null) {
for (AbstractAction abstractAction : list) {
JMenuItem itemItalic = new JMenuItem(abstractAction);
itemItalic.setFont(itemItalic.getFont().deriveFont(Font.ITALIC));
menuDroit.add(itemItalic);
}
}
menuDroit.add(new JSeparator());
if (Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) {
 
if (this.showIsVisible) {
AbstractAction actionShow = new AbstractAction(this.showString) {
public void actionPerformed(ActionEvent ev) {
bSheet.showDocument();
}
};
JMenuItem item = new JMenuItem(actionShow);
 
actionShow.setEnabled(bSheet.isFileOOExist());
menuDroit.add(item);
menuDroit.add(new JSeparator());
}
}
if (this.printIsVisible) {
 
AbstractAction actionFastPrint = new AbstractAction(this.fastPrintString) {
public void actionPerformed(ActionEvent ev) {
bSheet.fastPrintDocument();
}
};
actionFastPrint.setEnabled(bSheet.isFileOOExist());
menuDroit.add(actionFastPrint);
 
AbstractAction actionPrint = new AbstractAction(this.printString) {
public void actionPerformed(ActionEvent ev) {
bSheet.printDocument();
}
};
actionPrint.setEnabled(bSheet.isFileOOExist());
menuDroit.add(actionPrint);
 
if (this.liste.getSelection().getSelectedIDs().size() > 1) {
AbstractAction actionPrintAll = new AbstractAction(this.printAllString) {
@Override
public void actionPerformed(ActionEvent e) {
 
final int[] l = liste.getJTable().getSelectedRows();
final List<SQLRow> list = new ArrayList<SQLRow>();
 
for (int i = 0; i < l.length; i++) {
list.add(liste.getModel().getTable().getRow(liste.getLine(l[i]).getRow().getID()));
}
 
ListeFastPrintFrame frame = new ListeFastPrintFrame(list, clazz);
frame.setVisible(true);
}
};
menuDroit.add(actionPrintAll);
}
}
 
if (this.showIsVisible) {
 
if (bSheet.getSQLRow() != null) {
AbstractAction actionMailPDF = new AbstractAction(this.mailPDFString) {
public void actionPerformed(ActionEvent ev) {
sendMail(bSheet, true);
}
};
actionMailPDF.setEnabled(bSheet.isFileOOExist());
menuDroit.add(actionMailPDF);
}
 
AbstractAction actionMail = new AbstractAction(this.mailString) {
public void actionPerformed(ActionEvent ev) {
sendMail(bSheet, false);
}
};
actionMail.setEnabled(bSheet.isFileOOExist());
menuDroit.add(actionMail);
 
}
if (this.generateIsVisible) {
menuDroit.add(new AbstractAction(this.generateString) {
public void actionPerformed(ActionEvent ev) {
 
bSheet.genere(true, false);
}
});
}
 
menuDroit.pack();
menuDroit.show(e.getComponent(), e.getPoint().x, e.getPoint().y);
menuDroit.setVisible(true);
295,6 → 185,8
 
final String adresseMail = mail;
 
final String subject = sheet.getReference();
 
if (readOnly) {
 
final Thread t = new Thread() {
310,7 → 202,8
 
// Future<File> pdf = doc.saveToPDF(f);
 
EmailComposer.getInstance().compose(adresseMail, "", "", sheet.getFilePDF().getAbsoluteFile());
EmailComposer.getInstance().compose(adresseMail, subject + (subject.trim().length() == 0 ? "" : ", ") + sheet.getFilePDF().getName(), "",
sheet.getFilePDF().getAbsoluteFile());
} catch (Exception e) {
e.printStackTrace();
ExceptionHandler.handle("Impossible de charger le document PDF", e);
317,7 → 210,7
}
} else {
try {
EmailComposer.getInstance().compose(adresseMail, "", "", f.getAbsoluteFile());
EmailComposer.getInstance().compose(adresseMail, subject + (subject.trim().length() == 0 ? "" : ", ") + f.getName(), "", f.getAbsoluteFile());
} catch (Exception exn) {
ExceptionHandler.handle(null, "Impossible de créer le courriel", exn);
}
329,7 → 222,7
t.start();
} else {
try {
EmailComposer.getInstance().compose(adresseMail, "", "", sheet.getFileODS().getAbsoluteFile());
EmailComposer.getInstance().compose(adresseMail, subject + (subject.trim().length() == 0 ? "" : ", ") + sheet.getFileODS().getName(), "", sheet.getFileODS().getAbsoluteFile());
} catch (Exception exn) {
ExceptionHandler.handle(null, "Impossible de créer le courriel", exn);
}
363,4 → 256,169
public void setprintString(String printString) {
this.printString = printString;
}
 
public List<RowAction> getRowActions() {
List<RowAction> l = new ArrayList<RowAction>();
 
if (!Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) {
if (this.showIsVisible) {
l.add(new RowAction(new AbstractAction(this.showString) {
public void actionPerformed(ActionEvent ev) {
createAbstractSheet(liste.getSelectedRow()).showDocument();
}
 
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
}
});
 
// if (bSheet.isFileOOExist()) {
// item.setFont(item.getFont().deriveFont(Font.BOLD));
// }
}
} else {
if (this.previewIsVisible) {
l.add(new RowAction(new AbstractAction(this.previewString) {
public void actionPerformed(ActionEvent ev) {
createAbstractSheet(liste.getSelectedRow()).showPreviewDocument();
}
 
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
}
});
// if (bSheet.isFileOOExist()) {
// item.setFont(item.getFont().deriveFont(Font.BOLD));
// }
}
}
 
// action supplémentaire
List<AbstractAction> list = addToMenu();
if (list != null) {
for (AbstractAction abstractAction : list) {
// JMenuItem itemItalic = new JMenuItem(abstractAction);
// itemItalic.setFont(itemItalic.getFont().deriveFont(Font.ITALIC));
l.add(new RowAction(abstractAction, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return selection != null && selection.size() > 0;
}
});
}
}
 
if (Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) {
 
if (this.showIsVisible) {
l.add(new RowAction(new AbstractAction(this.showString) {
public void actionPerformed(ActionEvent ev) {
createAbstractSheet(liste.getSelectedRow()).showDocument();
}
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
}
});
}
}
 
if (this.printIsVisible) {
 
l.add(new RowAction(new AbstractAction(this.fastPrintString) {
public void actionPerformed(ActionEvent ev) {
createAbstractSheet(liste.getSelectedRow()).fastPrintDocument();
}
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
}
});
 
l.add(new RowAction(new AbstractAction(this.printString) {
public void actionPerformed(ActionEvent ev) {
createAbstractSheet(liste.getSelectedRow()).printDocument();
}
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
}
});
 
if (this.liste.getSelection().getSelectedIDs().size() > 1) {
l.add(new RowAction(new AbstractAction(this.printAllString) {
@Override
public void actionPerformed(ActionEvent e) {
 
final int[] l = liste.getJTable().getSelectedRows();
final List<SQLRow> list = new ArrayList<SQLRow>();
 
for (int i = 0; i < l.length; i++) {
list.add(liste.getModel().getTable().getRow(liste.getLine(l[i]).getRow().getID()));
}
 
ListeFastPrintFrame frame = new ListeFastPrintFrame(list, clazz);
frame.setVisible(true);
}
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
}
});
 
}
 
}
 
if (this.showIsVisible) {
 
// if (createAbstractSheet(liste.getSelectedRow()).getSQLRow() != null) {
l.add(new RowAction(new AbstractAction(this.mailPDFString) {
public void actionPerformed(ActionEvent ev) {
sendMail(createAbstractSheet(liste.getSelectedRow()), true);
}
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
}
});
 
// }
l.add(new RowAction(new AbstractAction(this.mailString) {
public void actionPerformed(ActionEvent ev) {
sendMail(createAbstractSheet(liste.getSelectedRow()), false);
}
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
}
});
 
}
if (this.generateIsVisible) {
l.add(new RowAction(new AbstractAction(this.generateString) {
public void actionPerformed(ActionEvent ev) {
 
createAbstractSheet(liste.getSelectedRow()).genere(true, false);
}
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return selection != null && selection.size() == 1;
}
});
}
 
return l;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/rights/ComptaTotalUserRight.java
35,6 → 35,7
public List<RightTuple> expand(UserRightsManager mngr, String rightCode, String object, boolean haveRight) {
final List<RightTuple> res = new ArrayList<RightTuple>();
res.add(new RightTuple(ComptaUserRight.MENU, haveRight));
res.add(new RightTuple(ComptaUserRight.ACCES_NOT_RESCTRICTED_TO_411, haveRight));
return res;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/ActionDB.java
17,23 → 17,26
import org.openconcerto.erp.model.PrixTTC;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.changer.Changer;
import org.openconcerto.sql.changer.correct.FixSerial;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBStructureItemDB;
import org.openconcerto.sql.model.DBSystemRoot;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSchema;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLSystem;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.utils.SQLCreateRoot;
import org.openconcerto.utils.ExceptionHandler;
 
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
58,279 → 61,59
* @param baseDefault nom de la base par défaut
* @param newBase nom de la nouvelle base
*/
public static void dupliqueMySQLDB(String baseDefault, String newBase, StatusListener l) {
public static void dupliqueDB(String baseDefault, String newBase, StatusListener l) {
final DBSystemRoot sysRoot = Configuration.getInstance().getSystemRoot();
 
// ComptaPropsConfiguration instance = ComptaPropsConfiguration.create();
// Configuration.setInstance(instance);
 
// instance.setUpSocieteDataBaseConnexion(baseDefault);
DatabaseMetaData dbMetaDataSocieteDefault;
try {
 
// Creation de la nouvelle base
String reqDatabase = "CREATE DATABASE \"" + newBase + "\" CHARACTER SET 'UTF8'";
 
Configuration.getInstance().getBase().getDataSource().getConnection().prepareStatement(reqDatabase).executeUpdate();
SQLBase baseSQLNew = Configuration.getInstance().getBase().getServer().getBase(newBase, "openconcerto", "openconcerto");
SQLBase baseSQLDefault = Configuration.getInstance().getBase().getServer().getBase(baseDefault, "openconcerto", "openconcerto");
// Table de la base par defaut
dbMetaDataSocieteDefault = baseSQLDefault.getDataSource().getConnection().getMetaData();
 
ResultSet rs = dbMetaDataSocieteDefault.getTables("", "", null, null);
while (rs.next()) {
StringBuffer result = new StringBuffer();
String tableName = rs.getString("TABLE_NAME");
String tableType = rs.getString("TABLE_TYPE");
 
if ("TABLE".equalsIgnoreCase(tableType)) {
 
// Creation d'une table
// result.append("\n\n-- " + tableName);
result.append("\nCREATE TABLE `" + newBase + "`.`" + tableName + "` (\n");
ResultSet tableMetaData = dbMetaDataSocieteDefault.getColumns(null, null, tableName, "%");
boolean firstLine = true;
 
// On recupere la cle primaire
String primaryKey = "";
try {
ResultSet primaryKeys = dbMetaDataSocieteDefault.getPrimaryKeys(null, null, tableName);
while (primaryKeys.next()) {
primaryKey = primaryKeys.getString("COLUMN_NAME");
}
} catch (SQLException e) {
ExceptionHandler.handle("Erreur pendant la création de la base!", e);
System.err.println("Unable to get primary keys for table " + tableName + " because " + e);
}
 
System.err.println(primaryKey);
 
// Creation des columns
while (tableMetaData.next()) {
 
if (firstLine) {
firstLine = false;
} else {
result.append(",\n");
}
 
// COLUMN NAME, TYPE AND SIZE
String columnName = tableMetaData.getString("COLUMN_NAME");
String columnType = tableMetaData.getString("TYPE_NAME");
String decimalDigits = tableMetaData.getString("DECIMAL_DIGITS");
 
int columnSize = tableMetaData.getInt("COLUMN_SIZE");
 
// NULL OR NOT NULL
String nullable = tableMetaData.getString("IS_NULLABLE");
String nullString = "NULL";
if ("NO".equalsIgnoreCase(nullable)) {
nullString = "NOT NULL";
}
 
// DEFAULT
String defaultValue = tableMetaData.getString("COLUMN_DEF");
String defaultValueString = "";
if (defaultValue != null) {
defaultValueString = " default '" + defaultValue + "'";
}
 
if (columnType.trim().equalsIgnoreCase("int unsigned")) {
result.append(" " + " `" + columnName + "` " + "int (" + columnSize + ")" + " unsigned " + nullString);
} else {
if (columnType.trim().equalsIgnoreCase("bigint unsigned")) {
result.append(" " + " `" + columnName + "` " + "bigint (" + columnSize + ")" + " unsigned " + nullString);
} else {
if (columnType.trim().equalsIgnoreCase("date")) {
result.append(" " + " `" + columnName + "` date " + nullString);
} else {
if (columnType.trim().equalsIgnoreCase("numeric")) {
result.append(" " + " `" + columnName + "` " + columnType + " (" + columnSize + "," + decimalDigits + ")" + " " + nullString);
} else {
result.append(" " + " `" + columnName + "` " + columnType + " (" + columnSize + ")" + " " + nullString);
}
}
}
}
 
if (primaryKey.equalsIgnoreCase(columnName) && (columnType.trim().equalsIgnoreCase("int unsigned") || columnType.trim().equalsIgnoreCase("int"))) {
result.append(" auto_increment");
} else {
result.append(defaultValueString);
}
 
// for (int i = 1; i < 20; i++) {
// System.err.println(i + " " + tableMetaData.getObject(i));
// }
 
}
tableMetaData.close();
 
// PRIMARY
if (primaryKey.trim().length() != 0) {
result.append(",\n PRIMARY KEY (`" + primaryKey + "`)\n);\n");
} else {
result.append(");\n");
}
// Creation de la table dans la nouvelle base
baseSQLNew.getDataSource().getConnection().prepareStatement("DROP TABLE IF EXISTS `" + newBase + "`.`" + tableName + "`").executeUpdate();
System.err.println("Execute Query " + result);
baseSQLNew.getDataSource().getConnection().prepareStatement(result.toString()).executeUpdate();
 
// Dump Table
// dumpTable(baseSQLDefault, baseSQLNew, tableName);
}
}
} catch (SQLException e) {
e.printStackTrace();
ExceptionHandler.handle("Erreur pendant la création de la base!", e);
}
}
 
public static void dupliquePGSqlDB(String baseDefault, String newBase, StatusListener l) {
final SQLBase base = Configuration.getInstance().getBase();
 
// FIXME Replace by SQLCopy
 
// FIXME ADD TRIGGER TO UPDATE SOLDE COMPTE_PCE
// ComptaPropsConfiguration instance = ComptaPropsConfiguration.create();
// Configuration.setInstance(instance);
 
// instance.setUpSocieteDataBaseConnexion(baseDefault);
// DatabaseMetaData dbMetaDataSocieteDefault;
List<SQLTable> listTableDefault;
try {
log(l, "Création du schéma");
if (!sysRoot.getRootsToMap().contains(baseDefault)) {
sysRoot.getRootsToMap().add(baseDefault);
sysRoot.refetch(Collections.singleton(baseDefault));
}
final DBRoot baseSQLDefault = sysRoot.getRoot(baseDefault);
log(l, "Traitement des " + baseSQLDefault.getChildrenNames().size() + " tables");
 
// Creation de la nouvelle base
final String reqDatabase = SQLSelect.quote("CREATE SCHEMA %i", newBase);
final SQLCreateRoot createRoot = baseSQLDefault.getDefinitionSQL(sysRoot.getServer().getSQLSystem());
final SQLDataSource ds = sysRoot.getDataSource();
// be safe don't add DROP SCHEMA
ds.execute(createRoot.asString(newBase, false, true));
sysRoot.getRootsToMap().add(newBase);
// TODO find a more functional way
final boolean origVal = Boolean.getBoolean(SQLSchema.NOAUTO_CREATE_METADATA);
if (!origVal)
System.setProperty(SQLSchema.NOAUTO_CREATE_METADATA, "true");
sysRoot.refetch(Collections.singleton(newBase));
if (!origVal)
System.setProperty(SQLSchema.NOAUTO_CREATE_METADATA, "false");
final DBRoot baseSQLNew = sysRoot.getRoot(newBase);
 
base.getDataSource().execute(reqDatabase);
final Set<String> rootsToMap = base.getDBSystemRoot().getRootsToMap();
rootsToMap.add(baseDefault);
rootsToMap.add(newBase);
// TODO: Sylvain voir pour y faire rapidement
base.fetchTables();
final SQLSchema baseSQLDefault = base.getSchema(baseDefault);
final SQLSchema baseSQLNew = base.getSchema(newBase);
// Table de la base par defaut
listTableDefault = new ArrayList<SQLTable>(baseSQLDefault.getTables());
log(l, "Traitement des " + listTableDefault.size() + " tables");
// SQLSchema baseSQLNew = Configuration.getInstance().getBase().getSchema(newBase);
// ResultSet rs = dbMetaDataSocieteDefault.getTables("", "", null, null);
for (int i = 0; i < listTableDefault.size(); i++) {
SQLTable table = listTableDefault.get(i);
StringBuffer result = new StringBuffer();
final Set<SQLTable> newTables = baseSQLNew.getTables();
int i = 0;
final SQLSyntax syntax = sysRoot.getServer().getSQLSystem().getSyntax();
// MAYBE SQLCreateRoot can avoid creating foreign constraints, then we insert data,
// finally SQLCreateRoot adds just the constraints
ds.execute(syntax.disableFKChecks(baseSQLNew));
for (final SQLTable table : newTables) {
String tableName = table.getName();
 
// Creation d'une table
// result.append("\n\n-- " + tableName);
result.append("\nCREATE TABLE \"" + newBase + "\".\"" + tableName + "\" (\n");
Set<SQLField> tableFields = table.getFields();
boolean firstLine = true;
 
// On recupere la cle primaire
String primaryKey = (table.getKey() == null) ? "" : table.getKey().getName();
 
System.err.println(primaryKey);
 
// Creation des columns
for (SQLField field : tableFields) {
 
if (firstLine) {
firstLine = false;
} else {
result.append(",\n");
log(l, "Copie de la table " + tableName + " " + (i + 1) + "/" + newTables.size());
// Dump Table
dumpTable(baseSQLDefault, table);
log(l, "Table " + tableName + " " + (i + 1) + "/" + newTables.size() + " OK");
i++;
}
ds.execute(syntax.enableFKChecks(baseSQLNew));
 
// COLUMN NAME, TYPE AND SIZE
String columnName = field.getName();
String columnType = field.getType().getTypeName();
 
// NULL OR NOT NULL
// field.getType().getSize();
// String nullable = tableMetaData.getString("IS_NULLABLE");
String nullString = "NULL";
DBStructureItemDB db = field.getDB();
// if ("NO".equalsIgnoreCase(nullable)) {
// nullString = "NOT NULL";
// }
 
// DEFAULT
Object defaultValueO = field.getDefaultValue();
String defaultValue = (defaultValueO == null) ? null : defaultValueO.toString();
String defaultValueString = "";
if (defaultValue != null) {
defaultValueString = " default " + defaultValue;
if (syntax.getSystem() == SQLSystem.POSTGRESQL) {
log(l, "Maj des séquences des tables");
new FixSerial(sysRoot).changeAll(baseSQLNew);
}
 
int columnSize = field.getType().getSize();
Integer decimalDigit = (Integer) field.getMetadata("DECIMAL_DIGITS");
String stringColumnSize = "";
if (Integer.valueOf(columnSize).intValue() > 0 && Integer.valueOf(columnSize).intValue() < 10000) {
stringColumnSize = " (" + columnSize;
 
if (decimalDigit != null && Integer.valueOf(decimalDigit).intValue() > 0) {
stringColumnSize += ", " + decimalDigit;
}
 
stringColumnSize += ")";
}
 
if (primaryKey.equalsIgnoreCase(columnName) && (columnType.trim().equalsIgnoreCase("serial"))) {
result.append(" " + " \"" + columnName + "\" " + columnType);
} else {
if ((columnType.trim().equalsIgnoreCase("character varying") || columnType.trim().equalsIgnoreCase("varchar") || columnType.trim().equalsIgnoreCase("numeric"))
&& stringColumnSize.length() > 0) {
result.append(" " + " \"" + columnName + "\" " + columnType + stringColumnSize + " ");
result.append(defaultValueString);
} else {
result.append(" " + " \"" + columnName + "\" " + columnType + " ");
result.append(defaultValueString);
}
}
}
 
// FOREIGN
Set<SQLField> setForeign = table.getForeignKeys();
for (SQLField field2 : setForeign) {
 
// Only if not in default
final SQLTable foreignTable = base.getGraph().getForeignTable(field2);
SQLName pointsToTable = foreignTable.getSQLName();
String pointsToBase = "\"" + pointsToTable.getFirst() + "\"";
String pointsToSchema = foreignTable.getSchema().getName();
String pointsToField = foreignTable.getKey().getName();
 
if (!pointsToSchema.equalsIgnoreCase(baseSQLDefault.getName())) {
result.append(",\n FOREIGN KEY (\"" + field2.getName() + "\")" + " REFERENCES " + pointsToBase + ".\"" + pointsToSchema + "\".\"" + pointsToTable.getName() + "\" (\""
+ pointsToField + "\") MATCH SIMPLE" + " ON UPDATE NO ACTION ON DELETE NO ACTION");
}
}
 
// PRIMARY
if (primaryKey.trim().length() != 0) {
result.append(",\n PRIMARY KEY (\"" + primaryKey + "\")\n);\n");
} else {
result.append(");\n");
}
// Creation de la table dans la nouvelle base
log(l, "Création de la table " + tableName + " " + (i + 1) + "/" + listTableDefault.size());
base.getDataSource().getConnection().prepareStatement("DROP TABLE IF EXISTS \"" + newBase + "\".\"" + tableName + "\"").executeUpdate();
System.err.println("Execute Query " + result);
base.getDataSource().getConnection().prepareStatement(result.toString()).executeUpdate();
 
log(l, "Copie de la table " + tableName + " " + (i + 1) + "/" + listTableDefault.size());
 
// Dump Table
dumpTable(baseSQLDefault, baseSQLNew, tableName);
log(l, "Maj des séquences table " + tableName + " " + (i + 1) + "/" + listTableDefault.size());
log(l, "Table " + tableName + " " + (i + 1) + "/" + listTableDefault.size() + " OK");
}
// TODO: Sylvain voir pour le faire rapidement: fetchSchema(...)
 
base.fetchTables();
Changer.change(baseSQLNew, FixSerial.class);
 
log(l, "Duplication terminée");
 
} catch (SQLException e) {
341,94 → 124,6
 
}
 
private static String getControleStatement(String customer, String base, String year) {
 
StringBuffer s = new StringBuffer();
s.append("ALTER TABLE \"" + base + "\".\"AFFAIRE_ELEMENT\" ADD COLUMN \"ID_DOMAINE\" integer default 1;");
s.append("ALTER TABLE \"" + base + "\".\"AFFAIRE_ELEMENT\" ADD CONSTRAINT \"AFFAIRE_ELEMENT_ID_DOMAINE_fkey\" FOREIGN KEY (\"ID_DOMAINE\") REFERENCES \"" + customer
+ "_Common\".\"DISCIPLINE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
s.append("ALTER TABLE \"" + base + "\".\"CODE_MISSION\" ADD COLUMN \"ID_DOMAINE\" integer default 1;");
s.append("ALTER TABLE \"" + base + "\".\"CODE_MISSION\" ADD CONSTRAINT \"CODE_MISSION_ID_DOMAINE_fkey\" FOREIGN KEY (\"ID_DOMAINE\") REFERENCES \"" + customer
+ "_Common\".\"DISCIPLINE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS_ELEMENT\" ADD COLUMN \"ID_DOMAINE\" integer default 1;");
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS_ELEMENT\" ADD CONSTRAINT \"FICHE_RENDEZ_VOUS_ELEMENT_ID_DOMAINE_fkey\" FOREIGN KEY (\"ID_DOMAINE\") REFERENCES \"" + customer
+ "_Common\".\"DISCIPLINE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"PROPOSITION_ELEMENT\" ADD COLUMN \"ID_DOMAINE\" integer default 1;");
s.append("ALTER TABLE \"" + base + "\".\"PROPOSITION_ELEMENT\" ADD CONSTRAINT \"PROPOSITION_ELEMENT_ID_DOMAINE_fkey\" FOREIGN KEY (\"ID_DOMAINE\") REFERENCES \"" + customer
+ "_Common\".\"DISCIPLINE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"SAISIE_VENTE_FACTURE_ELEMENT\" ADD COLUMN \"ID_DOMAINE\" integer default 1;");
s.append("ALTER TABLE \"" + base + "\".\"SAISIE_VENTE_FACTURE_ELEMENT\" ADD CONSTRAINT \"SAISIE_VENTE_FACTURE_ELEMENT_ID_DOMAINE_fkey\" FOREIGN KEY (\"ID_DOMAINE\") REFERENCES \"" + customer
+ "_Common\".\"DISCIPLINE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"SAISIE_VENTE_FACTURE\" ADD COLUMN \"ID_VERIFICATEUR\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"SAISIE_VENTE_FACTURE\" ADD CONSTRAINT \"SAISIE_VENTE_FACTURE_ID_VERIFICATEUR_fkey\" FOREIGN KEY (\"ID_VERIFICATEUR\") REFERENCES \"" + customer + "_"
+ year + "\".\"VERIFICATEUR\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"POURCENT_SERVICE\" ADD COLUMN \"ID_VERIFICATEUR\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"POURCENT_SERVICE\" ADD CONSTRAINT \"POURCENT_SERVICE_ID_VERIFICATEUR_fkey\" FOREIGN KEY (\"ID_VERIFICATEUR\") REFERENCES \"" + customer + "_" + year
+ "\".\"VERIFICATEUR\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS\" ADD COLUMN \"ID_VERIFICATEUR\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS\" ADD CONSTRAINT \"FICHE_RENDEZ_VOUS_ID_VERIFICATEUR_fkey\" FOREIGN KEY (\"ID_VERIFICATEUR\") REFERENCES \"" + customer + "_" + year
+ "\".\"VERIFICATEUR\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS_ELEMENT\" ADD COLUMN \"ID_VERIFICATEUR\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS_ELEMENT\" ADD CONSTRAINT \"FICHE_RENDEZ_VOUS_ELEMENT_ID_VERIFICATEUR_fkey\" FOREIGN KEY (\"ID_VERIFICATEUR\") REFERENCES \""
+ customer + "_" + year + "\".\"VERIFICATEUR\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"RAPPORT\" ADD COLUMN \"ID_VERIFICATEUR\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"RAPPORT\" ADD CONSTRAINT \"RAPPORT_ID_VERIFICATEUR_fkey\" FOREIGN KEY (\"ID_VERIFICATEUR\") REFERENCES \"" + customer + "_" + year
+ "\".\"VERIFICATEUR\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"ORDRE_MISSION\" ADD COLUMN \"ID_VERIFICATEUR\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"ORDRE_MISSION\" ADD CONSTRAINT \"ORDRE_MISSION_ID_VERIFICATEUR_fkey\" FOREIGN KEY (\"ID_VERIFICATEUR\") REFERENCES \"" + customer + "_" + year
+ "\".\"VERIFICATEUR\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"SAISIE_VENTE_FACTURE_ELEMENT\" ADD COLUMN \"ID_MISSION\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"SAISIE_VENTE_FACTURE_ELEMENT\" ADD CONSTRAINT \"SAISIE_VENTE_FACTURE_ELEMENT_ID_MISSION_fkey\" FOREIGN KEY (\"ID_MISSION\") REFERENCES \"" + customer
+ "_" + year + "\".\"MISSION\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS_ELEMENT\" ADD COLUMN \"ID_MISSION\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS_ELEMENT\" ADD CONSTRAINT \"FICHE_RENDEZ_VOUS_ELEMENT_ID_MISSION_fkey\" FOREIGN KEY (\"ID_MISSION\") REFERENCES \"" + customer + "_"
+ year + "\".\"MISSION\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"POURCENT_SERVICE\" ADD COLUMN \"ID_SERVICE\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"POURCENT_SERVICE\" ADD CONSTRAINT \"POURCENT_SERVICE_ID_SERVICE_fkey\" FOREIGN KEY (\"ID_SERVICE\") REFERENCES \"" + customer
+ "_Common\".\"SERVICE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"CODE_MISSION\" ADD COLUMN \"ID_SERVICE\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"CODE_MISSION\" ADD CONSTRAINT \"CODE_MISSION_ID_SERVICE_fkey\" FOREIGN KEY (\"ID_SERVICE\") REFERENCES \"" + customer
+ "_Common\".\"SERVICE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"AFFAIRE_ELEMENT\" ADD COLUMN \"ID_PERIODICITE\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"AFFAIRE_ELEMENT\" ADD CONSTRAINT \"AFFAIRE_ELEMENT_ID_PERIODICITE_fkey\" FOREIGN KEY (\"ID_PERIODICITE\") REFERENCES \"" + customer
+ "_Common\".\"PERIODICITE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS_ELEMENT\" ADD COLUMN \"ID_PERIODICITE\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"FICHE_RENDEZ_VOUS_ELEMENT\" ADD CONSTRAINT \"FICHE_RENDEZ_VOUS_ELEMENT_ID_PERIODICITE_fkey\" FOREIGN KEY (\"ID_PERIODICITE\") REFERENCES \""
+ customer + "_Common\".\"PERIODICITE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"PROPOSITION_ELEMENT\" ADD COLUMN \"ID_PERIODICITE\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"PROPOSITION_ELEMENT\" ADD CONSTRAINT \"PROPOSITION_ELEMENT_ID_PERIODICITE_fkey\" FOREIGN KEY (\"ID_PERIODICITE\") REFERENCES \"" + customer
+ "_Common\".\"PERIODICITE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"RAPPORT\" ADD COLUMN \"ID_PERIODICITE\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"RAPPORT\" ADD CONSTRAINT \"RAPPORT_ID_PERIODICITE_fkey\" FOREIGN KEY (\"ID_PERIODICITE\") REFERENCES \"" + customer
+ "_Common\".\"PERIODICITE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"SAISIE_VENTE_FACTURE_ELEMENT\" ADD COLUMN \"ID_PERIODICITE\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"SAISIE_VENTE_FACTURE_ELEMENT\" ADD CONSTRAINT \"SAISIE_VENTE_FACTURE_ELEMENT_ID_PERIODICITE_fkey\" FOREIGN KEY (\"ID_PERIODICITE\") REFERENCES \""
+ customer + "_Common\".\"PERIODICITE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
 
s.append("ALTER TABLE \"" + base + "\".\"AVOIR_CLIENT_ELEMENT\" ADD COLUMN \"ID_PERIODICITE\" int4 default 1;");
s.append("ALTER TABLE \"" + base + "\".\"AVOIR_CLIENT_ELEMENT\" ADD CONSTRAINT \"AVOIR_CLIENT_ELEMENT_ID_PERIODICITE_fkey\" FOREIGN KEY (\"ID_PERIODICITE\") REFERENCES \"" + customer
+ "_Common\".\"PERIODICITE\" (\"ID\") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION;");
return s.toString();
}
 
private static void log(StatusListener l, String message) {
if (l != null) {
l.statusChanged(message);
442,56 → 137,11
* @param baseNew
* @param tableName
*/
private static void dumpTable(SQLSchema base, SQLSchema baseNew, String tableName) {
 
private static void dumpTable(DBRoot source, SQLTable newTable) {
try {
// First we output the create table stuff
// PreparedStatement stmt = dbConn.prepareStatement("SELECT * FROM " + tableName);
 
List<Map> rs = base.getBase().getDataSource().execute("SELECT * FROM \"" + base.getName() + "\".\"" + tableName + "\"");
 
// ResultSetMetaData metaData = rs.getMetaData();
if (rs == null || rs.size() == 0) {
return;
}
int columnCount = rs.get(0).keySet().size();
 
// Now we can output the actual data
PreparedStatement statement;
StringBuffer query = new StringBuffer();
query = new StringBuffer("INSERT INTO \"" + baseNew.getName() + "\".\"" + tableName + "\"(");
 
Map m = rs.get(0);
for (Iterator i = m.keySet().iterator(); i.hasNext();) {
String key = i.next().toString();
if (i.hasNext()) {
query.append("\"" + key.toString() + "\", ");
} else {
query.append("\"" + key.toString() + "\") VALUES (");
}
}
 
// StringBuffer query = new StringBuffer("INSERT INTO `" + baseNew.getName() + "`.`" +
// tableName + "` VALUES (");
for (int i = 0; i < columnCount - 1; i++) {
query.append("?,");
}
query.append("?)");
statement = baseNew.getBase().getDataSource().getConnection().prepareStatement(query.toString());
 
for (Map map : rs) {
int i = 0;
for (Object key : map.keySet()) {
 
statement.setObject(i + 1, map.get(key));
i++;
}
// TODO: g
statement.executeUpdate();
}
 
SQLRowValues.insertFromTable(newTable, source.getTable(newTable.getName()));
} catch (SQLException e) {
System.err.println("Unable to dump table " + tableName + " because: " + e);
System.err.println("Unable to dump table " + newTable.getName());
e.printStackTrace();
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/PlanningRdvXmlSheet.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/FicheRendezVousXmlSheet.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/AffacturageXmlSheet.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/CommandeXmlSheet.java
32,6 → 32,16
return tuple;
}
 
@Override
public SQLRow getRowLanguage() {
SQLRow rowFournisseur = this.row.getForeignRow("ID_FOURNISSEUR");
if (rowFournisseur.getTable().contains("ID_LANGUE")) {
return rowFournisseur.getForeignRow("ID_LANGUE");
} else {
return super.getRowLanguage();
}
}
 
// FIXME Prefs printer location
public CommandeXmlSheet(SQLRow row) {
super(row);
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/CourrierClientSheet.java
22,8 → 22,6
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.utils.Tuple2;
 
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
32,7 → 30,6
public class CourrierClientSheet extends AbstractJOOReportsSheet {
 
private SQLRow rowCourrier;
private DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
 
private static final Tuple2<String, String> tuple = Tuple2.create("LocationCourrier", "Courrier");
 
55,69 → 52,11
 
Map<String, Object> m = new HashMap<String, Object>();
 
SQLElement eltAffaire = Configuration.getInstance().getDirectory().getElement("AFFAIRE");
SQLRow rowAffaire = eltAffaire.getTable().getRow(this.rowCourrier.getInt("ID_AFFAIRE"));
 
SQLElement eltProp = Configuration.getInstance().getDirectory().getElement("PROPOSITION");
final int idProp = rowAffaire.getInt("ID_PROPOSITION");
SQLRow rowProp = eltProp.getTable().getRow(idProp);
 
SQLElement elt = Configuration.getInstance().getDirectory().getElement("MODELE_COURRIER_CLIENT");
SQLRow rowModele = elt.getTable().getRow(this.rowCourrier.getInt("ID_MODELE_COURRIER_CLIENT"));
String contenu = rowModele.getString("CONTENU");
 
// Missions
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("AFFAIRE_ELEMENT");
List<SQLRow> rowsMission = rowAffaire.getReferentRows(tableElt);
String listeMissions = "";
for (SQLRow rowMission : rowsMission) {
listeMissions += rowMission.getString("NOM") + ", ";
}
 
listeMissions = listeMissions.trim();
if (listeMissions.length() != 0) {
listeMissions = listeMissions.substring(0, listeMissions.length() - 1);
}
 
contenu = contenu.replaceAll("%mission", listeMissions);
m.put("Corps", contenu);
m.put("Objet", this.rowCourrier.getString("NOM"));
m.put("Date", dateFormat.format(this.rowCourrier.getDate("DATE").getTime()));
if (idProp > 1) {
m.put("Numero", rowProp.getString("NUMERO"));
} else {
m.put("Numero", "");
}
 
m.put("NumeroAffaire", rowAffaire.getString("NUMERO"));
m.put("NomAffaire", rowAffaire.getString("OBJET"));
m.put("Objet", this.rowCourrier.getString("NOM"));
 
// Initiale Comm
SQLElement eltComm = Configuration.getInstance().getDirectory().getElement("COMMERCIAL");
SQLRow rowCommercial = eltComm.getTable().getRow(rowProp.getInt("ID_COMMERCIAL"));
String initialeComm = getInitiales(rowCommercial);
 
m.put("IR", initialeComm);
 
// initiale Secr
SQLElement eltSecretaire = Configuration.getInstance().getDirectory().getElement("SECRETAIRE");
SQLRow rowSecretaire = eltSecretaire.getTable().getRow(this.rowCourrier.getInt("ID_SECRETAIRE"));
String initialeSecr = getInitiales(rowSecretaire);
 
m.put("IS", initialeSecr);
SQLElement eltContact = Configuration.getInstance().getDirectory().getElement("CONTACT");
SQLElement eltTitre = Configuration.getInstance().getDirectory().getElement("TITRE_PERSONNEL");
SQLRow rowContactCom = eltContact.getTable().getRow(rowAffaire.getInt("ID_CONTACT_COM"));
SQLRow rowTitre = eltTitre.getTable().getRow(rowContactCom.getInt("ID_TITRE_PERSONNEL"));
String correspondant = rowTitre.getString("NOM");
 
String contact = rowTitre.getString("NOM");
contact += " " + rowContactCom.getString("PRENOM");
contact += " " + rowContactCom.getString("NOM");
 
m.put("Correspondant", correspondant);
m.put("Contact", contact);
 
int idAdresse = this.rowCourrier.getInt("ID_ADRESSE");
 
if (idAdresse > 1) {
140,30 → 79,7
}
 
m.put("ville", villeCli);
} else {
// Client
SQLRow rowClient;
rowClient = rowAffaire.getForeignRow("ID_CLIENT");
m.put("clientNom", rowClient.getString("FORME_JURIDIQUE") + " " + rowClient.getString("NOM"));
 
SQLRow rowAdresseClient = rowClient.getForeignRow("ID_ADRESSE");
 
m.put("clientAdresse", rowAdresseClient.getString("RUE"));
 
m.put("codePostal", getVilleCP(rowAdresseClient.getString("VILLE")));
String villeCli = getVille(rowAdresseClient.getString("VILLE"));
final Object cedexCli = rowAdresseClient.getObject("CEDEX");
final boolean hasCedexCli = rowAdresseClient.getBoolean("HAS_CEDEX");
 
if (hasCedexCli) {
villeCli += " CEDEX";
if (cedexCli != null && cedexCli.toString().trim().length() > 0) {
villeCli += " " + cedexCli.toString().trim();
}
}
 
m.put("ville", villeCli);
}
return m;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/RelanceSheet.java
42,20 → 42,19
/**
* @return une Map contenant les valeurs à remplacer dans la template
*/
protected Map createMap() {
protected Map<String, Object> createMap() {
 
SQLRow rowSoc = ((ComptaPropsConfiguration) Configuration.getInstance()).getRowSociete();
SQLRow rowSocAdresse = rowSoc.getForeignRow("ID_ADRESSE_COMMON");
final SQLRow rowSoc = ((ComptaPropsConfiguration) Configuration.getInstance()).getRowSociete();
final SQLRow rowSocAdresse = rowSoc.getForeignRow("ID_ADRESSE_COMMON");
 
Map<String, Object> m = new HashMap<String, Object>();
final Map<String, Object> map = new HashMap<String, Object>();
 
// Infos societe
m.put("SocieteType", rowSoc.getString("TYPE"));
m.put("SocieteNom", rowSoc.getString("NOM"));
map.put("SocieteType", rowSoc.getString("TYPE"));
map.put("SocieteNom", rowSoc.getString("NOM"));
map.put("SocieteAdresse", rowSocAdresse.getString("RUE"));
map.put("SocieteCodePostal", getVilleCP(rowSocAdresse.getString("VILLE")));
 
m.put("SocieteAdresse", rowSocAdresse.getString("RUE"));
m.put("SocieteCodePostal", getVilleCP(rowSocAdresse.getString("VILLE")));
 
String ville = getVille(rowSocAdresse.getString("VILLE"));
final Object cedex = rowSocAdresse.getObject("CEDEX");
final boolean hasCedex = rowSocAdresse.getBoolean("HAS_CEDEX");
67,7 → 66,7
}
}
 
m.put("SocieteVille", ville);
map.put("SocieteVille", ville);
 
SQLRow rowClient;
final SQLRow clientRowNX = this.rowRelance.getForeignRow("ID_CLIENT");
77,13 → 76,13
// Client compte
SQLRow rowCompteClient = clientRowNX.getForeignRow("ID_COMPTE_PCE");
String numero = rowCompteClient.getString("NUMERO");
m.put("ClientNumeroCompte", numero);
map.put("ClientNumeroCompte", numero);
 
// Infos Client
m.put("ClientType", rowClient.getString("FORME_JURIDIQUE"));
m.put("ClientNom", rowClient.getString("NOM"));
m.put("ClientAdresse", rowAdresse.getString("RUE"));
m.put("ClientCodePostal", getVilleCP(rowAdresse.getString("VILLE")));
map.put("ClientType", rowClient.getString("FORME_JURIDIQUE"));
map.put("ClientNom", rowClient.getString("NOM"));
map.put("ClientAdresse", rowAdresse.getString("RUE"));
map.put("ClientCodePostal", getVilleCP(rowAdresse.getString("VILLE")));
String villeCli = getVille(rowAdresse.getString("VILLE"));
final Object cedexCli = rowAdresse.getObject("CEDEX");
final boolean hasCedexCli = rowAdresse.getBoolean("HAS_CEDEX");
95,52 → 94,48
}
}
 
m.put("ClientVille", villeCli);
map.put("ClientVille", villeCli);
 
// Date relance
Date d = (Date) this.rowRelance.getObject("DATE");
m.put("RelanceDate", dateFormat.format(d));
map.put("RelanceDate", dateFormat.format(d));
 
SQLRow rowFacture = this.rowRelance.getForeignRow("ID_SAISIE_VENTE_FACTURE");
 
SQLRow rowPole = rowFacture.getForeignRow("ID_POLE_PRODUIT");
m.put("RaisonSociale", rowPole.getString("RAISON_SOCIALE"));
 
// Infos facture
Long lTotal = (Long) rowFacture.getObject("T_TTC");
Long lRestant = (Long) this.rowRelance.getObject("MONTANT");
Long lVerse = new Long(lTotal.longValue() - lRestant.longValue());
m.put("FactureNumero", rowFacture.getString("NUMERO"));
m.put("FactureTotal", GestionDevise.currencyToString(lTotal.longValue(), true));
m.put("FactureRestant", GestionDevise.currencyToString(lRestant.longValue(), true));
m.put("FactureVerse", GestionDevise.currencyToString(lVerse.longValue(), true));
m.put("FactureDate", dateFormat2.format((Date) rowFacture.getObject("DATE")));
map.put("FactureNumero", rowFacture.getString("NUMERO"));
map.put("FactureTotal", GestionDevise.currencyToString(lTotal.longValue(), true));
map.put("FactureRestant", GestionDevise.currencyToString(lRestant.longValue(), true));
map.put("FactureVerse", GestionDevise.currencyToString(lVerse.longValue(), true));
map.put("FactureDate", dateFormat2.format((Date) rowFacture.getObject("DATE")));
 
Date dFacture = (Date) rowFacture.getObject("DATE");
SQLRow modeRegRow = rowFacture.getForeignRow("ID_MODE_REGLEMENT");
Date dateEch = ModeDeReglementSQLElement.calculDate(modeRegRow.getInt("AJOURS"), modeRegRow.getInt("LENJOUR"), dFacture);
m.put("FactureDateEcheance", dateFormat2.format(dateEch));
map.put("FactureDateEcheance", dateFormat2.format(dateEch));
 
SQLSelect sel = new SQLSelect(Configuration.getInstance().getBase());
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 listResult = Configuration.getInstance().getBase().getDataSource().execute(sel.asString());
List<Map> listResult = Configuration.getInstance().getBase().getDataSource().execute(sel.asString());
if (listResult != null && listResult.size() > 0) {
Map o = (Map) listResult.get(0);
Map o = listResult.get(0);
Number n = (Number) o.get(this.rowRelance.getTable().getKey().getName());
SQLRow rowOldRelance = this.rowRelance.getTable().getRow(n.intValue());
Date dOldRelance = (Date) rowOldRelance.getObject("DATE");
m.put("DatePremiereRelance", dateFormat2.format(dOldRelance));
map.put("DatePremiereRelance", dateFormat2.format(dOldRelance));
} else {
m.put("DatePremiereRelance", "");
map.put("DatePremiereRelance", "");
}
 
return m;
return map;
}
 
public RelanceSheet(SQLRow row) {
super();
this.rowRelance = row;
Date d = (Date) this.rowRelance.getObject("DATE");
String year = yearFormat.format(d);
151,13 → 146,6
init(year, string, "RelancePrinter", tuple);
}
 
// public void generate(boolean print, boolean show, String printer, boolean overwrite) {
// // this.locationTemplate =
// // TemplateNXProps.getInstance().getStringProperty("LocationTemplate");
//
// super.generate(print, show, printer, overwrite);
// }
 
protected boolean savePDF() {
return true;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/AvoirClientXmlSheet.java
35,6 → 35,16
return tuple;
}
 
@Override
public SQLRow getRowLanguage() {
SQLRow rowClient = this.row.getForeignRow("ID_CLIENT");
if (rowClient.getTable().contains("ID_LANGUE")) {
return rowClient.getForeignRow("ID_LANGUE");
} else {
return super.getRowLanguage();
}
}
 
public AvoirClientXmlSheet(SQLRow row) {
super(row);
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter");
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLField.java
14,6 → 14,7
package org.openconcerto.erp.generationDoc;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.map.model.Ville;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
26,7 → 27,10
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.GestionDevise;
import org.openconcerto.utils.Nombre;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.Tuple2;
 
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
37,7 → 41,6
import java.util.List;
import java.util.Map;
 
 
import org.jdom.Element;
 
public class OOXMLField extends OOXMLElement {
44,11 → 47,10
 
private String op = "";
 
public OOXMLField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id) {
super(eltField, sqlElt, id);
public OOXMLField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id, SQLRow rowLanguage) {
super(eltField, sqlElt, id, rowLanguage);
 
String base = eltField.getAttributeValue("base");
 
this.op = eltField.getAttributeValue("op");
 
this.row = row;
55,7 → 57,7
if ((this.row == null || !this.row.getTable().getSchema().getName().equalsIgnoreCase("Common")) && base != null && base.equalsIgnoreCase("COMMON")) {
this.row = ((ComptaPropsConfiguration) Configuration.getInstance()).getRowSociete();
}
if (row == null) {
if (this.row == null) {
this.row = sqlElt.getTable().getRow(id);
}
 
102,10 → 104,14
 
String result = "";
for (Element ssComposant : children) {
OOXMLField childElt = new OOXMLField(ssComposant, foreignRow, this.sqlElt, this.id);
OOXMLField childElt = new OOXMLField(ssComposant, foreignRow, this.sqlElt, this.id, this.rowLanguage);
final Object valueComposantO = childElt.getValue();
result += (valueComposantO == null) ? "" : valueComposantO.toString() + " ";
}
String cellSize = this.elt.getAttributeValue("cellSize");
if (cellSize != null && cellSize.trim().length() != 0) {
result = splitStringCell(cellSize, result);
}
return result.trim();
} else {
return "";
112,7 → 118,7
}
} else {
if (isValid()) {
OOXMLField childElt = new OOXMLField(this.elt.getChild("field"), foreignRow, this.sqlElt, this.id);
OOXMLField childElt = new OOXMLField(this.elt.getChild("field"), foreignRow, this.sqlElt, this.id, this.rowLanguage);
return childElt.getValue();
} else {
return "";
145,11 → 151,24
}
 
// Liste des valeurs à ne pas afficher
List<String> listOfExpectedValues = null;
List<String> listOfExcludedValues = null;
if (this.elt.getAttributeValue("valuesExpected") != null) {
listOfExpectedValues = SQLRow.toList(this.elt.getAttributeValue("valuesExpected"));
listOfExcludedValues = SQLRow.toList(this.elt.getAttributeValue("valuesExpected"));
}
List<Element> excludeValue = this.elt.getChildren("exclude");
if (excludeValue != null && excludeValue.size() > 0) {
if (listOfExcludedValues == null) {
listOfExcludedValues = new ArrayList<String>();
} else {
listOfExcludedValues = new ArrayList<String>(listOfExcludedValues);
}
 
for (Element element : excludeValue) {
String attributeValue = element.getAttributeValue("value");
listOfExcludedValues.add(attributeValue);
}
}
 
// Champ boolean
String condField = this.elt.getAttributeValue("conditionField");
String condValue = this.elt.getAttributeValue("conditionExpValue");
192,10 → 211,11
}
 
// on ne fait rien si le champ n'est pas à afficher
if (listOfExpectedValues == null || ((!listOfExpectedValues.contains(stringValue)) && stringValue.trim().length() > 0)) {
if (listOfExcludedValues == null || ((!listOfExcludedValues.contains(stringValue)) && stringValue.trim().length() > 0)) {
String prefix = this.elt.getAttributeValue("prefix");
String suffix = this.elt.getAttributeValue("suffix");
String display = this.elt.getAttributeValue("display");
String cellSize = this.elt.getAttributeValue("cellSize");
if (prefix != null || suffix != null) {
 
String result = "";
212,7 → 232,9
if (suffix != null) {
result += suffix;
}
 
if (cellSize != null && cellSize.trim().length() != 0) {
result = splitStringCell(cellSize, result);
}
return result;
} else {
if (display == null || !display.equalsIgnoreCase("false")) {
226,13 → 248,23
}
}
 
return "";
return null;
 
}
 
private String splitStringCell(String cellSize, String result) {
try {
int nbCar = Integer.parseInt(cellSize);
result = StringUtils.splitString(result, nbCar);
} catch (NumberFormatException e) {
e.printStackTrace();
}
return result;
}
 
protected Object getSpecialValue(String typeComp) {
String field = this.elt.getAttributeValue("name");
final Object object = this.row.getObject(field);
final Object result = this.row.getObject(field);
 
// Liste des valeurs à ne pas afficher
List<String> listOfExpectedValues = null;
240,7 → 272,7
listOfExpectedValues = SQLRow.toList(this.elt.getAttributeValue("valuesExpected"));
}
 
String stringValue = (object == null) ? "" : object.toString();
String stringValue = (result == null) ? "" : result.toString();
if (typeComp != null && typeComp.trim().length() > 0) {
 
// Type spécial
250,13 → 282,10
SQLSelect sel = new SQLSelect(this.row.getTable().getBase());
sel.addSelect(this.row.getTable().getKey(), "COUNT");
Where w = new Where(this.row.getTable().getField("DATE"), "<=", this.row.getDate("DATE").getTime());
w = w.and(new Where(this.row.getTable().getField("ID_AFFAIRE"), "=", this.row.getInt("ID_AFFAIRE")));
sel.setWhere(w);
 
return this.row.getTable().getBase().getDataSource().executeScalar(sel.asString());
} else {
if (typeComp.equalsIgnoreCase("Devise")) {
Number prix = (Number) object;
} else if (typeComp.equalsIgnoreCase("Devise")) {
Number prix = (Number) result;
if (listOfExpectedValues != null) {
for (String string : listOfExpectedValues) {
Long l = Long.parseLong(string);
266,60 → 295,37
}
}
return new Double(GestionDevise.currencyToString(prix.longValue(), false));
} else {
if (typeComp.equalsIgnoreCase("globalAcompte")) {
Long prix = (Long) object;
} else if (typeComp.equalsIgnoreCase("globalAcompte")) {
Long prix = (Long) result;
int pourcent = this.row.getInt("POURCENT_ACOMPTE");
long l = Math.round(prix.longValue() / (pourcent / 100.0));
return new Double(GestionDevise.currencyToString(l, false));
} else {
if (typeComp.equalsIgnoreCase("DateEcheanceFiche")) {
Date d = getDateEch(this.row);
if (d != null) {
final DateFormat format2 = new SimpleDateFormat("dd/MM/yyyy");
return format2.format(d);
} else {
return "";
}
} else {
if (typeComp.equalsIgnoreCase("MoisEcheanceFiche")) {
return getMoisEch(this.row);
} else {
if (typeComp.equalsIgnoreCase("SituationAdminFiche")) {
return getSituationAdmin(this.row);
} else {
if (typeComp.equalsIgnoreCase("AcompteVerse")) {
return getAcompteVerse(this.row);
} else {
if (typeComp.equalsIgnoreCase("CumulPrec")) {
} else if (typeComp.equalsIgnoreCase("CumulPrec")) {
 
final long cumulPrecedent = getCumulPrecedent(this.row);
return new Double(GestionDevise.currencyToString(cumulPrecedent, false));
} else {
if (typeComp.equalsIgnoreCase("Activite")) {
return object.toString() + getActivite(this.id);
} else {
} else if (typeComp.equalsIgnoreCase("DeviseLettre")) {
// Devise exprimée en lettre
if (typeComp.equalsIgnoreCase("DeviseLettre")) {
Long prix = (Long) object;
return getLettreFromDevise(prix.longValue());
Long prix = (Long) result;
return getLettreFromDevise(prix.longValue(), Nombre.FR, Tuple2.create(" euros ", " cents"));
} else if (typeComp.equalsIgnoreCase("DeviseLettreEng")) {
// Devise exprimée en lettre
Long prix = (Long) result;
SQLRowAccessor tarif = this.row.getForeign("ID_TARIF");
if (tarif.isUndefined()) {
return getLettreFromDevise(prix.longValue(), Nombre.EN, Tuple2.create(" euros ", " cents"));
} else {
// Proposition associée à la facture (Notre
// propo N°
// ...
// du
// ...)
if (typeComp.equalsIgnoreCase("propositionFacture")) {
return getStringProposition(this.row);
SQLRowAccessor rowDevise = tarif.getForeign("ID_DEVISE");
if (rowDevise.isUndefined()) {
return getLettreFromDevise(prix.longValue(), Nombre.EN, Tuple2.create(" euros ", " cents"));
} else {
 
return getLettreFromDevise(prix.longValue(), Nombre.EN, Tuple2.create(" " + rowDevise.getString("LIBELLE") + " ", " " + rowDevise.getString("LIBELLE_CENT") + " "));
}
}
} else if (typeComp.equalsIgnoreCase("Ville")) {
// Ville si null on retourne la valeur du
// champ
// de
// la
// base
if (typeComp.equalsIgnoreCase("Ville")) {
stringValue = (object == null) ? "" : object.toString();
// champ de la base
stringValue = (result == null) ? "" : result.toString();
final String ville = getVille(stringValue);
if (ville == null) {
return stringValue;
326,40 → 332,26
} else {
return ville;
}
} else {
} else if (typeComp.equalsIgnoreCase("VilleCP")) {
// Code postal de la ville
if (typeComp.equalsIgnoreCase("ListeVerificateur")) {
return getListeVerificateur(this.row);
} else {
 
// Code postal de la ville
if (typeComp.equalsIgnoreCase("VilleCP")) {
stringValue = (object == null) ? "" : object.toString();
stringValue = (result == null) ? "" : result.toString();
return getVilleCP(stringValue, this.row);
} else {
 
} else if (typeComp.equalsIgnoreCase("DateEcheance")) {
// Retourne la date d'échéance
if (typeComp.equalsIgnoreCase("DateEcheance")) {
 
int idModeReglement = this.row.getInt("ID_MODE_REGLEMENT");
Date d = (Date) this.row.getObject("DATE");
return getDateEcheance(idModeReglement, d);
} else {
if (typeComp.equalsIgnoreCase("Jour")) {
} else if (typeComp.equalsIgnoreCase("Jour")) {
int day = this.row.getInt(field);
stringValue = "le " + String.valueOf(day);
if (day == 31) {
return "fin de mois";
} else {
if (day == 0) {
} else if (day == 0) {
return "Date de facture";
} else {
 
return stringValue;
}
}
} else {
if (typeComp.equalsIgnoreCase("Date")) {
} else if (typeComp.equalsIgnoreCase("Date")) {
 
String datePattern = this.elt.getAttributeValue("DatePattern");
if (datePattern == null || datePattern.trim().length() == 0) {
366,41 → 358,44
datePattern = "dd/MM/yyyy";
}
SimpleDateFormat format = new SimpleDateFormat(datePattern);
if (object != null) {
Date d = (Date) object;
if (result != null) {
Date d = (Date) result;
return format.format(d);
} else {
return "";
}
}
if (typeComp.equalsIgnoreCase("initiale")) {
stringValue = (object == null) ? "" : object.toString();
} else if (typeComp.equalsIgnoreCase("initiale")) {
stringValue = (result == null) ? "" : result.toString();
if (stringValue.trim().length() > 0) {
stringValue = String.valueOf(stringValue.charAt(0));
}
return stringValue;
}
 
}
 
return (result == null) ? "" : result;
}
 
private Object getTraduction() {
if (this.rowLanguage == null || this.rowLanguage.isUndefined()) {
return null;
}
int id = ReferenceArticleSQLElement.getIdForCNM(row.asRowValues(), false);
SQLTable table = Configuration.getInstance().getBase().getTable("ARTICLE_DESIGNATION");
SQLSelect sel = new SQLSelect(table.getBase());
sel.addSelectStar(table);
Where w = new Where(table.getField("ID_ARTICLE"), "=", id);
w = w.and(new Where(table.getField("ID_LANGUE"), "=", this.rowLanguage.getID()));
sel.setWhere(w);
List<SQLRow> rows = (List<SQLRow>) Configuration.getInstance().getBase().getDataSource().execute(sel.asString(), SQLRowListRSH.createFromSelect(sel));
if (rows != null && rows.size() > 0) {
return rows.get(0).getString(this.elt.getAttributeValue("name"));
} else {
return this.row.getObject(this.elt.getAttributeValue("name"));
}
}
}
}
}
}
}
}
}
}
}
}
}
}
 
return (object == null) ? "" : object;
}
 
public boolean isValid() {
String condField = this.elt.getAttributeValue("conditionField");
String condValue = this.elt.getAttributeValue("conditionExpValue");
418,7 → 413,10
Collection<? extends SQLRowAccessor> factElts = rowFact.getReferentRows(tableElt);
 
for (SQLRowAccessor row : factElts) {
Collection<? extends SQLRowAccessor> rowsElt = row.getForeign("ID_MISSION").getReferentRows(tableElt);
 
final SQLRowAccessor foreign = row.getForeign("ID_MISSION");
if (foreign.getID() > 1) {
Collection<? extends SQLRowAccessor> rowsElt = foreign.getReferentRows(tableElt);
for (SQLRowAccessor row2 : rowsElt) {
SQLRowAccessor rowFacture = row2.getForeign("ID_SAISIE_VENTE_FACTURE");
if (rowFacture.getDate("DATE").before(rowFact.getDate("DATE"))) {
426,81 → 424,56
}
}
}
}
 
return cumul;
}
 
private static Date getDateEch(SQLRowAccessor rowFiche) {
private static long getMontantGlobal(SQLRowAccessor rowFact) {
 
Date d = null;
long cumul = 0;
 
// On recupere les missions associées
Collection<? extends SQLRowAccessor> factElts = rowFiche.getReferentRows(rowFiche.getTable().getTable("FICHE_RENDEZ_VOUS_ELEMENT"));
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("SAISIE_VENTE_FACTURE_ELEMENT");
Collection<? extends SQLRowAccessor> factElts = rowFact.getReferentRows(tableElt);
 
if (factElts != null && factElts.size() > 0) {
Object[] rows = factElts.toArray();
int i = 0;
Calendar date;
while (i < factElts.size()) {
date = ((SQLRow) rows[i]).getDate("DATE_ECHEANCE");
if (date != null) {
d = date.getTime();
break;
}
i++;
}
}
for (SQLRowAccessor row : factElts) {
Long p0 = (Long) row.getObject("MONTANT_INITIAL");
Long l0 = (Long) row.getObject("INDICE_0");
Long lN = (Long) row.getObject("INDICE_N");
final Object o = row.getObject("POURCENT_ACOMPTE");
final Object o2 = row.getObject("POURCENT_REMISE");
double lA = (o == null) ? 0 : ((BigDecimal) o).doubleValue();
double lremise = (o2 == null) ? 0 : ((BigDecimal) o2).doubleValue();
Long p;
if (l0 != 0) {
double d;
double coeff = ((double) lN) / ((double) l0);
 
return d;
d = 0.15 + (0.85 * coeff);
p = Math.round(d * p0);
} else {
p = p0;
}
 
private static String getMoisEch(SQLRowAccessor rowFiche) {
 
String mois = "";
 
// On recupere les missions associées
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("FICHE_RENDEZ_VOUS_ELEMENT");
Collection<? extends SQLRowAccessor> factElts = rowFiche.getReferentRows(tableElt);
 
if (factElts != null && factElts.size() > 0) {
Object[] rows = factElts.toArray();
int i = 0;
while (i < factElts.size()) {
int idMois = ((SQLRow) rows[i]).getInt("ID_MOIS_PREV");
if (idMois > 1) {
mois = ((SQLRow) rows[i]).getForeign("ID_MOIS_PREV").getString("NOM");
break;
// if (lA >= 0 && lA != 100) {
// p = Math.round(p * (lA / 100.0));
// }
if (lremise > 0 && lremise != 100) {
p = Math.round(p * (100.0 - lremise) / 100.0);
}
i++;
cumul += p;
}
}
 
return mois;
// Echantillons
SQLTable tableEchElt = Configuration.getInstance().getRoot().findTable("ECHANTILLON_ELEMENT");
Collection<? extends SQLRowAccessor> echElts = rowFact.getReferentRows(tableEchElt);
for (SQLRowAccessor sqlRowAccessor : echElts) {
cumul += sqlRowAccessor.getLong("T_PV_HT");
}
 
private static String getSituationAdmin(SQLRowAccessor rowFiche) {
 
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("FICHE_RENDEZ_VOUS_ELEMENT");
Collection<? extends SQLRowAccessor> rows = rowFiche.getReferentRows(tableElt);
 
String text = "";
List<String> l = new ArrayList<String>();
for (SQLRowAccessor row : rows) {
 
final String situation = row.getString("SITUATION_ADMIN");
if (!l.contains(situation)) {
text += situation + ", ";
l.add(situation);
return cumul;
}
}
 
if (text.length() > 0) {
text = text.substring(0, text.length() - 2);
}
 
return text;
}
 
private static List<Integer> getListId(Collection<SQLRow> rowFactElts) {
return getListId(rowFactElts, null);
}
518,32 → 491,7
return l;
}
 
/**
*
* @param idAffaire
* @return la liste des activités séparées par des -
*/
private static String getActivite(int idAffaire) {
 
SQLElement eltAffaire = Configuration.getInstance().getDirectory().getElement("AFFAIRE");
SQLElement eltAffaireElt = Configuration.getInstance().getDirectory().getElement("AFFAIRE_ELEMENT");
List<SQLRow> s = eltAffaire.getTable().getRow(idAffaire).getReferentRows(eltAffaireElt.getTable());
 
String codes = "";
List<String> l = new ArrayList<String>(s.size());
for (SQLRow row : s) {
 
final String string = row.getString("ACTIVITE");
if (!l.contains(string)) {
l.add(string);
String code = "-" + string;
codes += code;
}
}
 
return codes;
}
 
/**
* transforme une devise exprimée en chiffres en lettres
*
550,7 → 498,7
* @param value
* @return la devise exprimée en lettres
*/
private static String getLettreFromDevise(long value) {
private static String getLettreFromDevise(long value, int langue, Tuple2<String, String> deviseName) {
 
StringBuffer result = new StringBuffer();
 
557,13 → 505,15
Long decimal = Long.valueOf(value % 100);
Long entier = Long.valueOf(value / 100);
 
Nombre n1 = new Nombre(entier.intValue());
Nombre n2 = new Nombre(decimal.intValue());
Nombre n1 = new Nombre(entier.intValue(), langue);
Nombre n2 = new Nombre(decimal.intValue(), langue);
 
result.append(n1.getText() + " euros");
// result.append(n1.getText() + " euros");
result.append(n1.getText() + deviseName.get0());
 
if (decimal.intValue() > 0) {
result.append(" et " + n2.getText() + " cents");
// result.append(" et " + n2.getText() + " cents");
result.append((langue == Nombre.FR ? " et " : " and ") + n2.getText() + deviseName.get1());
}
if (result != null && result.length() > 0) {
return result.toString().replaceFirst(String.valueOf(result.charAt(0)), String.valueOf(result.charAt(0)).toUpperCase());
601,79 → 551,6
return ville.getCodepostal();
}
 
protected static void initCacheAffaireCT(SQLRow row) {
SQLSelect sel = new SQLSelect(row.getTable().getBase());
final SQLTable tableFactElt = row.getTable().getTable("SAISIE_VENTE_FACTURE_ELEMENT");
final SQLTable tableAffElt = row.getTable().getTable("AFFAIRE_ELEMENT");
 
sel.addSelectStar(tableFactElt);
sel.addJoin("LEFT", tableFactElt.getField("ID_AFFAIRE_ELEMENT"));
 
Where w = new Where(sel.getAlias(tableAffElt.getField("ID_AFFAIRE")), "=", row.getInt("ID_AFFAIRE"));
w = w.or(new Where(sel.getAlias(tableFactElt.getField("ID_SAISIE_VENTE_FACTURE")), "=", row.getID()));
sel.setWhere(w);
List<SQLRowAccessor> l = (List<SQLRowAccessor>) row.getTable().getBase().getDataSource().execute(sel.asString(), new SQLRowListRSH(tableFactElt, true));
System.err.println(l.size());
for (SQLRowAccessor sqlRow : l) {
 
// On cache les elt de factures references par les elements d'affaire
SQLRowAccessor affElt = OOXMLCache.getForeignRow(sqlRow, sqlRow.getTable().getField("ID_AFFAIRE_ELEMENT"));
Map<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>> cacheReferent = OOXMLCache.getCacheReferent();
if (affElt != null) {
 
Map<SQLTable, List<SQLRowAccessor>> m = cacheReferent.get(affElt);
if (m == null) {
m = new HashMap<SQLTable, List<SQLRowAccessor>>();
cacheReferent.put(affElt, m);
}
List<SQLRowAccessor> list = m.get(sqlRow.getTable());
if (list == null) {
list = new ArrayList();
m.put(sqlRow.getTable(), list);
}
list.add(sqlRow);
}
// On cache les elements de
if (sqlRow.getInt("ID_SAISIE_VENTE_FACTURE") == row.getID()) {
Map<SQLTable, List<SQLRowAccessor>> m = cacheReferent.get(row);
if (m == null) {
m = new HashMap<SQLTable, List<SQLRowAccessor>>();
cacheReferent.put(row, m);
}
List<SQLRowAccessor> list = m.get(sqlRow.getTable());
if (list == null) {
list = new ArrayList<SQLRowAccessor>();
m.put(sqlRow.getTable(), list);
}
list.add(sqlRow);
 
}
}
}
 
private static Double getAcompteVerse(SQLRowAccessor row) {
 
SQLRowAccessor rowAff = OOXMLCache.getForeignRow(row, row.getTable().getField("ID_AFFAIRE"));
List<? extends SQLRowAccessor> list = OOXMLCache.getReferentRows(rowAff, row.getTable());
 
double total = 0.0;
for (SQLRowAccessor sqlRow : list) {
Calendar date = row.getDate("DATE");
Calendar date2 = sqlRow.getDate("DATE");
if (date2.before(date)) {
total += sqlRow.getFloat("T_HT");
}
}
 
// On cumul ce qui a déja était verse
List<? extends SQLRowAccessor> listElt = OOXMLCache.getReferentRows(rowAff, rowAff.getTable().getTable("AFFAIRE_ELEMENT"));
for (SQLRowAccessor sqlRow : listElt) {
total += sqlRow.getFloat("TOTAL_HT_REALISE");
}
 
return total / 100.0;
}
 
private static Number calcul(Object o1, Object o2, String op) {
 
double d1 = (o1 == null) ? 0 : Double.parseDouble(o1.toString());
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLElement.java
36,18 → 36,21
protected SQLElement sqlElt;
protected int id;
protected SQLRowAccessor row = null;
protected SQLRow rowLanguage;
 
public OOXMLElement(Element elt, SQLElement sqlElt, int id) {
public OOXMLElement(Element elt, SQLElement sqlElt, int id, SQLRow rowLanguage) {
this.elt = elt;
this.sqlElt = sqlElt;
this.id = id;
this.rowLanguage = rowLanguage;
}
 
public OOXMLElement(Element elt, SQLElement sqlElt, int id, SQLRowAccessor row) {
public OOXMLElement(Element elt, SQLElement sqlElt, int id, SQLRowAccessor row, SQLRow rowLanguage) {
this.elt = elt;
this.sqlElt = sqlElt;
this.id = id;
this.row = row;
this.rowLanguage = rowLanguage;
}
 
public Object getValue() {
67,22 → 70,10
return getInitialesUserCreate();
}
 
if (attributeValue.equalsIgnoreCase("propositionFacture")) {
return getProposition(row);
}
 
if (attributeValue.equalsIgnoreCase("ListeVerificateur")) {
return getListeVerificateur(row);
}
 
if (attributeValue.equalsIgnoreCase("TotalHTTable")) {
return getTotalHTTable(row);
}
 
if (attributeValue.equalsIgnoreCase("codesMissions")) {
return getCodesMissions(this.id);
}
 
if (attributeValue.equalsIgnoreCase("DateEcheance")) {
int idModeReglement = row.getInt("ID_MODE_REGLEMENT");
Date d = (Date) row.getObject("DATE");
96,7 → 87,7
String result = "";
for (Element eltField : eltFields) {
 
OOXMLField field = new OOXMLField(eltField, this.row, this.sqlElt, this.id);
OOXMLField field = new OOXMLField(eltField, this.row, this.sqlElt, this.id, this.rowLanguage);
 
Object value = field.getValue();
if (value != null) {
105,7 → 96,7
}
res = result;
} else {
OOXMLField field = new OOXMLField(eltFields.get(0), this.row, this.sqlElt, this.id);
OOXMLField field = new OOXMLField(eltFields.get(0), this.row, this.sqlElt, this.id, this.rowLanguage);
res = field.getValue();
}
}
158,24 → 149,7
return result.toString();
}
 
/**
* String proposition préventec
*
* @param row
* @return une string du format Proposition + numero + du + date
*/
protected String getProposition(SQLRowAccessor row) {
String source = row.getString("SOURCE");
int idSource = row.getInt("IDSOURCE");
 
if (source.equalsIgnoreCase("PROPOSITION") && idSource > 1) {
SQLElement eltProp = Configuration.getInstance().getDirectory().getElement("PROPOSITION");
SQLRow rowProp = eltProp.getTable().getRow(idSource);
return getStringProposition(rowProp);
}
return "";
}
 
public static DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
 
protected String getStringProposition(SQLRowAccessor rowProp) {
183,50 → 157,7
return "Notre proposition " + rowProp.getString("NUMERO") + " du " + format.format(rowProp.getObject("DATE"));
}
 
/**
* Liste des vérificateur séparée par des virgules, premiere lettre du prenom + nom
*
* @param rowFact
* @return
*/
protected String getListeVerificateur(SQLRowAccessor rowFact) {
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("SAISIE_VENTE_FACTURE_ELEMENT");
SQLTable tablePourcent = Configuration.getInstance().getRoot().findTable("POURCENT_SERVICE");
Collection<? extends SQLRowAccessor> rows = rowFact.getReferentRows(tableElt);
List<SQLRowAccessor> l = new ArrayList<SQLRowAccessor>();
 
StringBuffer result = new StringBuffer();
for (SQLRowAccessor row : rows) {
 
Collection<? extends SQLRowAccessor> s = row.getReferentRows(tablePourcent);
 
for (SQLRowAccessor row2 : s) {
SQLRowAccessor rowVerif = row2.getForeign("ID_VERIFICATEUR");
 
if (rowVerif != null && !l.contains(rowVerif)) {
String prenom = rowVerif.getString("PRENOM");
if (prenom.length() > 1) {
prenom = String.valueOf(prenom.charAt(0));
}
result.append(prenom + ".");
String nom = rowVerif.getString("NOM");
if (nom.length() > 1) {
nom = String.valueOf(nom.charAt(0));
}
 
result.append(nom + ", ");
l.add(rowVerif);
}
}
}
if (result.length() > 0) {
result.deleteCharAt(result.length() - 1);
result.deleteCharAt(result.length() - 1);
}
 
return result.toString();
}
 
public Double getTotalHTTable(SQLRowAccessor rowFact) {
 
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("SAISIE_VENTE_FACTURE_ELEMENT");
239,36 → 170,7
return new Double(GestionDevise.currencyToString(total, false));
}
 
/**
*
* @param idAffaire
* @return la liste des noms des missions séparés par des virgules
*/
protected String getCodesMissions(int idAffaire) {
 
SQLElement eltAffaire = Configuration.getInstance().getDirectory().getElement("AFFAIRE");
SQLElement eltAffaireElt = Configuration.getInstance().getDirectory().getElement("AFFAIRE_ELEMENT");
List<SQLRow> s = eltAffaire.getTable().getRow(idAffaire).getReferentRows(eltAffaireElt.getTable());
 
String codes = "";
List<String> l = new ArrayList<String>(s.size());
for (SQLRow row : s) {
 
final String string = row.getString("NOM");
if (!l.contains(string)) {
l.add(string);
String code = string;
codes += code + ", ";
}
}
if (codes.trim().length() > 0) {
codes = codes.trim().substring(0, codes.trim().length() - 1);
}
 
return codes;
 
}
 
/**
* Calcul la date d'échéance d'un élément par rapport au mode de reglement et à la date
* d'émission
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLTableField.java
14,11 → 14,15
package org.openconcerto.erp.generationDoc;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.GestionDevise;
import org.openconcerto.utils.Nombre;
 
35,8 → 39,8
private String type;
private int filterId, line;
 
public OOXMLTableField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id, int filterId) {
super(eltField, row, sqlElt, id);
public OOXMLTableField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id, int filterId, SQLRow rowLanguage) {
super(eltField, row, sqlElt, id, rowLanguage);
this.type = eltField.getAttributeValue("type");
this.filterId = filterId;
String s = eltField.getAttributeValue("line");
52,102 → 56,20
 
if (this.type.equalsIgnoreCase("DescriptifArticle")) {
value = getDescriptifArticle(this.row);
} else {
if (this.type.equalsIgnoreCase("TotalFacture")) {
value = getDejaFacture(this.row);
} else {
if (this.type.equalsIgnoreCase("propositionFacture")) {
value = getProposition(this.row);
} else {
if (this.type.equalsIgnoreCase("pourcentRealise")) {
value = getPourcentRealise(this.row);
} else {
if (this.type.equalsIgnoreCase("DateEcheance")) {
} else if (this.type.equalsIgnoreCase("DateEcheance")) {
value = getDateEcheance(this.row.getInt("ID_MODE_REGLEMENT"), (Date) this.row.getObject("DATE"));
} else {
if (this.type.equalsIgnoreCase("MontantRevise")) {
} else if (this.type.equalsIgnoreCase("MontantRevise")) {
value = getMontantRevise(this.row);
} else {
if (this.type.equalsIgnoreCase("Localisation")) {
} else if (this.type.equalsIgnoreCase("Localisation")) {
value = getLocalisation(this.row);
} else {
if (this.type.equalsIgnoreCase("Verificateurs")) {
value = getVerificateur(this.row, this.filterId);
} else {
if (this.type.equalsIgnoreCase("CCIP")) {
value = getCCIP(this.row);
} else {
if (this.type.equalsIgnoreCase("Echantillon")) {
value = getStringEchantillon(this.row);
} else {
OOXMLElement eltXml = new OOXMLElement(this.elt, this.sqlElt, this.id, this.row);
OOXMLElement eltXml = new OOXMLElement(this.elt, this.sqlElt, this.id, this.row, this.rowLanguage);
value = eltXml.getValue();
}
}
}
 
}
}
}
}
}
}
}
 
return value;
}
 
private static Double getDejaFacture(SQLRowAccessor rowElt) {
SQLRowAccessor rowAffElt = OOXMLCache.getForeignRow(rowElt, rowElt.getTable().getField("ID_AFFAIRE_ELEMENT"));
List<? extends SQLRowAccessor> list = OOXMLCache.getReferentRows(rowAffElt, rowElt.getTable());
SQLRowAccessor rowFact = OOXMLCache.getForeignRow(rowElt, rowElt.getTable().getField("ID_SAISIE_VENTE_FACTURE"));
 
double total = rowAffElt.getFloat("TOTAL_HT_REALISE");
for (SQLRowAccessor sqlRow : list) {
SQLRowAccessor rowFact2 = OOXMLCache.getForeignRow(sqlRow, sqlRow.getTable().getField("ID_SAISIE_VENTE_FACTURE"));
Calendar date = rowFact.getDate("DATE");
Calendar date2 = rowFact2.getDate("DATE");
if (date2.before(date)) {
total += sqlRow.getFloat("T_PV_HT");
}
}
return total / 100.0;
}
 
private static Double getPourcentRealise(SQLRowAccessor rowElt) {
 
SQLRowAccessor rowAffElt = OOXMLCache.getForeignRow(rowElt, rowElt.getTable().getField("ID_AFFAIRE_ELEMENT"));
if (rowAffElt.getID() <= 1) {
return 100.0;
}
SQLRowAccessor rowFact = OOXMLCache.getForeignRow(rowElt, rowElt.getTable().getField("ID_SAISIE_VENTE_FACTURE"));
List<? extends SQLRowAccessor> list = OOXMLCache.getReferentRows(rowAffElt, rowElt.getTable());
 
double percent = rowAffElt.getFloat("POURCENT_REALISE");
for (SQLRowAccessor sqlRow : list) {
SQLRowAccessor rowFact2 = OOXMLCache.getForeignRow(sqlRow, sqlRow.getTable().getField("ID_SAISIE_VENTE_FACTURE"));
Calendar date = rowFact.getDate("DATE");
Calendar date2 = rowFact2.getDate("DATE");
if (date2.before(date) || date2.equals(date)) {
if (rowAffElt.getInt("NOMBRE") != 0) {
percent += sqlRow.getInt("QTE") * sqlRow.getFloat("POURCENT_ACOMPTE") / rowAffElt.getInt("NOMBRE");
} else {
percent += sqlRow.getFloat("POURCENT_ACOMPTE");
}
}
}
return percent;
}
 
protected static String getStringEchantillon(SQLRowAccessor rowEch) {
 
final int nbEch = rowEch.getInt("QTE");
Nombre n = new Nombre(nbEch);
Long ht = rowEch.getLong("PV_HT");
 
return "Par " + n.getText() + " échantillon" + ((nbEch > 1) ? "s " : " ") + "au " + rowEch.getString("NOM") + ", soit " + nbEch + " x " + GestionDevise.currencyToString(ht) + " € HT";
}
 
public boolean isNeeding2Lines() {
return (this.type.equalsIgnoreCase("DescriptifArticle") || this.type.equalsIgnoreCase("propositionFacture") || this.type.equalsIgnoreCase("DateEcheance") || this.type
.equalsIgnoreCase("MontantRevise"));
261,59 → 183,6
}
}
 
/**
* @param row
* @return La liste des vérificateurs prévus pour la mission
*/
public static String getVerificateur(SQLRowAccessor row, int filterID) {
StringBuffer result = new StringBuffer();
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("POURCENT_SERVICE");
Collection<? extends SQLRowAccessor> s = row.getReferentRows(tableElt);
for (SQLRowAccessor row2 : s) {
SQLRowAccessor rowVerif = row2.getForeign("ID_VERIFICATEUR");
 
if (rowVerif != null && (filterID <= 1 || filterID == rowVerif.getID())) {
String prenom = rowVerif.getString("PRENOM");
if (prenom.length() > 1) {
prenom = String.valueOf(prenom.charAt(0));
}
result.append(prenom + "." + rowVerif.getString("NOM"));
result.append(", ");
}
}
 
if (result.length() > 0) {
result.deleteCharAt(result.length() - 1);
result.deleteCharAt(result.length() - 1);
}
return result.toString();
}
 
/**
* @param row
* @return La liste des mois CCIP
*/
public static String getCCIP(SQLRowAccessor row) {
StringBuffer result = new StringBuffer();
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("POURCENT_CCIP");
Collection<? extends SQLRowAccessor> s = row.getReferentRows(tableElt);
for (SQLRowAccessor row2 : s) {
SQLRowAccessor rowMois = row2.getForeign("ID_MOIS");
 
if (rowMois != null) {
String nom = rowMois.getString("NOM");
result.append(nom);
result.append(",\n");
}
}
 
if (result.length() > 0) {
result.deleteCharAt(result.length() - 1);
result.deleteCharAt(result.length() - 1);
}
return result.toString();
}
 
public List<String> getBlankStyle() {
// Cellule pour un style défini
String blankOnStyle = this.elt.getAttributeValue("blankOnStyle");
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationXML.java
73,7 → 73,7
 
private static int answer = JOptionPane.NO_OPTION;
 
public static synchronized File genere(String modele, String pathDest, final String fileDest, SQLRow row) {
public static synchronized File genere(String modele, String pathDest, final String fileDest, SQLRow row, SQLRow rowLanguage) {
 
cacheStyle.clear();
OOXMLCache.clearCache();
108,18 → 108,14
}
}
 
if (modele.startsWith("VenteFactureCT")) {
OOXMLField.initCacheAffaireCT(row);
}
 
Date d = new Date();
SAXBuilder builder = new SAXBuilder();
try {
 
if (needAnnexe(modele, row)) {
if (needAnnexe(modele, row, rowLanguage)) {
try {
// check if it exists
getOOTemplate(modele + "_annexe");
getOOTemplate(modele + "_annexe", rowLanguage);
modele += "_annexe";
System.err.println("modele With annexe " + modele);
} catch (FileNotFoundException e) {
129,7 → 125,7
 
System.err.println("modele " + modele);
 
Document doc = builder.build(getXmlTemplate(modele));
Document doc = builder.build(getXmlTemplate(modele, rowLanguage));
 
// On initialise un nouvel élément racine avec l'élément racine du document.
Element racine = doc.getRootElement();
138,8 → 134,8
List<Element> listElts = racine.getChildren("element");
 
// Création et génération du fichier OO
SpreadSheet spreadSheet = SpreadSheet.create(new ODPackage(getOOTemplate(modele)));
 
SpreadSheet spreadSheet = SpreadSheet.create(new ODPackage(getOOTemplate(modele, rowLanguage)));
try {
// On remplit les cellules de la feuille
parseElementsXML(listElts, row, spreadSheet);
 
148,11 → 144,13
 
for (Element tableChild : listTable) {
// On remplit les cellules du tableau
parseTableauXML(tableChild, row, spreadSheet);
parseTableauXML(tableChild, row, spreadSheet, rowLanguage);
}
 
} catch (Exception e) {
ExceptionHandler.handle("Impossible de remplir le document " + modele + " " + rowLanguage.getString("CHEMIN"), e);
}
// Sauvegarde du fichier
return saveSpreadSheet(spreadSheet, new File(pathDest), fileDest, modele);
return saveSpreadSheet(spreadSheet, new File(pathDest), fileDest, modele, rowLanguage);
 
} catch (final JDOMException e) {
 
182,7 → 180,7
* @param id
* @param sheet
*/
private static void parseTableauXML(Element tableau, SQLRow row, SpreadSheet spreadsheet) {
private static void parseTableauXML(Element tableau, SQLRow row, SpreadSheet spreadsheet, SQLRow rowLanguage) {
 
if (tableau == null) {
return;
207,7 → 205,7
fillTaxe(tableau, sheet, mapStyle, false);
return;
}
int nbPage = fillTable(tableau, row, sheet, mapStyle, true);
int nbPage = fillTable(tableau, row, sheet, mapStyle, true, rowLanguage);
int firstLine = Integer.valueOf(tableau.getAttributeValue("firstLine"));
int endLine = Integer.valueOf(tableau.getAttributeValue("endLine"));
Object printRangeObj = sheet.getPrintRanges();
214,7 → 212,7
 
System.err.println("Nombre de page == " + nbPage);
if (nbPage == 1) {
fillTable(tableau, row, sheet, mapStyle, false);
fillTable(tableau, row, sheet, mapStyle, false, rowLanguage);
} else {
if (printRangeObj != null) {
String s = printRangeObj.toString();
228,7 → 226,7
int rowEnd = -1;
if (range.length > 1) {
rowEnd = sheet.resolveHint(range[1]).y + 1;
int rowEndNew = rowEnd * (nbPage + 1);
int rowEndNew = rowEnd * (nbPage);
String sNew = s.replaceAll(String.valueOf(rowEnd), String.valueOf(rowEndNew));
sheet.setPrintRanges(sNew);
System.err.println(" ****** Replace print ranges; Old:" + rowEnd + "--" + s + " New:" + rowEndNew + "--" + sNew);
259,8 → 257,17
if (nbPage > 2) {
sheet.duplicateFirstRows(endPageLine, nbPage - 2);
}
fillTable(tableau, row, sheet, mapStyle, false);
String pageRef = tableau.getAttributeValue("pageRef");
if (pageRef != null && pageRef.trim().length() > 0) {
MutableCell<SpreadSheet> cell = sheet.getCellAt(pageRef);
cell.setValue("Page 1/" + nbPage);
for (int i = 1; i < nbPage; i++) {
MutableCell<SpreadSheet> cell2 = sheet.getCellAt(cell.getX(), cell.getY() + (endPageLine * i));
cell2.setValue("Page " + (i + 1) + "/" + nbPage);
}
}
fillTable(tableau, row, sheet, mapStyle, false, rowLanguage);
}
 
}
 
304,7 → 311,7
 
}
 
private static int fillTable(Element tableau, SQLRow row, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test) {
private static int fillTable(Element tableau, SQLRow row, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test, SQLRow rowLanguage) {
 
if (tableau == null) {
return 1;
379,10 → 386,12
boolean first = true;
 
int tableLine = 1;
int toAdd = 0;
// on remplit chaque cellule de la ligne
for (Element e : listElts) {
 
OOXMLTableField tableField = new OOXMLTableField(e, rowElt, tableElement.getSQLElement(), rowElt.getID(), tableElement.getTypeStyleWhere() ? -1 : tableElement.getFilterId());