diff --git a/migration/iD10/oracle/202210311529_IDEMPIERE-5467.sql b/migration/iD10/oracle/202210311529_IDEMPIERE-5467.sql new file mode 100644 index 0000000000..e142c4efe1 --- /dev/null +++ b/migration/iD10/oracle/202210311529_IDEMPIERE-5467.sql @@ -0,0 +1,134 @@ +-- IDEMPIERE-5467 +SELECT register_migration_script('202210311529_IDEMPIERE-5467.sql') FROM dual; + +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- Oct 31, 2022, 3:29:03 PM CET +INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,Help,AD_Table_ID,ColumnName,DefaultValue,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,FKConstraintType,IsHtml) VALUES (215630,0,'Range','The parameter is a range of values','The Range checkbox indicates that this parameter is a range of values.',897,'IsRange','N',1,'N','N','Y','N','N',0,'N',20,0,0,'Y',TO_TIMESTAMP('2022-10-31 15:29:02','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-10-31 15:29:02','YYYY-MM-DD HH24:MI:SS'),100,404,'Y','N','D','N','N','N','Y','dfe41787-eea0-4bf2-8cf8-4c294ae9e384','Y',0,'N','N','N','N') +; + +-- Oct 31, 2022, 3:29:05 PM CET +ALTER TABLE AD_InfoColumn ADD IsRange CHAR(1) DEFAULT 'N' CHECK (IsRange IN ('Y','N')) NOT NULL +; + +-- Oct 31, 2022, 3:31:48 PM CET +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,IsQuickForm) VALUES (207409,'Range','The parameter is a range of values','The Range checkbox indicates that this parameter is a range of values.',844,215630,'Y','@QueryOperator@=''=''',0,330,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-10-31 15:31:48','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-10-31 15:31:48','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','23f54a5d-4e01-4f83-8225-c9dcd10b5595','Y',200,1,1,1,'N','N','N','N') +; + +-- Oct 31, 2022, 3:34:55 PM CET +UPDATE AD_Field SET IsDisplayed='Y', SeqNo=260, XPosition=2,Updated=TO_TIMESTAMP('2022-10-31 15:34:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207409 +; + +-- Oct 31, 2022, 3:34:55 PM CET +UPDATE AD_Field SET SeqNo=270,Updated=TO_TIMESTAMP('2022-10-31 15:34:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13603 +; + +-- Oct 31, 2022, 3:34:55 PM CET +UPDATE AD_Field SET SeqNo=280,Updated=TO_TIMESTAMP('2022-10-31 15:34:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201622 +; + +-- Oct 31, 2022, 3:34:55 PM CET +UPDATE AD_Field SET SeqNo=290,Updated=TO_TIMESTAMP('2022-10-31 15:34:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201623 +; + +-- Oct 31, 2022, 3:34:55 PM CET +UPDATE AD_Field SET SeqNo=300,Updated=TO_TIMESTAMP('2022-10-31 15:34:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13597 +; + +-- Oct 31, 2022, 3:34:55 PM CET +UPDATE AD_Field SET SeqNo=310,Updated=TO_TIMESTAMP('2022-10-31 15:34:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588 +; + +-- Oct 31, 2022, 3:34:55 PM CET +UPDATE AD_Field SET SeqNo=320,Updated=TO_TIMESTAMP('2022-10-31 15:34:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206178 +; + +-- Oct 31, 2022, 3:34:55 PM CET +UPDATE AD_Field SET SeqNo=330,Updated=TO_TIMESTAMP('2022-10-31 15:34:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206409 +; + +-- Nov 2, 2022, 1:05:05 PM CET +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,FKConstraintType,IsHtml) VALUES (215634,0,'Default Logic 2','Default value hierarchy, separated by ;','The defaults are evaluated in the order of definition, the first not null value becomes the default value of the column. The values are separated by comma or semicolon. a) Literals:. ''Text'' or 123 b) Variables - in format @Variable@ - Login e.g. #Date, #AD_Org_ID, #AD_Tenant_ID - Accounting Schema: e.g. $C_AcctSchema_ID, $C_Calendar_ID - Global defaults: e.g. DateFormat - Window values (all Picks, CheckBoxes, RadioButtons, and DateDoc/DateAcct) c) SQL code with the tag: @SQL=SELECT something AS DefaultValue FROM ... The SQL statement can contain variables. There can be no other value other than the SQL statement. The default is only evaluated, if no user preference is defined. Default definitions are ignored for record columns as Key, Parent, Tenant as well as Buttons.',897,'DefaultValue2',2000,'N','N','N','N','N',0,'N',10,0,0,'Y',TO_TIMESTAMP('2022-11-02 13:05:05','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-02 13:05:05','YYYY-MM-DD HH24:MI:SS'),100,1529,'Y','N','D','N','N','N','Y','818e812b-dff2-44f2-a6ce-fc12572a1418','Y',0,'N','N','N','N') +; + +-- Nov 2, 2022, 1:05:07 PM CET +ALTER TABLE AD_InfoColumn ADD DefaultValue2 VARCHAR2(2000 CHAR) DEFAULT NULL +; + +-- Nov 2, 2022, 1:05:36 PM CET +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,FKConstraintType,IsHtml) VALUES (215635,0,'Placeholder2',897,'Placeholder2',255,'N','N','N','N','N',0,'N',10,0,0,'Y',TO_TIMESTAMP('2022-11-02 13:05:36','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-02 13:05:36','YYYY-MM-DD HH24:MI:SS'),100,203164,'Y','N','D','N','N','N','Y','d4ded311-b942-4108-ae5e-e6770dd2b9fd','Y',0,'N','N','N','N') +; + +-- Nov 2, 2022, 1:05:37 PM CET +ALTER TABLE AD_InfoColumn ADD Placeholder2 VARCHAR2(255 CHAR) DEFAULT NULL +; + +-- Nov 2, 2022, 1:07:16 PM CET +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,IsQuickForm) VALUES (207411,'Default Logic 2','Default value hierarchy, separated by ;','The defaults are evaluated in the order of definition, the first not null value becomes the default value of the column. The values are separated by comma or semicolon. a) Literals:. ''Text'' or 123 b) Variables - in format @Variable@ - Login e.g. #Date, #AD_Org_ID, #AD_Tenant_ID - Accounting Schema: e.g. $C_AcctSchema_ID, $C_Calendar_ID - Global defaults: e.g. DateFormat - Window values (all Picks, CheckBoxes, RadioButtons, and DateDoc/DateAcct) c) SQL code with the tag: @SQL=SELECT something AS DefaultValue FROM ... The SQL statement can contain variables. There can be no other value other than the SQL statement. The default is only evaluated, if no user preference is defined. Default definitions are ignored for record columns as Key, Parent, Tenant as well as Buttons.',844,215634,'Y','@IsRange@=Y',0,340,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-11-02 13:07:16','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-02 13:07:16','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','72729959-a426-42db-9003-39ca086e05ff','Y',210,1,1,1,'N','N','N','N') +; + +-- Nov 2, 2022, 1:07:46 PM CET +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,IsQuickForm) VALUES (207412,'Placeholder2',844,215635,'Y','@IsRange@=Y',0,350,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-11-02 13:07:46','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-02 13:07:46','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','b3767594-080c-44dc-9fce-32aa8eecfa6c','Y',220,1,1,1,'N','N','N','N') +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET IsDisplayed='Y', SeqNo=270, XPosition=4, ColumnSpan=2,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207411 +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET IsDisplayed='Y', SeqNo=280, XPosition=7, ColumnSpan=2,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207412 +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET SeqNo=290,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13603 +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET SeqNo=300,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201622 +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET SeqNo=310,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201623 +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET SeqNo=320,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13597 +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET SeqNo=330,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588 +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET SeqNo=340,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206178 +; + +-- Nov 2, 2022, 1:10:05 PM CET +UPDATE AD_Field SET SeqNo=350,Updated=TO_TIMESTAMP('2022-11-02 13:10:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206409 +; + +-- Nov 2, 2022, 3:56:18 PM CET +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,FKConstraintType,IsHtml) VALUES (215636,0,'Placeholder2',898,'Placeholder2',255,'N','N','N','N','N',0,'N',10,0,0,'Y',TO_TIMESTAMP('2022-11-02 15:56:18','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-02 15:56:18','YYYY-MM-DD HH24:MI:SS'),100,203164,'Y','N','D','N','N','N','Y','fd9f96fe-5be5-46f1-94b8-fe60e8862182','Y',0,'N','N','N','N') +; + +-- Nov 2, 2022, 3:56:19 PM CET +ALTER TABLE AD_InfoColumn_Trl ADD Placeholder2 VARCHAR2(255 CHAR) DEFAULT NULL +; + +-- Nov 2, 2022, 3:56:40 PM CET +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) VALUES (207413,'Placeholder2',845,215636,'Y',0,100,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-11-02 15:56:39','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-11-02 15:56:39','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','7c908cea-25bf-4956-bcae-72c7f64952ff','Y',80,1,1,1,'N','N','N','N') +; + +-- Nov 2, 2022, 3:56:54 PM CET +UPDATE AD_Field SET IsDisplayed='Y', SeqNo=90, XPosition=1, ColumnSpan=5,Updated=TO_TIMESTAMP('2022-11-02 15:56:54','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207413 +; + +-- Nov 2, 2022, 3:56:54 PM CET +UPDATE AD_Field SET SeqNo=100,Updated=TO_TIMESTAMP('2022-11-02 15:56:54','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13615 +; + +-- Nov 2, 2022, 3:57:15 PM CET +UPDATE AD_Column SET IsTranslated='Y',Updated=TO_TIMESTAMP('2022-11-02 15:57:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=215635 +; + diff --git a/migration/iD10/oracle/202211100946_IDEMPIERE-5467.sql b/migration/iD10/oracle/202211100946_IDEMPIERE-5467.sql new file mode 100644 index 0000000000..6aa08cea46 --- /dev/null +++ b/migration/iD10/oracle/202211100946_IDEMPIERE-5467.sql @@ -0,0 +1,30 @@ +-- IDEMPIERE-5467 +SELECT register_migration_script('202211100946_IDEMPIERE-5467.sql') FROM dual; + +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- Oct 26, 2022, 2:58:22 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','{0} {1,choice,1#|1<{1}} {1,choice,1#Years|-1#Year|1 0) ValidationCode = MValRule.get(ctx, infoColumn.getAD_Val_Rule_ID()).getCode(); + // Range is supported only for Date and Numeric Reference Types + operator "=" must be selected + if(QueryOperator != null && QueryOperator.equals(MInfoColumn.QUERYOPERATOR_Eq) + && (DisplayType.isDate(AD_Reference_ID) || DisplayType.isNumeric(AD_Reference_ID))) + isRange = infoColumn.isRange(); + else + isRange = false; this.afterCreate(); @@ -318,6 +333,10 @@ public class InfoColumnVO implements Serializable, Cloneable { public String getPlaceholder() { return Placeholder; } + + public String getPlaceholder2() { + return Placeholder2; + } public boolean isReadOnly() { return isReadOnly; @@ -378,6 +397,10 @@ public class InfoColumnVO implements Serializable, Cloneable { public String getDefaultValue() { return DefaultValue; } + + public String getDefaultValue2() { + return DefaultValue2; + } public String getHelpTrl() { return HelpTrl; @@ -406,4 +429,8 @@ public class InfoColumnVO implements Serializable, Cloneable { public int getSeqNo() { return SeqNo; } + + public boolean isRange() { + return isRange; + } } diff --git a/org.adempiere.base/src/org/compiere/model/X_AD_InfoColumn.java b/org.adempiere.base/src/org/compiere/model/X_AD_InfoColumn.java index 7b36573319..b5dbceaf6a 100644 --- a/org.adempiere.base/src/org/compiere/model/X_AD_InfoColumn.java +++ b/org.adempiere.base/src/org/compiere/model/X_AD_InfoColumn.java @@ -31,7 +31,7 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent /** * */ - private static final long serialVersionUID = 20220914L; + private static final long serialVersionUID = 20221102L; /** Standard Constructor */ public X_AD_InfoColumn (Properties ctx, int AD_InfoColumn_ID, String trxName) @@ -58,6 +58,8 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent setIsQueryAfterChange (false); // N setIsQueryCriteria (false); + setIsRange (false); +// N setIsReadOnly (true); // Y setName (null); @@ -92,6 +94,8 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent setIsQueryAfterChange (false); // N setIsQueryCriteria (false); + setIsRange (false); +// N setIsReadOnly (true); // Y setName (null); @@ -366,6 +370,22 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent return (String)get_Value(COLUMNNAME_DefaultValue); } + /** Set Default Logic 2. + @param DefaultValue2 Default value hierarchy, separated by ; + */ + public void setDefaultValue2 (String DefaultValue2) + { + set_Value (COLUMNNAME_DefaultValue2, DefaultValue2); + } + + /** Get Default Logic 2. + @return Default value hierarchy, separated by ; + */ + public String getDefaultValue2() + { + return (String)get_Value(COLUMNNAME_DefaultValue2); + } + /** Set Description. @param Description Optional short description of the record */ @@ -633,6 +653,29 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent return false; } + /** Set Range. + @param IsRange The parameter is a range of values + */ + public void setIsRange (boolean IsRange) + { + set_Value (COLUMNNAME_IsRange, Boolean.valueOf(IsRange)); + } + + /** Get Range. + @return The parameter is a range of values + */ + public boolean isRange() + { + Object oo = get_Value(COLUMNNAME_IsRange); + if (oo != null) + { + if (oo instanceof Boolean) + return ((Boolean)oo).booleanValue(); + return "Y".equals(oo); + } + return false; + } + /** Set Read Only. @param IsReadOnly Field is read only */ @@ -695,6 +738,21 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent return (String)get_Value(COLUMNNAME_Placeholder); } + /** Set Placeholder2. + @param Placeholder2 Placeholder2 + */ + public void setPlaceholder2 (String Placeholder2) + { + set_Value (COLUMNNAME_Placeholder2, Placeholder2); + } + + /** Get Placeholder2. + @return Placeholder2 */ + public String getPlaceholder2() + { + return (String)get_Value(COLUMNNAME_Placeholder2); + } + /** Set Query Function. @param QueryFunction Database function for query */ @@ -725,10 +783,10 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent public static final String QUERYOPERATOR_Gt = ">"; /** >= = >= */ public static final String QUERYOPERATOR_GtEq = ">="; - /** Like = Like */ - public static final String QUERYOPERATOR_Like = "Like"; /** Full Like = LIKE */ public static final String QUERYOPERATOR_FullLike = "LIKE"; + /** Like = Like */ + public static final String QUERYOPERATOR_Like = "Like"; /** Set Query Operator. @param QueryOperator Operator for database query */ diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDateEditor.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDateEditor.java index ca6809887d..8e6dd5e56c 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDateEditor.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDateEditor.java @@ -170,10 +170,14 @@ public class WDateEditor extends WEditor implements ContextMenuListener { oldValue = null; getComponent().setValue(null); + ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), oldValue, value); + super.fireValueChange(changeEvent); } else if (value instanceof Timestamp) { getComponent().setValueInLocalDateTime(((Timestamp)value).toLocalDateTime()); + ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), oldValue, value); + super.fireValueChange(changeEvent); oldValue = (Timestamp)value; } else @@ -181,6 +185,8 @@ public class WDateEditor extends WEditor implements ContextMenuListener try { getComponent().setText(value.toString()); + ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), oldValue, value); + super.fireValueChange(changeEvent); } catch (Exception e) {} if (getComponent().getValue() != null) oldValue = Timestamp.valueOf(getComponent().getValue().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDatetimeEditor.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDatetimeEditor.java index 033dcb92f9..d3b72aadcd 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDatetimeEditor.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDatetimeEditor.java @@ -213,11 +213,15 @@ public class WDatetimeEditor extends WEditor implements ContextMenuListener { ZonedDateTime zdt = ts.toInstant().atZone(getComponent().getDatebox().getTimeZone().toZoneId()); getComponent().setValueInZonedDateTime(zdt); + ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), oldValue, value); + super.fireValueChange(changeEvent); } else { LocalDateTime localTime = ts.toLocalDateTime(); getComponent().setValueInLocalDateTime(localTime); + ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), oldValue, value); + super.fireValueChange(changeEvent); } oldValue = ts; } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java index 1a8f080a1d..ba90052eef 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java @@ -42,6 +42,7 @@ import org.adempiere.webui.component.GridFactory; import org.adempiere.webui.component.Label; import org.adempiere.webui.component.ListModelTable; import org.adempiere.webui.component.Menupopup; +import org.adempiere.webui.component.NumberBox; import org.adempiere.webui.component.Row; import org.adempiere.webui.component.Rows; import org.adempiere.webui.component.Tab; @@ -127,6 +128,7 @@ import org.zkoss.zul.South; import org.zkoss.zul.Space; import org.zkoss.zul.Vbox; import org.zkoss.zul.Vlayout; +import org.zkoss.zul.impl.InputElement; /** * AD_InfoWindow implementation @@ -144,6 +146,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL private Vbox southBody; /** List of WEditors */ protected List editors; + protected ArrayList editors2; protected List queryAfterChangeEditors; protected List identifiers; protected Properties infoContext; @@ -163,7 +166,9 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL protected AbstractWQuickEntry vqe; private List gridFields; + private List gridFields2; private TreeMap> parameterTree; + private TreeMap> parameterTree2; private Checkbox checkAND; // F3P: Keep original values: when a row is unselected, restore original values @@ -660,6 +665,8 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL gridFields = new ArrayList(); parameterTree = new TreeMap>(); + gridFields2 = new ArrayList(); + parameterTree2 = new TreeMap>(); for(InfoColumnVO infoColumn : infoColumns) { if (infoColumn.isKey()) @@ -682,6 +689,13 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL vo.DisplayLogic = infoColumn.getDisplayLogic(); if (infoColumn.isQueryCriteria() && infoColumn.getDefaultValue() != null) vo.DefaultValue = infoColumn.getDefaultValue(); + if (infoColumn.isQueryCriteria() && infoColumn.getDefaultValue2() != null) + vo.DefaultValue2 = infoColumn.getDefaultValue2(); + if (infoColumn.isQueryCriteria() && infoColumn.getPlaceholder() != null) + vo.Placeholder = infoColumn.getPlaceholder(); + if (infoColumn.isQueryCriteria() && infoColumn.getPlaceholder2() != null) + vo.Placeholder2 = infoColumn.getPlaceholder2(); + String desc = infoColumn.getDescriptionTrl(); vo.Description = desc != null ? desc : ""; String help = infoColumn.getHelpTrl(); @@ -691,7 +705,14 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL vo.IsReadOnly = infoColumn.isReadOnly(); GridField gridField = new GridField(vo); gridFields.add(gridField); - + + GridFieldVO vo2 = null; + GridField gridField2 = null; + if(infoColumn.isRange()) { + vo2 = GridFieldVO.createParameter(vo); + gridField2 = new GridField(vo2); + } + gridFields2.add(gridField2); //IDEMPIERE-4485 Clone new Gridfields with IsReadOnly = false if(infoColumn.isQueryCriteria()) { vo = vo.clone(infoContext, p_WindowNo, 0, vo.AD_Window_ID, 0, false); @@ -699,12 +720,18 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL vo.TabNo = Env.TAB_INFO; gridField = new GridField(vo); List list = parameterTree.get(infoColumn.getSeqNoSelection()); + List list2 = parameterTree2.get(infoColumn.getSeqNoSelection()); if (list == null) { list = new ArrayList(); parameterTree.put(infoColumn.getSeqNoSelection(), list); } + if (list2 == null) { + list2 = new ArrayList(); + parameterTree2.put(infoColumn.getSeqNoSelection(), list2); + } - list.add(new Object[]{infoColumn, gridField}); + list.add(new Object[]{infoColumn, gridField}); + list2.add(new Object[]{infoColumn, gridField2}); } } @@ -1004,10 +1031,16 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL builder.append(tableInfos[0].getSynonym()).append(".IsActive='Y'"); } int count = 0; + int idx = 0; for(WEditor editor : editors) { - if (!editor.isVisible()) + if (!editor.isVisible()) { + idx++; continue; - + } + WEditor editor2 = editors2.get(idx); + boolean isRange = false; + if(editor2 != null) + isRange = true; if (editor instanceof IWhereClauseEditor) { String whereClause = ((IWhereClauseEditor) editor).getWhereClause(); if (whereClause != null && whereClause.trim().length() > 0) { @@ -1025,7 +1058,8 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL } builder.append(whereClause); } - } else if (editor.getGridField() != null && editor.getValue() != null && editor.getValue().toString().trim().length() > 0) { + } else if (editor.getGridField() != null && (editor.getValue() != null && editor.getValue().toString().trim().length() > 0) + || (isRange && editor2.getValue() != null && editor2.getValue().toString().trim().length() > 0)) { InfoColumnVO InfoColumnVO = findInfoColumnParameter(editor.getGridField()); if (InfoColumnVO == null || InfoColumnVO.getSelectClause().equals("0")) { continue; @@ -1096,16 +1130,44 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL } else { columnClause = columnName; } - builder.append(columnClause) - .append(" ") - .append(InfoColumnVO.getQueryOperator()); - if (columnClause.toUpperCase().startsWith("UPPER(")) { - builder.append(" UPPER(?)"); - } else { - builder.append(" ?"); + if(!isRange) { + builder.append(columnClause) + .append(" ") + .append(InfoColumnVO.getQueryOperator()); + if (columnClause.toUpperCase().startsWith("UPPER(")) { + builder.append(" UPPER(?)"); + } else { + builder.append(" ?"); + } + } + else { + if(editor.getValue() != null && editor.getValue().toString().trim().length() > 0) { + builder.append(columnClause) + .append(" ") + .append(X_AD_InfoColumn.QUERYOPERATOR_GtEq); + if (columnClause.toUpperCase().startsWith("UPPER(")) { + builder.append(" UPPER(?)"); + } else { + builder.append(" ?"); + } + } + if(editor2.getValue() != null && editor2.getValue().toString().trim().length() > 0) { + if(editor.getValue() != null && editor.getValue().toString().trim().length() > 0) { + builder.append(" AND "); + } + builder.append(columnClause) + .append(" ") + .append(X_AD_InfoColumn.QUERYOPERATOR_LeEq); + if (columnClause.toUpperCase().startsWith("UPPER(")) { + builder.append(" UPPER(?)"); + } else { + builder.append(" ?"); + } + } } } } + idx++; } if (count > 0 && !checkAND.isChecked()) { builder.append(" ) "); @@ -1204,30 +1266,41 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL } int parameterIndex = 0; + int idx = 0; for(WEditor editor : editors) { - if (!editor.isVisible()) - continue; - - if (editor.getGridField() != null && editor.getValue() != null && editor.getValue().toString().trim().length() > 0) { - InfoColumnVO InfoColumnVO = findInfoColumnParameter(editor.getGridField()); - if (InfoColumnVO == null || InfoColumnVO.getSelectClause().equals("0")) { - continue; - } - if (InfoColumnVO.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionList || InfoColumnVO.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionSearch - || InfoColumnVO.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionTable) { - continue; - } - Object value = editor.getValue(); - parameterIndex++; - prevParameterValues.add(value); - prevQueryOperators.add(InfoColumnVO.getQueryOperator()); - prevRefParmeterEditor.add(editor); - setParameter (pstmt, parameterIndex, value, InfoColumnVO.getQueryOperator()); - } + InfoColumnVO infoColumnVO = findInfoColumnParameter(editor.getGridField()); + parameterIndex = setParameter(editor, infoColumnVO, pstmt, parameterIndex); + parameterIndex = setParameter(editors2.get(idx), infoColumnVO, pstmt, parameterIndex); + idx++; } } + protected int setParameter(WEditor editor, InfoColumnVO infoColumnVO, PreparedStatement pstmt, int parameterIndex) throws SQLException { + if(editor == null) + return parameterIndex; + + if (!editor.isVisible()) + return parameterIndex; + + if (editor.getGridField() != null && editor.getValue() != null && editor.getValue().toString().trim().length() > 0) { + if (infoColumnVO == null || infoColumnVO.getSelectClause().equals("0")) { + return parameterIndex; + } + if (infoColumnVO.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionList || infoColumnVO.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionSearch + || infoColumnVO.getAD_Reference_ID()==DisplayType.ChosenMultipleSelectionTable) { + return parameterIndex; + } + Object value = editor.getValue(); + parameterIndex++; + prevParameterValues.add(value); + prevQueryOperators.add(infoColumnVO.getQueryOperator()); + prevRefParmeterEditor.add(editor); + setParameter (pstmt, parameterIndex, value, infoColumnVO.getQueryOperator()); + } + return parameterIndex; + } + /** * set parameter for statement. * not need check null for value @@ -1513,23 +1586,33 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL if (!update) { editors = new ArrayList(); + editors2 = new ArrayList(); queryAfterChangeEditors = new ArrayList<>(); identifiers = new ArrayList(); } for (Integer i : parameterTree.keySet()) { List list = parameterTree.get(i); + List list2 = parameterTree2.get(i); + int j = 0; for(Object[] value : list) { + Object[] value2 = list2.get(j); if (update) { + int idx = 0; for (WEditor editor : editors) { if (editor.getGridField() == value[1]) { - addSearchParameter(editor.getLabel(), editor.getComponent()); + WEditor editor2 = null; + if(editors2.get(idx) != null) + editor2 = editors2.get(idx); + addSearchParameter(editor, editor2); break; } + idx++; } } else { - addSelectionColumn((InfoColumnVO)value[0], (GridField)value[1]); + addSelectionColumn((InfoColumnVO)value[0], (GridField)value[1], (GridField)value2[1]); } + j++; } } @@ -1574,17 +1657,24 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL } protected void evalDisplayLogic() { + int idx = 0; for(WEditor editor : editors) { + WEditor editor2 = editors2.get(idx); if (editor.getGridField() != null && !editor.getGridField().isDisplayed(true)) { editor.getComponent().setVisible(false); + if(editor2 != null) + editor2.getComponent().setVisible(false); if (editor.getLabel() != null) editor.getLabel().setVisible(false); } else if (!editor.getComponent().isVisible()) { editor.getComponent().setVisible(true); + if(editor2 != null) + editor2.getComponent().setVisible(true); if (editor.getLabel() != null) editor.getLabel().setVisible(true); } + idx++; } } @@ -1594,7 +1684,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL * @param infoColumn * @param mField field **/ - protected void addSelectionColumn(InfoColumnVO infoColumn, GridField mField) + protected void addSelectionColumn(InfoColumnVO infoColumn, GridField mField, GridField mField2) { int displayLength = mField.getDisplayLength(); if (displayLength <= 0 || displayLength > FIELDLENGTH) @@ -1604,6 +1694,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL // Editor WEditor editor = null; + WEditor editor2 = null; if (mField.getDisplayType() == DisplayType.PAttribute) { editor = new WInfoPAttributeEditor(infoContext, p_WindowNo, mField); @@ -1620,6 +1711,13 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL { ((WTableDirEditor) editor).setRetainSelectedValueAfterRefresh(false); } + if(infoColumn.isRange()) { + editor2 = WebEditorFactory.getEditor(mField2, false); + editor2.setReadWrite(true); + editor2.dynamicDisplay(); + editor2.addValueChangeListener(this); + editor2.fillHorizontal(); + } } Label label = editor.getLabel(); Component fieldEditor = editor.getComponent(); @@ -1638,9 +1736,10 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL } } - addSearchParameter(label, fieldEditor); + addSearchParameter(editor, editor2); editors.add(editor); + editors2.add(editor2); if (infoColumn.isQueryAfterChange()) { queryAfterChangeEditors.add(editor); } @@ -1654,12 +1753,23 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL fieldEditor.addEventListener(Events.ON_OK, this); mField.addPropertyChangeListener(editor); - mField.setValue(mField.getDefaultForPanel(), true); + + if(infoColumn.isRange()) { + mField2.addPropertyChangeListener(editor2); + mField2.setValue(mField2.getDefaultForPanel(), true); + } } // addSelectionColumn - protected void addSearchParameter(Label label, Component fieldEditor) { + protected void addSearchParameter(WEditor editor, WEditor editor2) { + Label label = editor.getLabel(); + Component fieldEditor = editor.getComponent(); + Component fieldEditor2 = null; + + if(editor2 != null) + fieldEditor2 = editor2.getComponent(); + Row panel = null; if (parameterGrid.getRows().getChildren().isEmpty()) { @@ -1699,7 +1809,26 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL // add out parent to add menu for this field, without outerDiv, a new cell will auto make for menu. Div outerParent = new Div(); + outerParent.setStyle("display: flex;"); outerParent.appendChild(fieldEditor); + if(fieldEditor2 != null) { + Label dash = new Label("-"); + dash.setStyle("padding-left:3px;padding-right:3px;display:flex;align-items:center;"); + outerParent.appendChild(dash); + outerParent.appendChild(fieldEditor2); + if(editor.getGridField() != null && DisplayType.isDate(editor.getGridField().getDisplayType())) { + DateRangeButton drb = (new DateRangeButton(editor, editor2)); + outerParent.appendChild(drb); + drb.setDateButtonVisible(false); + } + if (fieldEditor instanceof InputElement && fieldEditor2 instanceof InputElement) { + ((InputElement)fieldEditor).setPlaceholder(Msg.getMsg(Env.getCtx(), "From")); + ((InputElement)fieldEditor2).setPlaceholder(Msg.getMsg(Env.getCtx(), "To")); + } else if (fieldEditor instanceof NumberBox && fieldEditor2 instanceof NumberBox) { + ((NumberBox)fieldEditor).getDecimalbox().setPlaceholder(Msg.getMsg(Env.getCtx(), "From")); + ((NumberBox)fieldEditor2).getDecimalbox().setPlaceholder(Msg.getMsg(Env.getCtx(), "To")); + } + } panel.appendChild(outerParent); } @@ -1883,13 +2012,24 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL protected void dynamicDisplay(WEditor editor) { validateField(editor); + evalDisplayLogic(); + // if attribute set changed (from any value to any value) clear the attribute set instance m_pAttributeWhere boolean asiChanged = false; if (editor != null && editor instanceof WTableDirEditor && editor.getColumnName().equals("M_AttributeSet_ID")) asiChanged = true; + int idx = 0; for(WEditor otherEditor : editors) { + if(editors2.get(idx) != null) { + if(editors2.get(idx) == editor) { + idx++; + continue; + } + editors2.get(idx).dynamicDisplay(); + } + idx++; if (otherEditor == editor) continue; @@ -1899,8 +2039,6 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL otherEditor.dynamicDisplay(); } - - evalDisplayLogic(); } public void onEvent(Event event) @@ -1978,23 +2116,11 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL @Override protected void resetParameters() { // reset value of parameter to null, just reset display parameter + int idx = 0; for (WEditor editor : editors) { - GridField gField = editor.getGridField(); - if (gField == null || !gField.isDisplayed()) { - continue; - } - - // just reset to default Field set explicit DefaultValue - Object resetValue = null; - if (! Util.isEmpty(gField.getVO().DefaultValue, true)) { - resetValue = gField.getDefaultForPanel(); - } - Object oldValue = gField.getValue(); - gField.setValue(resetValue, true); - - // call valueChange to update env - ValueChangeEvent changeEvent = new ValueChangeEvent (editor, "", oldValue, resetValue); - valueChange (changeEvent); + resetParameters(editor); + resetParameters(editors2.get(idx)); + idx++; } // init again parameter @@ -2010,6 +2136,28 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL layout.invalidate(); } + protected void resetParameters(WEditor editor) { + if(editor == null) + return; + + GridField gField = editor.getGridField(); + if (gField == null || !gField.isDisplayed()) { + return; + } + + // just reset to default Field set explicit DefaultValue + Object resetValue = null; + if (! Util.isEmpty(gField.getVO().DefaultValue, true)) { + resetValue = gField.getDefaultForPanel(); + } + Object oldValue = gField.getValue(); + gField.setValue(resetValue, true); + + // call valueChange to update env + ValueChangeEvent changeEvent = new ValueChangeEvent (editor, "", oldValue, resetValue); + valueChange (changeEvent); + } + @Override public void onPageAttached(Page newpage, Page oldpage) { super.onPageAttached(newpage, oldpage); @@ -2252,13 +2400,16 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL boolean isValid = true; for (int i = 0; i < editors.size(); i++){ - WEditor wEditor = (WEditor) editors.get(i); + WEditor wEditor = editors.get(i); + WEditor wEditor2 = editors2.get(i); // cancel editor not display if (wEditor == null || !wEditor.isVisible() || wEditor.getGridField() == null){ continue; } isValid = isValid & validateField (wEditor); + if(wEditor2 != null) + isValid = isValid & validateField(wEditor2); } return isValid; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/DateRangeButton.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/DateRangeButton.java index 455d020adf..6ac7214fbb 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/DateRangeButton.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/DateRangeButton.java @@ -28,6 +28,7 @@ import java.util.Properties; import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.component.ToolBarButton; +import org.adempiere.webui.editor.WDateEditor; import org.adempiere.webui.editor.WEditor; import org.adempiere.webui.theme.ThemeManager; import org.compiere.util.Env; @@ -84,4 +85,18 @@ public class DateRangeButton extends ToolBarButton implements WEditor.DynamicDis setVisible(this.editor.isVisible() && editor2.isVisible()); setDisabled(!(this.editor.isReadWrite() && editor2.isReadWrite())); } + + + /** + * set visibility of date button + * @param visible + */ + public void setDateButtonVisible(boolean visible) { + if (editor instanceof WDateEditor && editor2 instanceof WDateEditor) { + WDateEditor de1 = (WDateEditor) editor; + WDateEditor de2 = (WDateEditor) editor2; + de1.getComponent().setButtonVisible(visible); + de2.getComponent().setButtonVisible(visible); + } + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/DateRangePicker.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/DateRangePicker.java index 77de7be271..758c65f073 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/DateRangePicker.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/DateRangePicker.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.concurrent.TimeUnit; import org.adempiere.exceptions.AdempiereException; import org.adempiere.webui.component.Button; @@ -39,6 +40,8 @@ import org.adempiere.webui.component.ListItem; import org.adempiere.webui.component.Listbox; import org.adempiere.webui.component.Textbox; import org.adempiere.webui.editor.WEditor; +import org.adempiere.webui.event.ValueChangeEvent; +import org.adempiere.webui.event.ValueChangeListener; import org.adempiere.webui.factory.ButtonFactory; import org.compiere.model.MChart; import org.compiere.model.MRefList; @@ -53,6 +56,7 @@ 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.zul.Comboitem; import org.zkoss.zul.Div; import org.zkoss.zul.Popup; import org.zkoss.zul.Spinner; @@ -62,7 +66,7 @@ import org.zkoss.zul.Spinner; * @author Peter Takacs, Cloudempiere * */ -public class DateRangePicker extends Popup implements EventListener { +public class DateRangePicker extends Popup implements EventListener, ValueChangeListener { /** * @@ -99,7 +103,9 @@ public class DateRangePicker extends Popup implements EventListener { private Date dateTo; private Date oldValueFrom; private Date oldValueTo; - + private String displayValue; + private boolean enableValueChange = true; + private ArrayList quickListBoxesArray = new ArrayList(); private ListItem selectedQuickListItem; @@ -116,18 +122,21 @@ public class DateRangePicker extends Popup implements EventListener { private void init() { + editor.addValueChangeListener(this); + editor2.addValueChangeListener(this); + Div div = new Div(); okBtn = ButtonFactory.createNamedButton(Msg.getMsg(Env.getCtx(), "ApplyFilter"), true, false); okBtn.setStyle("color: white; background: #A9A9A9; float: right;"); modeCombobox = new Combobox(); modeCombobox.setSclass("date-picker-component"); - modeCombobox.setWidth("90px"); + modeCombobox.setWidth("120px"); modeCombobox.addEventListener(Events.ON_SELECT, this); numberBox = new Spinner(1); numberBox.setConstraint("no empty, min 1"); - numberBox.setStyle("margin: 5px;"); + numberBox.setSclass("date-picker-component"); numberBox.addEventListener(Events.ON_CHANGING, this); unitCombobox = new Combobox(); @@ -146,24 +155,27 @@ public class DateRangePicker extends Popup implements EventListener { dateTextBoxLabel.setSclass("date-picker-label"); dateTextBox = new Textbox(); + dateTextBox.setReadonly(true); dateTextBox.setSclass("date-picker-component"); - dateTextBox.setStyle("min-width: 170px;"); + dateTextBox.setStyle("min-width: 170px; background: white !important"); dateTextBox.setValue(DisplayType.getDateFormat().format(cal.getValue())); dateTextBox.addEventListener(Events.ON_CHANGE, this); okBtn.setSclass("date-picker-component"); okBtn.addEventListener(Events.ON_CLICK, event -> { + setDateTextBoxAndDisplayValue(); if(dateFrom != null && dateTo != null && dateTo.before(dateFrom)) throw new WrongValueException(dateTextBox, Msg.getMsg(Env.getCtx(), "EndDateAfterStartDate")); - setTimesOnDates(); if(Util.isEmpty(dateTextBox.getValue())) { oldValueFrom = dateFrom; oldValueTo = dateTo; dateFrom = null; dateTo = null; } + enableValueChange = false; editor.setValue(dateFrom); editor2.setValue(dateTo); + enableValueChange = true; this.detach(); }); @@ -171,31 +183,20 @@ public class DateRangePicker extends Popup implements EventListener { quickListBoxes.appendChild(getQuickModeContent()); // Load Modes to ListBox - ComboItem selectedOnOpen = null; ValueNamePair[] modes = MRefList.getList(Env.getCtx(), REFERENCE_DATESELECTIONMODE, false, "Value"); for(ValueNamePair mode : modes) { ComboItem item = new ComboItem(mode.getName(), mode.getValue()); - if(mode.getValue().equalsIgnoreCase(DATESELECTIONMODE_CURRENT)) - selectedOnOpen = item; modeCombobox.appendChild(item); } - if(selectedOnOpen != null) - modeCombobox.setSelectedItem(selectedOnOpen); - else - modeCombobox.setSelectedIndex(0); + modeCombobox.setSelectedIndex(0); // Load Units to ListBox ValueNamePair[] units = MRefList.getList(Env.getCtx(), REFERENCE_TIMEUNIT, false); for(ValueNamePair timeUnit : units) { ComboItem item = new ComboItem(timeUnit.getName(), timeUnit.getValue()); - if(timeUnit.getValue().equalsIgnoreCase(MChart.TIMEUNIT_Month)) - selectedOnOpen = item; unitCombobox.appendChild(item); } - if(selectedOnOpen != null) - unitCombobox.setSelectedItem(selectedOnOpen); - else - modeCombobox.setSelectedIndex(0); + unitCombobox.setSelectedIndex(0); div.setSclass("date-picker-container"); div.appendChild(modeCombobox); @@ -221,10 +222,42 @@ public class DateRangePicker extends Popup implements EventListener { this.appendChild(div); this.setStyle("min-width: 320px;"); + + dateFrom = (Date) editor.getValue(); + dateTo = (Date) editor2.getValue(); + if(dateFrom != null || dateTo != null) { // Set the picker to defined Default Logic + Date[] dates = setTimesOnDates(dateFrom, dateTo); + dateFrom = dates[0]; + dateTo = dates[1]; + loadPickerSelection(); + } + else { + // If no Default Logic defined, set Current Month as selected range + setPickerSelection(DATESELECTIONMODE_CURRENT, MChart.TIMEUNIT_Month, 0); + Date[] dates = setTimesOnDates(dateFrom, dateTo); + dateFrom = dates[0]; + dateTo = dates[1]; + editor.setValue(dateFrom); + editor2.setValue(dateTo); + } updateUI(); - setDisplayValue(); } + private void setPickerSelection(String mode, String unit, int offset) { + for(Comboitem item : modeCombobox.getItems()) { + if(item.getValue().equals(mode)) + modeCombobox.setSelectedItem(item); + } + for(Comboitem item : unitCombobox.getItems()) { + if(item.getValue().equals(unit)) + unitCombobox.setSelectedItem(item); + } + int numBoxValue = Math.abs(offset) >= 1 ? Math.abs(offset) : 1; + numberBox.setValue(numBoxValue); + + setDateTextBoxAndDisplayValue(); + } + private void updateUI() { String selectedMode = modeCombobox.getSelectedItem().getValue().toString(); switch (selectedMode) { @@ -291,32 +324,32 @@ public class DateRangePicker extends Popup implements EventListener { } dateTextBox.clearErrorMessage(); - if(!Util.isEmpty(dateTextBox.getValue()) || !event.getTarget().equals(dateTextBox)) - setDisplayValue(); + if(!Util.isEmpty(dateTextBox.getValue()) || !event.getTarget().equals(dateTextBox)) { + setDateTextBoxAndDisplayValue(); + } } - private void setDisplayValue() { - String displayValue = getDisplayValue(); - dateTextBox.setValue(displayValue); + private void setDateTextBoxAndDisplayValue() { + displayValue = ""; + String dateTextBoxValue = getDateTextBoxValue(); + dateTextBox.setValue(dateTextBoxValue); + + if(Util.isEmpty(displayValue)) + displayValue = dateTextBoxValue; } - private String getDisplayValue() { + private String getDateTextBoxValue() { String returnVal = ""; - Timestamp ts = new Timestamp(cal.getValue().getTime()); + Date[] dates; + switch (modeCombobox.getSelectedItem().getValue().toString()) { - case DATESELECTIONMODE_AFTER: - returnVal = Msg.getMsg(Env.getCtx(), "AfterDate", new Object[] {DisplayType.getDateFormat().format(ts)}); - oldValueFrom = dateFrom; - oldValueTo = dateTo; - dateFrom = ts; - dateTo = null; - break; + case DATESELECTIONMODE_PREVIOUS: + case DATESELECTIONMODE_NEXT: + case DATESELECTIONMODE_CURRENT: case DATESELECTIONMODE_BEFORE: - returnVal = Msg.getMsg(Env.getCtx(), "BeforeDate", new Object[] {DisplayType.getDateFormat().format(ts)}); - oldValueFrom = dateFrom; - oldValueTo = dateTo; - dateFrom = null; - dateTo = ts; + case DATESELECTIONMODE_AFTER: + case DATESELECTIONMODE_ON: + returnVal = getIntervalHumanReadable(); break; case DATESELECTIONMODE_BETWEEN: returnVal = DisplayType.getDateFormat().format(cal.getValue()) + " - " + DisplayType.getDateFormat().format(cal2.getValue()); @@ -324,29 +357,23 @@ public class DateRangePicker extends Popup implements EventListener { oldValueTo = dateTo; dateFrom = new Timestamp(cal.getValue().getTime()); dateTo = new Timestamp(cal2.getValue().getTime()); - break; - case DATESELECTIONMODE_CURRENT: - case DATESELECTIONMODE_NEXT: - case DATESELECTIONMODE_PREVIOUS: - returnVal = getInterval(); - break; - case DATESELECTIONMODE_ON: - returnVal = Msg.getMsg(Env.getCtx(), "OnDate", new Object[] {DisplayType.getDateFormat().format(ts)}); - oldValueFrom = dateFrom; - oldValueTo = dateTo; - dateFrom = ts; - dateTo = ts; + dates = setTimesOnDates(dateFrom, dateTo); + dateFrom = dates[0]; + dateTo = dates[1]; break; case DATESELECTIONMODE_QUICK: if(selectedQuickListItem != null) { String unit = (String) selectedQuickListItem.getAttribute("TimeUnit"); int offset = (int) selectedQuickListItem.getAttribute("Offset"); Date dateFrom = (Date) selectedQuickListItem.getAttribute("DateFrom"); - Date[] dates = getInterval(unit, unit, offset, false, false, dateFrom); + dates = getInterval(unit, unit, offset, false, false, dateFrom); this.oldValueFrom = this.dateFrom; this.oldValueTo = this.dateTo; this.dateFrom = new Timestamp(dates[0].getTime()); this.dateTo = new Timestamp(dates[1].getTime()); + dates = setTimesOnDates(dateFrom, dateTo); + dateFrom = dates[0]; + dateTo = dates[1]; returnVal = DisplayType.getDateFormat().format(this.dateFrom) + " - " + DisplayType.getDateFormat().format(this.dateTo); } break; @@ -355,19 +382,235 @@ public class DateRangePicker extends Popup implements EventListener { } return returnVal; } - - private String getInterval() { + + private void loadPickerSelection() { + String detectedMode = null; + String detectedUnit = null; + int detectedOffset = 0; + Timestamp today = new Timestamp(System.currentTimeMillis()); + today = new Timestamp(setTimesOnDates(today, null)[0].getTime()); + + detectedMode = autodetectMode(today); + if(detectedMode != null) { + String[] arr = autodetectUnitAndCorrectMode(today, detectedMode); + if(arr != null) { + detectedUnit = arr[0]; + if(!Util.isEmpty(arr[1])) + detectedMode = arr[1]; + } + } + + if(!Util.isEmpty(detectedMode) && !Util.isEmpty(detectedUnit)) { + detectedOffset = autodetectOffset(detectedMode, detectedUnit); + } + + for(Comboitem item : modeCombobox.getItems()) { + if(item.getValue().equals(detectedMode)) { + modeCombobox.setSelectedItem(item); + break; + } + } + for(Comboitem item : unitCombobox.getItems()) { + if(item.getValue().equals(detectedUnit)) { + unitCombobox.setSelectedItem(item); + break; + } + } + int numBoxValue = Math.abs(detectedOffset) >= 1 ? Math.abs(detectedOffset) : 1; + numberBox.setValue(numBoxValue); + if(dateFrom == null) { + cal.setValue(dateTo); + cal2.setValue(dateTo); + } + else if(dateTo == null) { + cal.setValue(dateFrom); + cal2.setValue(dateFrom); + } + else { + cal.setValue(dateFrom); + cal2.setValue(dateTo); + } + setDateTextBoxAndDisplayValue(); + } + + private String autodetectMode(Timestamp today) { + Date d1 = dateFrom; + Date d2 = dateTo; + d1 = setTimesOnDates(d1, null)[0]; + d2 = setTimesOnDates(d2, null)[0]; + if(d1 != null && d2 == null) + return DATESELECTIONMODE_AFTER; + else if(d1 == null && d2 != null) + return DATESELECTIONMODE_BEFORE; + else if(d1.compareTo(d2) == 0) + return DATESELECTIONMODE_ON; + + if(d1.after(d2)) + return null; + + if(d1.before(today)){ + if(d2.before(today)) + return DATESELECTIONMODE_PREVIOUS; + else if(d2.after(today)) + return DATESELECTIONMODE_CURRENT; + else + return DATESELECTIONMODE_BETWEEN; + } + else if(d1.after(today)){ + return DATESELECTIONMODE_NEXT; + } + else + return DATESELECTIONMODE_BETWEEN; + } + + private String[] autodetectUnitAndCorrectMode(Timestamp today, String predictedMode) { + // use case: modes Before, After, On - unit is not needed + Date d1 = dateFrom; + Date d2 = dateTo; + d1 = setTimesOnDates(d1, null)[0]; + d2 = setTimesOnDates(d2, null)[0]; + if(d1 == null || d2 == null || (d1.compareTo(d2) == 0)) + return null; + + if(dateFrom.after(dateTo)) + return null; + + String detectedUnit = ""; + String correctedMode = predictedMode; + Calendar calendar = Calendar.getInstance(Env.getLocale(Env.getCtx())); + Calendar calendar2 = Calendar.getInstance(Env.getLocale(Env.getCtx())); + Calendar calendarToday = Calendar.getInstance(Env.getLocale(Env.getCtx())); + Calendar testCalendar = (Calendar) calendarToday.clone(); + int timeUnit = 0; + + calendar.setTime(dateFrom); + calendar2.setTime(dateTo); + calendarToday.setTime(today); + + // check start and end day of periods + if(calendar.get(Calendar.DAY_OF_YEAR) == 1 && + calendar2.get(Calendar.DAY_OF_YEAR) == calendar2.getActualMaximum(Calendar.DAY_OF_YEAR)) { + detectedUnit = MChart.TIMEUNIT_Year; + timeUnit = Calendar.YEAR; + } + else if(calendar.get(Calendar.DAY_OF_MONTH) == 1 && + calendar2.get(Calendar.DAY_OF_MONTH) == calendar2.getActualMaximum(Calendar.DAY_OF_MONTH)) { + if((calendar.get(Calendar.MONTH) == Calendar.JANUARY || + calendar.get(Calendar.MONTH) == Calendar.APRIL || + calendar.get(Calendar.MONTH) == Calendar.JULY || + calendar.get(Calendar.MONTH) == Calendar.OCTOBER) && + (calendar2.get(Calendar.MONTH) == Calendar.MARCH || + calendar2.get(Calendar.MONTH) == Calendar.JUNE || + calendar2.get(Calendar.MONTH) == Calendar.SEPTEMBER || + calendar2.get(Calendar.MONTH) == Calendar.DECEMBER) && + (calendar.get(Calendar.MONTH) != calendar2.get(Calendar.MONTH))) + detectedUnit = MChart.TIMEUNIT_Quarter; + else + detectedUnit = MChart.TIMEUNIT_Month; + timeUnit = Calendar.MONTH; + } + else if(calendar.get(Calendar.DAY_OF_WEEK) == calendar.getFirstDayOfWeek() && + calendar2.get(Calendar.DAY_OF_WEEK) == calendar2.getActualMaximum(Calendar.DAY_OF_WEEK)) { + detectedUnit = MChart.TIMEUNIT_Week; + timeUnit = Calendar.WEEK_OF_YEAR; + } + else { + if(predictedMode.equalsIgnoreCase(DATESELECTIONMODE_CURRENT)) + correctedMode = DATESELECTIONMODE_BETWEEN; + else { + detectedUnit = MChart.TIMEUNIT_Day; + timeUnit = Calendar.DAY_OF_YEAR; + } + } + int testOffset = 1; + if(detectedUnit.equalsIgnoreCase(MChart.TIMEUNIT_Quarter)) + testOffset = 3; // three months = 1 quarter + testCalendar.add(timeUnit, -testOffset); + if(testCalendar.getTime().after(dateTo)) { + detectedUnit = MChart.TIMEUNIT_Day; + correctedMode = DATESELECTIONMODE_BETWEEN; + } + + testCalendar = (Calendar) calendarToday.clone(); + testCalendar.add(timeUnit, testOffset); + if(testCalendar.getTime().before(dateFrom)) { + detectedUnit = MChart.TIMEUNIT_Day; + correctedMode = DATESELECTIONMODE_BETWEEN; + } + + return new String[] {detectedUnit, correctedMode}; + } + + private int autodetectOffset(String mode, String unit) { + Date date = dateFrom; + Date date2 = dateTo; + + long diffInMillies = Math.abs(date2.getTime() - date.getTime()); + long diff = TimeUnit.DAYS.convert(diffInMillies+1, TimeUnit.MILLISECONDS); + + switch (unit) { + case MChart.TIMEUNIT_Year: + diff = diff / 365; + break; + case MChart.TIMEUNIT_Quarter: + diff = diff / 89; + break; + case MChart.TIMEUNIT_Month: + diff = diff / 28; + break; + case MChart.TIMEUNIT_Week: + diff = diff / 7; + break; + } + if(mode.equalsIgnoreCase(DATESELECTIONMODE_PREVIOUS)) + diff = -diff; + return (int) diff; + } + + private String getIntervalHumanReadable() { + + Timestamp ts = new Timestamp(cal.getValue().getTime()); String mode = modeCombobox.getSelectedItem().getValue().toString(); String unit = unitCombobox.getSelectedItem().getValue().toString(); Integer numBoxValue = numberBox.getValue(); Date[] dates; if(numBoxValue == null) { - numBoxValue = 0; + numBoxValue = 1; numberBox.setValue(numBoxValue); } + if(mode.equalsIgnoreCase(DATESELECTIONMODE_AFTER)) { + displayValue = Msg.getMsg(Env.getCtx(), "AfterDate", new Object[] {DisplayType.getDateFormat().format(ts)}); + oldValueFrom = dateFrom; + oldValueTo = dateTo; + dateFrom = ts; + dateFrom = setTimesOnDates(dateFrom, null)[0]; + dateTo = null; + return displayValue; + } + else if(mode.equalsIgnoreCase(DATESELECTIONMODE_BEFORE)) { + displayValue = Msg.getMsg(Env.getCtx(), "BeforeDate", new Object[] {DisplayType.getDateFormat().format(ts)}); + oldValueFrom = dateFrom; + oldValueTo = dateTo; + dateFrom = null; + dateTo = ts; + dateTo = setTimesOnDates(null, dateTo)[1]; + return displayValue; + } + else if(mode.equalsIgnoreCase(DATESELECTIONMODE_ON)) { + displayValue = Msg.getMsg(Env.getCtx(), "OnDate", new Object[] {DisplayType.getDateFormat().format(ts)}); + oldValueFrom = dateFrom; + oldValueTo = dateTo; + dateFrom = ts; + dateTo = ts; + dates = setTimesOnDates(dateFrom, dateTo); + dateFrom = dates[0]; + dateTo = dates[1]; + return displayValue; + } + if(mode.equalsIgnoreCase(DATESELECTIONMODE_PREVIOUS)) numBoxValue = -numBoxValue; @@ -380,6 +623,11 @@ public class DateRangePicker extends Popup implements EventListener { oldValueTo = dateTo; dateFrom = new Timestamp(dates[0].getTime()); dateTo = new Timestamp(dates[1].getTime()); + dates = setTimesOnDates(dateFrom, dateTo); + dateFrom = dates[0]; + dateTo = dates[1]; + + displayValue = datesToHumanReadable(mode, unit, numBoxValue); return DisplayType.getDateFormat().format(dateFrom) + " - " + DisplayType.getDateFormat().format(dateTo); } @@ -429,11 +677,38 @@ public class DateRangePicker extends Popup implements EventListener { if(!Util.isEmpty(timeUnitForRange) || !isToDate){ boolean hasTimeUnitForRange = true; - // Set first and last Day of the given time period + if(Util.isEmpty(timeUnitForRange)) { timeUnitForRange = timeUnit; hasTimeUnitForRange = false; } + // Add the offset + if(hasTimeUnitForRange && offset != 0) { + cal1.add(iUnit, offset); + cal2.add(iUnit, offset); + } + else if(!hasTimeUnitForRange && !isToDate) { + if(offset < 0) { + cal1.add(iUnit, offset); + if(!includeThis) { + if(timeUnitForRange.equalsIgnoreCase(MChart.TIMEUNIT_Quarter)) + cal2.add(iUnit, -3); + else + cal2.add(iUnit, -1); + } + } + else if (offset > 0) { + if(!includeThis) { + if(timeUnitForRange.equalsIgnoreCase(MChart.TIMEUNIT_Quarter)) + cal1.add(iUnit, 3); + else + cal1.add(iUnit, 1); + } + cal2.add(iUnit, offset); + } + } + + // Set first and last Day of the given time period if(timeUnitForRange.equalsIgnoreCase(MChart.TIMEUNIT_Week)) { cal1.set(iDayUnit, cal1.getFirstDayOfWeek()); cal2.set(iDayUnit, cal2.getFirstDayOfWeek()); @@ -463,32 +738,6 @@ public class DateRangePicker extends Popup implements EventListener { cal1.set(iDayUnit, cal1.getActualMinimum(iDayUnit)); cal2.set(iDayUnit, cal2.getActualMaximum(iDayUnit)); } - - // Add the offset - if(hasTimeUnitForRange && offset != 0) { - cal1.add(iUnit, offset); - cal2.add(iUnit, offset); - } - else if(!hasTimeUnitForRange && !isToDate) { - if(offset < 0) { - cal1.add(iUnit, offset); - if(!includeThis) { - if(timeUnitForRange.equalsIgnoreCase(MChart.TIMEUNIT_Quarter)) - cal2.add(iUnit, -3); - else - cal2.add(iUnit, -1); - } - } - else if (offset > 0) { - if(!includeThis) { - if(timeUnitForRange.equalsIgnoreCase(MChart.TIMEUNIT_Quarter)) - cal1.add(iUnit, 3); - else - cal1.add(iUnit, 1); - } - cal2.add(iUnit, offset); - } - } } else if(isToDate) { if(offset < 0) @@ -503,7 +752,42 @@ public class DateRangePicker extends Popup implements EventListener { return new Date[] {date1, date2}; } - private void setTimesOnDates() { + private String datesToHumanReadable(String mode, String unit, Integer offset) { + String msgVal = ""; + String modeVal = ""; + + if(offset < 0) + offset = -offset; + if(mode.equalsIgnoreCase(DATESELECTIONMODE_CURRENT)) + offset = -1; + + switch (unit) { + case MChart.TIMEUNIT_Day: + msgVal = "DatePickerDay"; + break; + case MChart.TIMEUNIT_Month: + msgVal = "DatePickerMonth"; + break; + case MChart.TIMEUNIT_Quarter: + msgVal = "DatePickerQuarter"; + break; + case MChart.TIMEUNIT_Week: + msgVal = "DatePickerWeek"; + break; + case MChart.TIMEUNIT_Year: + msgVal = "DatePickerYear"; + break; + default: + throw new AdempiereException("TimeUnitNotSupported"); + } + for(Comboitem item : modeCombobox.getItems()) { + if(item.getValue().equals(mode)) + modeVal = item.getLabel(); + } + return Msg.getMsg(Env.getCtx(), msgVal, new Object[]{modeVal, offset}); + } + + private Date[] setTimesOnDates(Date dateFrom, Date dateTo) { Calendar cal = Calendar.getInstance(Env.getLocale(Env.getCtx())); if(dateFrom != null) { cal.setTime(dateFrom); @@ -523,6 +807,7 @@ public class DateRangePicker extends Popup implements EventListener { cal.add(Calendar.MILLISECOND, -1); dateTo = new Timestamp(cal.getTime().getTime()); } + return new Date[] {dateFrom, dateTo}; } private ListItem createItem(String value, String timeUnit, int offset, Date dateFrom) { @@ -689,4 +974,34 @@ public class DateRangePicker extends Popup implements EventListener { public Date getOldValueTo() { return oldValueTo; } + + /** + * Get Display Value + * @return String + */ + public String getDisplayValue() { + return this.displayValue; + } + + @Override + public void valueChange(ValueChangeEvent evt) { + if(enableValueChange) { + dateFrom = (Date) editor.getValue(); + dateTo = (Date) editor2.getValue(); + if(dateFrom != null || dateTo != null) { // Set the picker to defined Default Logic + Date[] dates = setTimesOnDates(dateFrom, dateTo); + dateFrom = dates[0]; + dateTo = dates[1]; + loadPickerSelection(); + } + else { + // If no Default Logic defined, set Current Month as selected range + setPickerSelection(DATESELECTIONMODE_CURRENT, MChart.TIMEUNIT_Month, 0); + Date[] dates = setTimesOnDates(dateFrom, dateTo); + dateFrom = dates[0]; + dateTo = dates[1]; + } + updateUI(); + } + } }