diff --git a/org.adempiere.base/src/org/compiere/model/GridField.java b/org.adempiere.base/src/org/compiere/model/GridField.java index 6128804986..467bb6dcc1 100644 --- a/org.adempiere.base/src/org/compiere/model/GridField.java +++ b/org.adempiere.base/src/org/compiere/model/GridField.java @@ -37,6 +37,7 @@ import java.util.logging.Level; import org.adempiere.base.ILookupFactory; import org.adempiere.base.Service; +import org.adempiere.exceptions.AdempiereException; import org.compiere.util.CLogMgt; import org.compiere.util.CLogger; import org.compiere.util.DB; @@ -45,6 +46,7 @@ import org.compiere.util.Env; import org.compiere.util.Evaluatee; import org.compiere.util.Evaluator; import org.compiere.util.Util; +import org.idempiere.util.ParseSeq; /** * Grid Field Model. @@ -552,25 +554,11 @@ public class GridField if (isIgnoreDefault()) return null; + String orderGetDefault = "123457";// this value can put to system configuration + Object defaultValue = null; - if ((defaultValue = defaultForSpecialCase ()) != null){ - return defaultValue; - } - - if ((defaultValue = defaultFromSQLExpression ()) != null){ - return defaultValue; - } - - if ((defaultValue = defaultFromExpression()) != null){ - return defaultValue; - } - - if ((defaultValue = defaultFromPreference()) != null){ - return defaultValue; - } - - if ((defaultValue = defaultFromDatatype()) != null){ + if ((defaultValue = getDefault (orderGetDefault)) != null){ return defaultValue; } @@ -581,6 +569,75 @@ public class GridField return null; } // getDefault + /** + * get default of field when field don't lie down at standard window + * @return + */ + public Object getDefaultForPanel (){ + //default is preference for field > special case > default logic > sql default > data-type default + String defaultSeq = "61327"; + return getDefault (MSysConfig.getValue(MSysConfig.ZK_SEQ_DEFAULT_VALUE_PANEL, defaultSeq, Env.getAD_Client_ID(m_vo.ctx))); + } + + /** + * Get default value with priority define by seqGetDefaultValueStr + * @param seqGetDefaultValueStr + * @return + */ + public Object getDefault(String seqGetDefaultValueStr){ + ParseSeq seqGetDefaultValue = ParseSeq.getNumberOrder(seqGetDefaultValueStr); + + if (seqGetDefaultValue == null) + throw new AdempiereException ("seq define for get default value has wrong value"); + + return getDefault (seqGetDefaultValue); + } + + /** + * Get default value with priority define by seqGetDefaultValue + * @param seqGetDefaultValue + * @return + */ + public Object getDefault(ParseSeq seqGetDefaultValue){ + Object defaultValue = null; + for (Character seqType : seqGetDefaultValue){ + defaultValue = getDefaultValueByType(seqType); + if (defaultValue != null) + return defaultValue; + } + + return defaultValue; + } + + /** + * "1" mean from special case + * "2" mean from sql default + * "3" mean from default logic + * "4" mean user preference + * "5" mean from system preference + * "6" mean preference for field lie down at panel as process parameter, info parameter,... + * "7" mean data-type default + * @param initValueType + * @return + */ + protected Object getDefaultValueByType (Character defaultValueType){ + if (defaultValueType.equals('1')){ + return defaultForSpecialCase(); + }else if (defaultValueType.equals('2')){ + return defaultFromSQLExpression(); + }else if (defaultValueType.equals('3')){ + return defaultFromExpression(); + }else if (defaultValueType.equals('4') || defaultValueType.equals('5')){ + return defaultFromPreference(defaultValueType); + }else if (defaultValueType.equals('6')){ + return defaultFromPreferenceForPanel(); + }else if (defaultValueType.equals('7')){ + return defaultFromDatatype(); + } + + return null; + } + protected boolean isIgnoreDefault (){ // No defaults for these fields return (m_vo.IsKey || m_vo.displayType == DisplayType.RowID @@ -742,7 +799,11 @@ public class GridField return null; } - protected Object defaultFromPreference() { + /** + * get preference when field don't lie down at standard window + * @return + */ + protected Object defaultFromPreferenceForPanel() { String defStr = ""; if (getAD_Process_ID_Of_Panel() > 0) { defStr = Env.getPreference(m_vo.ctx, getAD_Window_ID_Of_Panel(), @@ -802,7 +863,17 @@ public class GridField + m_vo.ColumnName + "=" + defStr); return createDefault(defStr); } - } else { + } + return null; + } + + /** + * @param defaultValueType "4" for user preference and "5" for system preference + * @return + */ + protected Object defaultFromPreference(Character defaultValueType) { + String defStr = ""; + if (defaultValueType.equals('4')){ /** * (d) Preference (user) - P| */ @@ -814,7 +885,7 @@ public class GridField + defStr); return createDefault(defStr); } - + }else if (defaultValueType.equals('5')){ /** * (e) Preference (System) - # $ */ @@ -825,10 +896,9 @@ public class GridField log.fine("[SystemPreference] " + m_vo.ColumnName + "=" + defStr); return createDefault(defStr); - } - + } } - + return null; } diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java index 235f2820df..4e50c7edcb 100644 --- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java +++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java @@ -158,6 +158,7 @@ public class MSysConfig extends X_AD_SysConfig public static final String ZK_ROOT_FOLDER_BROWSER = "ZK_ROOT_FOLDER_BROWSER"; public static final String ZK_SESSION_TIMEOUT_IN_SECONDS = "ZK_SESSION_TIMEOUT_IN_SECONDS"; public static final String ZK_THEME = "ZK_THEME"; + public static final String ZK_SEQ_DEFAULT_VALUE_PANEL = "ZK_SEQ_DEFAULT_VALUE_PANEL"; /** * Standard Constructor diff --git a/org.adempiere.base/src/org/idempiere/util/ParseSeq.java b/org.adempiere.base/src/org/idempiere/util/ParseSeq.java new file mode 100644 index 0000000000..bf9c1122f7 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/util/ParseSeq.java @@ -0,0 +1,215 @@ +/****************************************************************************** + * Copyright (C) 2015 iDempiere * + * Product: iDempiere ERP & CRM Smart Business Solution * + * 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.idempiere.util; + +import java.util.Iterator; +import java.util.regex.Pattern; + +/** + * This class help for parse order configuration + * example problem in IDEMPIERE-2296. some people wish priority of "default value" is higher than "user value preference" + * some other wish reverse. + * it's better for define 1 is representative for "default value" and 2 is representative for "user value preference" + * in configuration just set 12 or 21 for order configuration. + * + * this class will help by provide method same in Iterable, it's also provider validate for duplicate value as 221 or 211 + * @author hieplq + * + */ +public class ParseSeq implements Iterable { + + public static String MSG_NOT_NULL = "configuration must is a not null or non empty string"; + public static String MSG_ONLY_NUNBER = "your value must contain only number character"; + public static String MSG_CONTAIN_DUP = "your value must contain non duplicate character"; + /** + * init a Order configuration by parse configuration value, + * configuration can contain duplicate value or contain only number + * when detect wrong configuration value, a {@link IllegalArgumentException} will throw + * + * @param orderConfiguration configuration value as "5ry76t" + * @param allowDupCharacter if false configuration value as "1245648" is wrong value by "4" is duplicate + * @param onlyNumber configuration value contain only number + */ + private ParseSeq (String orderConfiguration, boolean allowDupCharacter, boolean onlyNumber){ + parseValue(orderConfiguration, allowDupCharacter, onlyNumber); + this.orderConfiguration = orderConfiguration; + } + + private String orderConfiguration; + + /** + * pattern matching a string only number character + */ + private Pattern regCheckOnlyNumber = Pattern.compile("\\d+"); + /** + * pattern find duplicate character in string + */ + private Pattern regCheckDupChar = Pattern.compile("(\\w).*\\1"); + + /** + * validate input string + * @param orderConfiguration + * @param allowDupCharacter + * @param onlyNumber + */ + protected void parseValue (String orderConfiguration, boolean allowDupCharacter, boolean onlyNumber){ + if (orderConfiguration == null || orderConfiguration.length() == 0) + throw new IllegalArgumentException(MSG_NOT_NULL); + + if (onlyNumber && !regCheckOnlyNumber.matcher(orderConfiguration).matches()){ + throw new IllegalArgumentException(MSG_ONLY_NUNBER); + } + + if (!allowDupCharacter && regCheckDupChar.matcher(orderConfiguration).find()){ + throw new IllegalArgumentException(MSG_CONTAIN_DUP); + } + } + + @Override + public Iterator iterator() { + return new IteratorOrderUtil (orderConfiguration); + + } + + /** + * constructor maybe become complicate by add more validate (don't allow space, don't allow special,...) + * use get for simple when init this object, don't need add try catch block when use + * @param orderConfiguration + * @return null when input string isn't suitable + */ + public static ParseSeq getNumberOrder (String orderConfiguration){ + ParseSeq numberOrder = null; + try{ + numberOrder = new ParseSeq(orderConfiguration, false, true); + }catch (IllegalArgumentException ex){ + return null; + } + + return numberOrder; + } + + /** + * support class for iterator throw start to end of order + * @author hieplq + * + */ + public static class IteratorOrderUtil implements Iterator{ + private String orderConfiguration; + int currentIndex = -1; + public IteratorOrderUtil (String orderConfiguration){ + this.orderConfiguration = orderConfiguration; + } + + @Override + public boolean hasNext() { + return currentIndex < orderConfiguration.length() - 1; + } + + @Override + public Character next() { + currentIndex++; + return orderConfiguration.charAt(currentIndex); + } + + /** + * don't support this function + */ + @Override + public void remove() { + throw new UnsupportedOperationException("Don't support this action"); + } + + } + + /** + * run test for utility + * @param args + */ + public static void main(String[] args) { + ParseSeq test = null; + try{ + test = new ParseSeq ("e345", true, true); + System.out.printf("Test for check only number case has non number:%s", false); + System.out.println(); + }catch (IllegalArgumentException ex){ + System.out.printf("Test for check only number case has non number:%1$s", MSG_ONLY_NUNBER.equals(ex.getMessage())); + System.out.println(); + } + + try{ + test = new ParseSeq ("345", true, true); + System.out.printf("Test for check only number case normal:%1$s", true); + System.out.println(); + }catch (IllegalArgumentException ex){ + System.out.printf("Test for check only number case normal:%1$s", false); + System.out.println(); + } + + try{ + test = new ParseSeq ("3545", true, true); + System.out.printf("Test for check dup character case allow:%1$s", true); + System.out.println(); + }catch (IllegalArgumentException ex){ + System.out.printf("Test for check dup character case allow:%1$s", false); + System.out.println(); + } + + try{ + test = new ParseSeq ("3afa5", true, false); + System.out.printf("Test for check dup character case allow:%1$s", true); + System.out.println(); + }catch (IllegalArgumentException ex){ + System.out.printf("Test for check dup character case allow:%1$s", false); + System.out.println(); + } + + try{ + test = new ParseSeq ("3545", false, false); + System.out.printf("Test for check dup character case disallow:%1$s", false); + System.out.println(); + }catch (IllegalArgumentException ex){ + System.out.printf("Test for check dup character case disallow:%1$s", MSG_CONTAIN_DUP.equals(ex.getMessage())); + System.out.println(); + } + + try{ + test = new ParseSeq ("3afa5", false, false); + System.out.printf("Test for check dup character case disallow:%1$s", false); + System.out.println(); + }catch (IllegalArgumentException ex){ + System.out.printf("Test for check dup character case disallow:%1$s", MSG_CONTAIN_DUP.equals(ex.getMessage())); + System.out.println(); + } + + try{ + test = new ParseSeq ("3sfa5", false, false); + System.out.printf("Test for check dup character case disallow:%1$s", true); + System.out.println(); + }catch (IllegalArgumentException ex){ + System.out.printf("Test for check dup character case disallow:%1$s", false); + System.out.println(); + } + + test = ParseSeq.getNumberOrder("4567289"); + System.out.printf("travel configuration:%1$s", "4567289"); + System.out.println(); + + for (Character ch : test){ + System.out.print(ch); + } + + } + +} diff --git a/org.adempiere.ui.swing/src/org/compiere/apps/ProcessParameter.java b/org.adempiere.ui.swing/src/org/compiere/apps/ProcessParameter.java index 3eb9195287..71f7ef8367 100644 --- a/org.adempiere.ui.swing/src/org/compiere/apps/ProcessParameter.java +++ b/org.adempiere.ui.swing/src/org/compiere/apps/ProcessParameter.java @@ -331,7 +331,7 @@ public class ProcessParameter extends CDialog // MField => VEditor - New Field value to be updated to editor mField.addPropertyChangeListener(vEditor); // Set Default - Object defaultObject = mField.getDefault(); + Object defaultObject = mField.getDefaultForPanel(); mField.setValue (defaultObject, true); // centerPanel.add ((Component)vEditor, gbc); @@ -360,7 +360,7 @@ public class ProcessParameter extends CDialog // New Field value to be updated to editor mField2.addPropertyChangeListener(vEditor2); // Set Default - Object defaultObject2 = mField2.getDefault(); + Object defaultObject2 = mField2.getDefaultForPanel(); mField2.setValue (defaultObject2, true); // centerPanel.add ((Component)vEditor2, gbc); diff --git a/org.adempiere.ui.swing/src/org/compiere/apps/ProcessParameterPanel.java b/org.adempiere.ui.swing/src/org/compiere/apps/ProcessParameterPanel.java index 851d342e48..58c9088e62 100644 --- a/org.adempiere.ui.swing/src/org/compiere/apps/ProcessParameterPanel.java +++ b/org.adempiere.ui.swing/src/org/compiere/apps/ProcessParameterPanel.java @@ -326,7 +326,7 @@ public class ProcessParameterPanel extends CPanel implements VetoableChangeListe centerPanel.add ((Component)vEditor, gbc); m_vEditors.add (vEditor); // add to Editors // Set Default - Object defaultObject = mField.getDefault(); + Object defaultObject = mField.getDefaultForPanel(); mField.setValue (defaultObject, true); // if (voF.isRange) @@ -356,7 +356,7 @@ public class ProcessParameterPanel extends CPanel implements VetoableChangeListe centerPanel.add ((Component)vEditor2, gbc); m_vEditors2.add (vEditor2); // Set Default - Object defaultObject2 = mField2.getDefault(); + Object defaultObject2 = mField2.getDefaultForPanel(); mField2.setValue (defaultObject2, true); } else diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessParameterPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessParameterPanel.java index 2c852756a3..3834aafb63 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessParameterPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessParameterPanel.java @@ -287,7 +287,7 @@ public class ProcessParameterPanel extends Panel implements // MField => VEditor - New Field value to be updated to editor mField.addPropertyChangeListener(editor); // Set Default - Object defaultObject = mField.getDefault(); + Object defaultObject = mField.getDefaultForPanel(); mField.setValue(defaultObject, true); // streach component to fill grid cell editor.fillHorizontal(); @@ -349,7 +349,7 @@ public class ProcessParameterPanel extends Panel implements this.appendChild(popupMenu); } // Set Default - Object defaultObject2 = mField2.getDefault(); + Object defaultObject2 = mField2.getDefaultForPanel(); mField2.setValue(defaultObject2, true); // m_wEditors2.add(editor2); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java index ee805afbe4..8699ba16db 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java @@ -1292,7 +1292,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL if (!Util.isEmpty(mField.getVO().DefaultValue, true)) { // set default value - mField.setValue(mField.getDefault(), true); + mField.setValue(mField.getDefaultForPanel(), true); } } // addSelectionColumn @@ -1580,7 +1580,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL // just reset to default Field set explicit DefaultValue Object resetValue = null; if (! Util.isEmpty(gField.getVO().DefaultValue, true)) { - resetValue = gField.getDefault(); + resetValue = gField.getDefaultForPanel(); } Object oldValue = gField.getValue(); gField.setValue(resetValue, true);