IDEMPIERE-3413 Multi Select List and table reference

This commit is contained in:
Heng Sin Low 2019-06-24 18:23:41 +08:00
parent cc8f48acd2
commit d00c07c2b9
28 changed files with 4203 additions and 39 deletions

View File

@ -0,0 +1,86 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- Dec 4, 2018 3:41:36 PM MYT
-- AP2-766 Implement Chosen Box control
INSERT INTO AD_Reference (AD_Reference_ID,Name,AD_Reference_UU,IsOrderByValue,Description,ValidationType,Updated,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,EntityType,AD_Org_ID) VALUES (200161,'Chosen Multiple Selection List','fa2c2787-e93f-42be-a5d1-7a12f6b30b72','N','Chosen multiple selection box for reference list','D',TO_DATE('2018-12-04 15:41:35','YYYY-MM-DD HH24:MI:SS'),'Y',100,100,0,TO_DATE('2018-12-04 15:41:35','YYYY-MM-DD HH24:MI:SS'),'D',0)
;
-- Dec 4, 2018 3:41:56 PM MYT
INSERT INTO AD_Reference (AD_Reference_ID,Name,AD_Reference_UU,IsOrderByValue,Description,ValidationType,Updated,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,EntityType,AD_Org_ID) VALUES (200162,'Chosen Multiple Selection Table','07d7bf33-8998-4538-920d-5c0e0b2d46d2','N','Chosen multiple selection box for table list','D',TO_DATE('2018-12-04 15:41:56','YYYY-MM-DD HH24:MI:SS'),'Y',100,100,0,TO_DATE('2018-12-04 15:41:56','YYYY-MM-DD HH24:MI:SS'),'D',0)
;
-- Dec 4, 2018 3:44:27 PM MYT
UPDATE AD_Val_Rule SET Code='AD_Reference.ValidationType=CASE WHEN @AD_Reference_ID@ IN (17,28,200152,200161) THEN ''L'' ELSE ''T'' END',Updated=TO_DATE('2018-12-04 15:44:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Val_Rule_ID=115
;
-- Dec 4, 2018 3:48:07 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=30 | @AD_Reference_ID@=28 | @AD_Reference_ID@=200152 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2018-12-04 15:48:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=171
;
-- Dec 4, 2018 3:48:49 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=19 | @AD_Reference_ID@=28 | @AD_Reference_ID@=30 | @AD_Reference_ID@=200012 | @AD_Reference_ID@=31 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2018-12-04 15:48:49','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=172
;
-- Dec 4, 2018 4:49:17 PM MYT
INSERT INTO AD_Reference (AD_Reference_ID,Name,AD_Reference_UU,IsOrderByValue,Description,ValidationType,Updated,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,EntityType,AD_Org_ID) VALUES (200163,'Chosen Multiple Selection Search','563a482c-4f06-448d-bb7f-e109d33cead9','N','Chosen multiple selection box for search','D',TO_DATE('2018-12-04 16:49:16','YYYY-MM-DD HH24:MI:SS'),'Y',100,100,0,TO_DATE('2018-12-04 16:49:16','YYYY-MM-DD HH24:MI:SS'),'D',0)
;
-- Dec 4, 2018 4:49:55 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=19 | @AD_Reference_ID@=28 | @AD_Reference_ID@=30 | @AD_Reference_ID@=200012 | @AD_Reference_ID@=31 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2018-12-04 16:49:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=172
;
-- Dec 4, 2018 4:50:41 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=30 | @AD_Reference_ID@=28 | @AD_Reference_ID@=200152 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2018-12-04 16:50:41','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=171
;
-- Dec 5, 2018 11:18:30 AM MYT
-- AP2-766 Implement Chosen Box control
UPDATE AD_Field SET AD_Val_Rule_ID=NULL, MandatoryLogic='@AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2018-12-05 11:18:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=171
;
-- Dec 7, 2018 4:37:39 PM MYT
-- AP2-766 Implement Chosen Box control
UPDATE AD_Field SET AD_Val_Rule_ID=NULL, MandatoryLogic='@AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2018-12-07 16:37:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=2540
;
-- IDEMPIERE-3413 Multi Select List and table reference
-- Jun 22, 2019, 5:11:30 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=30 | @AD_Reference_ID@=28 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2019-06-22 17:11:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201622
;
-- Jun 22, 2019, 5:12:43 PM MYT
UPDATE AD_Field SET DisplayLogic='@IsQueryCriteria@=Y & @AD_Reference_ID@!200161 & @AD_Reference_ID@!200162 & @AD_Reference_ID@!200163', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2019-06-22 17:12:43','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201636
;
-- Jun 22, 2019, 5:13:24 PM MYT
UPDATE AD_Field SET DisplayLogic='@IsQueryCriteria@=Y & @AD_Reference_ID@!200161 & @AD_Reference_ID@!200162 & @AD_Reference_ID@!200163', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2019-06-22 17:13:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201635
;
-- Jun 22, 2019, 5:15:39 PM MYT
UPDATE AD_Field SET AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, MandatoryLogic='@AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', IsToolbarButton=NULL,Updated=TO_DATE('2019-06-22 17:15:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201622
;
CREATE TYPE TABLE_OF_VARCHAR2 AS TABLE OF VARCHAR2(4000)
;
CREATE OR REPLACE FUNCTION toTableOfVarchar2(p_list IN VARCHAR2)
RETURN TABLE_OF_VARCHAR2 DETERMINISTIC
AS
l_tab TABLE_OF_VARCHAR2 := TABLE_OF_VARCHAR2();
BEGIN
FOR i IN
( select trim('"' from REGEXP_SUBSTR(p_list, '(".*?"|.*?)(,|$)', 1, level, NULL, 1)) split
from dual
connect by level<=length(regexp_replace(p_list,'".*?"|[^,]*'))+1)
LOOP
l_tab.EXTEND;
l_tab(l_tab.COUNT) := i.split;
END LOOP;
RETURN l_tab;
END toTableOfVarchar2
;
SELECT register_migration_script('201906171811_IDEMPIERE-3413.sql') FROM dual
;

View File

@ -0,0 +1,63 @@
-- Dec 4, 2018 3:41:36 PM MYT
-- AP2-766 Implement Chosen Box control
INSERT INTO AD_Reference (AD_Reference_ID,Name,AD_Reference_UU,IsOrderByValue,Description,ValidationType,Updated,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,EntityType,AD_Org_ID) VALUES (200161,'Chosen Multiple Selection List','fa2c2787-e93f-42be-a5d1-7a12f6b30b72','N','Chosen multiple selection box for reference list','D',TO_TIMESTAMP('2018-12-04 15:41:35','YYYY-MM-DD HH24:MI:SS'),'Y',100,100,0,TO_TIMESTAMP('2018-12-04 15:41:35','YYYY-MM-DD HH24:MI:SS'),'D',0)
;
-- Dec 4, 2018 3:41:56 PM MYT
INSERT INTO AD_Reference (AD_Reference_ID,Name,AD_Reference_UU,IsOrderByValue,Description,ValidationType,Updated,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,EntityType,AD_Org_ID) VALUES (200162,'Chosen Multiple Selection Table','07d7bf33-8998-4538-920d-5c0e0b2d46d2','N','Chosen multiple selection box for table list','D',TO_TIMESTAMP('2018-12-04 15:41:56','YYYY-MM-DD HH24:MI:SS'),'Y',100,100,0,TO_TIMESTAMP('2018-12-04 15:41:56','YYYY-MM-DD HH24:MI:SS'),'D',0)
;
-- Dec 4, 2018 3:44:27 PM MYT
UPDATE AD_Val_Rule SET Code='AD_Reference.ValidationType=CASE WHEN @AD_Reference_ID@ IN (17,28,200152,200161) THEN ''L'' ELSE ''T'' END',Updated=TO_TIMESTAMP('2018-12-04 15:44:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Val_Rule_ID=115
;
-- Dec 4, 2018 3:48:07 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=30 | @AD_Reference_ID@=28 | @AD_Reference_ID@=200152 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-12-04 15:48:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=171
;
-- Dec 4, 2018 3:48:49 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=19 | @AD_Reference_ID@=28 | @AD_Reference_ID@=30 | @AD_Reference_ID@=200012 | @AD_Reference_ID@=31 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-12-04 15:48:49','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=172
;
-- Dec 4, 2018 4:49:17 PM MYT
INSERT INTO AD_Reference (AD_Reference_ID,Name,AD_Reference_UU,IsOrderByValue,Description,ValidationType,Updated,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,EntityType,AD_Org_ID) VALUES (200163,'Chosen Multiple Selection Search','563a482c-4f06-448d-bb7f-e109d33cead9','N','Chosen multiple selection box for search','D',TO_TIMESTAMP('2018-12-04 16:49:16','YYYY-MM-DD HH24:MI:SS'),'Y',100,100,0,TO_TIMESTAMP('2018-12-04 16:49:16','YYYY-MM-DD HH24:MI:SS'),'D',0)
;
-- Dec 4, 2018 4:49:55 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=19 | @AD_Reference_ID@=28 | @AD_Reference_ID@=30 | @AD_Reference_ID@=200012 | @AD_Reference_ID@=31 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-12-04 16:49:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=172
;
-- Dec 4, 2018 4:50:41 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=30 | @AD_Reference_ID@=28 | @AD_Reference_ID@=200152 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-12-04 16:50:41','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=171
;
-- Dec 5, 2018 11:18:30 AM MYT
-- AP2-766 Implement Chosen Box control
UPDATE AD_Field SET AD_Val_Rule_ID=NULL, MandatoryLogic='@AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-12-05 11:18:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=171
;
-- Dec 7, 2018 4:37:39 PM MYT
-- AP2-766 Implement Chosen Box control
UPDATE AD_Field SET AD_Val_Rule_ID=NULL, MandatoryLogic='@AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-12-07 16:37:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=2540
;
-- IDEMPIERE-3413 Multi Select List and table reference
-- Jun 22, 2019, 5:11:30 PM MYT
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=17 | @AD_Reference_ID@=18 | @AD_Reference_ID@=30 | @AD_Reference_ID@=28 | @AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2019-06-22 17:11:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201622
;
-- Jun 22, 2019, 5:12:43 PM MYT
UPDATE AD_Field SET DisplayLogic='@IsQueryCriteria@=Y & @AD_Reference_ID@!200161 & @AD_Reference_ID@!200162 & @AD_Reference_ID@!200163', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2019-06-22 17:12:43','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201636
;
-- Jun 22, 2019, 5:13:24 PM MYT
UPDATE AD_Field SET DisplayLogic='@IsQueryCriteria@=Y & @AD_Reference_ID@!200161 & @AD_Reference_ID@!200162 & @AD_Reference_ID@!200163', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2019-06-22 17:13:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201635
;
-- Jun 22, 2019, 5:15:39 PM MYT
UPDATE AD_Field SET AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, MandatoryLogic='@AD_Reference_ID@=200161 | @AD_Reference_ID@=200162 | @AD_Reference_ID@=200163', IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2019-06-22 17:15:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201622
;
SELECT register_migration_script('201906171811_IDEMPIERE-3413.sql') FROM dual
;

View File

@ -339,5 +339,18 @@ public interface AdempiereDatabase
public String getNameOfUniqueConstraintError(Exception e);
/**
* @param columnName
* @param csv comma separated value
* @return subset sql clause
*/
public String subsetClauseForCSV(String columnName, String csv);
/**
* @param columnName
* @param csv comma separated value
* @return subset sql clause
*/
public String intersectClauseForCSV(String columnName, String csv);
} // AdempiereDatabase

View File

@ -238,8 +238,29 @@ public final class MLookup extends Lookup implements Serializable
public String getDisplay (Object key)
{
if (key == null)
return "";
//
return "";
//
if (m_info.DisplayType==DisplayType.ChosenMultipleSelectionList || m_info.DisplayType==DisplayType.ChosenMultipleSelectionSearch
|| m_info.DisplayType==DisplayType.ChosenMultipleSelectionTable)
{
StringBuilder builder = new StringBuilder();
String[] keys = key.toString().split("[,]");
for(String k : keys)
{
if (builder.length() > 0)
builder.append(", ");
Object display = get(k);
if (display == null)
{
builder.append("<").append(k).append(">");
}
else
{
builder.append(display.toString());
}
}
return builder.toString();
}
Object display = get (key);
if (display == null){
StringBuilder msgreturn = new StringBuilder("<").append(key.toString()).append(">");

View File

@ -185,13 +185,14 @@ public class MLookupFactory
MLookupInfo info = null;
boolean needToAddSecurity = true;
// List
if (AD_Reference_ID == DisplayType.List) // 17
if (AD_Reference_ID == DisplayType.List || AD_Reference_ID == DisplayType.ChosenMultipleSelectionList) // 17
{
info = getLookup_List(language, AD_Reference_Value_ID);
needToAddSecurity = false;
}
// Table or Search with Reference_Value
else if ((AD_Reference_ID == DisplayType.Table || AD_Reference_ID == DisplayType.Search)
else if ((AD_Reference_ID == DisplayType.Table || AD_Reference_ID == DisplayType.Search
|| AD_Reference_ID == DisplayType.ChosenMultipleSelectionTable || AD_Reference_ID == DisplayType.ChosenMultipleSelectionSearch)
&& AD_Reference_Value_ID != 0)
{
info = getLookup_Table (ctx, language, WindowNo, AD_Reference_Value_ID);

View File

@ -87,7 +87,7 @@ public class MQuery implements Serializable
SQL = "SELECT ip.ParameterName,ip.P_String,ip.P_String_To," // 1..3
+ "ip.P_Number,ip.P_Number_To," // 4..5
+ "ip.P_Date,ip.P_Date_To, ip.Info,ip.Info_To, " // 6..9
+ "pp.Name, pp.IsRange, pp.AD_Reference_ID " // 10..12
+ "pp.Name, pp.IsRange, pp.AD_Reference_ID " // 10..12
+ "FROM AD_PInstance_Para ip, AD_PInstance i, AD_Process_Para pp "
+ "WHERE i.AD_PInstance_ID=ip.AD_PInstance_ID"
+ " AND pp.AD_Process_ID=i.AD_Process_ID"
@ -166,12 +166,32 @@ public class MQuery implements Serializable
{
if (P_String_To == null)
{
if (P_String.indexOf('%') == -1)
query.addRestriction(ParameterName, MQuery.EQUAL,
P_String, Name, Info);
if (Reference_ID == DisplayType.ChosenMultipleSelectionList)
{
String columnName = TableName + "." + ParameterName;
int cnt = DB.getSQLValueEx(null, "SELECT Count(*) From AD_Column WHERE IsActive='Y' AND AD_Client_ID=0 AND Upper(ColumnName)=? AND AD_Reference_ID=?", ParameterName.toUpperCase(), DisplayType.ChosenMultipleSelectionList);
if (cnt > 0)
query.addRestriction(DB.intersectClauseForCSV(columnName, P_String), MQuery.EQUAL, Name, Info);
else
query.addRestriction(DB.inClauseForCSV(columnName, P_String), MQuery.EQUAL, Name, Info);
}
else if (Reference_ID == DisplayType.ChosenMultipleSelectionTable || Reference_ID == DisplayType.ChosenMultipleSelectionSearch)
{
String columnName = TableName + "." + ParameterName;
if (columnName.endsWith("_ID"))
query.addRestriction(DB.inClauseForCSV(columnName, P_String), MQuery.EQUAL, Name, Info);
else
query.addRestriction(DB.intersectClauseForCSV(columnName, P_String), MQuery.EQUAL, Name, Info);
}
else
query.addRestriction(ParameterName, MQuery.LIKE,
P_String, Name, Info);
{
if (P_String.indexOf('%') == -1)
query.addRestriction(ParameterName, MQuery.EQUAL,
P_String, Name, Info);
else
query.addRestriction(ParameterName, MQuery.LIKE,
P_String, Name, Info);
}
}
else
query.addRangeRestriction(ParameterName,
@ -235,7 +255,6 @@ public class MQuery implements Serializable
return query;
} // get
/**
* Get Zoom Column Name.
* Converts Synonyms like SalesRep_ID to AD_User_ID
@ -632,6 +651,20 @@ public class MQuery implements Serializable
m_newRecord = whereClause.equals(NEWRECORD);
} // addRestriction
public void addRestriction (String whereClause, String Operator, String InfoName, String InfoDisplay)
{
if (whereClause == null || whereClause.trim().length() == 0)
return;
Restriction r = new Restriction (whereClause, true, 0);
r.Operator = Operator;
if (InfoName != null)
r.InfoName = InfoName;
if (InfoDisplay != null)
r.InfoDisplay = InfoDisplay.trim();
m_list.add(r);
m_newRecord = whereClause.equals(NEWRECORD);
}
/**
* New Record Query
* @return true if new record query

View File

@ -96,6 +96,9 @@ public class SystemIDs
public final static int REFERENCE_DATATYPE_ASSIGNMENT = 33;
public final static int REFERENCE_DATATYPE_BINARY = 23;
public final static int REFERENCE_DATATYPE_BUTTON = 28;
public final static int REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_LIST = 200161;
public final static int REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_TABLE = 200162;
public final static int REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_SEARCH = 200163;
public final static int REFERENCE_DATATYPE_COLOR = 27;
public final static int REFERENCE_DATATYPE_COSTPRICE = 37;
public final static int REFERENCE_DATATYPE_DATE = 15;

View File

@ -2578,4 +2578,57 @@ public final class DB
return ProxyFactory.newCPreparedStatement(resultSetType, resultSetConcurrency, sql, trxName);
}
/**
* @param columnName
* @param csv comma separated value
* @return IN clause
*/
public static String inClauseForCSV(String columnName, String csv)
{
StringBuilder builder = new StringBuilder();
builder.append(columnName).append(" IN (");
String[] values = csv.split("[,]");
for(int i = 0; i < values.length; i++)
{
if (i > 0)
builder.append(",");
String key = values[i];
if (columnName.endsWith("_ID"))
{
builder.append(key);
}
else
{
if (key.startsWith("\"") && key.endsWith("\""))
{
key = key.substring(1, key.length()-1);
}
builder.append(TO_STRING(key));
}
}
builder.append(")");
return builder.toString();
}
/**
*
* @param columnName
* @param csv
* @return subset sql clause
*/
public static String subsetClauseForCSV(String columnName, String csv)
{
return getDatabase().subsetClauseForCSV(columnName, csv);
}
/**
*
* @param columnName
* @param csv
* @return intersect sql clause
*/
public static String intersectClauseForCSV(String columnName, String csv)
{
return getDatabase().intersectClauseForCSV(columnName, csv);
}
} // DB

View File

@ -21,6 +21,9 @@ import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_AMOUNT;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_ASSIGNMENT;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_BINARY;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_BUTTON;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_LIST;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_TABLE;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_SEARCH;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_COLOR;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_COSTPRICE;
import static org.compiere.model.SystemIDs.REFERENCE_DATATYPE_DATE;
@ -156,6 +159,12 @@ public final class DisplayType
public static final int MultipleSelectionGrid = REFERENCE_DATATYPE_MULTIPLE_SELECTION_GRID;
public static final int ChosenMultipleSelectionList = REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_LIST;
public static final int ChosenMultipleSelectionTable = REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_TABLE;
public static final int ChosenMultipleSelectionSearch = REFERENCE_DATATYPE_CHOSEN_MULTIPLE_SELECTION_SEARCH;
/**
* - New Display Type
INSERT INTO AD_REFERENCE
@ -272,7 +281,10 @@ public final class DisplayType
|| displayType == FilePath || displayType == FileName
|| displayType == URL || displayType == PrinterName
|| displayType == SingleSelectionGrid || displayType == Color
|| displayType == MultipleSelectionGrid)
|| displayType == MultipleSelectionGrid
|| displayType == ChosenMultipleSelectionList
|| displayType == ChosenMultipleSelectionTable
|| displayType == ChosenMultipleSelectionSearch)
return true;
List<IDisplayTypeFactory> factoryList = Service.locator().list(IDisplayTypeFactory.class).getServices();
@ -312,7 +324,10 @@ public final class DisplayType
public static boolean isLookup(int displayType)
{
if (displayType == List || displayType == Table
|| displayType == TableDir || displayType == Search)
|| displayType == TableDir || displayType == Search
|| displayType == ChosenMultipleSelectionTable
|| displayType == ChosenMultipleSelectionSearch
|| displayType == ChosenMultipleSelectionList)
return true;
List<IDisplayTypeFactory> factoryList = Service.locator().list(IDisplayTypeFactory.class).getServices();

View File

@ -91,6 +91,10 @@ Export-Package: fi.jawsy.jawwa.zk.atmosphere,
org.adempiere.webui.window,
org.zkforge.ckez,
org.zkforge.keylistener,
web.chosenbox.img,
web.js.chosenbox,
web.js.chosenbox.css,
web.js.chosenbox.mold,
web.ckez.html,
web.ckez.img,
web.js.ckez,

View File

@ -33,6 +33,17 @@ Copyright (C) 2007 Ashley G Ramdass (ADempiere WebUI).
</mold>
</component>
<component>
<component-name>chosenbox</component-name>
<component-class>org.zkoss.addon.chosenbox.Chosenbox</component-class>
<widget-class>chosenbox.Chosenbox</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>mold/chosenbox.js</mold-uri>
<css-uri>css/chosenbox.css.dsp</css-uri>
</mold>
</component>
<javascript src="/js/calc.js" charset="UTF-8"/>
<javascript src="/js/layout.js" charset="UTF-8"/>
<javascript src="/js/report.js" charset="UTF-8"/>

View File

@ -0,0 +1,152 @@
/******************************************************************************
* Project: Trek Global ERP *
* Copyright (C) 2009-2018 Trek Global Corporation *
* *
* 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.adempiere.webui.component;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import org.adempiere.webui.LayoutUtils;
import org.compiere.util.ValueNamePair;
import org.zkoss.addon.chosenbox.Chosenbox;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Div;
/**
* @author Low Heng Sin
*/
public class ChosenSearchBox extends Div {
/**
*
*/
private static final long serialVersionUID = -3152111756471436612L;
protected PropertyChangeSupport m_propertyChangeListeners = new PropertyChangeSupport(
this);
protected Chosenbox<ValueNamePair> chosenbox;
protected Button btn;
public ChosenSearchBox() {
initComponents();
}
/**
* @param imageSrc
*/
public void setButtonImage(String imageSrc) {
btn.setImage(imageSrc);
}
private void initComponents() {
chosenbox = new Chosenbox<>();
chosenbox.setSclass("editor-input");
chosenbox.setWidth("100%");
appendChild(chosenbox);
btn = new Button();
btn.setTabindex(-1);
btn.setHflex("0");
btn.setSclass("editor-button");
appendChild(btn);
LayoutUtils.addSclass("editor-box", this);
setTableEditorMode(false);
}
/**
* @return chosenbox component
*/
public Chosenbox<ValueNamePair> getChosenbox() {
return chosenbox;
}
/**
* @param enabled
*/
public void setEnabled(boolean enabled) {
chosenbox.setDisabled(!enabled);
btn.setEnabled(enabled);
btn.setVisible(enabled);
if (enabled) {
if (btn.getParent() != chosenbox.getParent())
btn.setParent(chosenbox.getParent());
} else {
if (btn.getParent() != null)
btn.detach();
}
if (enabled) {
LayoutUtils.removeSclass("editor-input-disd", chosenbox);
} else {
LayoutUtils.addSclass("editor-input-disd", chosenbox);
}
}
/**
* @return boolean
*/
public boolean isEnabled() {
return btn.isEnabled();
}
/**
* @param evtnm
* @param listener
*/
public boolean addEventListener(String evtnm, EventListener<?> listener) {
if (Events.ON_CLICK.equals(evtnm)) {
return btn.addEventListener(evtnm, listener);
} else {
return chosenbox.addEventListener(evtnm, listener);
}
}
/**
* @param l
*/
public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
m_propertyChangeListeners.addPropertyChangeListener(l);
}
/**
* @param tooltiptext
*/
public void setToolTipText(String tooltiptext) {
chosenbox.setTooltiptext(tooltiptext);
}
/**
* @return Button
*/
public Button getButton() {
return btn;
}
public void setTableEditorMode(boolean flag) {
if (flag) {
setHflex("0");
LayoutUtils.addSclass("grid-editor-input", chosenbox);
LayoutUtils.addSclass("grid-editor-button", btn);
} else {
setHflex("1");
LayoutUtils.removeSclass("grid-editor-input", chosenbox);
LayoutUtils.removeSclass("grid-editor-button", btn);
}
}
@Override
public void onPageAttached(Page newpage, Page oldpage) {
super.onPageAttached(newpage, oldpage);
}
}

View File

@ -0,0 +1,560 @@
/******************************************************************************
* Project: Trek Global ERP *
* Copyright (C) 2009-2018 Trek Global Corporation *
* 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.adempiere.webui.editor;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.adempiere.webui.ValuePreference;
import org.adempiere.webui.event.ContextMenuEvent;
import org.adempiere.webui.event.ContextMenuListener;
import org.adempiere.webui.event.ValueChangeEvent;
import org.adempiere.webui.window.WFieldRecordInfo;
import org.compiere.model.GridField;
import org.compiere.model.Lookup;
import org.compiere.model.MLookup;
import org.compiere.util.CCache;
import org.compiere.util.CLogger;
import org.compiere.util.CacheMgt;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
import org.zkoss.addon.chosenbox.Chosenbox;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.DesktopCleanup;
import org.zkoss.zul.ListModelList;
/**
*
* @author hengsin
*
*/
public class WChosenboxListEditor extends WEditor implements ContextMenuListener
{
public final static String[] LISTENER_EVENTS = {Events.ON_SELECT};
@SuppressWarnings("unused")
private static final CLogger logger;
static
{
logger = CLogger.getCLogger(WTableDirEditor.class);
}
private Lookup lookup;
private Object oldValue;
private CCacheListener tableCacheListener;
private boolean onselecting = false;
private ListModelList<ValueNamePair> model = new ListModelList<>();
public WChosenboxListEditor(GridField gridField)
{
this(new ChosenboxEditor(), gridField);
}
private WChosenboxListEditor(Component comp, GridField gridField)
{
super(comp, gridField);
lookup = gridField.getLookup();
init();
}
/**
* Constructor for use if a grid field is unavailable
*
* @param lookup Store of selectable data
* @param label column name (not displayed)
* @param description description of component
* @param mandatory whether a selection must be made
* @param readonly whether or not the editor is read only
* @param updateable whether the editor contents can be changed
*/
public WChosenboxListEditor(Lookup lookup, String label, String description, boolean mandatory, boolean readonly, boolean updateable)
{
this(lookup, label, description, mandatory, readonly, updateable, false);
}
public WChosenboxListEditor(Lookup lookup, String label, String description, boolean mandatory, boolean readonly, boolean updateable, boolean autocomplete)
{
this(new ChosenboxEditor(), lookup, label, description, mandatory, readonly, updateable);
}
private WChosenboxListEditor(Component comp, Lookup lookup, String label, String description, boolean mandatory, boolean readonly, boolean updateable)
{
super(comp, label, description, mandatory, readonly, updateable);
if (lookup == null)
{
throw new IllegalArgumentException("Lookup cannot be null");
}
this.lookup = lookup;
super.setColumnName(lookup.getColumnName());
init();
}
/**
* For ease of porting swing form
* @param columnName
* @param mandatory
* @param isReadOnly
* @param isUpdateable
* @param lookup
*/
public WChosenboxListEditor(String columnName, boolean mandatory, boolean isReadOnly, boolean isUpdateable, Lookup lookup)
{
this(columnName, mandatory, isReadOnly, isUpdateable, lookup, false);
}
public WChosenboxListEditor(String columnName, boolean mandatory, boolean isReadOnly, boolean isUpdateable, Lookup lookup, boolean autocomplete)
{
this(new ChosenboxEditor(), columnName, mandatory, isReadOnly, isUpdateable, lookup);
}
private WChosenboxListEditor(Component comp, String columnName, boolean mandatory, boolean isReadOnly, boolean isUpdateable, Lookup lookup)
{
super(comp, columnName, null, null, mandatory, isReadOnly, isUpdateable);
if (lookup == null)
{
throw new IllegalArgumentException("Lookup cannot be null");
}
this.lookup = lookup;
init();
}
private void init()
{
getComponent().setHflex("true");
getComponent().editor = this;
getComponent().setModel(model);
if (lookup != null)
{
lookup.setMandatory(true);
//no need to refresh readonly lookup
if (isReadWrite())
{
refreshLookup();
}
else
{
updateModel();
}
}
if (gridField != null)
{
popupMenu = new WEditorPopupMenu(false, true, isShowPreference(), false, false, false, lookup);
addChangeLogMenu(popupMenu);
}
}
protected void refreshLookup() {
lookup.refresh();
updateModel();
}
@Override
public String getDisplay()
{
StringBuilder display = new StringBuilder();
LinkedHashSet<ValueNamePair> selected = getComponent().getSelectedObjects();
if (selected != null && selected.size() > 0)
{
for(ValueNamePair pair : selected)
{
if (display.length() > 0)
display.append(", ");
display.append(pair.getName());
}
}
return display.toString();
}
@Override
public Object getValue()
{
return oldValue;
}
private String getValueFromComponent()
{
StringBuilder retVal = new StringBuilder();
LinkedHashSet<ValueNamePair> selected = getComponent().getSelectedObjects();
if (selected != null && selected.size() > 0)
{
for(ValueNamePair pair : selected)
{
if (retVal.length() > 0)
retVal.append(",");
StringBuilder builder = new StringBuilder(pair.getValue());
if (builder.indexOf(",") >= 0)
{
builder.insert(0, "\"");
builder.append("\"");
}
retVal.append(builder.toString());
}
}
return retVal.length() > 0 ? retVal.toString() : null;
}
public void setValue(Object value)
{
if (onselecting) {
return;
}
if (value != null)
{
String[] values = ((String)value).split("[,]");
Set<ValueNamePair> selected = new LinkedHashSet<>();
for (String key : values) {
if (!Util.isEmpty(key)) {
if (key.startsWith("\"") && key.endsWith("\"")) {
key = key.substring(1, key.length()-1);
}
String name = lookup.getDisplay(key);
ValueNamePair pair = new ValueNamePair(key, name);
selected.add(pair);
}
}
getComponent().setSelectedObjects(selected);
if (getComponent().getSelectedObjects().size() != selected.size())
{
Object curValue = oldValue;
oldValue = value;
if (isReadWrite() && lookup != null)
{
refreshLookup();
}
else
{
updateModel();
}
getComponent().setSelectedObjects(selected);
//still not in list, reset to zero
if (getComponent().getSelectedObjects().size() != selected.size())
{
getComponent().setSelectedObjects(new LinkedHashSet<ValueNamePair>());
if (curValue == null)
curValue = value;
ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), curValue, null);
super.fireValueChange(changeEvent);
oldValue = null;
}
}
else
{
oldValue = value;
}
}
else
{
getComponent().setSelectedObjects(new LinkedHashSet<ValueNamePair>());
oldValue = value;
}
}
@Override
public ChosenboxEditor getComponent() {
return (ChosenboxEditor) component;
}
@Override
public boolean isReadWrite() {
return getComponent().isEnabled();
}
@Override
public void setReadWrite(boolean readWrite) {
getComponent().setEnabled(readWrite);
}
private void updateModel()
{
List<ValueNamePair> list = new ArrayList<>();
if (isReadWrite())
{
if (lookup != null)
{
int size = lookup.getSize();
for (int i = 0; i < size; i++)
{
Object obj = lookup.getElementAt(i);
if (obj instanceof KeyNamePair)
{
KeyNamePair lookupKNPair = (KeyNamePair) obj;
ValueNamePair vnp = new ValueNamePair(Integer.toString(lookupKNPair.getKey()), lookupKNPair.getName());
list.add(vnp);
}
else if (obj instanceof ValueNamePair)
{
ValueNamePair lookupKNPair = (ValueNamePair) obj;
list.add(lookupKNPair);
}
}
}
}
else
{
if (lookup != null && oldValue != null)
{
String[] values = ((String)oldValue).split("[,]");
List<ValueNamePair> selected = new ArrayList<>();
for (String key : values) {
if (!Util.isEmpty(key)) {
if (key.startsWith("\"") && key.endsWith("\"")) {
key = key.substring(1, key.length()-1);
}
String name = lookup.getDisplay(key);
ValueNamePair pair = new ValueNamePair(key, name);
selected.add(pair);
}
}
list = selected;
}
}
model.clear();
model.addAll(list);
}
public void onEvent(Event event)
{
if (Events.ON_SELECT.equalsIgnoreCase(event.getName()))
{
try {
onselecting = true;
Object newValue = getValueFromComponent();
if (isValueChange(newValue)) {
try {
if (gridField != null)
gridField.setLookupEditorSettingValue(true);
ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), oldValue, newValue);
super.fireValueChange(changeEvent);
oldValue = newValue;
} finally {
if (gridField != null)
gridField.setLookupEditorSettingValue(false);
}
}
} finally {
onselecting = false;
}
}
}
private boolean isValueChange(Object newValue) {
return (oldValue == null && newValue != null) || (oldValue != null && newValue == null)
|| ((oldValue != null && newValue != null) && !oldValue.equals(newValue));
}
public String[] getEvents()
{
return LISTENER_EVENTS;
}
public void actionRefresh()
{
if (lookup != null)
{
Object curValue = getValue();
if (isReadWrite())
refreshLookup();
else
updateModel();
if (curValue != null)
{
setValue(curValue);
}
}
}
public Lookup getLookup()
{
return lookup;
}
public void onMenu(ContextMenuEvent evt)
{
if (WEditorPopupMenu.REQUERY_EVENT.equals(evt.getContextEvent()))
{
actionRefresh();
}
else if (WEditorPopupMenu.PREFERENCE_EVENT.equals(evt.getContextEvent()))
{
if (isShowPreference())
ValuePreference.start (getComponent(), this.getGridField(), getValue());
return;
}
else if (WEditorPopupMenu.CHANGE_LOG_EVENT.equals(evt.getContextEvent()))
{
WFieldRecordInfo.start(gridField);
}
}
public void propertyChange(PropertyChangeEvent evt)
{
if ("FieldValue".equals(evt.getPropertyName()))
{
setValue(evt.getNewValue());
}
}
@Override
public void dynamicDisplay(Properties ctx)
{
if (lookup instanceof MLookup)
{
((MLookup) lookup).getLookupInfo().ctx = ctx;
}
if ((lookup != null) && (!lookup.isValidated() || !lookup.isLoaded()
|| (isReadWrite() && lookup.getSize() != getComponent().getModel().getSize())))
this.actionRefresh();
super.dynamicDisplay(ctx);
}
private void createCacheListener() {
if (lookup != null) {
String columnName = lookup.getColumnName();
int dotIndex = columnName.indexOf(".");
if (dotIndex > 0) {
String tableName = columnName.substring(0, dotIndex);
tableCacheListener = new CCacheListener(tableName, this);
}
}
}
private final static class ChosenboxEditor extends Chosenbox<ValueNamePair> {
/**
* generated serial id
*/
private static final long serialVersionUID = 7777300782255405327L;
private DesktopCleanup listener = null;
private WChosenboxListEditor editor = null;
protected ChosenboxEditor() {
}
public void setEnabled(boolean readWrite) {
setDisabled(readWrite==false);
}
public boolean isEnabled() {
return isDisabled() == false;
}
@Override
public void setPage(Page page) {
super.setPage(page);
}
@Override
public void onPageAttached(Page newpage, Page oldpage) {
super.onPageAttached(newpage, oldpage);
if (editor != null && editor.tableCacheListener == null) {
editor.createCacheListener();
if (listener == null) {
listener = new DesktopCleanup() {
@Override
public void cleanup(Desktop desktop) throws Exception {
ChosenboxEditor.this.cleanup();
}
};
newpage.getDesktop().addListener(listener);
}
}
}
@Override
public void onPageDetached(Page page) {
super.onPageDetached(page);
if (listener != null && page.getDesktop() != null)
page.getDesktop().removeListener(listener);
cleanup();
}
/**
*
*/
protected void cleanup() {
if (editor != null && editor.tableCacheListener != null) {
CacheMgt.get().unregister(editor.tableCacheListener);
editor.tableCacheListener = null;
}
}
}
private static class CCacheListener extends CCache<String, Object> {
/**
* generated serial
*/
private static final long serialVersionUID = 3543247404379028327L;
private WChosenboxListEditor editor;
protected CCacheListener(String tableName, WChosenboxListEditor editor) {
super(tableName, tableName, 0, true);
this.editor = editor;
}
@Override
public int reset() {
if (editor.getComponent().getDesktop() != null && editor.isReadWrite()) {
refreshLookupList();
}
return 0;
}
private void refreshLookupList() {
Executions.schedule(editor.getComponent().getDesktop(), new EventListener<Event>() {
@Override
public void onEvent(Event event) {
try {
if (editor.isReadWrite())
editor.actionRefresh();
} catch (Exception e) {}
}
}, new Event("onResetLookupList"));
}
@Override
public void newRecord(int record_ID) {
if (editor.getComponent().getDesktop() != null && editor.isReadWrite()) {
refreshLookupList();
}
}
}
}

View File

@ -0,0 +1,793 @@
/******************************************************************************
* Project: Trek Global ERP *
* Copyright (C) 2009-2018 Trek Global Corporation *
* 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.adempiere.webui.editor;
import java.beans.PropertyChangeEvent;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import org.adempiere.webui.ValuePreference;
import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.component.ChosenSearchBox;
import org.adempiere.webui.event.ContextMenuEvent;
import org.adempiere.webui.event.ContextMenuListener;
import org.adempiere.webui.event.DialogEvents;
import org.adempiere.webui.event.ValueChangeEvent;
import org.adempiere.webui.factory.InfoManager;
import org.adempiere.webui.panel.IHelpContext;
import org.adempiere.webui.panel.InfoPanel;
import org.adempiere.webui.part.WindowContainer;
import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.window.WFieldRecordInfo;
import org.compiere.model.GridField;
import org.compiere.model.Lookup;
import org.compiere.model.MLookup;
import org.compiere.model.MRole;
import org.compiere.model.X_AD_CtxHelp;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.ListSubModel;
/**
*
* @author hengsin
*
*/
public class WChosenboxSearchEditor extends WEditor implements ContextMenuListener
{
private static final String[] LISTENER_EVENTS = {Events.ON_CLICK, Events.ON_SELECT};
private Lookup lookup;
private String m_tableName = null;
private String m_keyColumnName = null;
private String columnName;
private String value;
private InfoPanel infoPanel = null;
private String imageUrl;
private MyListModel model = new MyListModel();
private static CLogger log = CLogger.getCLogger(WChosenboxSearchEditor.class);
private boolean onselecting;
public WChosenboxSearchEditor (GridField gridField)
{
super(new ChosenSearchBox(), gridField);
lookup = gridField.getLookup();
if (lookup != null)
columnName = lookup.getColumnName();
init();
}
@Override
public ChosenSearchBox getComponent() {
return (ChosenSearchBox) super.getComponent();
}
@Override
public boolean isReadWrite() {
return getComponent().isEnabled();
}
@Override
public void setReadWrite(boolean readWrite) {
getComponent().setEnabled(readWrite);
}
/**
* Constructor for use if a grid field is unavailable
*
* @param lookup Store of selectable data
* @param label column name (not displayed)
* @param description description of component
* @param mandatory whether a selection must be made
* @param readonly whether or not the editor is read only
* @param updateable whether the editor contents can be changed
*/
public WChosenboxSearchEditor (Lookup lookup, String label, String description, boolean mandatory, boolean readonly, boolean updateable)
{
super(new ChosenSearchBox(), label, description, mandatory, readonly, updateable);
if (lookup == null)
{
throw new IllegalArgumentException("Lookup cannot be null");
}
this.lookup = lookup;
columnName = lookup.getColumnName();
super.setColumnName(columnName);
init();
}
public WChosenboxSearchEditor(String columnName, boolean mandatory, boolean readonly, boolean updateable,
Lookup lookup)
{
super(new ChosenSearchBox(), null, null, mandatory, readonly, updateable);
if (lookup == null)
{
throw new IllegalArgumentException("Lookup cannot be null");
}
this.lookup = lookup;
this.columnName = columnName;
super.setColumnName(columnName);
init();
}
/**
* initialise editor
* @param columnName columnName
*/
private void init()
{
columnName = this.getColumnName();
imageUrl = ThemeManager.getThemeResource("images/PickOpen16.png");
if (lookup instanceof MLookup)
{
MLookup mlookup = (MLookup) lookup;
if ("C_BPartner_ID".equals(mlookup.getLookupInfo().KeyColumn))
{
imageUrl = ThemeManager.getThemeResource("images/BPartner16.png");
}
else if ("M_Product_ID".equals(mlookup.getLookupInfo().KeyColumn))
{
imageUrl = ThemeManager.getThemeResource("images/Product16.png");
}
}
popupMenu = new WEditorPopupMenu(false, true, isShowPreference(), false, false, false, lookup);
getComponent().getButton().setImage(imageUrl);
getComponent().getChosenbox().setModel(model);
addChangeLogMenu(popupMenu);
return;
}
@Override
public void setValue(Object value)
{
if (onselecting) {
return;
}
if (value != null && value instanceof String && !Util.isEmpty((String) value, true))
{
String[] values = ((String)value).split("[,]");
Set<ValueNamePair> selected = new LinkedHashSet<>();
for (String key : values) {
if (!Util.isEmpty(key)) {
if (key.startsWith("\"") && key.endsWith("\"")) {
key = key.substring(1, key.length()-1);
}
String name = lookup.getDisplay(key);
ValueNamePair pair = new ValueNamePair(key, name);
selected.add(pair);
}
}
model.clear();
model.addAll(selected);
getComponent().getChosenbox().setSelectedObjects(selected);
this.value = (String)value;
}
else
{
model.clear();
getComponent().getChosenbox().setSelectedObjects(new LinkedHashSet<ValueNamePair>());
this.value = null;
}
}
@Override
public Object getValue()
{
return value;
}
private String getValueFromComponent()
{
StringBuilder retVal = new StringBuilder();
LinkedHashSet<ValueNamePair> selected = getComponent().getChosenbox().getSelectedObjects();
if (selected != null && selected.size() > 0)
{
for(ValueNamePair pair : selected)
{
if (retVal.length() > 0)
retVal.append(",");
StringBuilder builder = new StringBuilder(pair.getValue());
if (builder.indexOf(",") >= 0)
{
builder.insert(0, "\"");
builder.append("\"");
}
retVal.append(builder.toString());
}
}
return retVal.length() > 0 ? retVal.toString() : null;
}
@Override
public String getDisplay()
{
StringBuilder display = new StringBuilder();
LinkedHashSet<ValueNamePair> selected = getComponent().getChosenbox().getSelectedObjects();
if (selected != null && selected.size() > 0)
{
for(ValueNamePair pair : selected)
{
if (display.length() > 0)
display.append(", ");
display.append(pair.getName());
}
}
return display.toString();
}
public void onEvent(Event e)
{
if (Events.ON_CLICK.equals(e.getName()))
{
if (infoPanel != null)
{
infoPanel.detach();
infoPanel = null;
}
actionButton();
}
else if (Events.ON_SELECT.equalsIgnoreCase(e.getName()))
{
try {
onselecting = true;
String newValue = getValueFromComponent();
if (isValueChange(newValue)) {
try {
if (gridField != null)
gridField.setLookupEditorSettingValue(true);
ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), value, newValue);
super.fireValueChange(changeEvent);
value = newValue;
} finally {
if (gridField != null)
gridField.setLookupEditorSettingValue(false);
}
}
} finally {
onselecting = false;
}
}
}
private boolean isValueChange(Object newValue) {
return (value == null && newValue != null) || (value != null && newValue == null)
|| ((value != null && newValue != null) && !value.equals(newValue));
}
@Override
public void propertyChange(PropertyChangeEvent evt)
{
if ("FieldValue".equals(evt.getPropertyName()))
{
setValue(evt.getNewValue());
}
}
public void onMenu(ContextMenuEvent evt)
{
if (WEditorPopupMenu.PREFERENCE_EVENT.equals(evt.getContextEvent()))
{
if (isShowPreference())
ValuePreference.start (getComponent(), this.getGridField(), getValue());
return;
}
else if (WEditorPopupMenu.CHANGE_LOG_EVENT.equals(evt.getContextEvent()))
{
WFieldRecordInfo.start(gridField);
}
}
private void processSelectedKeys (Object value)
{
if (log.isLoggable(Level.FINE))
log.fine("Value=" + value);
try
{
if (gridField != null)
gridField.setLookupEditorSettingValue(true);
String newValue = this.value;
if (newValue == null)
{
if (value instanceof Object[])
{
if (((Object[])value).length > 0)
{
StringBuilder builder = new StringBuilder();
for(Object obj : (Object[])value)
{
if (obj != null)
{
if (builder.length() > 0)
builder.append(",");
builder.append(obj.toString());
}
}
newValue = builder.toString();
}
}
else
{
newValue = value != null ? value.toString() : null;
}
}
else if (value != null)
{
if (value instanceof Object[])
{
if (((Object[])value).length > 0)
{
StringBuilder builder = new StringBuilder(newValue);
for(Object obj : (Object[])value)
{
if (obj != null)
{
if (builder.length() > 0)
builder.append(",");
builder.append(obj.toString());
}
}
newValue = builder.toString();
}
}
else
{
newValue = newValue + "," + value.toString();
}
}
fireValueChangeEvent(newValue);
// is the value updated ?
boolean updated = false;
if (newValue == null && getValue() == null) {
updated = true;
} else if (newValue != null && newValue.equals(getValue())) {
updated = true;
}
if (!updated)
{
setValue(newValue);
}
}
finally
{
if (gridField != null)
gridField.setLookupEditorSettingValue(false);
}
} // actionCombo
protected void fireValueChangeEvent(Object newValue) {
ValueChangeEvent evt = new ValueChangeEvent(this, this.getColumnName(), getValue(), newValue);
// -> ADTabpanel - valuechange
fireValueChange(evt);
}
private void actionButton()
{
if (lookup == null)
return; // leave button disabled
/**
* Three return options:
* - Value Selected & OK pressed => store result => result has value
* - Cancel pressed => store null => result == null && cancelled
* - Window closed -> ignore => result == null && !cancalled
*/
// Validation
String whereClause = getWhereClause();
if (m_tableName == null) // sets table name & key column
getDirectAccessSQL("*");
final InfoPanel ip = InfoManager.create(lookup, gridField, m_tableName, m_keyColumnName, null, false, whereClause);
if (ip != null)
showInfoPanel(ip);
}
protected void showInfoPanel(final InfoPanel ip) {
ip.setVisible(true);
ip.setStyle("border: 2px");
ip.setClosable(true);
infoPanel = ip;
ip.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener<Event>() {
@Override
public void onEvent(Event event) throws Exception {
Component component = SessionManager.getAppDesktop().getActiveWindow();
if (component instanceof IHelpContext)
Events.sendEvent(new Event(WindowContainer.ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT, component));
else
SessionManager.getAppDesktop().updateHelpContext(X_AD_CtxHelp.CTXTYPE_Home, 0);
boolean cancelled = ip.isCancelled();
Object[] result = ip.getSelectedKeys();
infoPanel = null;
// Result
if (!cancelled && result != null && result.length > 0)
{
//ensure data binding happen
if (result.length > 1)
processSelectedKeys (result);
else
processSelectedKeys (result[0]);
}
getComponent().getChosenbox().focus();
}
});
ip.setId(ip.getTitle()+"_"+ip.getWindowNo());
AEnv.showWindow(ip);
}
/**
* Generate Access SQL for Search.
* The SQL returns the ID of the value entered
* Also sets m_tableName and m_keyColumnName
* @param text uppercase text for LIKE comparison
* @return sql or ""
* Example
* SELECT C_Payment_ID FROM C_Payment WHERE UPPER(DocumentNo) LIKE x OR ...
*/
private String getDirectAccessSQL (String text)
{
String m_columnName = getColumnName();
StringBuffer sql = new StringBuffer();
m_tableName = m_columnName.substring(0, m_columnName.length()-3);
m_keyColumnName = m_columnName;
if (m_columnName.equals("M_Product_ID"))
{
// Reset
Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_Product_ID", "0");
Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_AttributeSetInstance_ID", "0");
Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_Locator_ID", "0");
sql.append("SELECT M_Product_ID FROM M_Product WHERE (UPPER(Value) LIKE ")
.append(DB.TO_STRING(text))
.append(" OR UPPER(Name) LIKE ").append(DB.TO_STRING(text))
.append(" OR UPC LIKE ").append(DB.TO_STRING(text)).append(")");
}
else if (m_columnName.equals("C_BPartner_ID"))
{
sql.append("SELECT C_BPartner_ID FROM C_BPartner WHERE (UPPER(Value) LIKE ")
.append(DB.TO_STRING(text))
.append(" OR UPPER(Name) LIKE ").append(DB.TO_STRING(text)).append(")");
}
else if (m_columnName.equals("C_Order_ID"))
{
sql.append("SELECT C_Order_ID FROM C_Order WHERE UPPER(DocumentNo) LIKE ")
.append(DB.TO_STRING(text));
}
else if (m_columnName.equals("C_Invoice_ID"))
{
sql.append("SELECT C_Invoice_ID FROM C_Invoice WHERE UPPER(DocumentNo) LIKE ")
.append(DB.TO_STRING(text));
}
else if (m_columnName.equals("M_InOut_ID"))
{
sql.append("SELECT M_InOut_ID FROM M_InOut WHERE UPPER(DocumentNo) LIKE ")
.append(DB.TO_STRING(text));
}
else if (m_columnName.equals("C_Payment_ID"))
{
sql.append("SELECT C_Payment_ID FROM C_Payment WHERE UPPER(DocumentNo) LIKE ")
.append(DB.TO_STRING(text));
}
else if (m_columnName.equals("GL_JournalBatch_ID"))
{
sql.append("SELECT GL_JournalBatch_ID FROM GL_JournalBatch WHERE UPPER(DocumentNo) LIKE ")
.append(DB.TO_STRING(text));
}
else if (m_columnName.equals("SalesRep_ID"))
{
sql.append("SELECT AD_User_ID FROM AD_User WHERE UPPER(Name) LIKE ")
.append(DB.TO_STRING(text));
m_tableName = "AD_User";
m_keyColumnName = "AD_User_ID";
}
// Predefined
if (sql.length() > 0)
{
String wc = getWhereClause();
if (wc != null && wc.length() > 0)
sql.append(" AND ").append(wc);
sql.append(" AND IsActive='Y'");
// ***
if (log.isLoggable(Level.FINEST)) log.finest(m_columnName + " (predefined) " + sql.toString());
return MRole.getDefault().addAccessSQL(sql.toString(),
m_tableName, MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
}
// Check if it is a Table Reference
if (lookup != null && lookup instanceof MLookup)
{
int AD_Reference_ID = ((MLookup)lookup).getAD_Reference_Value_ID();
if (AD_Reference_ID != 0)
{
boolean isValueDisplayed = false;
String query = "SELECT kc.ColumnName, dc.ColumnName, t.TableName, rt.IsValueDisplayed "
+ "FROM AD_Ref_Table rt"
+ " INNER JOIN AD_Column kc ON (rt.AD_Key=kc.AD_Column_ID)"
+ " INNER JOIN AD_Column dc ON (rt.AD_Display=dc.AD_Column_ID)"
+ " INNER JOIN AD_Table t ON (rt.AD_Table_ID=t.AD_Table_ID) "
+ "WHERE rt.AD_Reference_ID=?";
String displayColumnName = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(query, null);
pstmt.setInt(1, AD_Reference_ID);
rs = pstmt.executeQuery();
if (rs.next())
{
m_keyColumnName = rs.getString(1);
displayColumnName = rs.getString(2);
m_tableName = rs.getString(3);
String t = rs.getString(4);
isValueDisplayed = "Y".equalsIgnoreCase(t);
}
}
catch (Exception e)
{
log.log(Level.SEVERE, query, e);
}
finally
{
DB.close(rs, pstmt);
}
if (displayColumnName != null)
{
sql = new StringBuffer();
sql.append("SELECT ").append(m_keyColumnName)
.append(" FROM ").append(m_tableName)
.append(" WHERE (UPPER(").append(displayColumnName)
.append(") LIKE ").append(DB.TO_STRING(text));
if (isValueDisplayed)
{
sql.append(" OR UPPER(").append("Value")
.append(") LIKE ").append(DB.TO_STRING(text));
}
sql.append(")");
sql.append(" AND IsActive='Y'");
String wc = getWhereClause();
if (wc != null && wc.length() > 0)
sql.append(" AND ").append(wc);
// ***
if (log.isLoggable(Level.FINEST)) log.finest(m_columnName + " (Table) " + sql.toString());
return MRole.getDefault().addAccessSQL(sql.toString(),
m_tableName, MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
}
} // Table Reference
} // MLookup
/** Check Well Known Columns of Table - assumes TableDir **/
String query = "SELECT t.TableName, c.ColumnName "
+ "FROM AD_Column c "
+ " INNER JOIN AD_Table t ON (c.AD_Table_ID=t.AD_Table_ID AND t.IsView='N') "
+ "WHERE (c.ColumnName IN ('DocumentNo', 'Value', 'Name') OR c.IsIdentifier='Y')"
+ " AND c.AD_Reference_ID IN (10,14)"
+ " AND EXISTS (SELECT * FROM AD_Column cc WHERE cc.AD_Table_ID=t.AD_Table_ID"
+ " AND cc.IsKey='Y' AND cc.ColumnName=?)";
m_keyColumnName = m_columnName;
sql = new StringBuffer();
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(query, null);
pstmt.setString(1, m_keyColumnName);
rs = pstmt.executeQuery();
while (rs.next())
{
if (sql.length() != 0)
sql.append(" OR ");
m_tableName = rs.getString(1);
sql.append("UPPER(").append(rs.getString(2)).append(") LIKE ").append(DB.TO_STRING(text));
}
}
catch (SQLException ex)
{
log.log(Level.SEVERE, query, ex);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
//
if (sql.length() == 0)
{
log.log(Level.SEVERE, m_columnName + " (TableDir) - no standard/identifier columns");
return "";
}
//
StringBuffer retValue = new StringBuffer ("SELECT ")
.append(m_columnName).append(" FROM ").append(m_tableName)
.append(" WHERE ").append(sql)
.append(" AND IsActive='Y'");
String wc = getWhereClause();
if (wc != null && wc.length() > 0)
retValue.append(" AND ").append(wc);
// ***
if (log.isLoggable(Level.FINEST)) log.finest(m_columnName + " (TableDir) " + sql.toString());
return MRole.getDefault().addAccessSQL(retValue.toString(),
m_tableName, MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
}
private String getWhereClause()
{
String whereClause = "";
if (lookup == null)
return "";
String validation = lookup.getValidation();
if (validation == null)
validation = "";
if (whereClause.length() == 0)
whereClause = validation;
else if (validation.length() > 0)
whereClause += " AND " + validation;
if (whereClause.indexOf('@') != -1)
{
Properties ctx = lookup instanceof MLookup ? ((MLookup)lookup).getLookupInfo().ctx : Env.getCtx();
String validated = Env.parseContext(ctx, lookup.getWindowNo(), whereClause, false);
if (validated.length() == 0)
log.severe(getColumnName() + " - Cannot Parse=" + whereClause);
else
{
if (log.isLoggable(Level.FINE))
log.fine(getColumnName() + " - Parsed: " + validated);
return validated;
}
}
return whereClause;
} // getWhereClause
public String[] getEvents()
{
return LISTENER_EVENTS;
}
@Override
public void setTableEditor(boolean b) {
super.setTableEditor(b);
getComponent().setTableEditorMode(b);
}
public Lookup getLookup() {
return lookup;
}
@Override
public void dynamicDisplay(Properties ctx) {
if (lookup instanceof MLookup) {
((MLookup) lookup).getLookupInfo().ctx = ctx;
}
super.dynamicDisplay(ctx);
}
private class MyListModel extends ListModelList<ValueNamePair> implements ListSubModel<ValueNamePair> {
/**
*
*/
private static final long serialVersionUID = -1210525428410505409L;
@Override
public ListModel<ValueNamePair> getSubModel(Object value, int nRows) {
ListModelList<ValueNamePair> model = new ListModelList<>();
if (value != null && !Util.isEmpty(value.toString(), true)) {
String queryText = value.toString().trim();
if (m_tableName == null) // sets table name & key column
getDirectAccessSQL("*");
final InfoPanel ip = InfoManager.create(lookup, gridField, m_tableName, m_keyColumnName, queryText, false, getWhereClause());
if (ip != null && ip.loadedOK()) {
int rowCount = ip.getRowCount();
if (rowCount > 0) {
List<String> added = new ArrayList<String>();
for(int i = 0; i < rowCount; i++) {
Integer key = ip.getRowKeyAt(i);
if (key != null && key.intValue() > 0) {
String name = getLookup().getDisplay(key);
if (added.contains(name))
continue;
else
added.add(name);
ValueNamePair pair = new ValueNamePair(key.toString(), name);
model.add(pair);
if (added.size() == 50)
break;
}
}
}
}
}
getComponent().getChosenbox().setSubListModel(model);
return model;
}
}
}

View File

@ -18,6 +18,8 @@ import org.adempiere.webui.editor.WAssignmentEditor;
import org.adempiere.webui.editor.WBinaryEditor;
import org.adempiere.webui.editor.WButtonEditor;
import org.adempiere.webui.editor.WChartEditor;
import org.adempiere.webui.editor.WChosenboxListEditor;
import org.adempiere.webui.editor.WChosenboxSearchEditor;
import org.adempiere.webui.editor.WDashboardContentEditor;
import org.adempiere.webui.editor.WDateEditor;
import org.adempiere.webui.editor.WDatetimeEditor;
@ -209,6 +211,14 @@ public class DefaultEditorFactory implements IEditorFactory {
{
editor = new WGridTabMultiSelectionEditor(gridField, tableEditor);
}
else if (displayType == DisplayType.ChosenMultipleSelectionList || displayType == DisplayType.ChosenMultipleSelectionTable)
{
editor = new WChosenboxListEditor(gridField);
}
else if (displayType == DisplayType.ChosenMultipleSelectionSearch)
{
editor = new WChosenboxSearchEditor(gridField);
}
else
{
editor = new WUnknownEditor(gridField);

View File

@ -71,7 +71,6 @@ import org.compiere.model.AccessSqlParser.TableInfo;
import org.compiere.model.GridField;
import org.compiere.model.GridFieldVO;
import org.compiere.model.GridWindow;
import org.compiere.model.Lookup;
import org.compiere.model.MInfoColumn;
import org.compiere.model.MInfoWindow;
import org.compiere.model.MLookupFactory;
@ -874,7 +873,8 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
if (! colSQL.toUpperCase().contains(" AS "))
colSQL += " AS " + infoColumn.getColumnName();
editorMap.put(colSQL, editor);
ColumnInfo columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, KeyNamePair.class, (String)null, infoColumn.isReadOnly() || haveNotProcess);
Class<?> colClass = columnName.endsWith("_ID") ? KeyNamePair.class : String.class;
ColumnInfo columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, colClass, (String)null, infoColumn.isReadOnly() || haveNotProcess);
return columnInfo;
}
@ -946,33 +946,60 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
} else {
builder.append(checkAND.isChecked() ? " AND " : " OR ");
}
String columnClause = null;
if (mInfoColumn.getQueryFunction() != null && mInfoColumn.getQueryFunction().trim().length() > 0) {
String function = mInfoColumn.getQueryFunction();
if (function.indexOf("@") >= 0) {
String s = Env.parseContext(infoContext, p_WindowNo, function, true, false);
if (s.length() == 0) {
log.log(Level.SEVERE, "Failed to parse query function. " + function);
} else {
function = s;
}
if (mInfoColumn.getAD_Reference_ID() == DisplayType.ChosenMultipleSelectionList)
{
String pString = editor.getValue().toString();
String column = columnName;
if (column.indexOf(".") > 0)
column = column.substring(column.indexOf(".")+1);
int cnt = DB.getSQLValueEx(null, "SELECT Count(*) From AD_Column WHERE IsActive='Y' AND AD_Client_ID=0 AND Upper(ColumnName)=? AND AD_Reference_ID=?", column.toUpperCase(), DisplayType.ChosenMultipleSelectionList);
if (cnt > 0)
builder.append(DB.intersectClauseForCSV(columnName, pString));
else
builder.append(DB.inClauseForCSV(columnName, pString));
}
else if (mInfoColumn.getAD_Reference_ID() == DisplayType.ChosenMultipleSelectionTable || mInfoColumn.getAD_Reference_ID() == DisplayType.ChosenMultipleSelectionSearch)
{
String pString = editor.getValue().toString();
if (columnName.endsWith("_ID"))
{
builder.append(DB.inClauseForCSV(columnName, pString));
}
if (function.indexOf("?") >= 0) {
columnClause = function.replaceFirst("[?]", columnName);
} else {
columnClause = function+"("+columnName+")";
else
{
builder.append(DB.intersectClauseForCSV(columnName, pString));
}
} else {
columnClause = columnName;
}
builder.append(columnClause)
.append(" ")
.append(mInfoColumn.getQueryOperator());
if (columnClause.toUpperCase().startsWith("UPPER(")) {
builder.append(" UPPER(?)");
} else {
builder.append(" ?");
else
{
String columnClause = null;
if (mInfoColumn.getQueryFunction() != null && mInfoColumn.getQueryFunction().trim().length() > 0) {
String function = mInfoColumn.getQueryFunction();
if (function.indexOf("@") >= 0) {
String s = Env.parseContext(infoContext, p_WindowNo, function, true, false);
if (s.length() == 0) {
log.log(Level.SEVERE, "Failed to parse query function. " + function);
} else {
function = s;
}
}
if (function.indexOf("?") >= 0) {
columnClause = function.replaceFirst("[?]", columnName);
} else {
columnClause = function+"("+columnName+")";
}
} else {
columnClause = columnName;
}
builder.append(columnClause)
.append(" ")
.append(mInfoColumn.getQueryOperator());
if (columnClause.toUpperCase().startsWith("UPPER(")) {
builder.append(" UPPER(?)");
} else {
builder.append(" ?");
}
}
}
}
@ -1070,6 +1097,10 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
if (mInfoColumn == null || mInfoColumn.getSelectClause().equals("0")) {
continue;
}
if (mInfoColumn.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionList || mInfoColumn.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionSearch
|| mInfoColumn.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionTable) {
continue;
}
Object value = editor.getValue();
parameterIndex++;
prevParameterValues.add(value);

View File

@ -651,6 +651,14 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
else
{
value = rs.getString(colIndex);
if (! rs.wasNull()) {
WEditor editor = editorMap.get(p_layout[col].getColSQL());
if (editor != null && editor.getGridField() != null && editor.getGridField().isLookup())
{
editor.setValue(value);
value = editor.getDisplay();
}
}
}
data.add(value);
}
@ -2532,6 +2540,10 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
return contentPanel.getFirstRowKey();
}
public Integer getRowKeyAt(int row) {
return contentPanel.getRowKeyAt(row);
}
/**
* @return the cacheStart
*/

