OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 156 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
132 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.erp.core.common.element;
15
 
16
import org.openconcerto.sql.Configuration;
17
import org.openconcerto.sql.element.SQLElement;
18
import org.openconcerto.sql.model.FieldPath;
19
import org.openconcerto.sql.model.SQLField;
142 ilm 20
import org.openconcerto.sql.model.SQLRowAccessor;
132 ilm 21
import org.openconcerto.sql.model.SQLRowValues;
22
import org.openconcerto.sql.model.SQLTable;
23
import org.openconcerto.sql.model.SQLTable.VirtualFields;
24
import org.openconcerto.sql.model.Where;
142 ilm 25
import org.openconcerto.sql.request.ComboSQLRequest;
132 ilm 26
import org.openconcerto.sql.request.ListSQLRequest;
27
import org.openconcerto.sql.request.SQLFieldTranslator;
144 ilm 28
import org.openconcerto.sql.view.list.RowAction;
132 ilm 29
import org.openconcerto.sql.view.list.SQLTableModelColumn;
142 ilm 30
import org.openconcerto.sql.view.list.SQLTableModelSource;
132 ilm 31
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
144 ilm 32
import org.openconcerto.sql.view.list.TableAction;
132 ilm 33
import org.openconcerto.ui.AutoHideListener;
34
import org.openconcerto.ui.light.InformationLine;
35
import org.openconcerto.ui.light.LightUIElement;
36
import org.openconcerto.ui.light.LightUILine;
37
import org.openconcerto.ui.light.LightUIPanel;
38
import org.openconcerto.ui.light.RowSelectionSpec;
39
import org.openconcerto.ui.light.SimpleTextLine;
40
import org.openconcerto.ui.table.TableCellRendererUtils;
41
import org.openconcerto.utils.GestionDevise;
42
import org.openconcerto.utils.convertor.ValueConvertor;
43
 
44
import java.awt.Color;
45
import java.awt.Component;
144 ilm 46
import java.awt.event.ActionEvent;
132 ilm 47
import java.lang.reflect.Modifier;
48
import java.math.BigDecimal;
49
import java.math.BigInteger;
50
import java.util.ArrayList;
51
import java.util.List;
52
 
144 ilm 53
import javax.swing.AbstractAction;
132 ilm 54
import javax.swing.JLabel;
55
import javax.swing.JPanel;
56
import javax.swing.JTable;
57
import javax.swing.SwingConstants;
58
import javax.swing.table.DefaultTableCellRenderer;
59
import javax.swing.table.TableCellRenderer;
60
 
61
import org.jdom2.Document;
62
import org.jdom2.input.DOMBuilder;
63
 
64
/**
65
 * SQLElement de la base société
66
 *
67
 * @author Administrateur
68
 *
69
 */
70
public abstract class SocieteSQLConfElement extends SQLElement {
144 ilm 71
    public static final String ACTION_ID_ADD = "add";
72
    public static final String ACTION_ID_MODIFY = "modify";
73
    public static final String ACTION_ID_REMOVE = "remove";
132 ilm 74
 
75
    public SocieteSQLConfElement(SQLTable table, String singular, String plural) {
76
        super(singular, plural, table);
77
    }
78
 
79
    public SocieteSQLConfElement(SQLTable table) {
80
        this(table, null);
81
    }
82
 
83
    public SocieteSQLConfElement(SQLTable table, String code) {
84
        super(table, null, code);
85
    }
86
 
87
    public static final TableCellRenderer CURRENCY_RENDERER = new DefaultTableCellRenderer() {
88
        @Override
89
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
90
            final Component res = super.getTableCellRendererComponent(table, GestionDevise.currencyToString((BigDecimal) value), isSelected, hasFocus, row, column);
91
            // this renderer can be decorated by e.g. ListeFactureRenderer which does a
92
            // setBackground(), thus always reset the colors
93
            // MAYBE always use ProxyComp as in AlternateTableCellRenderer to leave the decorated
94
            // renderer as found
95
            TableCellRendererUtils.setColors(res, table, isSelected);
96
            ((JLabel) res).setHorizontalAlignment(SwingConstants.RIGHT);
97
            return res;
98
        }
99
    };
100
 
101
    static public final JPanel createAdditionalPanel() {
102
        return AutoHideListener.listen(new JPanel());
103
    }
104
 
105
    @Override
106
    protected String createCode() {
156 ilm 107
        final String suffix = this.createCodeSuffix();
108
        if (suffix.indexOf(' ') >= 0)
109
            throw new IllegalStateException("Suffix contains space : '" + suffix + "'");
110
        if (suffix.length() < 2)
111
            throw new IllegalStateException("Suffix too short : '" + suffix + "'");
112
        return createCodeOfPackage() + suffix;
132 ilm 113
    }
