OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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.sql.ui.light;

import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.ListSQLLine;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.ui.light.ColumnSpec;
import org.openconcerto.ui.light.ColumnsSpec;
import org.openconcerto.ui.light.LightUIElement;
import org.openconcerto.ui.light.LightUITable;
import org.openconcerto.ui.light.Row;
import org.openconcerto.ui.light.TableSearchParameter;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearch;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.cc.ITransformer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;

import javax.swing.SwingUtilities;
import javax.swing.event.TableModelListener;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.DOMBuilder;

import net.minidev.json.JSONObject;

public abstract class LightRowValuesTable extends LightUITable {

    public static final int MAX_LINE_TO_SEND = 100;

    private int totalRowCount = -1;

    private int offset = 0;

    private transient ITableModel model;

    private transient ITransformer<SQLSelect, SQLSelect> orginTransformer;

    private transient List<TableModelListener> tableModelListeners = new ArrayList<>();

    private Map<TableSearchParameter, TableSearchMatcher> searchMap = new HashMap<>();

    public LightRowValuesTable() {
        // Serialization
    }

    public LightRowValuesTable(final Configuration configuration, final Number userId, final String id, final ITableModel model) {
        super(id);

        this.model = model;
        final ColumnsSpec columnsSpec = this.createColumnsSpecFromModelSource(configuration, userId);

        this.getTableSpec().setColumns(columnsSpec);

        if (model.getReq() instanceof SQLTableModelSourceOnline) {
            final SQLTableModelSourceOnline source = (SQLTableModelSourceOnline) model.getReq();
            this.orginTransformer = source.getReq().getSelectTransf();

            List<SQLTableModelColumn> columns = model.getReq().getColumns();
            // all
            // TODO : traduire
            TableSearchParameter tableSearchParameterAll = new TableSearchParameter("all", "Tous");

            TableSearchMatcher m = new TableSearchMatcher() {

                @Override
                public boolean useMatch() {
                    return false;
                }

                @Override
                public boolean match(SQLRowValues r, TableSearchParameterType type, String txt) {
                    return true;
                }

                @Override
                public Where getWhere(SQLSelect sel, TableSearchParameterType type, String txt) {
                    final Set<FieldPath> fields = new HashSet<>();
                    for (SQLTableModelColumn col : columns) {
                        fields.addAll(col.getPaths());
                    }
                    final List<Where> wFields = new ArrayList<>(fields.size());
                    for (final FieldPath fpath : fields) {
                        if (fpath.getField().getType().getJavaType().equals(String.class)) {
                            final FieldRef fieldRef = sel.followFieldPath(fpath);
                            if (type.getType().equals(UserSearchItem.TYPE_CONTAINS)) {
                                final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", "%" + txt.toLowerCase() + "%");
                                wFields.add(w);
                            }
                            if (type.getType().equals(UserSearchItem.TYPE_STARTS_WITH)) {
                                final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase() + "%");
                                wFields.add(w);
                            }
                            if (type.getType().equals(UserSearchItem.TYPE_IS)) {
                                final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase());
                                wFields.add(w);
                            }
                        }
                    }
                    return Where.or(wFields);
                }

                @Override
                public List<FieldPath> getAdditionnalFieldsToFetch() {
                    return Collections.emptyList();
                }
            };
            tableSearchParameterAll.add(TableSearchParameterType.getContainsStringInstance(Locale.FRENCH));
            tableSearchParameterAll.add(TableSearchParameterType.getIsStringInstance(Locale.FRENCH));

            this.addSearchParameter(tableSearchParameterAll, m);

