diff --git a/migration/iD10/oracle/202211091000_IDEMPIERE-3334.sql b/migration/iD10/oracle/202211091000_IDEMPIERE-3334.sql
new file mode 100644
index 0000000000..0cf987f266
--- /dev/null
+++ b/migration/iD10/oracle/202211091000_IDEMPIERE-3334.sql
@@ -0,0 +1,99 @@
+SET SQLBLANKLINES ON
+SET DEFINE OFF
+
+-- IDEMPIERE-3334 Adding support for Readonly Logic, Set Pressed Logic on custom toolbar button
+-- Apr 7, 2017 9:46:15 AM IST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,Help,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure) VALUES (212976,0,'Read Only Logic','Logic to determine if field is read only (applies only when field is read-write)','format := {expression} [{logic} {expression}]
+expression := @{context}@{operand}{value} or @{context}@{operand}{value}
+logic := {|}|{&}
+context := any global or window context
+value := strings or numbers
+logic operators := AND or OR with the previous result from left to right
+operand := eq{=}, gt{>}, le{<}, not{~^!}
+Examples:
+
+- @AD_Table_ID@=14 | @Language@!GERGER
+- @PriceLimit@>10 | @PriceList@>@PriceActual@
+- @Name@>J
+
+Strings may be in single quotes (optional)',200003,'ReadOnlyLogic',2000,'N','N','N','N','N',0,'N',14,0,0,'Y',TO_DATE('2017-04-07 09:46:14','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2017-04-07 09:46:14','YYYY-MM-DD HH24:MI:SS'),100,1663,'Y','N','D','N','N','N','Y','2c970c5d-b093-4b8a-b7df-da5260cb3afc','Y',0,'N','N')
+;
+
+-- Apr 7, 2017 9:46:25 AM IST
+ALTER TABLE AD_ToolBarButton ADD ReadOnlyLogic VARCHAR2(2000 CHAR) DEFAULT NULL
+;
+
+-- Apr 7, 2017 9:47:37 AM IST
+INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,PrintName,EntityType,AD_Element_UU) VALUES (203068,0,0,'Y',TO_DATE('2017-04-07 09:47:36','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2017-04-07 09:47:36','YYYY-MM-DD HH24:MI:SS'),100,'PressedLogic','Pressed Logic','Pressed Logic','D','3e4c5b2b-2b91-400f-8e18-fd1aee4627ff')
+;
+
+-- Apr 7, 2017 9:47:52 AM IST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure) VALUES (212977,0,'Pressed Logic',200003,'PressedLogic',2000,'N','N','N','N','N',0,'N',14,0,0,'Y',TO_DATE('2017-04-07 09:47:51','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2017-04-07 09:47:51','YYYY-MM-DD HH24:MI:SS'),100,203068,'Y','N','D','N','N','N','Y','e7df64af-a5db-4469-9620-d1008f2b6ae6','Y',0,'N','N')
+;
+
+-- Apr 7, 2017 9:47:53 AM IST
+ALTER TABLE AD_ToolBarButton ADD PressedLogic VARCHAR2(2000 CHAR) DEFAULT NULL
+;
+
+-- Apr 7, 2017 9:48:42 AM IST
+INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLogic,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField) VALUES (204384,'Pressed Logic',200002,212977,'Y','@IsCustomization@=Y',0,130,0,'N','N','N','N',0,0,'Y',TO_DATE('2017-04-07 09:48:40','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2017-04-07 09:48:40','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','fe0b2b2f-8f24-46d9-b497-c7fdbc6df87e','Y',130,1,1,1,'N','N','N')
+;
+
+-- Apr 7, 2017 9:49:03 AM IST
+INSERT INTO AD_Field (AD_Field_ID,Name,Description,Help,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLogic,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField) VALUES (204385,'Read Only Logic','Logic to determine if field is read only (applies only when field is read-write)','format := {expression} [{logic} {expression}]
+expression := @{context}@{operand}{value} or @{context}@{operand}{value}
+logic := {|}|{&}
+context := any global or window context
+value := strings or numbers
+logic operators := AND or OR with the previous result from left to right
+operand := eq{=}, gt{>}, le{<}, not{~^!}
+Examples:
+
+- @AD_Table_ID@=14 | @Language@!GERGER
+- @PriceLimit@>10 | @PriceList@>@PriceActual@
+- @Name@>J
+
+Strings may be in single quotes (optional)',200002,212976,'Y','@IsCustomization@=Y',0,140,0,'N','N','N','N',0,0,'Y',TO_DATE('2017-04-07 09:49:00','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2017-04-07 09:49:00','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','d721042e-1aa8-4c00-8c8c-615b7202bc7a','Y',140,1,1,1,'N','N','N')
+;
+
+-- Apr 7, 2017 9:49:33 AM IST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=110, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=1, ColumnSpan=5, NumLines=3, IsToolbarButton=NULL,Updated=TO_DATE('2017-04-07 09:49:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204384
+;
+
+-- Apr 7, 2017 9:49:33 AM IST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=120, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=1, ColumnSpan=5, NumLines=3, IsToolbarButton=NULL,Updated=TO_DATE('2017-04-07 09:49:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204385
+;
+
+-- Apr 7, 2017 9:49:33 AM IST
+UPDATE AD_Field SET SeqNo=130, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2017-04-07 09:49:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=202546
+;
+
+-- Apr 7, 2017 9:49:33 AM IST
+UPDATE AD_Field SET SeqNo=140, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2017-04-07 09:49:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=202547
+;
+
+
+-- Nov 17, 2022, 4:48:50 PM IST
+INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm,DisplayLogic) VALUES (207419,'Pressed Logic',200028,212977,'Y',0,110,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-11-17 16:48:49','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-17 16:48:49','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','9105d7d0-5208-4c49-ae06-69eb62367f81','Y',90,1,5,3,'N','N','N','N','')
+;
+
+-- Nov 17, 2022, 4:49:18 PM IST
+INSERT INTO AD_Field (AD_Field_ID,Name,Description,Help,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm,DisplayLogic) VALUES (207420,'Read Only Logic','Logic to determine if field is read only (applies only when field is read-write)','format := {expression} [{logic} {expression}]
+expression := @{context}@{operand}{value} or @{context}@{operand}{value}
+logic := {|}|{&}
+context := any global or window context
+value := strings or numbers
+logic operators := AND or OR with the previous result from left to right
+operand := eq{=}, gt{>}, le{<}, not{~^!}
+Examples:
+
+- @AD_Table_ID@=14 | @Language@!GERGER
+- @PriceLimit@>10 | @PriceList@>@PriceActual@
+- @Name@>J
+
+Strings may be in single quotes (optional)',200028,212976,'Y',0,120,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-11-17 16:49:17','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-17 16:49:17','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','766bf507-7d6b-4e17-b95a-1d6acb73da51','Y',100,1,5,3,'N','N','N','N','')
+;
+
+SELECT register_migration_script('202211091000_IDEMPIERE-3334.sql') FROM dual
+;
+
diff --git a/migration/iD10/postgresql/202211091000_IDEMPIERE-3334.sql b/migration/iD10/postgresql/202211091000_IDEMPIERE-3334.sql
new file mode 100644
index 0000000000..b38f36a31c
--- /dev/null
+++ b/migration/iD10/postgresql/202211091000_IDEMPIERE-3334.sql
@@ -0,0 +1,96 @@
+-- IDEMPIERE-3334 Adding support for Readonly Logic, Set Pressed Logic on custom toolbar button
+-- Apr 7, 2017 9:46:15 AM IST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,Help,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure) VALUES (212976,0,'Read Only Logic','Logic to determine if field is read only (applies only when field is read-write)','format := {expression} [{logic} {expression}]
+expression := @{context}@{operand}{value} or @{context}@{operand}{value}
+logic := {|}|{&}
+context := any global or window context
+value := strings or numbers
+logic operators := AND or OR with the previous result from left to right
+operand := eq{=}, gt{>}, le{<}, not{~^!}
+Examples:
+
+- @AD_Table_ID@=14 | @Language@!GERGER
+- @PriceLimit@>10 | @PriceList@>@PriceActual@
+- @Name@>J
+
+Strings may be in single quotes (optional)',200003,'ReadOnlyLogic',2000,'N','N','N','N','N',0,'N',14,0,0,'Y',TO_TIMESTAMP('2017-04-07 09:46:14','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2017-04-07 09:46:14','YYYY-MM-DD HH24:MI:SS'),100,1663,'Y','N','D','N','N','N','Y','2c970c5d-b093-4b8a-b7df-da5260cb3afc','Y',0,'N','N')
+;
+
+-- Apr 7, 2017 9:46:25 AM IST
+ALTER TABLE AD_ToolBarButton ADD COLUMN ReadOnlyLogic VARCHAR(2000) DEFAULT NULL
+;
+
+-- Apr 7, 2017 9:47:37 AM IST
+INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,PrintName,EntityType,AD_Element_UU) VALUES (203068,0,0,'Y',TO_TIMESTAMP('2017-04-07 09:47:36','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2017-04-07 09:47:36','YYYY-MM-DD HH24:MI:SS'),100,'PressedLogic','Pressed Logic','Pressed Logic','D','3e4c5b2b-2b91-400f-8e18-fd1aee4627ff')
+;
+
+-- Apr 7, 2017 9:47:52 AM IST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure) VALUES (212977,0,'Pressed Logic',200003,'PressedLogic',2000,'N','N','N','N','N',0,'N',14,0,0,'Y',TO_TIMESTAMP('2017-04-07 09:47:51','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2017-04-07 09:47:51','YYYY-MM-DD HH24:MI:SS'),100,203068,'Y','N','D','N','N','N','Y','e7df64af-a5db-4469-9620-d1008f2b6ae6','Y',0,'N','N')
+;
+
+-- Apr 7, 2017 9:47:53 AM IST
+ALTER TABLE AD_ToolBarButton ADD COLUMN PressedLogic VARCHAR(2000) DEFAULT NULL
+;
+
+-- Apr 7, 2017 9:48:42 AM IST
+INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLogic,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField) VALUES (204384,'Pressed Logic',200002,212977,'Y','@IsCustomization@=Y',0,130,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2017-04-07 09:48:40','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2017-04-07 09:48:40','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','fe0b2b2f-8f24-46d9-b497-c7fdbc6df87e','Y',130,1,1,1,'N','N','N')
+;
+
+-- Apr 7, 2017 9:49:03 AM IST
+INSERT INTO AD_Field (AD_Field_ID,Name,Description,Help,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLogic,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField) VALUES (204385,'Read Only Logic','Logic to determine if field is read only (applies only when field is read-write)','format := {expression} [{logic} {expression}]
+expression := @{context}@{operand}{value} or @{context}@{operand}{value}
+logic := {|}|{&}
+context := any global or window context
+value := strings or numbers
+logic operators := AND or OR with the previous result from left to right
+operand := eq{=}, gt{>}, le{<}, not{~^!}
+Examples:
+
+- @AD_Table_ID@=14 | @Language@!GERGER
+- @PriceLimit@>10 | @PriceList@>@PriceActual@
+- @Name@>J
+
+Strings may be in single quotes (optional)',200002,212976,'Y','@IsCustomization@=Y',0,140,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2017-04-07 09:49:00','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2017-04-07 09:49:00','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','d721042e-1aa8-4c00-8c8c-615b7202bc7a','Y',140,1,1,1,'N','N','N')
+;
+
+-- Apr 7, 2017 9:49:33 AM IST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=110, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=1, ColumnSpan=5, NumLines=3, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2017-04-07 09:49:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204384
+;
+
+-- Apr 7, 2017 9:49:33 AM IST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=120, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=1, ColumnSpan=5, NumLines=3, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2017-04-07 09:49:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204385
+;
+
+-- Apr 7, 2017 9:49:33 AM IST
+UPDATE AD_Field SET SeqNo=130, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2017-04-07 09:49:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=202546
+;
+
+-- Apr 7, 2017 9:49:33 AM IST
+UPDATE AD_Field SET SeqNo=140, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2017-04-07 09:49:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=202547
+;
+
+
+-- Nov 17, 2022, 4:48:50 PM IST
+INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm,DisplayLogic) VALUES (207419,'Pressed Logic',200028,212977,'Y',0,110,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-11-17 16:48:49','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-17 16:48:49','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','9105d7d0-5208-4c49-ae06-69eb62367f81','Y',90,1,5,3,'N','N','N','N','')
+;
+
+-- Nov 17, 2022, 4:49:18 PM IST
+INSERT INTO AD_Field (AD_Field_ID,Name,Description,Help,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm,DisplayLogic) VALUES (207420,'Read Only Logic','Logic to determine if field is read only (applies only when field is read-write)','format := {expression} [{logic} {expression}]
+expression := @{context}@{operand}{value} or @{context}@{operand}{value}
+logic := {|}|{&}
+context := any global or window context
+value := strings or numbers
+logic operators := AND or OR with the previous result from left to right
+operand := eq{=}, gt{>}, le{<}, not{~^!}
+Examples:
+
+- @AD_Table_ID@=14 | @Language@!GERGER
+- @PriceLimit@>10 | @PriceList@>@PriceActual@
+- @Name@>J
+
+Strings may be in single quotes (optional)',200028,212976,'Y',0,120,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-11-17 16:49:17','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-17 16:49:17','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','766bf507-7d6b-4e17-b95a-1d6acb73da51','Y',100,1,5,3,'N','N','N','N','')
+;
+
+SELECT register_migration_script('202211091000_IDEMPIERE-3334.sql') FROM dual
+;
+
diff --git a/org.adempiere.base/src/org/compiere/model/GridTab.java b/org.adempiere.base/src/org/compiere/model/GridTab.java
index 13b7571793..60b2410564 100644
--- a/org.adempiere.base/src/org/compiere/model/GridTab.java
+++ b/org.adempiere.base/src/org/compiere/model/GridTab.java
@@ -113,7 +113,7 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
/**
*
*/
- private static final long serialVersionUID = -2091725732178841608L;
+ private static final long serialVersionUID = 2604313946261586651L;
public static final String DEFAULT_STATUS_MESSAGE = "NavigateOrUpdate";
@@ -230,6 +230,7 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
public static final String CTX_FindSQL = "_TabInfo_FindSQL";
public static final String CTX_SQL = "_TabInfo_SQL";
public static final String CTX_IsSortTab = "_TabInfo_IsSortTab";
+ public static final String CTX_Record_ID = "_TabInfo_Record_ID";
public static final String CTX_IsLookupOnlySelection = "_TabInfo_IsLookupOnlySelection";
public static final String CTX_IsAllowAdvancedLookup = "_TabInfo_IsAllowAdvancedLookup";
diff --git a/org.adempiere.base/src/org/compiere/model/I_AD_ToolBarButton.java b/org.adempiere.base/src/org/compiere/model/I_AD_ToolBarButton.java
index baa3ff69f9..f9ac7a5cec 100644
--- a/org.adempiere.base/src/org/compiere/model/I_AD_ToolBarButton.java
+++ b/org.adempiere.base/src/org/compiere/model/I_AD_ToolBarButton.java
@@ -22,7 +22,7 @@ import org.compiere.util.KeyNamePair;
/** Generated Interface for AD_ToolBarButton
* @author iDempiere (generated)
- * @version Release 9
+ * @version Release 10
*/
public interface I_AD_ToolBarButton
{
@@ -298,6 +298,28 @@ public interface I_AD_ToolBarButton
*/
public String getName();
+ /** Column name PressedLogic */
+ public static final String COLUMNNAME_PressedLogic = "PressedLogic";
+
+ /** Set Pressed Logic */
+ public void setPressedLogic (String PressedLogic);
+
+ /** Get Pressed Logic */
+ public String getPressedLogic();
+
+ /** Column name ReadOnlyLogic */
+ public static final String COLUMNNAME_ReadOnlyLogic = "ReadOnlyLogic";
+
+ /** Set Read Only Logic.
+ * Logic to determine if field is read only (applies only when field is read-write)
+ */
+ public void setReadOnlyLogic (String ReadOnlyLogic);
+
+ /** Get Read Only Logic.
+ * Logic to determine if field is read only (applies only when field is read-write)
+ */
+ public String getReadOnlyLogic();
+
/** Column name SeqNo */
public static final String COLUMNNAME_SeqNo = "SeqNo";
diff --git a/org.adempiere.base/src/org/compiere/model/X_AD_ToolBarButton.java b/org.adempiere.base/src/org/compiere/model/X_AD_ToolBarButton.java
index 567c99801f..e2f7ea87de 100644
--- a/org.adempiere.base/src/org/compiere/model/X_AD_ToolBarButton.java
+++ b/org.adempiere.base/src/org/compiere/model/X_AD_ToolBarButton.java
@@ -23,7 +23,7 @@ import org.compiere.util.KeyNamePair;
/** Generated Model for AD_ToolBarButton
* @author iDempiere (generated)
- * @version Release 9 - $Id$ */
+ * @version Release 10 - $Id$ */
@org.adempiere.base.Model(table="AD_ToolBarButton")
public class X_AD_ToolBarButton extends PO implements I_AD_ToolBarButton, I_Persistent
{
@@ -31,7 +31,7 @@ public class X_AD_ToolBarButton extends PO implements I_AD_ToolBarButton, I_Pers
/**
*
*/
- private static final long serialVersionUID = 20220116L;
+ private static final long serialVersionUID = 20220217L;
/** Standard Constructor */
public X_AD_ToolBarButton (Properties ctx, int AD_ToolBarButton_ID, String trxName)
@@ -468,6 +468,37 @@ public class X_AD_ToolBarButton extends PO implements I_AD_ToolBarButton, I_Pers
return new KeyNamePair(get_ID(), getName());
}
+ /** Set Pressed Logic.
+ @param PressedLogic Pressed Logic
+ */
+ public void setPressedLogic (String PressedLogic)
+ {
+ set_Value (COLUMNNAME_PressedLogic, PressedLogic);
+ }
+
+ /** Get Pressed Logic.
+ @return Pressed Logic */
+ public String getPressedLogic()
+ {
+ return (String)get_Value(COLUMNNAME_PressedLogic);
+ }
+
+ /** Set Read Only Logic.
+ @param ReadOnlyLogic Logic to determine if field is read only (applies only when field is read-write)
+ */
+ public void setReadOnlyLogic (String ReadOnlyLogic)
+ {
+ set_Value (COLUMNNAME_ReadOnlyLogic, ReadOnlyLogic);
+ }
+
+ /** Get Read Only Logic.
+ @return Logic to determine if field is read only (applies only when field is read-write)
+ */
+ public String getReadOnlyLogic()
+ {
+ return (String)get_Value(COLUMNNAME_ReadOnlyLogic);
+ }
+
/** Set Sequence.
@param SeqNo Method of ordering records; lowest number comes first
*/
diff --git a/org.adempiere.base/src/org/compiere/util/Env.java b/org.adempiere.base/src/org/compiere/util/Env.java
index 6d2b44f791..e46ae02d36 100644
--- a/org.adempiere.base/src/org/compiere/util/Env.java
+++ b/org.adempiere.base/src/org/compiere/util/Env.java
@@ -47,6 +47,7 @@ import org.adempiere.util.ServerContext;
import org.adempiere.util.ServerContextProvider;
import org.compiere.Adempiere;
import org.compiere.db.CConnection;
+import org.compiere.model.GridTab;
import org.compiere.model.GridWindowVO;
import org.compiere.model.MClient;
import org.compiere.model.MColumn;
@@ -1596,7 +1597,19 @@ public final class Env
token = token.substring(0, idx);
}
- String ctxInfo = getContext(ctx, WindowNo, tabNo, token, onlyTab); // get context
+ String ctxInfo = null;
+
+ if (token.equalsIgnoreCase(GridTab.CTX_Record_ID))
+ {
+ String keycolumnName = Env.getContext(Env.getCtx(), WindowNo, tabNo, GridTab.CTX_KeyColumnName,
+ onlyTab);
+ ctxInfo = Env.getContext(Env.getCtx(), WindowNo, tabNo, keycolumnName, onlyTab);
+ }
+ else
+ {
+ ctxInfo = getContext(ctx, WindowNo, tabNo, token, onlyTab); // get context
+ }
+
if (ctxInfo.length() == 0 && (token.startsWith("#") || token.startsWith("$")) )
ctxInfo = getContext(ctx, token); // get global context
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java
index d481b4fc3c..bea9d494a6 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java
@@ -1205,9 +1205,11 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
listPanel.dynamicDisplay(col);
}
- for (ToolbarProcessButton btn : toolbarProcessButtons) {
- btn.dynamicDisplay();
- }
+ for (ToolbarProcessButton btn : toolbarProcessButtons) {
+ btn.dynamicDisplay();
+ btn.readOnlyLogic();
+ btn.pressedLogic();
+ }
Events.sendEvent(this, new Event(ON_DYNAMIC_DISPLAY_EVENT, this));
echoDeferSetSelectedNodeEvent();
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowToolbar.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowToolbar.java
index 3aea72b4f0..e2e7959b9c 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowToolbar.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowToolbar.java
@@ -991,6 +991,24 @@ public class ADWindowToolbar extends FToolbar implements EventListener
}
}
}
+ pressedLogic();
+ readOnlyLogic();
+ }
+
+ private void pressedLogic()
+ {
+ for (ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons)
+ {
+ toolbarCustomBtn.pressedLogic();
+ }
+ }
+
+ private void readOnlyLogic()
+ {
+ for (ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons)
+ {
+ toolbarCustomBtn.readOnlyLogic();
+ }
}
@Override
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ProcessButtonPopup.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ProcessButtonPopup.java
index 1b92aad495..cf12310339 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ProcessButtonPopup.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ProcessButtonPopup.java
@@ -13,6 +13,7 @@ import org.adempiere.webui.panel.WDocActionPanel;
import org.compiere.model.GridTab;
import org.compiere.util.Env;
import org.compiere.util.Msg;
+import org.compiere.util.Util;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
@@ -31,6 +32,8 @@ public class ProcessButtonPopup extends Menupopup implements EventListener, Evaluatee {
toolbarButton.setVisible(visible);
}
-
+
+ public void pressedLogic() {
+ if (toolbarButton.getParent() == null)
+ return;
+
+ String pressedLogic = mToolbarButton.getPressedLogic();
+
+ if (Util.isEmpty(pressedLogic, true))
+ return;
+
+ ADWindow window = ADWindow.get(windowNo);
+
+ if (window == null)
+ return;
+
+ IADTabpanel adTabpanel = window.getADWindowContent().getADTab().getSelectedTabpanel();
+
+ if (adTabpanel == null || adTabpanel.getRecord_ID() <= 0)
+ return;
+
+ boolean isPressed = validateLogic(pressedLogic, adTabpanel.getTabNo());
+ ((ToolBarButton) toolbarButton).setPressed(isPressed);
+ }
+
+ public void readOnlyLogic() {
+ if (toolbarButton.getParent() == null)
+ return;
+
+ String readOnlyLogic = mToolbarButton.getReadOnlyLogic();
+
+ if (Util.isEmpty(readOnlyLogic, true))
+ return;
+
+ ADWindow window = ADWindow.get(windowNo);
+
+ if (window == null)
+ return;
+
+ IADTabpanel adTabpanel = window.getADWindowContent().getADTab().getSelectedTabpanel();
+
+ if (adTabpanel == null || adTabpanel.getRecord_ID() <= 0)
+ return;
+
+ boolean isReadOnly = validateLogic(readOnlyLogic, adTabpanel.getTabNo());
+
+ toolbarButton.setDisabled(isReadOnly);
+ }
+
+ private boolean validateLogic(String logic, int tabNo) {
+ boolean isValid = false;
+
+ if (logic.startsWith("@SQL="))
+ {
+ isValid = Evaluator.parseSQLLogic(logic, Env.getCtx(), windowNo, tabNo, "");
+ }
+ else
+ {
+ isValid = Evaluator.evaluateLogic(this, logic);
+ }
+
+ return isValid;
+ }
+
public Toolbarbutton getToolbarbutton() {
return toolbarButton;
}
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ToolbarProcessButton.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ToolbarProcessButton.java
index 1bc9da0083..c8fe7f6dbc 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ToolbarProcessButton.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ToolbarProcessButton.java
@@ -126,14 +126,8 @@ public class ToolbarProcessButton implements IProcessButton, Evaluatee {
String displayLogic = mToolbarButton.getDisplayLogic();
if (displayLogic == null || displayLogic.trim().length() == 0)
return;
-
- boolean visible = true;
- if (displayLogic.startsWith("@SQL=")) {
- visible = Evaluator.parseSQLLogic(displayLogic, Env.getCtx(), windowNo, adTabpanel.getTabNo(), mToolbarButton.getActionName());
- }else {
- visible = Evaluator.evaluateLogic(this, displayLogic);
- }
+ boolean visible = validateLogic(displayLogic, adTabpanel.getTabNo());
button.setVisible(visible);
}
@@ -145,4 +139,36 @@ public class ToolbarProcessButton implements IProcessButton, Evaluatee {
else
return Env.getContext (Env.getCtx(), windowNo, tabNo, variableName, false, true);
}
+
+ public void readOnlyLogic() {
+
+ String readOnlyLogic = mToolbarButton.getReadOnlyLogic();
+ if (readOnlyLogic == null || readOnlyLogic.trim().length() == 0)
+ return;
+
+ boolean disabled = validateLogic(readOnlyLogic, adTabpanel.getTabNo());
+ button.setDisabled(disabled);
+ } // readOnlyLogic
+
+ public void pressedLogic() {
+
+ String pressedLogic = mToolbarButton.getPressedLogic();
+ if (pressedLogic == null || pressedLogic.trim().length() == 0)
+ return;
+
+ boolean isPressed = validateLogic(pressedLogic, adTabpanel.getTabNo());
+ button.setAttribute(ProcessButtonPopup.BUTTON_ATTRIBUTE_PRESSED, isPressed ? "Y" : "N");
+ } // pressedLogic
+
+ private boolean validateLogic(String logic, int tabNo) {
+
+ boolean isValid = false;
+ if (logic.startsWith("@SQL=")) {
+ isValid = Evaluator.parseSQLLogic(logic, Env.getCtx(), windowNo, tabNo, getColumnName());
+ } else {
+ isValid = Evaluator.evaluateLogic(this, logic);
+ }
+
+ return isValid;
+ } // validateLogic
}