114
 
156 ilm 115
    protected String createCodeSuffix() {
116
        return this.createCodeSuffixFromTable();
117
    }
118
 
119
    protected final String createCodeSuffixFromTable() {
120
        return '.' + this.getTable().getName();
121
    }
122
 
132 ilm 123
    /**
124
     * Return a code that doesn't change when subclassing to allow to easily change a SQLElement
125
     * while keeping the same code. To achieve that, the code isn't
156 ilm 126
     * {@link #createCodeOfPackage(Class) computed} with <code>this.getClass()</code>. We iterate up
127
     * through our superclass chain, and as soon as we find an abstract class, we stop and use the
128
     * previous class (i.e. non abstract). E.g. any direct subclass of {@link ComptaSQLConfElement}
129
     * will still use <code>this.getClass()</code>, but so is one of its subclass.
132 ilm 130
     *
131
     * @return a code computed from the superclass just under the first abstract superclass.
156 ilm 132
     * @see #createCodeOfPackage(Class)
132 ilm 133
     */
156 ilm 134
    protected final String createCodeOfPackage() {
135
        return createCodeOfPackage(getLastNonAbstractClass());
132 ilm 136
    }
137
 
149 ilm 138
    private final Class<? extends SocieteSQLConfElement> getLastNonAbstractClass() {
139
        return getLastNonAbstractClass(this.getClass(), SocieteSQLConfElement.class);
140
    }
141
 
142
    static protected final <T extends SQLElement> Class<? extends T> getLastNonAbstractClass(final Class<? extends T> clazz, final Class<T> superClass) {
132 ilm 143
        Class<?> prev = null;
149 ilm 144
        Class<?> cl = clazz;
132 ilm 145
        // test loop
149 ilm 146
        assert superClass.isAssignableFrom(cl);
147
        if (Modifier.isAbstract(cl.getModifiers()))
148
            throw new IllegalArgumentException("Class is abstract : " + cl);
149
        if (!Modifier.isAbstract(superClass.getModifiers()))
150
            throw new IllegalArgumentException("Superclass isn't abstract : " + superClass);
132 ilm 151
        while (!Modifier.isAbstract(cl.getModifiers())) {
152
            prev = cl;
153
            cl = cl.getSuperclass();
154
        }
149 ilm 155
        return prev.asSubclass(superClass);
132 ilm 156
    }
157
 
156 ilm 158
    static private final String ERP_CORE = ".erp.core.";
159
    static private final String ERP_ELEMENT = ".erp.element.";
160
 
161
    static protected String createCodeOfPackage(final Class<? extends SQLElement> cl) {
162
        String canonicalName = cl.getPackage().getName();
163
        if (canonicalName.contains(ERP_CORE) && canonicalName.contains(".element")) {
164
            int i = canonicalName.indexOf(ERP_CORE) + ERP_CORE.length();
132 ilm 165
            int j = canonicalName.indexOf(".element");
166
            canonicalName = canonicalName.substring(i, j);
156 ilm 167
        } else if (canonicalName.contains(ERP_ELEMENT)) {
168
            canonicalName = canonicalName.substring(canonicalName.indexOf(ERP_ELEMENT) + ERP_ELEMENT.length());
132 ilm 169
        }
170
        return canonicalName;
171
    }
172
 
173
    @Override
142 ilm 174
    protected void _initTableSource(SQLTableModelSource res) {
132 ilm 175
        super._initTableSource(res);
176
        for (final SQLTableModelColumn col : res.getColumns()) {
177
            // TODO getDeviseFields()
178
            if (col.getValueClass() == Long.class || col.getValueClass() == BigInteger.class) {
179
                col.setConverter(new ValueConvertor<Number, BigDecimal>() {
180
                    @Override
181
                    public BigDecimal convert(Number o) {
182
                        if (o == null) {
183
                            System.err.println("ComptaSQLConfElement._initTableSource: Warning null Number conversion (" + this + ")");
184
                            return BigDecimal.ZERO;
185
                        }
186
                        return new BigDecimal(o.longValue()).movePointLeft(2);
187
                    }
188
 
189
                    @Override
190
                    public Number unconvert(BigDecimal o) {
191
 
192
                        if (o == null) {
193
                            System.err.println("ComptaSQLConfElement._initTableSource: Warning null BigDecimal conversion (" + this + ")");
194
                            return 0;
195
                        }
196
                        return o.movePointRight(2);
197
                    }
198
                }, BigDecimal.class);
199
                col.setRenderer(CURRENCY_RENDERER);
200
            }
201
        }
202
    }
