Dépôt officiel du code source de l'ERP OpenConcerto
Rev 156 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.common.element;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTable.VirtualFields;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.request.SQLFieldTranslator;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelSource;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.sql.view.list.TableAction;
import org.openconcerto.ui.AutoHideListener;
import org.openconcerto.ui.light.InformationLine;
import org.openconcerto.ui.light.LightUIElement;
import org.openconcerto.ui.light.LightUILine;
import org.openconcerto.ui.light.LightUIPanel;
import org.openconcerto.ui.light.RowSelectionSpec;
import org.openconcerto.ui.light.SimpleTextLine;
import org.openconcerto.ui.table.TableCellRendererUtils;
import org.openconcerto.utils.GestionDevise;
import org.openconcerto.utils.convertor.ValueConvertor;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import org.jdom2.Document;
import org.jdom2.input.DOMBuilder;
/**
* SQLElement de la base société
*
* @author Administrateur
*
*/
public abstract class SocieteSQLConfElement extends SQLElement {
public static final String ACTION_ID_ADD = "add";
public static final String ACTION_ID_MODIFY = "modify";
public static final String ACTION_ID_REMOVE = "remove";
public SocieteSQLConfElement(SQLTable table, String singular, String plural) {
super(singular, plural, table);
}
public SocieteSQLConfElement(SQLTable table) {
this(table, null);
}
public SocieteSQLConfElement(SQLTable table, String code) {
super(table, null, code);
}
public static final TableCellRenderer CURRENCY_RENDERER = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
final Component res = super.getTableCellRendererComponent(table, GestionDevise.currencyToString((BigDecimal) value), isSelected, hasFocus, row, column);
// this renderer can be decorated by e.g. ListeFactureRenderer which does a
// setBackground(), thus always reset the colors
// MAYBE always use ProxyComp as in AlternateTableCellRenderer to leave the decorated
// renderer as found
TableCellRendererUtils.setColors(res, table, isSelected);
((JLabel) res).setHorizontalAlignment(SwingConstants.RIGHT);
return res;
}
};
static public final JPanel createAdditionalPanel() {
return AutoHideListener.listen(new JPanel());
}
@Override
protected String createCode() {
final String suffix = this.createCodeSuffix();
if (suffix.indexOf(' ') >= 0)
throw new IllegalStateException("Suffix contains space : '" + suffix + "'");
if (suffix.length() < 2)
throw new IllegalStateException("Suffix too short : '" + suffix + "'");
return createCodeOfPackage() + suffix;
}
protected String createCodeSuffix() {
return this.createCodeSuffixFromTable();
}
protected final String createCodeSuffixFromTable() {
return '.' + this.getTable().getName();
}
/**
* Return a code that doesn't change when subclassing to allow to easily change a SQLElement
* while keeping the same code. To achieve that, the code isn't
* {@link #createCodeOfPackage(Class) computed} with <code>this.getClass()</code>. We iterate up
* through our superclass chain, and as soon as we find an abstract class, we stop and use the
* previous class (i.e. non abstract). E.g. any direct subclass of {@link ComptaSQLConfElement}
* will still use <code>this.getClass()</code>, but so is one of its subclass.
*
* @return a code computed from the superclass just under the first abstract superclass.
* @see #createCodeOfPackage(Class)
*/
protected final String createCodeOfPackage() {
return createCodeOfPackage(getLastNonAbstractClass());
}
private final Class<? extends SocieteSQLConfElement> getLastNonAbstractClass() {
return getLastNonAbstractClass(this.getClass(), SocieteSQLConfElement.class);
}
static protected final <T extends SQLElement> Class<? extends T> getLastNonAbstractClass(final Class<? extends T> clazz, final Class<T> superClass) {
Class<?> prev = null;
Class<?> cl = clazz;
// test loop
assert superClass.isAssignableFrom(cl);
if (Modifier.isAbstract(cl.getModifiers()))
throw new IllegalArgumentException("Class is abstract : " + cl);
if (!Modifier.isAbstract(superClass.getModifiers()))
throw new IllegalArgumentException("Superclass isn't abstract : " + superClass);
while (!Modifier.isAbstract(cl.getModifiers())) {
prev = cl;
cl = cl.getSuperclass();
}
return prev.asSubclass(superClass);
}
static private final String ERP_CORE = ".erp.core.";
static private final String ERP_ELEMENT = ".erp.element.";
static protected String createCodeOfPackage(final Class<? extends SQLElement> cl) {
String canonicalName = cl.getPackage().getName();
if (canonicalName.contains(ERP_CORE) && canonicalName.contains(".element")) {
int i = canonicalName.indexOf(ERP_CORE) + ERP_CORE.length();
int j = canonicalName.indexOf(".element");
canonicalName = canonicalName.substring(i, j);
} else if (canonicalName.contains(ERP_ELEMENT)) {
canonicalName = canonicalName.substring(canonicalName.indexOf(ERP_ELEMENT) + ERP_ELEMENT.length());
}
return canonicalName;
}
@Override
protected void _initTableSource(SQLTableModelSource res) {
super._initTableSource(res);
for (final SQLTableModelColumn col : res.getColumns()) {
// TODO getDeviseFields()
if (col.getValueClass() == Long.class || col.getValueClass() == BigInteger.class) {
col.setConverter(new ValueConvertor<Number, BigDecimal>() {
@Override
public BigDecimal convert(Number o) {
if (o == null) {
System.err.println("ComptaSQLConfElement._initTableSource: Warning null Number conversion (" + this + ")");
return BigDecimal.ZERO;
}
return new BigDecimal(o.longValue()).movePointLeft(2);
}
@Override
public Number unconvert(BigDecimal o) {
if (o == null) {
System.err.println("ComptaSQLConfElement._initTableSource: Warning null BigDecimal conversion (" + this + ")");
return 0;
}
return o.movePointRight(2);
}
}, BigDecimal.class);
col.setRenderer(CURRENCY_RENDERER);
}
}
}
/**
* Get columns user preferences for a specific table
*
* @param userId - Id of the user who want view the table
* @param tableId - Id of table to show
* @param sqlColumns - List of columns to be displayed
* @return the XML which contains user preferences
*/
protected Document getColumnsUserPerfs(final Configuration configuration, final int userId, final String tableId, final List<SQLTableModelColumn> sqlColumns) {
Document columnsPrefs = null;
try {
final DOMBuilder in = new DOMBuilder();
final org.w3c.dom.Document w3cDoc = configuration.getXMLConf(userId, tableId);
if (w3cDoc != null) {
columnsPrefs = in.build(w3cDoc);
}
} catch (Exception ex) {
throw new IllegalArgumentException("Failed to get ColumnPrefs for table " + tableId + " and for user " + userId + "\n" + ex.getMessage());
}
return columnsPrefs;
}
/**
* Create buttons from SQLElement secondary row actions
*/
public LightUILine createSecondaryRowActionLine(final RowSelectionSpec selection) {
return null;
}
/**
* Create information ui panel for selected lines. By default, all fields in SQLRowValues are
* displayed
*
* @param sessionToken - String use to find session on server
* @param selection - List of SQLRowAccessor attach to selected lines
*
* @return null if selection is empty or a LightUIPanel
*/
public final LightUIPanel createDataPanel(final String sessionToken, final List<SQLRowAccessor> selection) {
if (selection == null || selection.isEmpty()) {
return null;
}
final LightUIPanel dataPanel = new LightUIPanel(this.getCode() + ".data.panel");
dataPanel.setVerticallyScrollable(true);
dataPanel.setWeightX(1);
dataPanel.setMarginLeft(4);
this.fillDataPanel(sessionToken, selection, dataPanel);
return dataPanel;
}
protected void fillDataPanel(final String sessionToken, final List<SQLRowAccessor> selection, final LightUIPanel dataPanel) {
final SQLFieldTranslator translator = this.getDirectory().getTranslator();
for (final SQLRowAccessor listRow : selection) {
final int rowId = listRow.getID();
final LightUILine mainLine = new LightUILine();
final LightUIPanel mainLinePanel = new LightUIPanel(dataPanel.getId() + ".main.line." + rowId);
mainLinePanel.setWeightX(1);
mainLinePanel.addChild(new SimpleTextLine("Information sur l'élément n°" + rowId, true, LightUIElement.HALIGN_CENTER));
final LightUILine lineData = new LightUILine();
final LightUIPanel panel = new LightUIPanel(this.getCode() + ".data.panel." + rowId);
panel.setWeightX(1);
final List<String> dataPanelFields = this.getDataPanelFields();
for (final String fieldName : dataPanelFields) {
this.addFieldToPanel(fieldName, panel, listRow, translator);
}
lineData.addChild(panel);
mainLinePanel.addChild(lineData);
mainLine.addChild(mainLinePanel);
dataPanel.addChild(mainLine);
}
}
protected List<String> getDataPanelFields() {
return this.getListFields();
}
public void addFieldToPanel(final String fieldName, final LightUIPanel dataPanel, final SQLRowAccessor sqlRow, final SQLFieldTranslator translator) {
addFieldToPanel(fieldName, dataPanel, sqlRow, translator, false, "");
}
static private final VirtualFields FIELDS_TO_IGNORE = VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE).union(VirtualFields.ORDER);
/**
* Add the field name translation and it's value to the information panel
*
* @param fieldName - Field to be translate
* @param dataPanel - Information panel
* @param sqlRow - Row which contains data
* @param translator - Field translator
*/
public void addFieldToPanel(final String fieldName, final LightUIPanel dataPanel, final SQLRowAccessor sqlRow, final SQLFieldTranslator translator, boolean addEmpty, String defaultValue) {
final SQLTable sqlTable = sqlRow.getTable();
final SQLField field = sqlTable.getField(fieldName);
if (!sqlTable.getFields(FIELDS_TO_IGNORE).contains(field)) {
String key = translator.getLabelFor(field);
boolean error = false;
if (key == null) {
error = true;
key = field.getFieldName();
}
String value = "";
if (field.isKey()) {
final List<FieldPath> fieldsPath = getListExpander().expand(field);
for (FieldPath fieldPath : fieldsPath) {
final SQLRowValues foreignRow = sqlRow.asRowValues().followPath(fieldPath.getPath());
if (foreignRow != null) {
value += foreignRow.getString(fieldPath.getField().getName()) + " ";
}
}
} else {
value = sqlRow.getString(fieldName);
}
boolean isDefault = false;
if (value == null || value.isEmpty()) {
isDefault = true;
value = defaultValue;
}
if (!value.isEmpty() || addEmpty) {
final InformationLine line = new InformationLine(key, value);
if (error) {
line.setLabelColor(Color.RED);
}
line.setItalicOnValue(isDefault);
dataPanel.addChild(line);
}
}
}
public List<SQLRowValues> getRowValues(final String fieldName, final long id) {
final SQLTableModelSourceOnline tableSource = this.getTableSource(true);
final ListSQLRequest req = tableSource.getReq();
req.setWhere(new Where(this.getTable().getField(fieldName), "=", id));
return req.getValues();
}
@Override
protected void _initComboRequest(ComboSQLRequest req) {
super._initComboRequest(req);
req.setSearchable(true);
}
/**
* Primary actions on the element (add/modify/remove)
*/
public List<TableAction> getPrimaryRowActions() {
final List<TableAction> actions = new ArrayList<>(3);
actions.add(new TableAction(getAddAction()));
actions.add(new TableAction(getModifyAction()));
actions.add(new TableAction(getRemoveAction()));
return actions;
}
/**
* Secondary actions on the element (send by email, ..)
*/
public List<TableAction> getSecondaryRowActions() {
return new ArrayList<>(0);
}
public RowAction getAddAction() {
return new RowAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
// nothing here because use on an ActionButtonWithSelection
}
}, true, ACTION_ID_ADD) {
@Override
public boolean enabledFor(final List<SQLRowValues> selection) {
return true;
};
};
}
public RowAction getModifyAction() {
final RowAction rowAction = new RowAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {// nothing here because use on an
// ActionButtonWithSelection
}
}, true, ACTION_ID_MODIFY) {
@Override
public boolean enabledFor(final List<SQLRowValues> selection) {
return (selection != null && selection.size() == 1);
};
};
return rowAction;
}
public RowAction getRemoveAction() {
return new RowAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {// nothing here because use on an
// ActionButtonWithSelection
}
}, true, ACTION_ID_REMOVE) {
@Override
public boolean enabledFor(final List<SQLRowValues> selection) {
return (selection != null && !selection.isEmpty());
};
};
}
}