View File

@ -1701,6 +1701,15 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
}
m_query.addRestriction(getSubCategoryWhereClause(field, ((Integer) parsedValue).intValue()), and, openBrackets);
}
else if ((field.getDisplayType()==DisplayType.ChosenMultipleSelectionList||field.getDisplayType()==DisplayType.ChosenMultipleSelectionSearch||field.getDisplayType()==DisplayType.ChosenMultipleSelectionTable) &&
(MQuery.OPERATORS[MQuery.EQUAL_INDEX].getValue().equals(Operator) || MQuery.OPERATORS[MQuery.NOT_EQUAL_INDEX].getValue().equals(Operator)))
{
String clause = DB.intersectClauseForCSV(ColumnSQL, parsedValue.toString());
if (MQuery.OPERATORS[MQuery.EQUAL_INDEX].getValue().equals(Operator))
m_query.addRestriction(clause, and, openBrackets);
else
m_query.addRestriction("NOT (" + clause + ")", and, openBrackets);
}
else
m_query.addRestriction(ColumnSQL, Operator, parsedValue,
infoName, infoDisplay, and, openBrackets);
@ -1849,6 +1858,13 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
continue;
}
if (field.getDisplayType()==DisplayType.ChosenMultipleSelectionList||field.getDisplayType()==DisplayType.ChosenMultipleSelectionSearch||field.getDisplayType()==DisplayType.ChosenMultipleSelectionTable)
{
String clause = DB.intersectClauseForCSV(ColumnSQL.toString(), value.toString());
m_query.addRestriction(clause);
continue;
}
//
// Be more permissive for String columns
if (isSearchLike(field))

