IDEMPIERE-2296:Value Preference should have precedence over Default Value of field

add ability set order for get default value
separate order get default value of field in standard window and field at other panel
This commit is contained in:
hieplq 2015-08-01 21:54:23 +08:00
parent a3c1d575bc
commit 329c91397a
7 changed files with 317 additions and 31 deletions

View File

@ -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) - # $
*/
@ -826,7 +897,6 @@ public class GridField
+ defStr);
return createDefault(defStr);
}
}
return null;

View File

@ -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

View File

@ -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<Character> {
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<Character> 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<Character>{
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);
}
}
}

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);