/****************************************************************************** * Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 Adempiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. This program is distributed in the hope * * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * *****************************************************************************/ package org.compiere.apps; import java.awt.BorderLayout; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.beans.PropertyChangeEvent; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.logging.Level; import javax.swing.Box; import javax.swing.JLabel; import org.adempiere.exceptions.DBException; import org.compiere.grid.ed.VEditor; import org.compiere.grid.ed.VEditorFactory; import org.compiere.model.GridField; import org.compiere.model.GridFieldVO; import org.compiere.model.MClient; import org.compiere.model.MLookup; import org.compiere.model.MPInstancePara; import org.compiere.process.ProcessInfo; import org.compiere.swing.CLabel; import org.compiere.swing.CPanel; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; import org.omidp.util.LocaleUtil; /** * Process Parameter Panel, based on existing ProcessParameter dialog. * - Embedded in ProcessDialog * - checks, if parameters exist and inquires and saves them * * @author Low Heng Sin * @author Juan David Arboleda (arboleda), GlobalQSS, [ 1795398 ] Process * Parameter: add display and readonly logic * @author Teo Sarca, www.arhipac.ro * <li>BF [ 2548216 ] Process Param Panel is not showing any parameter if error * @version 2006-12-01 */ public class ProcessParameterPanel extends CPanel implements VetoableChangeListener, IProcessParameter { /** * */ private static final long serialVersionUID = 4042260793108029845L; /** * Dynamic generated Parameter panel. * @param WindowNo window * @param pi process info */ public ProcessParameterPanel(int WindowNo, ProcessInfo pi) { try { jbInit(); } catch(Exception ex) { log.log(Level.SEVERE, ex.getMessage()); } // m_WindowNo = WindowNo; m_processInfo = pi; // } // ProcessParameterPanel private int m_WindowNo; private ProcessInfo m_processInfo; /** Logger */ private static CLogger log = CLogger.getCLogger(ProcessParameterPanel.class); // private GridBagConstraints gbc = new GridBagConstraints(); private Insets nullInset = new Insets(0,0,0,0); private Insets labelInset = new Insets(2,12,2,0); // top,left,bottom,right private Insets fieldInset = new Insets(2,5,2,0); // top,left,bottom,right private Insets fieldInsetRight = new Insets(2,5,2,12); // top,left,bottom,right private int m_line = 0; // private ArrayList<VEditor> m_vEditors = new ArrayList<VEditor>(); private ArrayList<VEditor> m_vEditors2 = new ArrayList<VEditor>(); // for ranges private ArrayList<GridField> m_mFields = new ArrayList<GridField>(); private ArrayList<GridField> m_mFields2 = new ArrayList<GridField>(); private ArrayList<JLabel> m_separators = new ArrayList<JLabel>(); // private BorderLayout mainLayout = new BorderLayout(); private CPanel centerPanel = new CPanel(); private GridBagLayout centerLayout = new GridBagLayout(); /** * Static Layout * @throws Exception */ void jbInit() throws Exception { this.setLayout(mainLayout); LocaleUtil.applyComponentOrientation(centerPanel); centerPanel.setLayout(centerLayout); this.add(centerPanel, BorderLayout.CENTER); } // jbInit /** * Dispose */ public void dispose() { m_vEditors.clear(); m_vEditors2.clear(); m_mFields.clear(); m_mFields2.clear(); m_separators.clear(); this.removeAll(); } // dispose /** * Read Fields to display * @return true if loaded OK */ public boolean init() { log.config(""); // Prepare panel gbc.anchor = GridBagConstraints.NORTHWEST; gbc.weightx = 0; gbc.weighty = 0; gbc.gridy = m_line++; gbc.gridx = 0; gbc.gridwidth = 1; gbc.insets = nullInset; gbc.fill = GridBagConstraints.HORIZONTAL; centerPanel.add(Box.createVerticalStrut(10), gbc); // top gap 10+2=12 // ASP MClient client = MClient.get(Env.getCtx()); String ASPFilter = ""; if (client.isUseASP()) ASPFilter = " AND ( p.AD_Process_Para_ID IN ( " // Just ASP subscribed process parameters for client " + " SELECT pp.AD_Process_Para_ID " + " FROM ASP_Process_Para pp, ASP_Process p, ASP_Level l, ASP_ClientLevel cl " + " WHERE p.ASP_Level_ID = l.ASP_Level_ID " + " AND cl.AD_Client_ID = " + client.getAD_Client_ID() + " AND cl.ASP_Level_ID = l.ASP_Level_ID " + " AND pp.ASP_Process_ID = p.ASP_Process_ID " + " AND pp.IsActive = 'Y' " + " AND p.IsActive = 'Y' " + " AND l.IsActive = 'Y' " + " AND cl.IsActive = 'Y' " + " AND pp.ASP_Status = 'S') " // Show + " OR p.AD_Process_Para_ID IN ( " // + show ASP exceptions for client + " SELECT AD_Process_Para_ID " + " FROM ASP_ClientException ce " + " WHERE ce.AD_Client_ID = " + client.getAD_Client_ID() + " AND ce.IsActive = 'Y' " + " AND ce.AD_Process_Para_ID IS NOT NULL " + " AND ce.AD_Tab_ID IS NULL " + " AND ce.AD_Field_ID IS NULL " + " AND ce.ASP_Status = 'S') " // Show + " ) " + " AND p.AD_Process_Para_ID NOT IN ( " // minus hide ASP exceptions for client + " SELECT AD_Process_Para_ID " + " FROM ASP_ClientException ce " + " WHERE ce.AD_Client_ID = " + client.getAD_Client_ID() + " AND ce.IsActive = 'Y' " + " AND ce.AD_Process_Para_ID IS NOT NULL " + " AND ce.AD_Tab_ID IS NULL " + " AND ce.AD_Field_ID IS NULL " + " AND ce.ASP_Status = 'H')"; // Hide // String sql = null; if (Env.isBaseLanguage(Env.getCtx(), "AD_Process_Para")) sql = "SELECT p.Name, p.Description, p.Help, " + "p.AD_Reference_ID, p.AD_Process_Para_ID, " + "p.FieldLength, p.IsMandatory, p.IsRange, p.ColumnName, " + "p.DefaultValue, p.DefaultValue2, p.VFormat, p.ValueMin, p.ValueMax, " + "p.SeqNo, p.AD_Reference_Value_ID, vr.Code AS ValidationCode, p.ReadOnlyLogic, p.DisplayLogic " + "FROM AD_Process_Para p" + " LEFT OUTER JOIN AD_Val_Rule vr ON (p.AD_Val_Rule_ID=vr.AD_Val_Rule_ID) " + "WHERE p.AD_Process_ID=?" // 1 + " AND p.IsActive='Y' " + ASPFilter + " ORDER BY SeqNo"; else sql = "SELECT t.Name, t.Description, t.Help, " + "p.AD_Reference_ID, p.AD_Process_Para_ID, " + "p.FieldLength, p.IsMandatory, p.IsRange, p.ColumnName, " + "p.DefaultValue, p.DefaultValue2, p.VFormat, p.ValueMin, p.ValueMax, " + "p.SeqNo, p.AD_Reference_Value_ID, vr.Code AS ValidationCode, p.ReadOnlyLogic, p.DisplayLogic " + "FROM AD_Process_Para p" + " INNER JOIN AD_Process_Para_Trl t ON (p.AD_Process_Para_ID=t.AD_Process_Para_ID)" + " LEFT OUTER JOIN AD_Val_Rule vr ON (p.AD_Val_Rule_ID=vr.AD_Val_Rule_ID) " + "WHERE p.AD_Process_ID=?" // 1 + " AND t.AD_Language='" + Env.getAD_Language(Env.getCtx()) + "'" + " AND p.IsActive='Y' " + ASPFilter + " ORDER BY SeqNo"; // Create Fields boolean hasFields = false; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, m_processInfo.getAD_Process_ID()); rs = pstmt.executeQuery(); while (rs.next()) { hasFields = true; createField (rs); } } catch(SQLException e) { throw new DBException(e, sql); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } // both vectors the same? if (m_mFields.size() != m_mFields2.size() || m_mFields.size() != m_vEditors.size() || m_mFields2.size() != m_vEditors2.size()) log.log(Level.SEVERE, "View & Model vector size is different"); // clean up if (hasFields) { gbc.gridy = m_line++; centerPanel.add(Box.createVerticalStrut(10), gbc); // bottom gap gbc.gridx = 3; centerPanel.add(Box.createHorizontalStrut(12), gbc); // right gap dynamicDisplay(); } else dispose(); return hasFields; } // init /** * Create Field. * - creates Fields and adds it to m_mFields list * - creates Editor and adds it to m_vEditors list * Handles Ranges by adding additional mField/vEditor. * <p> * mFields are used for default value and mandatory checking; * vEditors are used to retrieve the value (no data binding) * * @param rs result set */ private void createField (ResultSet rs) { // Create Field GridFieldVO voF = GridFieldVO.createParameter(Env.getCtx(), m_WindowNo, rs); GridField mField = new GridField (voF); m_mFields.add(mField); // add to Fields // Label Preparation gbc.gridy = m_line++; gbc.gridwidth = 1; gbc.fill = GridBagConstraints.HORIZONTAL; // required for right justified gbc.gridx = 0; gbc.weightx = 0; JLabel label = VEditorFactory.getLabel(mField); if (label == null) { gbc.insets = nullInset; centerPanel.add(Box.createHorizontalStrut(12), gbc); // left gap } else { gbc.insets = labelInset; centerPanel.add(label, gbc); } // Field Preparation gbc.insets = fieldInset; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridwidth = 1; gbc.gridx = 1; gbc.weightx = 1; // The Editor VEditor vEditor = VEditorFactory.getEditor(mField, false); vEditor.addVetoableChangeListener(this); // MField => VEditor - New Field value to be updated to editor mField.addPropertyChangeListener(vEditor); // centerPanel.add ((Component)vEditor, gbc); m_vEditors.add (vEditor); // add to Editors // Set Default Object defaultObject = mField.getDefault(); mField.setValue (defaultObject, true); // if (voF.isRange) { // To Label gbc.gridx = 2; gbc.weightx = 0; gbc.fill = GridBagConstraints.NONE; JLabel dash = new JLabel(" - "); centerPanel.add (dash, gbc); m_separators.add(dash); // To Field gbc.gridx = 3; gbc.insets = fieldInsetRight; gbc.weightx = 1; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.WEST; // GridFieldVO voF2 = GridFieldVO.createParameter(voF); GridField mField2 = new GridField (voF2); m_mFields2.add (mField2); // The Editor VEditor vEditor2 = VEditorFactory.getEditor(mField2, false); // New Field value to be updated to editor mField2.addPropertyChangeListener(vEditor2); // centerPanel.add ((Component)vEditor2, gbc); m_vEditors2.add (vEditor2); // Set Default Object defaultObject2 = mField2.getDefault(); mField2.setValue (defaultObject2, true); } else { m_separators.add(null); m_mFields2.add (null); m_vEditors2.add (null); } } // createField /** * Editor Listener * @param evt Event * @exception PropertyVetoException if the recipient wishes to roll back. */ public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { // log.fine( "ProcessParameterPanel.vetoableChange"); if (evt.getSource() instanceof VEditor) { GridField changedField = ((VEditor) evt.getSource()).getField(); if (changedField != null) { processDependencies (changedField); // future processCallout (changedField); } } processNewValue(evt.getNewValue(), evt.getPropertyName()); } // vetoableChange /** * Evaluate Dependencies * @param changedField changed field */ private void processDependencies (GridField changedField) { String columnName = changedField.getColumnName(); for (GridField field : m_mFields) { if (field == null || field == changedField) continue; verifyChangedField(field, columnName); } for (GridField field : m_mFields2) { if (field == null || field == changedField) continue; verifyChangedField(field, columnName); } } // processDependencies private void verifyChangedField(GridField field, String columnName) { ArrayList<String> list = field.getDependentOn(); if (list.contains(columnName)) { if (field.getLookup() instanceof MLookup) { MLookup mLookup = (MLookup)field.getLookup(); // if the lookup is dynamic (i.e. contains this columnName as variable) if (mLookup.getValidation().indexOf("@"+columnName+"@") != -1) { log.fine(columnName + " changed - " + field.getColumnName() + " set to null"); // invalidate current selection field.setValue(null, true); } } } } private void processNewValue(Object value, String name) { if (value == null) value = new String(""); if (value instanceof String) Env.setContext(Env.getCtx(), m_WindowNo, name, (String) value); else if (value instanceof Integer) Env.setContext(Env.getCtx(), m_WindowNo, name, ((Integer) value) .intValue()); else if (value instanceof Boolean) Env.setContext(Env.getCtx(), m_WindowNo, name, ((Boolean) value) .booleanValue()); else if (value instanceof Timestamp) Env.setContext(Env.getCtx(), m_WindowNo, name, (Timestamp) value); else Env.setContext(Env.getCtx(), m_WindowNo, name, value.toString()); dynamicDisplay(); } /** * Dynamic Display. * **/ public void dynamicDisplay() { Component[] comps = centerPanel.getComponents(); for (int i = 0; i < comps.length; i++) { Component comp = comps[i]; if (comp instanceof CLabel) continue; String columnName = comp.getName(); if (columnName != null && columnName.length() > 0) { int index = getIndex(columnName); if (m_mFields.get(index) != null) { if (m_mFields.get(index).isDisplayed(true)) { // check // context if (!comp.isVisible()) { comp.setVisible(true); // visibility if (m_mFields.get(index).getVO().isRange) m_separators.get(index).setText(" - "); } boolean rw = m_mFields.get(index).isEditablePara(true); // r/w - check if field is Editable m_vEditors.get(index).setReadWrite(rw); if (m_mFields.get(index).getVO().isRange) m_vEditors2.get(index).setReadWrite(rw); } else { if (comp.isVisible()) { comp.setVisible(false); if (m_mFields.get(index).getVO().isRange) m_separators.get(index).setText(""); } } } } } } // Dynamic Display. /** * getIndex. Get m_mFields index from columnName * * @param columnName * @return int **/ private int getIndex(String columnName) { for (int i = 0; i < m_mFields.size(); i++) { if (m_mFields.get(i).getColumnName().equals(columnName)) { return i; } } return 0; } // getIndex /* (non-Javadoc) * @see org.compiere.apps.ProcessParameters#saveParameters() */ public boolean saveParameters() { log.config(""); /** * Mandatory fields * see - MTable.getMandatory */ StringBuffer sb = new StringBuffer(); int size = m_mFields.size(); for (int i = 0; i < size; i++) { GridField field = (GridField)m_mFields.get(i); if (field.isMandatory(true)) // check context { VEditor vEditor = (VEditor)m_vEditors.get(i); Object data = vEditor.getValue(); if (data == null || data.toString().length() == 0) { field.setInserting (true); // set editable (i.e. updateable) otherwise deadlock field.setError(true); if (sb.length() > 0) sb.append(", "); sb.append(field.getHeader()); } else field.setError(false); // Check for Range VEditor vEditor2 = (VEditor)m_vEditors2.get(i); if (vEditor2 != null) { Object data2 = vEditor.getValue(); GridField field2 = (GridField)m_mFields2.get(i); if (data2 == null || data2.toString().length() == 0) { field.setInserting (true); // set editable (i.e. updateable) otherwise deadlock field2.setError(true); if (sb.length() > 0) sb.append(", "); sb.append(field.getHeader()); } else field2.setError(false); } // range field } // mandatory } // field loop if (sb.length() != 0) { ADialog.error(m_WindowNo, this, "FillMandatory", sb.toString()); return false; } /********************************************************************** * Save Now */ for (int i = 0; i < m_mFields.size(); i++) { // Get Values VEditor editor = (VEditor)m_vEditors.get(i); VEditor editor2 = (VEditor)m_vEditors2.get(i); Object result = editor.getValue(); Object result2 = null; if (editor2 != null) result2 = editor2.getValue(); // Create Parameter MPInstancePara para = new MPInstancePara (Env.getCtx(), m_processInfo.getAD_PInstance_ID(), i); GridField mField = (GridField)m_mFields.get(i); para.setParameterName(mField.getColumnName()); // Date if (result instanceof Timestamp || result2 instanceof Timestamp) { para.setP_Date((Timestamp)result); if (editor2 != null && result2 != null) para.setP_Date_To((Timestamp)result2); } // Integer else if (result instanceof Integer || result2 instanceof Integer) { if (result != null) { Integer ii = (Integer)result; para.setP_Number(ii.intValue()); } if (editor2 != null && result2 != null) { Integer ii = (Integer)result2; para.setP_Number_To(ii.intValue()); } } // BigDecimal else if (result instanceof BigDecimal || result2 instanceof BigDecimal) { para.setP_Number ((BigDecimal)result); if (editor2 != null && result2 != null) para.setP_Number_To ((BigDecimal)result2); } // Boolean else if (result instanceof Boolean) { Boolean bb = (Boolean)result; String value = bb.booleanValue() ? "Y" : "N"; para.setP_String (value); // to does not make sense } // String else { if (result != null) para.setP_String (result.toString()); if (editor2 != null && result2 != null) para.setP_String_To (result2.toString()); } // Info para.setInfo (editor.getDisplay()); if (editor2 != null) para.setInfo_To (editor2.getDisplay()); // para.save(); log.fine(para.toString()); } // for every parameter return true; } // saveParameters /** * Restore window context. * @author teo_sarca [ 1699826 ] * @see org.compiere.model.GridField#restoreValue() */ protected void restoreContext() { for (GridField f : m_mFields) { if (f != null) f.restoreValue(); } for (GridField f : m_mFields2) { if (f != null) f.restoreValue(); } } } // ProcessParameterPanel