View File

@ -0,0 +1,899 @@
/******************************************************************************
* Project: Trek Global ERP *
*
* Chosenbox.java
Purpose:
Description:
History:
Tue Nov 16 15:15:52 TST 2011, Created by benbai
Copyright (C) 2011 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 3.0 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.addon.chosenbox;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.zkoss.lang.Objects;
import org.zkoss.xel.VariableResolver;
import org.zkoss.zk.au.out.AuSetAttribute;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlBasedComponent;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zk.ui.util.ForEachStatus;
import org.zkoss.zk.ui.util.Template;
import org.zkoss.zul.ItemRenderer;
import org.zkoss.zul.Label;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.ListSubModel;
import org.zkoss.zul.event.ListDataEvent;
import org.zkoss.zul.event.ListDataListener;
/**
* A ZK component like JQuery Chosen.
* <p>Default {@link #getZclass}: z-chosenbox.
* It does not create child widgets for each data, so the memory usage is much
* lower at the server.
* @author benbai
*
*/
public class Chosenbox<T> extends HtmlBasedComponent {
private static final String CHOSENBOX_PREPARE_DATA = "chosenbox.prepareData";
/**
* generated serial id
*/
private static final long serialVersionUID = 4501010016457525407L;
private List<Integer> _selIdxs = new ArrayList<>();
private String _name, _value = "";
private boolean _disabled;
private int _jsel = -1;
private int _tabindex;
private boolean _open;
private boolean _creatable;
private String _emptyMessage;
private String _noResultsText;
private String _createMessage;
private String _separator;
private transient ListModelList<T> _model;
private transient ListModel<T> _subListModel;
private transient ListDataListener _dataListener;
private transient EventListener<InputEvent> _eventListener;
private transient ItemRenderer<T> _renderer;
private transient boolean _childable;
private transient String[] _options;
private transient String[] _chgSel;
private long _onSelectTimestamp;
private long _onOkTimestamp;
static {
addClientEvent(Chosenbox.class, Events.ON_SELECT, CE_DUPLICATE_IGNORE | CE_IMPORTANT);
addClientEvent(Chosenbox.class, Events.ON_FOCUS, CE_DUPLICATE_IGNORE);
addClientEvent(Chosenbox.class, Events.ON_BLUR, CE_DUPLICATE_IGNORE);
addClientEvent(Chosenbox.class, Events.ON_OPEN, CE_IMPORTANT);
addClientEvent(Chosenbox.class, "onSearching", CE_DUPLICATE_IGNORE | CE_IMPORTANT);
addClientEvent(Chosenbox.class, "onSearch", CE_DUPLICATE_IGNORE | CE_IMPORTANT);
addClientEvent(Chosenbox.class, Events.ON_OK, CE_DUPLICATE_IGNORE | CE_IMPORTANT);
}
public Chosenbox() {
addEventListener("onOkTimer", e -> {
onOkTimer();
});
}
private void onOkTimer() {
if (_onSelectTimestamp==0 || _onOkTimestamp==0) {
postOnOk();
} else {
long diff = _onSelectTimestamp - _onOkTimestamp;
_onSelectTimestamp = _onOkTimestamp = 0;
if (diff < 0)
diff = diff * -1l;
if (diff > 500)
postOnOk();
}
}
private void postOnOk() {
Component p = getParent();
while (p != null) {
Iterable<EventListener<? extends Event>> iterable = p.getEventListeners(Events.ON_OK);
if (iterable.iterator().hasNext()) {
Events.postEvent(Events.ON_OK, p, null);
break;
} else {
p = p.getParent();
}
}
}
public String getZclass() {
return _zclass == null ? "z-chosenbox" : _zclass;
}
public void setOpen(boolean open) {
if (_open != open) {
_open = open;
smartUpdate("open", _open);
}
}
public boolean isOpen() {
return _open;
}
/**
* Returns the tab order of the input node of this component.
* <p>
* Default: 0 (means the same as browser's default).
*/
public int getTabindex() {
return _tabindex;
}
/**
* Sets the tab order of the input node of this component.
*/
public void setTabindex(int tabindex) throws WrongValueException {
if (_tabindex != tabindex) {
_tabindex = tabindex;
smartUpdate("tabindex", tabindex);
}
}
/**
* Returns whether it is disabled.
* <p>
* Default: false.
*/
public boolean isDisabled() {
return _disabled;
}
/**
* Sets whether it is disabled.
*/
public void setDisabled(boolean disabled) {
if (_disabled != disabled) {
_disabled = disabled;
smartUpdate("disabled", _disabled);
}
}
/**
* Returns the name of this component.
* <p>
* Default: null.
* <p>
* The name is used only to work with "legacy" Web application that handles
* user's request by servlets. It works only with HTTP/HTML-based browsers.
* It doesn't work with other kind of clients.
* <p>
* Don't use this method if your application is purely based on ZK's
* event-driven model.
*/
public String getName() {
return _name;
}
/**
* Sets the name of the input element of this component.
* <p>
* The name is used only to work with "legacy" Web application that handles
* user's request by servlets. It works only with HTTP/HTML-based browsers.
* It doesn't work with other kind of clients.
* <p>
* Don't use this method if your application is purely based on ZK's
* event-driven model.
*
* @param name
* the name of this component.
*/
public void setName(String name) {
if (name != null && name.length() == 0)
name = null;
if (!Objects.equals(_name, name)) {
_name = name;
smartUpdate("name", name);
}
}
/**
* Returns the emptyMessage of the input of this component.
* <p>
* Default: null.
* <p>
* The emptyMessage will be displayed in input if nothing selected and not focused.
* @return String
*/
public String getEmptyMessage() {
return _emptyMessage;
}
/**
* Sets the emptyMessage of the input of this component.
* <p>
* The emptyMessage will be displayed in input if nothing selected and not focused.
* @param String emptyMessage
* the emptyMessage of the input of this component.
*/
public void setEmptyMessage(String emptyMessage) {
if (emptyMessage != null && emptyMessage.length() == 0)
emptyMessage = null;
if (!Objects.equals(_emptyMessage, emptyMessage)) {
_emptyMessage = emptyMessage;
smartUpdate("emptyMessage", getEmptyMessage());
}
}
/**
* Returns the no-result text of this component.
* <p>
* Default: null.
* <p>
* The no-result text will be displayed in popup if nothing match to the input value and can not create either,
* the syntax "{0}" will be replaced with the input value at client side.
* @return String
*/
public String getNoResultsText() {
return _noResultsText;
}
/**
* Sets the no-result text of this component.
* <p>
* The no-result text will be displayed in popup if nothing match to the input value and can not create either,
* the syntax "{0}" will be replaced with the input value at client side.
* @param String noResultsText
* the no-result text of this component.
*/
public void setNoResultsText(String noResultsText) {
if (noResultsText != null && noResultsText.length() == 0)
noResultsText = null;
if (!Objects.equals(_noResultsText, noResultsText)) {
_noResultsText = noResultsText;
smartUpdate("noResultsText", getNoResultsText());
}
}
/**
* Returns the create message of this component.
* <p>
* Default: null.
* <p>
* The create message will be displayed in popup if nothing match to the input value but can create as new label,
* the syntax "{0}" will be replaced with the input value at client side.
* @return String
*/
public String getCreateMessage() {
return _createMessage;
}
/**
* Sets the create message of this component.
* <p>
* The create message will be displayed in popup if nothing match to the input value but can create as new label,
* the syntax "{0}" will be replaced with the input value at client side.
* @param String createMessage
* the create message of this component.
*/
public void setCreateMessage(String createMessage) {
if (createMessage != null && createMessage.length() == 0)
createMessage = null;
if (!Objects.equals(_createMessage, createMessage)) {
_createMessage = createMessage;
smartUpdate("createMessage", getCreateMessage());
}
}
/**
* Returns the separate chars of this component.
* <p>
* Support: 0-9, A-Z (case insensitive), and ,.;'[]/\-=
* <p>
* Default: null.
* <p>
* The separate chars will work as 'Enter' key,
* it will not considered as input value but send onSerch or onSearching while key up.
* @return String
*/
public String getSeparator() {
return _separator;
}
/**
* Sets the separate chars of this component.
* <p>
* Support: 0-9, A-Z (case insensitive), and ,.;'[]/\-=
* <p>
* The separate chars will work as 'Enter' key,
* it will not considered as input value but send onSerch or onSelect while key up.
* @param String createMessage
* the create message of this component.
*/
public void setSeparator(String separator) {
if (separator != null && separator.length() == 0)
separator = null;
if (!Objects.equals(_separator, separator)) {
_separator = separator;
smartUpdate("separator", getSeparator());
}
}
/**
* Returns the selected objects.
* @return Set
*/
public LinkedHashSet<T> getSelectedObjects () {
final LinkedHashSet<T> objects = new LinkedHashSet<>();
ListModel<T> model = this.getModel();
if (model != null) {
for (int i = 0; i < _selIdxs.size(); i ++) {
objects.add(model.getElementAt(_selIdxs.get(i)));
}
}
return objects;
}
/**
* Sets the selected objects.
* It will clear selection first.
* @param List objects
* the objects to select.
*/
public void setSelectedObjects (Set<T> objects) {
// do nothing if no model
if (getModel() != null) {
_selIdxs.clear();
ListModel<T> lm = getModel();
boolean found = false;
for (T object : objects) {
for (int i = 0; i < lm.getSize(); i++) {
if (lm.getElementAt(i).equals(object)) {
if (_jsel == -1 || _jsel > i)
_jsel = i;
found = true;
_selIdxs.add(i);
break;
}
}
if (!found) {
if (Logger.getLogger(getClass().getName()).isLoggable(Level.INFO))
Logger.getLogger(getClass().getName()).info("No such item: " + object);
}
found = false;
}
smartUpdate("chgSel", getChgSel());
}
}
/**
* Returns the index of the selected item (-1 if no one is selected).
* @return int
*/
public int getSelectedIndex() {
return _jsel;
}
/**
* Sets the index of the selected item (-1 if no one is selected).
* It will clear selection first.
* @param int index
* the index to select.
*/
public void setSelectedIndex(int jsel) {
if (jsel <= -1)
jsel = -1;
if (jsel < 0) { // unselect all
clearSelection();
} else if (jsel != _jsel || _selIdxs.size() > 1) {
if (_selIdxs.size() > 1 && jsel == _jsel) {
// clear client side old value
smartUpdate("selectedIndex", -1);
}
// check size
if (getModel() != null && jsel >= getModel().getSize()) {
throw new UiException("Out of bound: " + jsel + " while size="
+ getModel().getSize());
}
_selIdxs.clear();
_jsel = jsel;
_selIdxs.add(jsel);
smartUpdate("chgSel", getChgSel());
}
}
/**
* Returns whether can create new item.
* <p>
* Default: false.
* <p>
* true: will show create message while value of input not exists.
* <p>
* false: will show no result message while value of input not exists.
*/
public boolean isCreatable() {
return _creatable;
}
/**
* Sets whether can create new item.
* <p>
* Default: false.
* <p>
* true: will show create message while value of input not exists.
* <p>
* false: will show no-result text while value of input not exists.
*
* @param creatable
* the boolean value.
*/
public void setCreatable(boolean creatable) {
if (_creatable != creatable) {
_creatable = creatable;
smartUpdate("creatable", _creatable);
}
}
public ItemRenderer<T> getRealRenderer() {
final ItemRenderer<T> renderer = getItemRenderer();
return renderer != null ? renderer : _defRend;
}
/**
* Returns the renderer to render each item, or null if the default renderer
* is used.
*/
public ItemRenderer<T> getItemRenderer() {
return _renderer;
}
/**
* Returns the model associated with this chosenbox, or null if this
* chosenbox is not associated with any list data model.
*/
public ListModel<T> getModel() {
return _model;
}
/**
* Sets the list model associated with this chosenbox. If a non-null model
* is assigned, no matter whether it is the same as the previous, it will
* always cause re-render.
*
* @param model
* the list model to associate, or null to dis-associate any
* previous model.
* @exception UiException
* if failed to initialize with the model
*/
public void setModel(ListModelList<T> model) {
if (model != null) {
if (_model != model) {
// fix selected index
if (getSelectedIndex() >= model.getSize())
setSelectedIndex(model.getSize()-1);
if (_model != null) {
_model.removeListDataListener(_dataListener);
}
_model = model;
initDataListener();
}
} else if (_model != null) {
_model.removeListDataListener(_dataListener);
if (_model instanceof ListSubModel)
removeEventListener("onSearching", _eventListener);
_model = null;
}
fixIndexs(true, null);
smartUpdate("renderByServer", _model instanceof ListSubModel);
updateItems();
}
/**
* Clear all selected objects.
*/
public void clearSelection() {
_selIdxs.clear();
_jsel = -1;
smartUpdate("chgSel", getChgSel());
}
/**
* Add an item into selection.
* @param o
* the object to add.
*/
public void addItemToSelection(Object o) {
// do nothing if no model
if (getModel() != null) {
ListModel<T> lm = getModel();
for (int i = 0;i < lm.getSize();i ++) {
if (lm.getElementAt(i).equals(o)) {
_selIdxs.add(i);
if (i < _jsel)
_jsel = i;
smartUpdate("chgSel", getChgSel());
}
}
}
}
/**
* Remove an item from selection.
* @param o
* the object to remove.
*/
public void removeItemFromSelection(Object o) {
// do nothing if no model
if (getModel() != null) {
ListModel<T> lm = getModel();
for (int i = 0;i < lm.getSize();i ++) {
if (lm.getElementAt(i).equals(o)) {
int cur = -1, min = -1;
for (int j = 0; j < _selIdxs.size(); j++) {
if (i == _selIdxs.get(j).intValue()) {
cur = j;
} else if (min == -1 || _selIdxs.get(j).intValue() < min) {
min = _selIdxs.get(j).intValue();
}
}
if (cur != -1) {
_jsel = min;
_selIdxs.remove(cur);
smartUpdate("chgSel", getChgSel());
}
break;
}
}
}
}
private String[] getChgSel() {
prepareItems(null, true, _model);
if (_options != null) {
String [] chgSel = _options;
_options = null;
return chgSel;
}
return new String[0];
}
protected boolean isChildable() {
return _childable;
}
private void prepareData() {
if (getAttribute(CHOSENBOX_PREPARE_DATA) != null)
return;
if (_selIdxs.size() > 0)
_chgSel = getChgSel();
if (!(_model instanceof ListSubModel))
prepareItems(null, false, _model);
setAttribute(CHOSENBOX_PREPARE_DATA, Boolean.TRUE);
}
// fix selected indexes while model changed or replaced
private void fixIndexs(boolean modelReplaced, ListDataEvent event) {
// model instance is changed
if (modelReplaced) {
if (_model == null) {
clearSelection();
} else {
// remove the out of range indexes
Iterator<Integer>it = _selIdxs.iterator();
while (it.hasNext()) {
if (it.next() >= _model.getSize()) {
it.remove();
}
}
}
} else {
int pos0 = event.getIndex0();
int pos1 = event.getIndex1();
int amount = pos1 - pos0 + 1;
switch (event.getType()) {
case ListDataEvent.INTERVAL_ADDED:
for (int i = 0; i < _selIdxs.size(); i++) {
if (_selIdxs.get(i) >= pos0)
_selIdxs.set(i, _selIdxs.get(i) + amount);
}
break;
case ListDataEvent.INTERVAL_REMOVED:
for(ListIterator<Integer> lit = _selIdxs.listIterator(); lit.hasNext();) {
Integer i = lit.next();
if (i > pos1)
lit.set(i - amount);
else if (i >= pos0)
lit.remove();
}
break;
}
}
}
/**
* prepare the list content or selected items to render,
* @param prefix
* Only add the item starts with it if it is not null.
* @param excludeUnselected
* Only add selected item, with select order.
* @param model
* the model to render.
*/
private void prepareItems(String prefix, boolean excludeUnselected, ListModel<T> model) {
if (model != null) {
List<String> optList = new ArrayList<String>();
final boolean old = _childable;
try {
_childable = true;
final ItemRenderer<T> renderer = getRealRenderer();
// order by _selIdxs content if only prepare selected items
if (excludeUnselected) {
for (int i = 0; i < _selIdxs.size(); i++) {
String s = renderer.render(this, model.getElementAt(_selIdxs.get(i)), _selIdxs.get(i));
if (prefix == null || s.toLowerCase().startsWith(prefix.toLowerCase()))
optList.add(s);
}
} else {
for (int i = 0; i < model.getSize(); i++) {
String s = renderer.render(this, model.getElementAt(i), i);
if (prefix == null || s.toLowerCase().startsWith(prefix.toLowerCase()))
optList.add(s);
}
}
if (optList.size() > 0)
_options = optList.toArray(new String[0]);
} catch (Exception e) {
throw UiException.Aide.wrap(e);
} finally {
//clear possible children created in renderer
_childable = old;
getChildren().clear();
}
}
}
private void updateItems() {
prepareItems(null, false, _model);
if (_options != null) {
smartUpdate("items", _options);
_options = null; //purge the data
}
smartUpdate("chgSel", getChgSel());
}
private void updateListContent(String prefix, ListModel<T> subModel) {
if (!(_model instanceof ListSubModel))
prepareItems(null, false, subModel);
else
prepareItems(prefix, false, subModel);
if (_options != null) {
smartUpdate("listContent", _options);
_options = null; //purge the data
} else
smartUpdate("listContent", new String[0]);
}
private void initDataListener() {
if (_dataListener == null)
_dataListener = new ListDataListener() {
public void onChange(ListDataEvent event) {
fixIndexs(false, event);
updateItems();
}
};
if (_eventListener == null)
_eventListener = new EventListener<InputEvent>() {
@SuppressWarnings("unchecked")
public void onEvent(InputEvent event) throws Exception {
if (getModel() instanceof ListSubModel) {
updateListContent(null, ((ListSubModel<T>)_model).getSubModel(event.getValue(), _model.getSize()));
}
}
};
_model.addListDataListener(_dataListener);
if (_model instanceof ListSubModel)
addEventListener("onSearching", _eventListener);
}
private Integer getIndexFromValue(String value, boolean checkSubList) {
for (int i = 0; i < _model.getSize(); i++) {
if (value.equals(_model.getElementAt(i).toString()))
return Integer.valueOf(i);
}
if (checkSubList && _subListModel != null) {
for (int i = 0; i < _subListModel.getSize(); i++) {
if (value.equals(_subListModel.getElementAt(i).toString())) {
_model.add(_subListModel.getElementAt(i));
return Integer.valueOf(_model.getSize()-1);
}
}
}
throw new UiException("No such item: " + value);
}
// -- ComponentCtrl --//
public void invalidate() {
prepareData();
super.invalidate();
}
protected void renderProperties(org.zkoss.zk.ui.sys.ContentRenderer renderer)
throws IOException {
super.renderProperties(renderer);
prepareData();
removeAttribute(CHOSENBOX_PREPARE_DATA);
if (_options != null) {
render(renderer, "items", _options);
_options = null; //purge the data
} else {
render(renderer, "items", new String[0]);
}
if (_chgSel != null) {
render(renderer, "chgSel", _chgSel);
_chgSel = null; //purge the data
} else {
render(renderer, "chgSel", new String[0]);
}
render(renderer, "name", _name);
render(renderer, "disabled", isDisabled());
if (_tabindex != 0)
renderer.render("tabindex", _tabindex);
render(renderer, "emptyMessage", getEmptyMessage());
render(renderer, "noResultsText", getNoResultsText());
render(renderer, "separator", getSeparator());
render(renderer, "createMessage", getCreateMessage());
renderer.render("selectedIndex", _jsel);
renderer.render("creatable", _creatable);
renderer.render("renderByServer", _model instanceof ListSubModel);
render(renderer, "open", _open);
//maintain selected items for listsubmodel/renderbyserver
if (_model instanceof ListSubModel && _selIdxs.size() > 0) {
prepareItems(null, true, _model);
if (_options != null && _options.length > 0) {
response("listContent", new AuSetAttribute(this, "listContent", _options));
response("chgSel", new AuSetAttribute(this, "chgSel", _options));
_options = null; //purge the data
}
}
}
public void service(org.zkoss.zk.au.AuRequest request, boolean everError) {
final String cmd = request.getCommand();
if (cmd.equals(Events.ON_SELECT)) {
List<?> selItems = (List<?>)request.getData().get("");
// clear at first
_selIdxs.clear();
_jsel = -1;
for (int i = 0; i < selItems.size(); i++) {
int idx = getIndexFromValue(selItems.get(i).toString(), true);
_selIdxs.add(idx);
if (idx < _jsel || _jsel == -1)
_jsel = idx;
}
final Integer index = getSelectedIndex();
final Set<T> objects = getSelectedObjects();
Events.postEvent(new SelectEvent<Component, T>(Events.ON_SELECT, this, null, null, null,
objects, null, null, null, index, 0));
_onSelectTimestamp = System.currentTimeMillis();
} else if (cmd.equals(Events.ON_OPEN)) {
_open = (Boolean)request.getData().get("open");
Events.postEvent(OpenEvent.getOpenEvent(request));
} else if (cmd.equals("onSearch")) {
Events.postEvent(new Event("onSearch", this, ((List<?>)request.getData().get("")).get(0).toString()));
} else if (cmd.equals("onSearching")) {
Object data = ((List<?>)request.getData().get("")).get(0);
Events.postEvent(new InputEvent(cmd, this, (String)data, _value));
_value = (String)data;
} else if (cmd.equals(Events.ON_OK)) {
_onOkTimestamp = System.currentTimeMillis();
Clients.evalJavaScript("setTimeout(function(){zAu.send(new zk.Event(zk.Widget.$('#"
+ getUuid() + "'), 'onOkTimer', null));}, 100);");
} else if (cmd.equals("onOkTimer")) {
Events.postEvent("onOkTimer", this, null);
}
}
public ListModel<T> getSubListModel() {
return _subListModel;
}
public void setSubListModel(ListModel<T> _subListModel) {
this._subListModel = _subListModel;
}
private final ItemRenderer<T> _defRend = new ItemRenderer<T>() {
public String render(final Component owner, final T data, final int index) {
final Chosenbox<?> self = (Chosenbox<?>) owner;
final Template tm = self.getTemplate("model");
if (tm == null)
return Objects.toString(data);
else {
final Component[] items = tm.create(owner, null,
new VariableResolver() {
public Object resolveVariable(String name) {
if ("each".equals(name)) {
return data;
} else if ("forEachStatus".equals(name)) {
return new ForEachStatus() {
public ForEachStatus getPrevious() {
return null;
}
public Object getEach() {
return data;
}
public int getIndex() {
return index;
}
public Integer getBegin() {
return 0;
}
public Integer getEnd() {
return ((Chosenbox<?>)owner).getModel().getSize();
}
public boolean isFirst() {
return index == 0;
}
public boolean isLast() {
return (index+1) == ((Chosenbox<?>)owner).getModel().getSize();
}
public int getCount() {
return index+1;
}
public Object getCurrent() {
return data;
}
public Integer getStep() {
return Integer.valueOf(1);
}
};
} else {
return null;
}
}
}, null);
if (items.length != 1)
throw new UiException(
"The model template must have exactly one item, not "
+ items.length);
if (!(items[0] instanceof Label))
throw new UiException(
"The model template can only support Label component, not "
+ items[0]);
items[0].detach(); //remove the label from owner
return ((Label) items[0]).getValue();
}
}
};
}