203
 
204
    /**
205
     * Get columns user preferences for a specific table
206
     *
207
     * @param userId - Id of the user who want view the table
208
     * @param tableId - Id of table to show
209
     * @param sqlColumns - List of columns to be displayed
210
     * @return the XML which contains user preferences
211
     */
212
    protected Document getColumnsUserPerfs(final Configuration configuration, final int userId, final String tableId, final List<SQLTableModelColumn> sqlColumns) {
213
        Document columnsPrefs = null;
214
        try {
215
            final DOMBuilder in = new DOMBuilder();
216
            final org.w3c.dom.Document w3cDoc = configuration.getXMLConf(userId, tableId);
217
            if (w3cDoc != null) {
218
                columnsPrefs = in.build(w3cDoc);
219
            }
220
        } catch (Exception ex) {
221
            throw new IllegalArgumentException("Failed to get ColumnPrefs for table " + tableId + " and for user " + userId + "\n" + ex.getMessage());
222
        }
223
 
224
        return columnsPrefs;
225
    }
226
 
227
    /**
228
     * Create buttons from SQLElement secondary row actions
229
     */
230
    public LightUILine createSecondaryRowActionLine(final RowSelectionSpec selection) {
231
        return null;
232
    }
233
 
234
    /**
235
     * Create information ui panel for selected lines. By default, all fields in SQLRowValues are
236
     * displayed
237
     *
142 ilm 238
     * @param sessionToken - String use to find session on server
239
     * @param selection - List of SQLRowAccessor attach to selected lines
240
     *
241
     * @return null if selection is empty or a LightUIPanel
132 ilm 242
     */
142 ilm 243
    public final LightUIPanel createDataPanel(final String sessionToken, final List<SQLRowAccessor> selection) {
244
        if (selection == null || selection.isEmpty()) {
132 ilm 245
            return null;
246
        }
142 ilm 247
        final LightUIPanel dataPanel = new LightUIPanel(this.getCode() + ".data.panel");
248
        dataPanel.setVerticallyScrollable(true);
249
        dataPanel.setWeightX(1);
250
        dataPanel.setMarginLeft(4);
251
        this.fillDataPanel(sessionToken, selection, dataPanel);
132 ilm 252
 
142 ilm 253
        return dataPanel;
254
    }
255
 
256
    protected void fillDataPanel(final String sessionToken, final List<SQLRowAccessor> selection, final LightUIPanel dataPanel) {
257
        final SQLFieldTranslator translator = this.getDirectory().getTranslator();
258
 
259
        for (final SQLRowAccessor listRow : selection) {
260
            final int rowId = listRow.getID();
132 ilm 261
            final LightUILine mainLine = new LightUILine();
142 ilm 262
            final LightUIPanel mainLinePanel = new LightUIPanel(dataPanel.getId() + ".main.line." + rowId);
132 ilm 263
            mainLinePanel.setWeightX(1);
264
            mainLinePanel.addChild(new SimpleTextLine("Information sur l'élément n°" + rowId, true, LightUIElement.HALIGN_CENTER));
265
            final LightUILine lineData = new LightUILine();
142 ilm 266
            final LightUIPanel panel = new LightUIPanel(this.getCode() + ".data.panel." + rowId);
267
            panel.setWeightX(1);
144 ilm 268
 
142 ilm 269
            final List<String> dataPanelFields = this.getDataPanelFields();
270
            for (final String fieldName : dataPanelFields) {
271
                this.addFieldToPanel(fieldName, panel, listRow, translator);
132 ilm 272
            }
142 ilm 273
            lineData.addChild(panel);
132 ilm 274
            mainLinePanel.addChild(lineData);
275
            mainLine.addChild(mainLinePanel);
142 ilm 276
 
277
            dataPanel.addChild(mainLine);
132 ilm 278
        }
279
    }
144 ilm 280
 
281
    protected List<String> getDataPanelFields() {
142 ilm 282
        return this.getListFields();
283
    }
132 ilm 284
 
142 ilm 285
    public void addFieldToPanel(final String fieldName, final LightUIPanel dataPanel, final SQLRowAccessor sqlRow, final SQLFieldTranslator translator) {
286
        addFieldToPanel(fieldName, dataPanel, sqlRow, translator, false, "");
132 ilm 287
    }
288
 
289
    static private final VirtualFields FIELDS_TO_IGNORE = VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE).union(VirtualFields.ORDER);
290
 
291
    /**
292
     * Add the field name translation and it's value to the information panel
293
     *
294
     * @param fieldName - Field to be translate
295
     * @param dataPanel - Information panel
142 ilm 296
     * @param sqlRow - Row which contains data
132 ilm 297
     * @param translator - Field translator
298
     */
