diff --git a/migration/i6.2z/oracle/201910041600_IDEMPIERE-4060.sql b/migration/i6.2z/oracle/201910041600_IDEMPIERE-4060.sql
new file mode 100644
index 0000000000..93f187e572
--- /dev/null
+++ b/migration/i6.2z/oracle/201910041600_IDEMPIERE-4060.sql
@@ -0,0 +1,85 @@
+SET SQLBLANKLINES ON
+SET DEFINE OFF
+
+-- IDEMPIERE-4060 Implement change scheduler state at scheduler window
+-- Oct 4, 2019, 2:16:47 PM MYT
+INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,ActionClassName,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,Action,DisplayLogic,SeqNo,IsAdvancedButton,IsAddSeparator,EntityType) VALUES (0,0,TO_DATE('2019-10-04 14:16:44','YYYY-MM-DD HH24:MI:SS'),100,'SchedulerState','Y',200099,'Change Scheduler State',TO_DATE('2019-10-04 14:16:44','YYYY-MM-DD HH24:MI:SS'),100,'Y','org.adempiere.webui.scheduler.ChangeStateAction',0,0,'e4011f77-6b09-4644-9781-746b74818962','W','@_WinInfo_AD_Window_ID@=305&@AD_Scheduler_ID@>0',0,'N','N','D')
+;
+
+-- Oct 4, 2019, 2:17:56 PM MYT
+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','Change Scheduler State',0,0,'Y',TO_DATE('2019-10-04 14:17:55','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:17:55','YYYY-MM-DD HH24:MI:SS'),100,200564,'org.adempiere.webui.scheduler.ChangeStateAction.label','D','d17e970c-d75e-4577-8862-90c41673c305')
+;
+
+-- Oct 4, 2019, 2:18:44 PM MYT
+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','Not Schedule',0,0,'Y',TO_DATE('2019-10-04 14:18:44','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:18:44','YYYY-MM-DD HH24:MI:SS'),100,200565,'SchedulerNotSchedule','D','d71cb5f4-1d4c-4d37-8a9b-2720d36a6670')
+;
+
+-- Oct 4, 2019, 2:19:04 PM MYT
+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','Scheduler Started',0,0,'Y',TO_DATE('2019-10-04 14:19:03','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:19:03','YYYY-MM-DD HH24:MI:SS'),100,200566,'SchedulerStarted','D','5d4b14e5-8300-4885-8dcc-25c438274dd4')
+;
+
+-- Oct 4, 2019, 2:19:28 PM MYT
+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','Scheduler Stopped',0,0,'Y',TO_DATE('2019-10-04 14:19:27','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:19:27','YYYY-MM-DD HH24:MI:SS'),100,200567,'SchedulerStopped','D','6bf707ce-3ca7-4e99-9199-cb9dffee12dc')
+;
+
+-- Oct 4, 2019, 2:19:58 PM MYT
+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 ('E','Failed to read current scheduler state',0,0,'Y',TO_DATE('2019-10-04 14:19:57','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:19:57','YYYY-MM-DD HH24:MI:SS'),100,200568,'CantReadCurrentSchedulerState','D','330bb791-8a1b-45d1-8e30-0da31ad7c4ed')
+;
+
+-- Oct 4, 2019, 2:21:34 PM MYT
+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','Add scheduler to server and start it?',0,0,'Y',TO_DATE('2019-10-04 14:21:34','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:21:34','YYYY-MM-DD HH24:MI:SS'),100,200569,'SchedulerAddAndStartPrompt','D','237fef1a-c876-4965-9abd-a64324452ea5')
+;
+
+-- Oct 4, 2019, 2:22:04 PM MYT
+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','Stop scheduler?',0,0,'Y',TO_DATE('2019-10-04 14:22:03','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:22:03','YYYY-MM-DD HH24:MI:SS'),100,200570,'SchedulerStopPrompt','D','3a0c3dbf-a78b-4110-900a-9d09b1e3026d')
+;
+
+-- Oct 4, 2019, 2:22:30 PM MYT
+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','Start scheduler?',0,0,'Y',TO_DATE('2019-10-04 14:22:29','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:22:29','YYYY-MM-DD HH24:MI:SS'),100,200571,'SchedulerStartPrompt','D','eb95b028-d5db-45e4-a911-6c690c3d0f58')
+;
+
+-- Oct 4, 2019, 2:23:07 PM MYT
+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','Scheduler added and started successfully',0,0,'Y',TO_DATE('2019-10-04 14:23:07','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:23:07','YYYY-MM-DD HH24:MI:SS'),100,200572,'SchedulerAddedAndStarted','D','1367e586-ac57-4216-9f98-daca4cb961bb')
+;
+
+-- Oct 4, 2019, 2:23:48 PM MYT
+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 ('E','Failed to add and start scheduler. Error:',0,0,'Y',TO_DATE('2019-10-04 14:23:47','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:23:47','YYYY-MM-DD HH24:MI:SS'),100,200573,'SchedulerAddAndStartFail','D','898a96bf-5b1b-405a-8507-a69ac58e364e')
+;
+
+-- Oct 4, 2019, 2:24:19 PM MYT
+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','Scheduler stopped successfully',0,0,'Y',TO_DATE('2019-10-04 14:24:18','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:24:18','YYYY-MM-DD HH24:MI:SS'),100,200574,'SchedulerStopped','D','f4620ecb-bac1-408b-8609-e1997cd5a598')
+;
+
+-- Oct 4, 2019, 2:30:12 PM MYT
+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','Scheduler stopped successfully',0,0,'Y',TO_DATE('2019-10-04 14:30:06','YYYY-MM-DD HH24:MI:SS
+'),100,TO_DATE('2019-10-04 14:30:06','YYYY-MM-DD HH24:MI:SS'),100,200575,'SchedulerStoppedSuccess','D','d918dd12-9578-4160-9212-28af2114b5fe')
+;
+
+-- Oct 4, 2019, 2:30:48 PM MYT
+UPDATE AD_Message SET Value='SchedulerStopSuccess',Updated=TO_DATE('2019-10-04 14:30:48','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200575
+;
+
+-- Oct 4, 2019, 2:31:14 PM MYT
+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 ('E','Failed to stop scheduler. Error:',0,0,'Y',TO_DATE('2019-10-04 14:31:13','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:31:13','YYYY-MM-DD HH24:MI:SS'),100,200576,'SchedulerStopFail','D','40ff365f-9a0f-4de6-849f-c6527d844e37')
+;
+
+-- Oct 4, 2019, 2:31:38 PM MYT
+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','Scheduler started successfully',0,0,'Y',TO_DATE('2019-10-04 14:31:38','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:31:38','YYYY-MM-DD HH24:MI:SS'),100,200577,'SchedulerStartSuccess','D','fc356061-f311-464b-9962-6a7dbac028dd')
+;
+
+-- Oct 4, 2019, 2:32:00 PM MYT
+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 ('E','Failed to start scheduler. Error:',0,0,'Y',TO_DATE('2019-10-04 14:32:00','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 14:32:00','YYYY-MM-DD HH24:MI:SS'),100,200578,'SchedulerStartFail','D','d79f3d08-2d00-4281-b01c-00cdc80f085c')
+;
+
+-- IDEMPIERE-4060 Implement change scheduler state at scheduler window
+-- Oct 4, 2019, 2:46:01 PM MYT
+UPDATE AD_Message SET Value='SchedulerAddAndStartSuccess',Updated=TO_DATE('2019-10-04 14:46:01','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200572
+;
+
+-- IDEMPIERE-4060 Implement change scheduler state at scheduler window
+-- Oct 4, 2019, 4:43:05 PM MYT
+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','Change scheduler state',0,0,'Y',TO_DATE('2019-10-04 16:43:04','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-10-04 16:43:04','YYYY-MM-DD HH24:MI:SS'),100,200579,'org.adempiere.webui.scheduler.ChangeStateAction.tooltip','D','241b6ad0-f3ad-4541-9ab9-8c6a163e7f0d')
+;
+
+SELECT register_migration_script('201910041600_IDEMPIERE-4060.sql') FROM dual
+;
diff --git a/migration/i6.2z/postgresql/201910041600_IDEMPIERE-4060.sql b/migration/i6.2z/postgresql/201910041600_IDEMPIERE-4060.sql
new file mode 100644
index 0000000000..aa7f2a3c07
--- /dev/null
+++ b/migration/i6.2z/postgresql/201910041600_IDEMPIERE-4060.sql
@@ -0,0 +1,81 @@
+-- IDEMPIERE-4060 Implement change scheduler state at scheduler window
+-- Oct 4, 2019, 2:16:47 PM MYT
+INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,ActionClassName,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,"action",DisplayLogic,SeqNo,IsAdvancedButton,IsAddSeparator,EntityType) VALUES (0,0,TO_TIMESTAMP('2019-10-04 14:16:44','YYYY-MM-DD HH24:MI:SS'),100,'SchedulerState','Y',200099,'Change Scheduler State',TO_TIMESTAMP('2019-10-04 14:16:44','YYYY-MM-DD HH24:MI:SS'),100,'Y','org.adempiere.webui.scheduler.ChangeStateAction',0,0,'e4011f77-6b09-4644-9781-746b74818962','W','@_WinInfo_AD_Window_ID@=305&@AD_Scheduler_ID@>0',0,'N','N','D')
+;
+
+-- Oct 4, 2019, 2:17:56 PM MYT
+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','Change Scheduler State',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:17:55','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:17:55','YYYY-MM-DD HH24:MI:SS'),100,200564,'org.adempiere.webui.scheduler.ChangeStateAction.label','D','d17e970c-d75e-4577-8862-90c41673c305')
+;
+
+-- Oct 4, 2019, 2:18:44 PM MYT
+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','Not Schedule',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:18:44','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:18:44','YYYY-MM-DD HH24:MI:SS'),100,200565,'SchedulerNotSchedule','D','d71cb5f4-1d4c-4d37-8a9b-2720d36a6670')
+;
+
+-- Oct 4, 2019, 2:19:04 PM MYT
+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','Scheduler Started',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:19:03','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:19:03','YYYY-MM-DD HH24:MI:SS'),100,200566,'SchedulerStarted','D','5d4b14e5-8300-4885-8dcc-25c438274dd4')
+;
+
+-- Oct 4, 2019, 2:19:28 PM MYT
+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','Scheduler Stopped',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:19:27','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:19:27','YYYY-MM-DD HH24:MI:SS'),100,200567,'SchedulerStopped','D','6bf707ce-3ca7-4e99-9199-cb9dffee12dc')
+;
+
+-- Oct 4, 2019, 2:19:58 PM MYT
+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 ('E','Failed to read current scheduler state',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:19:57','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:19:57','YYYY-MM-DD HH24:MI:SS'),100,200568,'CantReadCurrentSchedulerState','D','330bb791-8a1b-45d1-8e30-0da31ad7c4ed')
+;
+
+-- Oct 4, 2019, 2:21:34 PM MYT
+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','Add scheduler to server and start it?',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:21:34','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:21:34','YYYY-MM-DD HH24:MI:SS'),100,200569,'SchedulerAddAndStartPrompt','D','237fef1a-c876-4965-9abd-a64324452ea5')
+;
+
+-- Oct 4, 2019, 2:22:04 PM MYT
+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','Stop scheduler?',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:22:03','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:22:03','YYYY-MM-DD HH24:MI:SS'),100,200570,'SchedulerStopPrompt','D','3a0c3dbf-a78b-4110-900a-9d09b1e3026d')
+;
+
+-- Oct 4, 2019, 2:22:30 PM MYT
+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','Start scheduler?',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:22:29','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:22:29','YYYY-MM-DD HH24:MI:SS'),100,200571,'SchedulerStartPrompt','D','eb95b028-d5db-45e4-a911-6c690c3d0f58')
+;
+
+-- Oct 4, 2019, 2:23:07 PM MYT
+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','Scheduler added and started successfully',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:23:07','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:23:07','YYYY-MM-DD HH24:MI:SS'),100,200572,'SchedulerAddedAndStarted','D','1367e586-ac57-4216-9f98-daca4cb961bb')
+;
+
+-- Oct 4, 2019, 2:23:48 PM MYT
+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 ('E','Failed to add and start scheduler. Error:',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:23:47','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:23:47','YYYY-MM-DD HH24:MI:SS'),100,200573,'SchedulerAddAndStartFail','D','898a96bf-5b1b-405a-8507-a69ac58e364e')
+;
+
+-- Oct 4, 2019, 2:24:19 PM MYT
+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','Scheduler stopped successfully',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:24:18','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:24:18','YYYY-MM-DD HH24:MI:SS'),100,200574,'SchedulerStopped','D','f4620ecb-bac1-408b-8609-e1997cd5a598')
+;
+
+-- Oct 4, 2019, 2:30:12 PM MYT
+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','Scheduler stopped successfully',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:30:06','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:30:06','YYYY-MM-DD HH24:MI:SS'),100,200575,'SchedulerStoppedSuccess','D','d918dd12-9578-4160-9212-28af2114b5fe')
+;
+
+-- Oct 4, 2019, 2:30:48 PM MYT
+UPDATE AD_Message SET Value='SchedulerStopSuccess',Updated=TO_TIMESTAMP('2019-10-04 14:30:48','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200575
+;
+
+-- Oct 4, 2019, 2:31:14 PM MYT
+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 ('E','Failed to stop scheduler. Error:',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:31:13','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:31:13','YYYY-MM-DD HH24:MI:SS'),100,200576,'SchedulerStopFail','D','40ff365f-9a0f-4de6-849f-c6527d844e37')
+;
+
+-- Oct 4, 2019, 2:31:38 PM MYT
+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','Scheduler started successfully',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:31:38','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:31:38','YYYY-MM-DD HH24:MI:SS'),100,200577,'SchedulerStartSuccess','D','fc356061-f311-464b-9962-6a7dbac028dd')
+;
+
+-- Oct 4, 2019, 2:32:00 PM MYT
+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 ('E','Failed to start scheduler. Error:',0,0,'Y',TO_TIMESTAMP('2019-10-04 14:32:00','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 14:32:00','YYYY-MM-DD HH24:MI:SS'),100,200578,'SchedulerStartFail','D','d79f3d08-2d00-4281-b01c-00cdc80f085c')
+;
+
+-- IDEMPIERE-4060 Implement change scheduler state at scheduler window
+-- Oct 4, 2019, 2:46:01 PM MYT
+UPDATE AD_Message SET Value='SchedulerAddAndStartSuccess',Updated=TO_TIMESTAMP('2019-10-04 14:46:01','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200572
+;
+
+-- IDEMPIERE-4060 Implement change scheduler state at scheduler window
+-- Oct 4, 2019, 4:43:05 PM MYT
+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','Change scheduler state',0,0,'Y',TO_TIMESTAMP('2019-10-04 16:43:04','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-10-04 16:43:04','YYYY-MM-DD HH24:MI:SS'),100,200579,'org.adempiere.webui.scheduler.ChangeStateAction.tooltip','D','241b6ad0-f3ad-4541-9ab9-8c6a163e7f0d')
+;
+
+SELECT register_migration_script('201910041600_IDEMPIERE-4060.sql') FROM dual
+;
diff --git a/org.adempiere.ui.zk/.project b/org.adempiere.ui.zk/.project
index 82151d0d0a..7923d857aa 100644
--- a/org.adempiere.ui.zk/.project
+++ b/org.adempiere.ui.zk/.project
@@ -25,6 +25,11 @@
+
+ org.eclipse.pde.ds.core.builder
+
+
+
org.eclipse.m2e.core.maven2Nature
diff --git a/org.adempiere.ui.zk/META-INF/MANIFEST.MF b/org.adempiere.ui.zk/META-INF/MANIFEST.MF
index 74ee78fa5f..349814c05f 100644
--- a/org.adempiere.ui.zk/META-INF/MANIFEST.MF
+++ b/org.adempiere.ui.zk/META-INF/MANIFEST.MF
@@ -34,9 +34,11 @@ Import-Package: groovy.transform.stc;version="2.4.7",
org.apache.tools.ant,
org.apache.tools.ant.taskdefs,
org.compiere.css,
+ org.compiere.server,
org.eclipse.core.runtime;version="3.4.0",
org.eclipse.jetty.websocket.jsr356;version="9.4.12",
org.eclipse.jetty.websocket.jsr356.server;version="9.4.12",
+ org.idempiere.server.cluster,
org.jfree.chart,
org.jfree.chart.encoders,
org.jfree.chart.entity,
@@ -46,6 +48,7 @@ Import-Package: groovy.transform.stc;version="2.4.7",
org.jfree.data.time,
org.jfree.util,
org.osgi.framework;version="1.7.0",
+ org.osgi.service.component.annotations;version="1.3.0",
org.osgi.service.event;version="1.3.0",
org.osgi.util.tracker;version="1.5.0",
org.slf4j;version="1.7.2",
diff --git a/org.adempiere.ui.zk/OSGI-INF/org.adempiere.webui.scheduler.ChangeStateAction.xml b/org.adempiere.ui.zk/OSGI-INF/org.adempiere.webui.scheduler.ChangeStateAction.xml
new file mode 100644
index 0000000000..f150f9faed
--- /dev/null
+++ b/org.adempiere.ui.zk/OSGI-INF/org.adempiere.webui.scheduler.ChangeStateAction.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/scheduler/ChangeStateAction.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/scheduler/ChangeStateAction.java
new file mode 100644
index 0000000000..0a38457e8e
--- /dev/null
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/scheduler/ChangeStateAction.java
@@ -0,0 +1,219 @@
+/**********************************************************************
+* This file is part of iDempiere ERP Open Source *
+* http://www.idempiere.org *
+* *
+* Copyright (C) Contributors *
+* *
+* This program is free software; you can redistribute it and/or *
+* modify it under the terms of the GNU General Public License *
+* as published by the Free Software Foundation; either version 2 *
+* of the License, or (at your option) any later version. *
+* *
+* 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., 51 Franklin Street, Fifth Floor, Boston, *
+* MA 02110-1301, USA. *
+* *
+* Contributors: *
+* - Trek Global Corporation *
+* - Heng Sin Low *
+**********************************************************************/
+package org.adempiere.webui.scheduler;
+
+import org.adempiere.base.IServiceHolder;
+import org.adempiere.base.Service;
+import org.adempiere.util.Callback;
+import org.adempiere.webui.LayoutUtils;
+import org.adempiere.webui.action.IAction;
+import org.adempiere.webui.adwindow.ADWindow;
+import org.adempiere.webui.adwindow.ADWindowContent;
+import org.adempiere.webui.component.Button;
+import org.adempiere.webui.factory.ButtonFactory;
+import org.adempiere.webui.window.FDialog;
+import org.compiere.model.GridField;
+import org.compiere.model.GridTab;
+import org.compiere.model.MScheduler;
+import org.compiere.server.AdempiereServerMgr;
+import org.compiere.server.IServerManager;
+import org.compiere.util.Env;
+import org.compiere.util.Msg;
+import org.compiere.util.Util;
+import org.idempiere.distributed.IClusterService;
+import org.idempiere.server.cluster.ClusterServerMgr;
+import org.osgi.service.component.annotations.Component;
+import org.zkoss.image.Image;
+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.Clients;
+import org.zkoss.zul.Popup;
+import org.zkoss.zul.Toolbarbutton;
+
+/**
+ * @author hengsin
+ *
+ */
+@Component(name = "org.adempiere.webui.scheduler.ChangeStateAction", service = {IAction.class})
+public class ChangeStateAction implements IAction, EventListener {
+
+ private static final String ON_START_SCHEDULER_EVENT = "onStartScheduler";
+ private static final String ON_STOP_SCHEDULER_EVENT = "onStopScheduler";
+ private static final String ON_ADD_SCHEDULER_EVENT = "onAddScheduler";
+ private static final String SCHEDULER_MODEL = "scheduler.model";
+ private static final String SCHEDULER_STATE = "scheduler.state";
+
+ /**
+ * default constructor
+ */
+ public ChangeStateAction() {
+ }
+
+ @Override
+ public void execute(Object target) {
+ if (target instanceof ADWindow) {
+ ADWindow adwindow = (ADWindow) target;
+ ADWindowContent content = adwindow.getADWindowContent();
+ GridTab gridTab = content.getADTab().getADTabpanel(0).getGridTab();
+ if (MScheduler.Table_Name.equals(gridTab.getTableName()) && gridTab.getRecord_ID() > 0) {
+ MScheduler scheduler = new MScheduler(Env.getCtx(), gridTab.getRecord_ID(), null);
+ IServerManager serverMgr = getServerMgr();
+ int status = serverMgr.getServerStatus(scheduler.getServerID());
+ String label = null;
+ if (status == IServerManager.SERVER_STATE_NOT_SCHEDULE)
+ label = Msg.getMsg(Env.getCtx(), "SchedulerNotSchedule");
+ else if (status == IServerManager.SERVER_STATE_STARTED)
+ label = Msg.getMsg(Env.getCtx(), "SchedulerStarted");
+ else if (status == IServerManager.SERVER_STATE_STOPPED)
+ label = Msg.getMsg(Env.getCtx(), "SchedulerStopped");
+ else
+ FDialog.error(content.getWindowNo(), content.getComponent(), "CantReadCurrentSchedulerState");
+
+ if (label == null)
+ return;
+
+ Button btn = ButtonFactory.createButton(label, null, null);
+ btn.setAttribute(SCHEDULER_STATE, status);
+ btn.setAttribute(SCHEDULER_MODEL, scheduler);
+ btn.addActionListener(this);
+ Popup popup = new Popup();
+ popup.appendChild(btn);
+ content.getComponent().appendChild(popup);
+ popup.open(content.getToolbar().getButton("SchedulerState"), "after_end");
+
+ GridField descriptionField = gridTab.getField("Description");
+ if (!descriptionField.isEditable(Env.getCtx(), true, false)) {
+ btn.setEnabled(false);
+ }
+
+ btn.addEventListener(ON_START_SCHEDULER_EVENT, evt -> {
+ Object schedulerAttr = evt.getTarget().getAttribute(SCHEDULER_MODEL);
+ if (schedulerAttr != null && schedulerAttr instanceof MScheduler) {
+ MScheduler model = (MScheduler) schedulerAttr;
+ String error = serverMgr.start(model.getServerID());
+ if (error == null) {
+ FDialog.info(0, null, "SchedulerStartSuccess");
+ } else {
+ FDialog.error(0, "SchedulerStartFail", error);
+ }
+ Clients.clearBusy();
+ }
+ });
+
+ btn.addEventListener(ON_STOP_SCHEDULER_EVENT, evt -> {
+ Object schedulerAttr = evt.getTarget().getAttribute(SCHEDULER_MODEL);
+ if (schedulerAttr != null && schedulerAttr instanceof MScheduler) {
+ MScheduler model = (MScheduler) schedulerAttr;
+ String error = serverMgr.stop(model.getServerID());
+ if (error == null) {
+ FDialog.info(0, null, "SchedulerStopSuccess");
+ } else {
+ FDialog.error(0, "SchedulerStopFail", error);
+ }
+ Clients.clearBusy();
+ }
+ });
+
+ btn.addEventListener(ON_ADD_SCHEDULER_EVENT, evt -> {
+ Object schedulerAttr = evt.getTarget().getAttribute(SCHEDULER_MODEL);
+ if (schedulerAttr != null && schedulerAttr instanceof MScheduler) {
+ String error = serverMgr.addScheduler(scheduler);
+ if (error == null) {
+ FDialog.info(0, null, "SchedulerAddAndStartSuccess");
+ } else {
+ FDialog.error(0, "SchedulerAddAndStartFail", error);
+ }
+ Clients.clearBusy();
+ }
+ });
+ }
+ }
+ }
+
+ private IServerManager getServerMgr() {
+ IServerManager serverMgr = null;
+ IServiceHolder holder = Service.locator().locate(IClusterService.class);
+ IClusterService service = holder != null ? holder.getService() : null;
+ if (service != null)
+ serverMgr = ClusterServerMgr.getInstance();
+ else
+ serverMgr = AdempiereServerMgr.get(false);
+ return serverMgr;
+ }
+
+ @Override
+ public void decorate(Toolbarbutton toolbarButton) {
+ if (Util.isEmpty(toolbarButton.getTooltiptext()))
+ toolbarButton.setTooltiptext(toolbarButton.getLabel());
+ toolbarButton.setIconSclass("z-icon-spinner");
+ toolbarButton.setLabel(null);
+ toolbarButton.setImageContent((Image)null);
+ LayoutUtils.addSclass("font-icon-toolbar-button", toolbarButton);
+ }
+
+ @Override
+ public void onEvent(Event evt) throws Exception {
+ Object stateAttr = evt.getTarget().getAttribute(SCHEDULER_STATE);
+ Object schedulerAttr = evt.getTarget().getAttribute(SCHEDULER_MODEL);
+ if (stateAttr != null && stateAttr instanceof Number && schedulerAttr != null && schedulerAttr instanceof MScheduler) {
+ int state = ((Number)stateAttr).intValue();
+ if (state == IServerManager.SERVER_STATE_NOT_SCHEDULE) {
+ FDialog.ask(0, null, "SchedulerAddAndStartPrompt", new Callback() {
+ @Override
+ public void onCallback(Boolean result) {
+ if (result) {
+ Clients.showBusy(Msg.getMsg(Env.getCtx(), "Processing"));
+ Events.echoEvent(ON_ADD_SCHEDULER_EVENT, evt.getTarget(), null);
+ }
+ }
+ });
+ } else if (state == IServerManager.SERVER_STATE_STARTED) {
+ FDialog.ask(0, null, "SchedulerStopPrompt", new Callback() {
+ @Override
+ public void onCallback(Boolean result) {
+ if (result) {
+ Clients.showBusy(Msg.getMsg(Env.getCtx(), "Processing"));
+ Events.echoEvent(ON_STOP_SCHEDULER_EVENT, evt.getTarget(), null);
+ }
+
+ }
+ });
+ }
+ else if (state == IServerManager.SERVER_STATE_STOPPED) {
+ FDialog.ask(0, null, "SchedulerStartPrompt", new Callback() {
+ @Override
+ public void onCallback(Boolean result) {
+ if (result) {
+ Clients.showBusy(Msg.getMsg(Env.getCtx(), "Processing"));
+ Events.echoEvent(ON_START_SCHEDULER_EVENT, evt.getTarget(), null);
+ }
+ }
+ });
+ }
+ }
+ }
+}