View File

@ -0,0 +1,28 @@
/* Chosenbox.java
Purpose:
Description:
History:
Tue Nov 16 15:15:52 TST 2011, Created by benbai
Copyright (C) 2011 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 3.0 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.addon.chosenbox;
/**
* Specified this in lang.xml, such that ZK knows what lang-addon.xml is associated
* with chosenbox.
*
*/
public class Version {
/** Returns the version UID.
*/
public static final String UID = "1.0.0";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
<%@ taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" %>
.z-chosenbox {
background-color: #FFF;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #EEEEEE));
background-image: -webkit-linear-gradient(center bottom, white 85%, #EEEEEE 99%);
background-image: -moz-linear-gradient(center bottom, white 85%, #EEEEEE 99%);
background-image: -o-linear-gradient(bottom, white 85%, #EEEEEE 99%);
background-image: -ms-linear-gradient(top, #FFFFFF 85%,#EEEEEE 99%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#EEEEEE',GradientType=0 );
background-image: linear-gradient(top, #FFFFFF 85%,#EEEEEE 99%);
display:-moz-inline-box;
display: inline-block;
vertical-align: middle;
overflow: hidden;
<c:if test="${zk.ie < 8}">
zoom: 1;
display: inline;
</c:if>
border: 1px solid #cfcfcf;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-o-border-radius: 3px;
-ms-border-radius: 3px;
border-radius: 3px;
margin: 0;
padding: 2px 5px;
line-height: 14px;
}
.z-chosenbox-focus {
border: 1px solid #0000ff;
}
.z-chosenbox-sel {
padding-bottom: 3px;
}
.z-chosenbox-sel-item {
-webkit-border-radius: 3px;
-moz-border-radius : 3px;
border-radius : 3px;
-moz-background-clip : padding;
-webkit-background-clip: padding-box;
background-clip : padding-box;
background-color: #E4E4E4;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #E4E4E4), color-stop(0.7, #EEEEEE));
background-image: -webkit-linear-gradient(center bottom, #E4E4E4 0%, #EEEEEE 70%);
background-image: -moz-linear-gradient(center bottom, #E4E4E4 0%, #EEEEEE 70%);
background-image: -o-linear-gradient(bottom, #E4E4E4 0%, #EEEEEE 70%);
background-image: -ms-linear-gradient(top, #E4E4E4 0%,#EEEEEE 70%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#E4E4E4', endColorstr='#EEEEEE',GradientType=0 );
background-image: linear-gradient(top, #E4E4E4 0%,#EEEEEE 70%);
color: #333;
border: 1px solid #B4B4B4;
margin: 0px 0px 0px 4px;
white-space: nowrap;
display: inline-block;
<c:if test="${zk.ie < 8}">
display: inline;
zoom: 1;
</c:if>
font-size: ${fontSizeM};
font-family: ${fontFamilyC};
font-style: normal;
padding-bottom: 0px;
vertical-align: middle;
}
.z-chosenbox-sel-item-cnt {
font-size: 13px;
font-family: 'lucida grande',tahoma,verdana,arial,sans-serif;
padding: 0px 2px;
display: inline-block;
<c:if test="${zk.ie < 8}">
display: inline;
</c:if>
font-size: ${fontSizeM};
font-family: ${fontFamilyC};
}
.z-chosenbox-sel-item-focus {
background: #D4D4D4;
border-color: #FED700;
}
.z-chosenbox-del-btn {
width: 12px;
height: 13px;
font-size: 1px;
background: url(${c:encodeURL('~./chosenbox/img/chosen-sprite.png')}) right top no-repeat;
border: 1px solid #CCCCCC;
display: inline-block;
<c:if test="${zk.ie < 8}">
display: inline;
background: url(${c:encodeURL('~./chosenbox/img/chosen-del.gif')}) no-repeat;
zoom: 1;
</c:if>
}
.z-chosenbox-inp {
color: #666;
background: transparent !important;
border: 0 !important;
outline: 0;
-webkit-box-shadow: none;
-moz-box-shadow : none;
-o-box-shadow : none;
box-shadow : none;
padding: 3px 5px 3px 5px;
display: inline-block;
width: 30px;
<c:if test="${zk.ie < 8}">
display: inline;
</c:if>
font-size: ${fontSizeM};
font-family: ${fontFamilyC};
}
.z-chosenbox-txcnt {
display: none;
font-size: ${fontSizeM};
font-family: ${fontFamilyC};
white-space: nowrap;
}
.z-chosenbox-pp {
position: absolute;
background-color: #FFFFFF;
border: 1px solid #CCCCCC;
border-top: 0;
font-family: ${fontFamilyC};
font-size: ${fontSizeM};
font-weight: normal;
margin:0;
overflow:auto;
-webkit-box-shadow: 0 4px 5px rgba(0,0,0,.15);
-moz-box-shadow : 0 4px 5px rgba(0,0,0,.15);
-o-box-shadow : 0 4px 5px rgba(0,0,0,.15);
box-shadow : 0 4px 5px rgba(0,0,0,.15);
}
.z-chosenbox-pp-hidden {
display: none;
}
.z-chosenbox-option {
cursor: pointer;
padding-top: 3px;
padding-left: 10px;
}
.z-chosenbox-option-over {
background-color: #D3EFFA;
}
.z-chosenbox-empty {
padding: 3px;
padding-left: 10px;
}
.z-chosenbox-empty-creatable {
cursor: pointer;
background-color: #D3EFFA;
}

View File

@ -0,0 +1,28 @@
/* chosenbox.js
Purpose:
Description:
History:
Tue Nov 16 15:15:52 TST 2011, Created by benbai
Copyright (C) 2011 Potix Corporation. All Rights Reserved.
This program is distributed under LGPL Version 3.0 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
*/
function (out) {
var zcls = this.getZclass(),
uid = this.uuid;
out.push('<i id="', uid, '" class="',zcls,'"', (!this.isVisible() ? 'style="display:none;"' : ''), '>',
'<input id="', uid, '-inp" class="',zcls,'-inp"', this.domAttrs_(), '></input>',
'<div id="', uid, '-txcnt" class="',zcls,'-txcnt"></div>', // hidden field for change input width dynamically
'<div id="', uid, '-pp" class="',zcls,'-pp ', zcls,'-pp-hidden">',
'<div id="', uid, '-sel" class="',zcls,'-sel">');
if (!this._renderByServer)
this._renderItems(out);
out.push('</div>',
'<div id="', uid, '-empty" class="',zcls,'-empty"></div>','</div></i>');
}

View File

@ -0,0 +1,3 @@
<package name="chosenbox" language="xul/html" depends="zul.wgt">
<widget name="Chosenbox"/>
</package>

View File

@ -1420,5 +1420,33 @@ public class DB_Oracle implements AdempiereDatabase
if (toIndex == -1)
return info;
return info.substring(fromIndex + 1, toIndex);
}
@Override
public String subsetClauseForCSV(String columnName, String csv) {
StringBuilder builder = new StringBuilder();
builder.append("toTableOfVarchar2(")
.append(columnName)
.append(")");
builder.append(" submultiset of ")
.append("toTableOfVarchar2('")
.append(csv)
.append("')");
return builder.toString();
}
@Override
public String intersectClauseForCSV(String columnName, String csv) {
StringBuilder builder = new StringBuilder();
builder.append("toTableOfVarchar2(")
.append(columnName)
.append(")");
builder.append(" MULTISET INTERSECT ")
.append("toTableOfVarchar2('")
.append(csv)
.append("') IS NOT EMPTY");
return builder.toString();
}
} // DB_Oracle

View File

@ -1145,4 +1145,32 @@ public class DB_PostgreSQL implements AdempiereDatabase
return info;
return info.substring(fromIndex + 1, toIndex);
}
@Override
public String subsetClauseForCSV(String columnName, String csv) {
StringBuilder builder = new StringBuilder();
builder.append("string_to_array(")
.append(columnName)
.append(",',')");
builder.append(" <@ "); //is contained by
builder.append("string_to_array('")
.append(csv)
.append("',',')");
return builder.toString();
}
@Override
public String intersectClauseForCSV(String columnName, String csv) {
StringBuilder builder = new StringBuilder();
builder.append("string_to_array(")
.append(columnName)
.append(",',')");
builder.append(" && "); //is contained by
builder.append("string_to_array('")
.append(csv)
.append("',',')");
return builder.toString();
}
} // DB_PostgreSQL