142 ilm 299
    public void addFieldToPanel(final String fieldName, final LightUIPanel dataPanel, final SQLRowAccessor sqlRow, final SQLFieldTranslator translator, boolean addEmpty, String defaultValue) {
300
        final SQLTable sqlTable = sqlRow.getTable();
301
        final SQLField field = sqlTable.getField(fieldName);
302
 
303
        if (!sqlTable.getFields(FIELDS_TO_IGNORE).contains(field)) {
132 ilm 304
            String key = translator.getLabelFor(field);
305
            boolean error = false;
306
            if (key == null) {
307
                error = true;
308
                key = field.getFieldName();
309
            }
310
 
311
            String value = "";
312
            if (field.isKey()) {
313
                final List<FieldPath> fieldsPath = getListExpander().expand(field);
314
                for (FieldPath fieldPath : fieldsPath) {
142 ilm 315
                    final SQLRowValues foreignRow = sqlRow.asRowValues().followPath(fieldPath.getPath());
132 ilm 316
                    if (foreignRow != null) {
317
                        value += foreignRow.getString(fieldPath.getField().getName()) + " ";
318
                    }
319
                }
320
            } else {
142 ilm 321
                value = sqlRow.getString(fieldName);
132 ilm 322
            }
323
            boolean isDefault = false;
324
            if (value == null || value.isEmpty()) {
325
                isDefault = true;
326
                value = defaultValue;
327
            }
328
            if (!value.isEmpty() || addEmpty) {
329
                final InformationLine line = new InformationLine(key, value);
330
                if (error) {
331
                    line.setLabelColor(Color.RED);
332
                }
333
                line.setItalicOnValue(isDefault);
334
                dataPanel.addChild(line);
335
            }
336
        }
337
    }
338
 
339
    public List<SQLRowValues> getRowValues(final String fieldName, final long id) {
340
        final SQLTableModelSourceOnline tableSource = this.getTableSource(true);
341
 
342
        final ListSQLRequest req = tableSource.getReq();
343
        req.setWhere(new Where(this.getTable().getField(fieldName), "=", id));
344
        return req.getValues();
345
    }
346
 
142 ilm 347
    @Override
348
    protected void _initComboRequest(ComboSQLRequest req) {
349
        super._initComboRequest(req);
350
        req.setSearchable(true);
132 ilm 351
    }
144 ilm 352
 
353
    /**
354
     * Primary actions on the element (add/modify/remove)
355
     */
356
    public List<TableAction> getPrimaryRowActions() {
149 ilm 357
        final List<TableAction> actions = new ArrayList<>(3);
144 ilm 358
        actions.add(new TableAction(getAddAction()));
359
        actions.add(new TableAction(getModifyAction()));
360
        actions.add(new TableAction(getRemoveAction()));
361
        return actions;
362
    }
363
 
364
    /**
365
     * Secondary actions on the element (send by email, ..)
366
     */
367
    public List<TableAction> getSecondaryRowActions() {
149 ilm 368
        return new ArrayList<>(0);
144 ilm 369
    }
370
 
371
    public RowAction getAddAction() {
372
        return new RowAction(new AbstractAction() {
373
            public void actionPerformed(ActionEvent e) {
374
                // nothing here because use on an ActionButtonWithSelection
375
            }
376
        }, true, ACTION_ID_ADD) {
377
 
378
            @Override
379
            public boolean enabledFor(final List<SQLRowValues> selection) {
380
                return true;
381
            };
382
 
383
        };
384
    }
385
 
386
    public RowAction getModifyAction() {
387
        final RowAction rowAction = new RowAction(new AbstractAction() {
388
            public void actionPerformed(ActionEvent e) {// nothing here because use on an
389
                                                        // ActionButtonWithSelection
390
            }
391
 
392
        }, true, ACTION_ID_MODIFY) {
393
 
394
            @Override
395
            public boolean enabledFor(final List<SQLRowValues> selection) {
396
                return (selection != null && selection.size() == 1);
397
            };
398
 
399
        };
400
 
401
        return rowAction;
402
    }
403
 
404
    public RowAction getRemoveAction() {
405
        return new RowAction(new AbstractAction() {
406
            public void actionPerformed(ActionEvent e) {// nothing here because use on an
407
                                                        // ActionButtonWithSelection
408
            }
409
        }, true, ACTION_ID_REMOVE) {
410
 
411
            @Override
412
            public boolean enabledFor(final List<SQLRowValues> selection) {
413
                return (selection != null && !selection.isEmpty());
414
            };
415
        };
416
    }
132 ilm 417
}