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,23 +554,17 @@ public final class MLookup extends Lookup implements Serializable
CCache<String, ValueNamePair> vnpCache = null;
if (isNumber)
{
knpCache = s_directKeyNamePairCache.get(cacheKey);
if (knpCache != null)
{
KeyNamePair knp = knpCache.get(Integer.parseInt(key.toString()));
if (knp != null)
return knp;
}
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)
{
ValueNamePair vnp = vnpCache.get(key.toString());
if (vnp != null)
return vnp;
}
vnpCache = getDirectValueNamePairCache(m_info, cacheKey);
ValueNamePair vnp = vnpCache.get(key.toString());
if (vnp != null)
return vnp;
}
PreparedStatement pstmt = null;
ResultSet rs = null;
@ -596,16 +592,7 @@ 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);
}
knpCache.put(p.getKey(), p);
}
else
{
@ -614,16 +601,7 @@ public final class MLookup extends Lookup implements Serializable
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);
}
vnpCache.put(p.getValue(), p);
}
if (rs.next())
log.log(Level.SEVERE, m_info.KeyColumn + ": Not unique (first returned) for "
@ -682,110 +660,93 @@ 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 = knpCache.get(id);
}
if (knp == null)
knp = new KeyNamePair(id, null);
list.add(knp);
notInCaches.put(id, i);
notInCaches.put(id, i);
}
list.add(knp);
}
else
{
ValueNamePair vnp = null;
vnpCache = s_directValueNamePairCache.get(cacheKey);
if (vnpCache != null)
{
vnp = vnpCache.get(key.toString());
}
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);
notInCaches.put(key.toString(), i);
}
list.add(vnp);
}
}
StringBuilder builder = new StringBuilder();
for(int i = 0; i < notInCaches.size(); i++)
if (notInCaches.size() > 0)
{
if (builder.length() > 0)
builder.append(" UNION ALL ");
builder.append(m_info.QueryDirect);
}
try (PreparedStatement pstmt = DB.prepareStatement(builder.toString(), null))
{
Set<Object> keySet = notInCaches.keySet();
int i = 0;
for(Object id : keySet)
StringBuilder builder = new StringBuilder();
for(int i = 0; i < notInCaches.size(); i++)
{
i++;
if (id instanceof Integer)
{
pstmt.setInt(i, (int) id);
}
else
{
pstmt.setString(i, id.toString());
}
if (builder.length() > 0)
builder.append(" UNION ALL ");
builder.append(m_info.QueryDirect);
}
ResultSet rs = pstmt.executeQuery();
while (rs.next())
try (PreparedStatement pstmt = DB.prepareStatement(builder.toString(), null))
{
StringBuilder name = new StringBuilder().append(rs.getString(3));
boolean isActive = rs.getString(4).equals("Y");
if (!isActive)
Set<Object> keySet = notInCaches.keySet();
int i = 0;
for(Object id : keySet)
{
name.insert(0, INACTIVE_S).append(INACTIVE_E);
}
if (isNumber)
{
int keyValue = rs.getInt(1);
KeyNamePair p = new KeyNamePair(keyValue, name.toString());
if (knpCache != null)
i++;
if (id instanceof Integer)
{
knpCache.put(p.getKey(), p);
pstmt.setInt(i, (int) id);
}
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);
pstmt.setString(i, id.toString());
}
Integer idx = notInCaches.get(p.getKey());
if (idx != null)
list.set(idx.intValue(), p);
}
else
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
String value = rs.getString(2);
ValueNamePair p = new ValueNamePair(value, name.toString());
if (vnpCache != null)
StringBuilder name = new StringBuilder().append(rs.getString(3));
boolean isActive = rs.getString(4).equals("Y");
if (!isActive)
{
vnpCache.put(p.getValue(), p);
name.insert(0, INACTIVE_S).append(INACTIVE_E);
}
if (isNumber)
{
int keyValue = rs.getInt(1);
KeyNamePair p = new KeyNamePair(keyValue, name.toString());
knpCache.put(p.getKey(), p);
Integer idx = notInCaches.get(p.getKey());
if (idx != null)
list.set(idx.intValue(), p);
}
else
{
vnpCache = new CCache<String, ValueNamePair>(null, "MLookup.DirectValueNamePairCache", 100, 60, false, MAX_NAMEPAIR_CACHE_SIZE);
String value = rs.getString(2);
ValueNamePair p = new ValueNamePair(value, name.toString());
vnpCache.put(p.getValue(), p);
s_directValueNamePairCache.put(cacheKey, vnpCache);
Integer idx = notInCaches.get(p.getValue());
if (idx != null)
list.set(idx.intValue(), p);
}
Integer idx = notInCaches.get(p.getValue());
if (idx != null)
list.set(idx.intValue(), p);
}
} catch (SQLException e) {
log.log(Level.SEVERE, e.getMessage(), e);
}
for(int i = list.size()-1; i >= 0; i--)
{
NamePair np = list.get(i);
if (np.getName() == null)
list.remove(i);
}
} catch (SQLException e) {
log.log(Level.SEVERE, e.getMessage(), e);
}
for(int i = list.size()-1; i >= 0; i--)
{
NamePair np = list.get(i);
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;
//force refresh
m_lookup.clear();
fillComboBox(isMandatory(), true, true, false, isShortList()); // idempiere 90
m_refreshing = false;
return m_lookup.size();
try
{
//force refresh
m_lookup.clear();
fillComboBox(isMandatory(), true, true, false, isShortList()); // idempiere 90
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,36 +1073,42 @@ 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)
{
for(KeyNamePair knp : knpCache)
if (m_refreshCache)
{
m_lookup.put(knp.getKey(), knp);
knpCache.clear();
}
else
{
for(KeyNamePair knp : knpCache)
{
m_lookup.put(knp.getKey(), knp);
}
return;
}
return;
}
else
{
knpCache = new ArrayList<KeyNamePair>();
}
}
else
{
vnpCache = s_valueNamePairCache.get(cacheKey);
if (vnpCache != null)
vnpCache = getValueNamePairCache(m_info, cacheKey);
if (vnpCache.size() > 0)
{
for(ValueNamePair vnp : vnpCache)
if (m_refreshCache)
{
m_lookup.put(vnp.getValue(), vnp);
vnpCache.clear();
}
else
{
for(ValueNamePair vnp : vnpCache)
{
m_lookup.put(vnp.getValue(), vnp);
}
return;
}
return;
}
else
{
vnpCache = new ArrayList<ValueNamePair>();
}
}
m_hasInactive = false;
@ -1132,18 +1177,7 @@ public final class MLookup extends Lookup implements Serializable
vnpCache.add(p);
}
// 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;
@ -76,8 +74,7 @@ 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 int MAX_AUTO_COMPLETE_ROWS = 50;
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;
@ -217,27 +214,7 @@ public class WSearchEditor extends WEditor implements ContextMenuListener, Value
getComponent().getCombobox().addEventListener(Events.ON_CHANGING, (EventListener<InputEvent>)(e) -> {
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();
}
String s = e.getValue();
getComponent().getCombobox().setModel(listModel.getSubModel(s, MAX_AUTO_COMPLETE_ROWS));
}
});

View File

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