IDEMPIERE-1540 Autocomplete for field type "Search" (#91)

Refactoring
Fix table/tabledir auto refresh
Fix MLookupInfo.clone
This commit is contained in:
hengsin 2020-06-01 21:29:04 +08:00 committed by GitHub
parent 9a35f2054d
commit f2cbbc662d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 210 additions and 172 deletions

View File

@ -121,8 +121,10 @@ public final class MLookup extends Lookup implements Serializable
/** Inactive records exists */
private boolean m_hasInactive = false;
/* Refreshing - disable cashing */
/* Refreshing */
private boolean m_refreshing = false;
/* Refresh cache(if exists) */
private boolean m_refreshCache = false;
/** Next Read for Parent */
private long m_nextRead = 0;
@ -552,24 +554,18 @@ public final class MLookup extends Lookup implements Serializable
CCache<String, ValueNamePair> vnpCache = null;
if (isNumber)
{
knpCache = s_directKeyNamePairCache.get(cacheKey);
if (knpCache != null)
{
knpCache = getDirectKeyNamePairCache(m_info, cacheKey);
KeyNamePair knp = knpCache.get(Integer.parseInt(key.toString()));
if (knp != null)
return knp;
}
}
else
{
vnpCache = s_directValueNamePairCache.get(cacheKey);
if (vnpCache != null)
{
vnpCache = getDirectValueNamePairCache(m_info, cacheKey);
ValueNamePair vnp = vnpCache.get(key.toString());
if (vnp != null)
return vnp;
}
}
PreparedStatement pstmt = null;
ResultSet rs = null;
try
@ -596,35 +592,17 @@ public final class MLookup extends Lookup implements Serializable
if (saveInCache) // save if
m_lookup.put(Integer.valueOf(keyValue), p);
directValue = p;
if (knpCache != null)
{
knpCache.put(p.getKey(), p);
}
else
{
knpCache = new CCache<Integer, KeyNamePair>(null, "MLookup.DirectKeyNamePairCache", 100, 60, false, MAX_NAMEPAIR_CACHE_SIZE);
knpCache.put(p.getKey(), p);
s_directKeyNamePairCache.put(cacheKey, knpCache);
}
}
else
{
String value = rs.getString(2);
ValueNamePair p = new ValueNamePair(value, name.toString());
if (saveInCache) // save if
m_lookup.put(value, p);
directValue = p;
if (vnpCache != null)
{
vnpCache.put(p.getValue(), p);
}
else
{
vnpCache = new CCache<String, ValueNamePair>(null, "MLookup.DirectValueNamePairCache", 100, 60, false, MAX_NAMEPAIR_CACHE_SIZE);
vnpCache.put(p.getValue(), p);
s_directValueNamePairCache.put(cacheKey, vnpCache);
}
}
if (rs.next())
log.log(Level.SEVERE, m_info.KeyColumn + ": Not unique (first returned) for "
+ key + " SQL=" + m_info.QueryDirect);
@ -682,31 +660,31 @@ public final class MLookup extends Lookup implements Serializable
{
KeyNamePair knp = null;
int id = Integer.parseInt(key.toString());
knpCache = s_directKeyNamePairCache.get(cacheKey);
if (knpCache != null)
{
knpCache = getDirectKeyNamePairCache(m_info, cacheKey);
knp = knpCache.get(id);
}
if (knp == null)
{
knp = new KeyNamePair(id, null);
list.add(knp);
notInCaches.put(id, i);
}
list.add(knp);
}
else
{
ValueNamePair vnp = null;
vnpCache = s_directValueNamePairCache.get(cacheKey);
if (vnpCache != null)
{
vnpCache = getDirectValueNamePairCache(m_info, cacheKey);
vnp = vnpCache.get(key.toString());
}
if (vnp == null)
{
vnp = new ValueNamePair(key.toString(), null);
list.add(vnp);
notInCaches.put(key.toString(), i);
}
list.add(vnp);
}
}
if (notInCaches.size() > 0)
{
StringBuilder builder = new StringBuilder();
for(int i = 0; i < notInCaches.size(); i++)
{
@ -744,16 +722,7 @@ public final class MLookup extends Lookup implements Serializable
{
int keyValue = rs.getInt(1);
KeyNamePair p = new KeyNamePair(keyValue, name.toString());
if (knpCache != null)
{
knpCache.put(p.getKey(), p);
}
else
{
knpCache = new CCache<Integer, KeyNamePair>(null, "MLookup.DirectKeyNamePairCache", 100, 60, false, MAX_NAMEPAIR_CACHE_SIZE);
knpCache.put(p.getKey(), p);
s_directKeyNamePairCache.put(cacheKey, knpCache);
}
Integer idx = notInCaches.get(p.getKey());
if (idx != null)
list.set(idx.intValue(), p);
@ -762,16 +731,7 @@ public final class MLookup extends Lookup implements Serializable
{
String value = rs.getString(2);
ValueNamePair p = new ValueNamePair(value, name.toString());
if (vnpCache != null)
{
vnpCache.put(p.getValue(), p);
}
else
{
vnpCache = new CCache<String, ValueNamePair>(null, "MLookup.DirectValueNamePairCache", 100, 60, false, MAX_NAMEPAIR_CACHE_SIZE);
vnpCache.put(p.getValue(), p);
s_directValueNamePairCache.put(cacheKey, vnpCache);
}
Integer idx = notInCaches.get(p.getValue());
if (idx != null)
list.set(idx.intValue(), p);
@ -787,6 +747,7 @@ public final class MLookup extends Lookup implements Serializable
if (np.getName() == null)
list.remove(i);
}
}
return list.toArray(new NamePair[0]);
}
@ -854,6 +815,20 @@ public final class MLookup extends Lookup implements Serializable
return refresh(true);
} // refresh
public int refreshItemsAndCache()
{
if (m_refreshing) return 0;
m_refreshCache = true;
try
{
return refresh();
}
finally
{
m_refreshCache = false;
}
}
/**
* Refresh & return number of items read
* @param loadParent get data of parent lookups
@ -874,11 +849,17 @@ public final class MLookup extends Lookup implements Serializable
}
m_refreshing = true;
try
{
//force refresh
m_lookup.clear();
fillComboBox(isMandatory(), true, true, false, isShortList()); // idempiere 90
m_refreshing = false;
return m_lookup.size();
}
finally
{
m_refreshing = false;
}
} // refresh
/**
@ -934,12 +915,70 @@ public final class MLookup extends Lookup implements Serializable
return m_info;
}
private final static CCache<String, List<KeyNamePair>> s_keyNamePairCache = new CCache<String, List<KeyNamePair>>(null, "MLookup.KeyNamePairCache", 100, 60, false, 500);
private final static CCache<String, List<ValueNamePair>> s_valueNamePairCache = new CCache<String, List<ValueNamePair>>(null, "MLookup.ValueNamePairCache", 100, 60, false, 500);
private final static CCache<String, CCache<String, List<KeyNamePair>>> s_keyNamePairCache = new CCache<String, CCache<String, List<KeyNamePair>>>(null, "MLookup.KeyNamePairCache", 100, 60, false, 500);
private final static CCache<String, CCache<String, List<ValueNamePair>>> s_valueNamePairCache = new CCache<String, CCache<String, List<ValueNamePair>>>(null, "MLookup.ValueNamePairCache", 100, 60, false, 500);
private final static CCache<String, CCache<Integer, KeyNamePair>> s_directKeyNamePairCache = new CCache<String, CCache<Integer,KeyNamePair>>(null, "", 100, 60, false, 500);
private final static CCache<String, CCache<String, ValueNamePair>> s_directValueNamePairCache = new CCache<String, CCache<String,ValueNamePair>>(null, "", 100, 60, false, 500);
private synchronized static List<KeyNamePair> getKeyNamePairCache(MLookupInfo lookupInfo, String cacheKey)
{
CCache<String, List<KeyNamePair>> knpCache = s_keyNamePairCache.get(lookupInfo.TableName);
if (knpCache == null)
{
knpCache = new CCache<String, List<KeyNamePair>>(lookupInfo.TableName, lookupInfo.TableName + " KeyNamePair Cache", 100, 60, false, 500);
s_keyNamePairCache.put(lookupInfo.TableName, knpCache);
}
List<KeyNamePair> list = knpCache.get(cacheKey);
if (list == null)
{
list = new ArrayList<KeyNamePair>();
knpCache.put(cacheKey, list);
}
return list;
}
private synchronized static List<ValueNamePair> getValueNamePairCache(MLookupInfo lookupInfo, String cacheKey)
{
CCache<String, List<ValueNamePair>> vnpCache = s_valueNamePairCache.get(lookupInfo.TableName);
if (vnpCache == null)
{
vnpCache = new CCache<String, List<ValueNamePair>>(lookupInfo.TableName, lookupInfo.TableName + " ValueNamePair Cache", 100, 60, false, 500);
s_valueNamePairCache.put(lookupInfo.TableName, vnpCache);
}
List<ValueNamePair> list = vnpCache.get(cacheKey);
if (list == null)
{
list = new ArrayList<ValueNamePair>();
vnpCache.put(cacheKey, list);
}
return list;
}
private synchronized static CCache<Integer, KeyNamePair> getDirectKeyNamePairCache(MLookupInfo lookupInfo, String cacheKey)
{
CCache<Integer, KeyNamePair> knpCache = s_directKeyNamePairCache.get(cacheKey);
if (knpCache == null)
{
knpCache = new CCache<Integer, KeyNamePair>(lookupInfo.TableName, lookupInfo.TableName + " DirectKeyNamePairCache", 100, 60, false, MAX_NAMEPAIR_CACHE_SIZE);
s_directKeyNamePairCache.put(cacheKey, knpCache);
}
return knpCache;
}
private synchronized static CCache<String, ValueNamePair> getDirectValueNamePairCache(MLookupInfo lookupInfo, String cacheKey)
{
CCache<String, ValueNamePair> vnpCache = s_directValueNamePairCache.get(cacheKey);
if (vnpCache == null)
{
vnpCache = new CCache<String, ValueNamePair>(lookupInfo.TableName, lookupInfo.TableName + " DirectValueNamePairCache", 100, 60, false, MAX_NAMEPAIR_CACHE_SIZE);
s_directValueNamePairCache.put(cacheKey, vnpCache);
}
return vnpCache;
}
/**************************************************************************
* MLookup Loader
*/
@ -1034,8 +1073,14 @@ public final class MLookup extends Lookup implements Serializable
List<ValueNamePair> vnpCache = null;
if (isNumber)
{
knpCache = s_keyNamePairCache.get(cacheKey);
if (knpCache != null)
knpCache = getKeyNamePairCache(m_info, cacheKey);
if (knpCache.size() > 0)
{
if (m_refreshCache)
{
knpCache.clear();
}
else
{
for(KeyNamePair knp : knpCache)
{
@ -1043,26 +1088,26 @@ public final class MLookup extends Lookup implements Serializable
}
return;
}
else
{
knpCache = new ArrayList<KeyNamePair>();
}
}
else
{
vnpCache = s_valueNamePairCache.get(cacheKey);
if (vnpCache != null)
vnpCache = getValueNamePairCache(m_info, cacheKey);
if (vnpCache.size() > 0)
{
if (m_refreshCache)
{
vnpCache.clear();
}
else
{
for(ValueNamePair vnp : vnpCache)
{
m_lookup.put(vnp.getValue(), vnp);
}
return;
}
else
{
vnpCache = new ArrayList<ValueNamePair>();
}
}
@ -1133,17 +1178,6 @@ public final class MLookup extends Lookup implements Serializable
}
// if (log.isLoggable(Level.FINE)) log.fine( m_info.KeyColumn + ": " + name);
}
if (isNumber)
{
if (knpCache.size() <= MAX_NAMEPAIR_CACHE_SIZE)
s_keyNamePairCache.put(cacheKey, knpCache);
}
else
{
if (vnpCache.size() <= MAX_NAMEPAIR_CACHE_SIZE)
s_valueNamePairCache.put(cacheKey, vnpCache);
}
}
catch (SQLException e)
{

View File

@ -26,6 +26,7 @@ import java.util.logging.Level;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Util;
/**
* Info Class for Lookup SQL (ValueObject)
@ -234,7 +235,7 @@ public class MLookupInfo implements Serializable, Cloneable
{
MLookupInfo clone = (MLookupInfo)super.clone();
clone.parsedValidationCode = "";
clone.IsValidated = false;
clone.IsValidated = Util.isEmpty(ValidationCode);
clone.ctx = null;
if (ZoomQuery != null)
clone.ZoomQuery = ZoomQuery.clone();

View File

@ -31,6 +31,7 @@ import org.adempiere.webui.factory.InfoManager;
import org.adempiere.webui.panel.InfoPanel;
import org.compiere.model.GridField;
import org.compiere.model.Lookup;
import org.compiere.model.MLookup;
import org.compiere.util.NamePair;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
@ -51,6 +52,8 @@ public class InfoListSubModel implements ListSubModel<ValueNamePair> {
private String keyColumnName;
private String whereClause;
private static final int AUTO_COMPLETE_QUERY_TIMEOUT = 1; //1 second
/**
*
* @param lookup
@ -86,6 +89,24 @@ public class InfoListSubModel implements ListSubModel<ValueNamePair> {
ListModelList<ValueNamePair> model = new ListModelList<>();
if (value != null && !Util.isEmpty(value.toString(), true)) {
String queryText = value.toString().trim();
StringBuilder queryBuilder = new StringBuilder(queryText);
queryBuilder.append("?autocomplete={");
queryBuilder.append("timeout:")
.append(AUTO_COMPLETE_QUERY_TIMEOUT)
.append(",")
.append("pagesize:")
.append(nRows);
if (lookup instanceof MLookup) {
MLookup mlookup = (MLookup) lookup;
List<String> displayColumns = mlookup.getLookupInfo().lookupDisplayColumns;
if (displayColumns != null && displayColumns.size() > 0) {
queryBuilder.append(",")
.append("searchcolumn:")
.append(displayColumns.get(0));
}
}
queryBuilder.append("}");
queryText = queryBuilder.toString();
final InfoPanel ip = InfoManager.create(lookup, gridField, tableName, keyColumnName, queryText, false, getWhereClause());
if (ip != null && ip.loadedOK()) {

View File

@ -21,7 +21,6 @@ import static org.compiere.model.SystemIDs.COLUMN_C_INVOICELINE_M_PRODUCT_ID;
import static org.compiere.model.SystemIDs.COLUMN_C_INVOICE_C_BPARTNER_ID;
import java.beans.PropertyChangeEvent;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
@ -56,7 +55,6 @@ import org.compiere.model.X_AD_CtxHelp;
import org.compiere.util.CLogger;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.Util;
import org.zkoss.zk.au.out.AuScript;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
@ -77,7 +75,6 @@ import org.zkoss.zk.ui.util.Clients;
public class WSearchEditor extends WEditor implements ContextMenuListener, ValueChangeListener, IZoomableEditor
{
private static final int MAX_AUTO_COMPLETE_ROWS = 50;
private static final int AUTO_COMPLETE_QUERY_TIMEOUT = 1; //1 second
private static final String[] LISTENER_EVENTS = {Events.ON_CLICK, Events.ON_CHANGE, Events.ON_OK};
public static final String ATTRIBUTE_IS_INFO_PANEL_OPEN = "ATTRIBUTE_IS_INFO_PANEL_OPEN";
private Lookup lookup;
@ -218,26 +215,6 @@ public class WSearchEditor extends WEditor implements ContextMenuListener, Value
if (!e.isChangingBySelectBack()) {
listModel.setWhereClause(getWhereClause());
String s = e.getValue();
if (!Util.isEmpty(s, true)) {
StringBuilder query = new StringBuilder(s);
query.append("?autocomplete={");
query.append("timeout:")
.append(AUTO_COMPLETE_QUERY_TIMEOUT)
.append(",")
.append("pagesize:")
.append(MAX_AUTO_COMPLETE_ROWS);
if (lookup instanceof MLookup) {
MLookup mlookup = (MLookup) lookup;
List<String> displayColumns = mlookup.getLookupInfo().lookupDisplayColumns;
if (displayColumns != null && displayColumns.size() > 0) {
query.append(",")
.append("searchcolumn:")
.append(displayColumns.get(0));
}
}
query.append("}");
s = query.toString();
}
getComponent().getCombobox().setModel(listModel.getSubModel(s, MAX_AUTO_COMPLETE_ROWS));
}
});

View File

@ -599,7 +599,12 @@ ContextMenuListener, IZoomableEditor
Object curValue = getValue();
if (isReadWrite())
{
if (lookup instanceof MLookup)
((MLookup) lookup).refreshItemsAndCache();
else
lookup.refresh();
}
else
refreshList();
if (curValue != null)