            //
            for (int i = 0; i < columns.size(); i++) {
                SQLTableModelColumn col = columns.get(i);
                TableSearchParameter tableSearchParameter = new TableSearchParameter("col" + i, col.getName());
                // FIXME : locale à recuperer depuis le user
                // TODO : mettre d'autres TableSearchParameterType en fonction du type de la colonne
                tableSearchParameter.add(TableSearchParameterType.getContainsStringInstance(Locale.FRENCH));
                tableSearchParameter.add(TableSearchParameterType.getIsStringInstance(Locale.FRENCH));

                TableSearchMatcher tableSearchMatcher = new TableSearchColumnMatcher(col);
                this.addSearchParameter(tableSearchParameter, tableSearchMatcher);
            }

        } else {
            this.orginTransformer = null;
        }

        this.setDynamicLoad(true);
    }

    // Clone constructor
    public LightRowValuesTable(final LightRowValuesTable tableElement) {
        super(tableElement);

        this.model = tableElement.model;
        this.totalRowCount = tableElement.totalRowCount;
        this.orginTransformer = tableElement.orginTransformer;
    }

    // Json constructor
    public LightRowValuesTable(final JSONObject json) {
        super(json);
        this.orginTransformer = null;
    }

    public final int getTotalRowsCount() {
        return this.totalRowCount;
    }

    public final int getOffset() {
        return this.offset;
    }

    public final void setOffset(final int offset) {
        this.offset = offset;
    }

    public final void addTableModelListener(final TableModelListener tableModelListener) {
        this.tableModelListeners.add(tableModelListener);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                LightRowValuesTable.this.model.addTableModelListener(tableModelListener);
            }
        });

    }

    public final void removeTableModelListener(final TableModelListener tableModelListener) {
        this.tableModelListeners.remove(tableModelListener);
        this.model.removeTableModelListener(tableModelListener);
    }

    public ITableModel getModel() {
        return this.model;
    }

    public final LightListSqlRow getRowFromSqlID(final Number sqlID) {
        if (this.hasRow()) {
            final int size = this.getTableSpec().getContent().getRowsCount();
            for (int i = 0; i < size; i++) {
                final LightListSqlRow row = (LightListSqlRow) this.getRow(i);
                if (NumberUtils.areNumericallyEqual(row.getSqlRow().getIDNumber(), sqlID)) {
                    return row;
                }
            }
        }
        return null;
    }

    public final LightListSqlRow createLightListRowFromListLine(final ListSQLLine listSqlLine, final int index) throws IllegalStateException {
        final ColumnsSpec columnsSpec = this.getTableSpec().getColumns();
        final List<SQLTableModelColumn> sqlColumns = this.getModelColumns();
        final int colSize = sqlColumns.size();

        final LightListSqlRow row = new LightListSqlRow(listSqlLine.getRow(), listSqlLine.getID());
        final List<Object> values = new ArrayList<Object>();
        for (int i = 0; i < colSize; i++) {
            final String columnId = columnsSpec.getColumn(i).getId();
            final SQLTableModelColumn col = getColumnFromId(sqlColumns, columnId);

            if (col != null) {
                Object value = col.show(row.getSqlRow());
                if (col.getLightUIrenderer() != null) {
                    value = col.getLightUIrenderer().getLightUIElement(value, 0, i);
                }
                values.add(value);
            } else {
                throw new IllegalArgumentException("column " + columnId + " is in ColumnsSpec but it is not found in SQLTableModelColumn");
            }
        }
        row.setValues(values);

        return row;
    }

    public final SQLRowAccessor getFirstSelectedSqlRow() {
        final List<Row> selectedRows = this.getSelectedRows();
        if (selectedRows.isEmpty()) {
            return null;
        } else {
            return ((LightListSqlRow) selectedRows.get(0)).getSqlRow();
        }
    }

    private final List<SQLTableModelColumn> getModelColumns() {
        try {
            // TODO: clean swing
            return SwingThreadUtils.call(new Callable<List<SQLTableModelColumn>>() {
                @Override
                public List<SQLTableModelColumn> call() throws Exception {
                    return LightRowValuesTable.this.getModel().getReq().getColumns();
                }
            });
        } catch (final Exception ex) {
            throw new IllegalStateException(ex);
        }
    }

    private final SQLTableModelColumn getColumnFromId(final List<SQLTableModelColumn> allCols, final String columnId) {
        final int columnSize = allCols.size();
        for (int i = 0; i < columnSize; i++) {
            final SQLTableModelColumn tableModelColumn = allCols.get(i);
            if (tableModelColumn.getIdentifier().equals(columnId)) {
                return tableModelColumn;
            }
        }
        return null;
    }

    /**
     * Get columns user preferences for a specific table
     * 
     * @param configuration - The user SQL configuration
     * @param userId - Id of the user who want view the table
     * 
     * @return the XML which contains user preferences
     * 
     * @throws IllegalArgumentException
     * @throws IllegalStateException
     * 
     */
    // TODO: move in LightUITable, maybe move LightUITable in FrameWork_SQL
    private final Document getColumnsSpecUserPerfs(final Configuration configuration, final Number userId) throws IllegalArgumentException, IllegalStateException {
        Document columnsPrefs = null;
        final DOMBuilder in = new DOMBuilder();
        org.w3c.dom.Document w3cDoc = null;

        w3cDoc = configuration.getXMLConf(userId, this.getId());
        if (w3cDoc != null) {
            columnsPrefs = in.build(w3cDoc);
        }
        return columnsPrefs;
    }

    /**
     * Create ColumnsSpec from list of SQLTableModelColumn and apply user preferences
     * 
     * @param configuration - current SQL configuration of user
     * @param userId - Id of user
     * 
     * @return New ColumnsSpec with user preferences application
     * 
     * @throws IllegalArgumentException
     * @throws IllegalStateException
     */
    private final ColumnsSpec createColumnsSpecFromModelSource(final Configuration configuration, final Number userId) throws IllegalArgumentException, IllegalStateException {
        final List<String> possibleColumnIds = new ArrayList<String>();
        final List<String> sortedIds = new ArrayList<String>();
        final List<ColumnSpec> columnsSpec = new ArrayList<ColumnSpec>();

        final List<SQLTableModelColumn> columns = this.getModelColumns();
        final int columnsCount = columns.size();

        for (int i = 0; i < columnsCount; i++) {
            final SQLTableModelColumn sqlColumn = columns.get(i);
            // TODO : creer la notion d'ID un peu plus dans le l'esprit sales.invoice.amount
            final String columnId = sqlColumn.getIdentifier();

            possibleColumnIds.add(columnId);
            Class<?> valueClass = sqlColumn.getValueClass();
            if (sqlColumn.getLightUIrenderer() != null) {
                valueClass = LightUIElement.class;
            }

            columnsSpec.add(new ColumnSpec(columnId, valueClass, sqlColumn.getName(), null, false, null));
        }

        // TODO : recuperer l'info sauvegardée sur le serveur par user (à coder)
        sortedIds.add(columnsSpec.get(0).getId());

        final ColumnsSpec cSpec = new ColumnsSpec(this.getId(), columnsSpec, possibleColumnIds, sortedIds);
        cSpec.setAllowMove(true);
        cSpec.setAllowResize(true);
        try {
            final Document xmlColumnsPref = this.getColumnsSpecUserPerfs(configuration, userId);
            if (!cSpec.setUserPrefs(xmlColumnsPref)) {
                configuration.removeXMLConf(userId, this.getId());
            }
        } catch (Exception e) {
            System.err.println("LightRowValuesTable.createColumnsSpecFromModelSource() no column pref for conf : " + configuration.getRoot().getName() + " , user id : " + userId);
        }

        return cSpec;
    }

    // TODO: merge with OpenConcerto List search system
    public abstract void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset);

    public void addSearchParameter(TableSearchParameter tableSearchParameter, TableSearchMatcher tableSearchMatcher) {
        this.searchMap.put(tableSearchParameter, tableSearchMatcher);
        this.getTableSpec().addSearchParameter(tableSearchParameter);
    }

    protected TableSearchMatcher getSearchMatcher(String colId, String searchType) {
        for (TableSearchParameter p : this.searchMap.keySet()) {
            if (p.getId().equals(colId)) {
                for (TableSearchParameterType t : p.getTypes()) {
                    if (t.getType().equals(searchType)) {
                        return this.searchMap.get(p);
                    }
                }
            }
        }
        return null;
    }

    @Override
    public Row getRowById(Number rowId) {
        for (int i = 0; i < this.model.getRowCount(); i++) {
            if (NumberUtils.areNumericallyEqual(this.model.getRow(i).getID(), rowId)) {
                return this.createLightListRowFromListLine(this.model.getRow(i), i);
            }
        }
        return super.getRowById(rowId);
    }

    /**
     * Create default columns preferences from the SQLTableModelLinesSourceOnline
     * 
     * @return XML document with columns preferences
     */
    @Override
    public Document createDefaultXmlPreferences() {
        final Element rootElement = new Element("list");
        final List<SQLTableModelColumn> columns = this.getModelColumns();

        final int sqlColumnsCount = columns.size();
        for (int i = 0; i < sqlColumnsCount; i++) {
            final SQLTableModelColumn sqlColumn = columns.get(i);
            final String columnId = sqlColumn.getIdentifier();
            final ColumnSpec columnSpec = new ColumnSpec(columnId, sqlColumn.getValueClass(), sqlColumn.getName(), null, false, null);
            final Element columnElement = this.createXmlColumn(columnId, columnSpec.getMaxWidth(), columnSpec.getMinWidth(), columnSpec.getWidth());
            rootElement.addContent(columnElement);
        }
        final Document xmlConf = new Document(rootElement);

        return xmlConf;
    }

    @Override
    public void destroy() {
        super.destroy();

        // TODO: clean swing
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                @Override
                public void run() {

                    final List<TableModelListener> listeners = LightRowValuesTable.this.tableModelListeners;
                    for (int i = listeners.size() - 1; i > -1; i--) {
                        LightRowValuesTable.this.removeTableModelListener(listeners.get(i));
                    }
                }
            });
        } catch (final Exception ex) {
            throw new IllegalStateException(ex);
        }

        this.clearRows();

    }
}