From 32b4af94ae0ec6877ec37b19fc872f5529820a23 Mon Sep 17 00:00:00 2001 From: Diego Ruiz Date: Thu, 22 Oct 2015 12:10:16 +0200 Subject: [PATCH] IDEMPIERE-2895 UX: Save changes in Detail Tab of a Master-Detail window --- .../oracle/201510221142_IDEMPIERE-2895.sql | 48 ++++++++++ .../201510221142_IDEMPIERE-2895.sql | 45 +++++++++ .../webui/adwindow/CompositeADTabbox.java | 9 ++ .../adempiere/webui/adwindow/DetailPane.java | 95 +++++++++++++++++-- 4 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 migration/i2.1z/oracle/201510221142_IDEMPIERE-2895.sql create mode 100644 migration/i2.1z/postgresql/201510221142_IDEMPIERE-2895.sql diff --git a/migration/i2.1z/oracle/201510221142_IDEMPIERE-2895.sql b/migration/i2.1z/oracle/201510221142_IDEMPIERE-2895.sql new file mode 100644 index 0000000000..44cb875de7 --- /dev/null +++ b/migration/i2.1z/oracle/201510221142_IDEMPIERE-2895.sql @@ -0,0 +1,48 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- IDEMPIERE-2895 UX: Save changes in Detail Tab of a Master-Detail window +-- Oct 21, 2015 2:37:45 PM CEST +INSERT INTO AD_Ref_List (AD_Ref_List_ID,Name,AD_Reference_ID,Value,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,EntityType,AD_Ref_List_UU) VALUES (200318,'Detail',104,'D',0,0,'Y',TO_DATE('2015-10-21 14:37:45','YYYY-MM-DD HH24:MI:SS'),0,TO_DATE('2015-10-21 14:37:45','YYYY-MM-DD HH24:MI:SS'),0,'D','c08370ea-385c-4569-bc28-1b6a869f700a') +; + +-- Oct 21, 2015 2:38:16 PM CEST +UPDATE AD_Val_Rule SET Name='AD_ToolBarButton Action - Window/Report/Detail', Code='AD_Ref_List.Value IN (''W'',''R'',''D'')',Updated=TO_DATE('2015-10-22 10:25:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Val_Rule_ID=200002 +; + +-- Oct 21, 2015 2:45:15 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,Action,SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_DATE('2015-10-21 14:45:15','YYYY-MM-DD HH24:MI:SS'),0,'New','Y',200082,'Detail - New',TO_DATE('2015-10-21 14:45:15','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'6851393a-1f9b-4dae-8562-3d206a87ae62','D',10,'N','N') +; + +-- Oct 21, 2015 2:46:04 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,Action,SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_DATE('2015-10-21 14:46:04','YYYY-MM-DD HH24:MI:SS'),0,'Delete','Y',200083,'Detail - Delete',TO_DATE('2015-10-21 14:46:04','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'dd8ab071-0a60-42bc-948b-cd0a09d90fa3','D',30,'N','N') +; + +-- Oct 21, 2015 2:46:28 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,Action,SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_DATE('2015-10-21 14:46:28','YYYY-MM-DD HH24:MI:SS'),0,'Save','Y',200084,'Detail - Save',TO_DATE('2015-10-21 14:46:28','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'fb6ffe6d-3e54-43ba-8fac-d7e6145af116','D',40,'N','N') +; + +-- Oct 21, 2015 2:47:21 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,Action,SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_DATE('2015-10-21 14:47:21','YYYY-MM-DD HH24:MI:SS'),0,'Process','Y',200085,'Detail - Process',TO_DATE('2015-10-21 14:47:21','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'29608027-c79c-4a28-a8cb-89749077e0cd','D',50,'N','N') +; + +-- Oct 21, 2015 2:47:35 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,Action,SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_DATE('2015-10-21 14:47:34','YYYY-MM-DD HH24:MI:SS'),0,'Edit','Y',200086,'Detail - Edit',TO_DATE('2015-10-21 14:47:34','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'11b7e9ee-5f06-4595-96ca-a14321b93c38','D',20,'N','N') +; + +-- Oct 22, 2015 11:28:13 AM CEST +UPDATE AD_Val_Rule SET Code='(((AD_ToolbarButton.Action=''@Action@'') OR (AD_ToolbarButton.Action||''@Action@''=''RWD'' )) AND (AD_ToolbarButton.AD_Tab_ID IS NULL OR COALESCE(AD_ToolbarButton.AD_Tab_ID,0)=@AD_Tab_ID:0@))',Updated=TO_DATE('2015-10-22 11:28:13','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Val_Rule_ID=200011 +; + +-- Oct 22, 2015 11:42:03 AM CEST +UPDATE AD_Field SET DisplayLogic='@Action@=W | @Action@=D',Updated=TO_DATE('2015-10-22 11:42:03','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Field_ID=200070 +; + +-- Oct 22, 2015 11:42:13 AM CEST +UPDATE AD_Field SET DisplayLogic='@Action@=W | @Action@=D',Updated=TO_DATE('2015-10-22 11:42:13','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Field_ID=200732 +; + +SELECT register_migration_script('201510221142_IDEMPIERE-2895.sql') FROM dual +; + + diff --git a/migration/i2.1z/postgresql/201510221142_IDEMPIERE-2895.sql b/migration/i2.1z/postgresql/201510221142_IDEMPIERE-2895.sql new file mode 100644 index 0000000000..42fb4c1041 --- /dev/null +++ b/migration/i2.1z/postgresql/201510221142_IDEMPIERE-2895.sql @@ -0,0 +1,45 @@ +-- IDEMPIERE-2895 UX: Save changes in Detail Tab of a Master-Detail window +-- Oct 21, 2015 2:37:45 PM CEST +INSERT INTO AD_Ref_List (AD_Ref_List_ID,Name,AD_Reference_ID,Value,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,EntityType,AD_Ref_List_UU) VALUES (200318,'Detail',104,'D',0,0,'Y',TO_TIMESTAMP('2015-10-21 14:37:45','YYYY-MM-DD HH24:MI:SS'),0,TO_TIMESTAMP('2015-10-21 14:37:45','YYYY-MM-DD HH24:MI:SS'),0,'D','c08370ea-385c-4569-bc28-1b6a869f700a') +; + +-- Oct 21, 2015 2:38:16 PM CEST +UPDATE AD_Val_Rule SET Name='AD_ToolBarButton Action - Window/Report/Detail', Code='AD_Ref_List.Value IN (''W'',''R'',''D'')',Updated=TO_TIMESTAMP('2015-10-22 10:25:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Val_Rule_ID=200002 +; + +-- Oct 21, 2015 2:45:15 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,"action",SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_TIMESTAMP('2015-10-21 14:45:15','YYYY-MM-DD HH24:MI:SS'),0,'New','Y',200082,'Detail - New',TO_TIMESTAMP('2015-10-21 14:45:15','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'6851393a-1f9b-4dae-8562-3d206a87ae62','D',10,'N','N') +; + +-- Oct 21, 2015 2:46:04 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,"action",SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_TIMESTAMP('2015-10-21 14:46:04','YYYY-MM-DD HH24:MI:SS'),0,'Delete','Y',200083,'Detail - Delete',TO_TIMESTAMP('2015-10-21 14:46:04','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'dd8ab071-0a60-42bc-948b-cd0a09d90fa3','D',30,'N','N') +; + +-- Oct 21, 2015 2:46:28 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,"action",SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_TIMESTAMP('2015-10-21 14:46:28','YYYY-MM-DD HH24:MI:SS'),0,'Save','Y',200084,'Detail - Save',TO_TIMESTAMP('2015-10-21 14:46:28','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'fb6ffe6d-3e54-43ba-8fac-d7e6145af116','D',40,'N','N') +; + +-- Oct 21, 2015 2:47:21 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,"action",SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_TIMESTAMP('2015-10-21 14:47:21','YYYY-MM-DD HH24:MI:SS'),0,'Process','Y',200085,'Detail - Process',TO_TIMESTAMP('2015-10-21 14:47:21','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'29608027-c79c-4a28-a8cb-89749077e0cd','D',50,'N','N') +; + +-- Oct 21, 2015 2:47:35 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,KeyStroke_KeyCode,KeyStroke_Modifiers,AD_ToolBarButton_UU,"action",SeqNo,IsAdvancedButton,IsAddSeparator) VALUES (0,0,TO_TIMESTAMP('2015-10-21 14:47:34','YYYY-MM-DD HH24:MI:SS'),0,'Edit','Y',200086,'Detail - Edit',TO_TIMESTAMP('2015-10-21 14:47:34','YYYY-MM-DD HH24:MI:SS'),0,'N',0,0,'11b7e9ee-5f06-4595-96ca-a14321b93c38','D',20,'N','N') +; + +-- Oct 22, 2015 11:28:13 AM CEST +UPDATE AD_Val_Rule SET Code='(((AD_ToolbarButton.Action=''@Action@'') OR (AD_ToolbarButton.Action||''@Action@''=''RWD'' )) AND (AD_ToolbarButton.AD_Tab_ID IS NULL OR COALESCE(AD_ToolbarButton.AD_Tab_ID,0)=@AD_Tab_ID:0@))',Updated=TO_TIMESTAMP('2015-10-22 11:28:13','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Val_Rule_ID=200011 +; + +-- Oct 22, 2015 11:42:03 AM CEST +UPDATE AD_Field SET DisplayLogic='@Action@=W | @Action@=D',Updated=TO_TIMESTAMP('2015-10-22 11:42:03','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Field_ID=200070 +; + +-- Oct 22, 2015 11:42:13 AM CEST +UPDATE AD_Field SET DisplayLogic='@Action@=W | @Action@=D',Updated=TO_TIMESTAMP('2015-10-22 11:42:13','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Field_ID=200732 +; + +SELECT register_migration_script('201510221142_IDEMPIERE-2895.sql') FROM dual +; + + diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java index 5c7e4c05ca..bdf8bd386c 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java @@ -145,6 +145,15 @@ public class CompositeADTabbox extends AbstractADTabbox } }); } + else if (DetailPane.ON_SAVE_EVENT.equals(event.getName())) { + if (headerTab.getGridTab().isNew()) return; + + final IADTabpanel tabPanel = getSelectedDetailADTabpanel(); + if (!tabPanel.getGridTab().dataSave(true)) { + showLastError(); + } + tabPanel.getGridTab().dataRefreshAll(true, true); + } else if (DetailPane.ON_DELETE_EVENT.equals(event.getName())) { onDelete(); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/DetailPane.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/DetailPane.java index 460671f875..81670707e8 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/DetailPane.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/DetailPane.java @@ -3,11 +3,15 @@ */ package org.adempiere.webui.adwindow; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.adempiere.base.IServiceHolder; import org.adempiere.webui.LayoutUtils; +import org.adempiere.webui.action.Actions; +import org.adempiere.webui.action.IAction; import org.adempiere.webui.component.ADTabListModel.ADTabLabel; import org.adempiere.webui.component.Label; import org.adempiere.webui.component.Panel; @@ -19,9 +23,11 @@ import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.component.Window; import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.theme.ThemeManager; +import org.compiere.model.MToolBarButton; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; +import org.zkoss.image.AImage; import org.zkoss.zhtml.Text; import org.zkoss.zk.au.out.AuScript; import org.zkoss.zk.ui.Component; @@ -37,6 +43,7 @@ import org.zkoss.zk.ui.sys.ExecutionCtrl; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.Div; import org.zkoss.zul.Hbox; +import org.zkoss.zul.Separator; import org.zkoss.zul.Space; import org.zkoss.zul.Tabpanels; import org.zkoss.zul.Tabs; @@ -59,6 +66,8 @@ public class DetailPane extends Panel implements EventListener, IdSpace { private static final String BTN_EDIT_ID = "BtnEdit"; private static final String BTN_NEW_ID = "BtnNew"; + + private static final String BTN_SAVE_ID = "BtnSave"; private static final String TABBOX_ONSELECT_ATTRIBUTE = "detailpane.tabbox.onselect"; @@ -72,6 +81,8 @@ public class DetailPane extends Panel implements EventListener, IdSpace { private static final String EDIT_IMAGE = "images/EditRecord16.png"; private static final String NEW_IMAGE = "images/New16.png"; private static final String PROCESS_IMAGE = "images/Process16.png"; + private static final String SAVE_IMAGE = "images/Save16.png"; + private ToolBarButton btnNew; private long prevKeyEventTime = 0; @@ -96,6 +107,11 @@ public class DetailPane extends Panel implements EventListener, IdSpace { public static final String ON_NEW_EVENT = "onNew"; public static final String ON_EDIT_EVENT = "onEdit"; + + public static final String ON_SAVE_EVENT = "onSave"; + + private HashMap buttons = new HashMap(); + private List toolbarCustomButtons = new ArrayList(); public DetailPane() { tabbox = new Tabbox(); @@ -259,7 +275,6 @@ public class DetailPane extends Panel implements EventListener, IdSpace { btnNew = new ToolBarButton(); btnNew.setImage(ThemeManager.getThemeResource(NEW_IMAGE)); btnNew.setId(BTN_NEW_ID); - toolbar.appendChild(btnNew); btnNew.addEventListener(Events.ON_CLICK, new EventListener() { @Override public void onEvent(Event event) throws Exception { @@ -267,13 +282,13 @@ public class DetailPane extends Panel implements EventListener, IdSpace { } }); btnNew.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "New")) + " Shift+Alt+N"); - + buttons.put(BTN_NEW_ID.substring(3, BTN_NEW_ID.length()), btnNew); + ToolBarButton button = new ToolBarButton(); button = new ToolBarButton(); button.setImage(ThemeManager.getThemeResource(EDIT_IMAGE)); button.setId(BTN_EDIT_ID); - toolbar.appendChild(button); button.addEventListener(Events.ON_CLICK, new EventListener() { @Override public void onEvent(Event event) throws Exception { @@ -281,11 +296,11 @@ public class DetailPane extends Panel implements EventListener, IdSpace { } }); button.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "EditRecord"))); - + buttons.put(BTN_EDIT_ID.substring(3, BTN_EDIT_ID.length()), button); + button = new ToolBarButton(); button.setImage(ThemeManager.getThemeResource(DELETE_IMAGE)); button.setId(BTN_DELETE_ID); - toolbar.appendChild(button); button.addEventListener(Events.ON_CLICK, new EventListener() { @Override public void onEvent(Event event) throws Exception { @@ -294,12 +309,26 @@ public class DetailPane extends Panel implements EventListener, IdSpace { } }); button.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Delete"))); + buttons.put(BTN_DELETE_ID.substring(3, BTN_DELETE_ID.length()), button); + + button = new ToolBarButton(); + button.setImage(ThemeManager.getThemeResource(SAVE_IMAGE)); + button.setId(BTN_SAVE_ID); + button.addEventListener(Events.ON_CLICK, new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + Event openEvent = new Event(ON_SAVE_EVENT, DetailPane.this); + eventListener.onEvent(openEvent); + } + }); + button.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Save"))); + buttons.put(BTN_SAVE_ID.substring(3, BTN_SAVE_ID.length()), button); + if (!tabPanel.getGridTab().isSortTab()) { button = new ToolBarButton(); button.setImage(ThemeManager.getThemeResource(PROCESS_IMAGE)); button.setId(BTN_PROCESS_ID); - toolbar.appendChild(button); button.addEventListener(Events.ON_CLICK, new EventListener() { @Override public void onEvent(Event event) throws Exception { @@ -307,6 +336,56 @@ public class DetailPane extends Panel implements EventListener, IdSpace { } }); button.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Process"))); + buttons.put(BTN_PROCESS_ID.substring(3, BTN_PROCESS_ID.length()), button); + } + + MToolBarButton[] officialButtons = MToolBarButton.getToolbarButtons("D", null); + for (MToolBarButton toolbarButton : officialButtons) { + if ( !toolbarButton.isActive() ) { + buttons.remove(toolbarButton.getComponentName()); + } else { + if ( toolbarButton.isCustomization() ) { + String actionId = toolbarButton.getActionClassName(); + IServiceHolder serviceHolder = Actions.getAction(actionId); + if ( serviceHolder != null && serviceHolder.getService() != null ) { + + String labelKey = actionId + ".label"; + String tooltipKey = actionId + ".tooltip"; + String label = Msg.getMsg(Env.getCtx(), labelKey); + String tooltiptext = Msg.getMsg(Env.getCtx(), tooltipKey); + if ( labelKey.equals(label) ) { + label = toolbarButton.getName(); + } + if ( tooltipKey.equals(tooltiptext) ) { + tooltipKey = null; + } + ToolBarButton btn = new ToolBarButton(); + btn.setName("Btn"+toolbarButton.getComponentName()); + btn.setId("Btn"+toolbarButton.getComponentName()); + btn.setTooltiptext(tooltiptext); + btn.setDisabled(false); + + AImage aImage = Actions.getActionImage(actionId); + if ( aImage != null ) { + btn.setImageContent(aImage); + } else { + btn.setLabel(label); + } + + ToolbarCustomButton toolbarCustomBtn = new ToolbarCustomButton(toolbarButton, btn, actionId, tabPanel.getGridTab().getWindowNo()); + toolbarCustomButtons.add(toolbarCustomBtn); + + toolbar.appendChild(btn); + } + } else { + if (buttons.get(toolbarButton.getComponentName()) != null) { + toolbar.appendChild(buttons.get(toolbarButton.getComponentName())); + if (toolbarButton.isAddSeparator()) { + toolbar.appendChild(new Separator("vertical")); + } + } + } + } } Hbox messageContainer = new Hbox(); @@ -604,7 +683,9 @@ public class DetailPane extends Panel implements EventListener, IdSpace { btn.setDisabled(!enableDelete); } else if (BTN_EDIT_ID.equals(btn.getId())) { btn.setDisabled(false); - } + } else if (BTN_SAVE_ID.equals(btn.getId())) { + btn.setDisabled(false); + } if (windowRestrictList.contains(btn.getId())) { btn.setVisible(false); } else if (tabRestrictList.contains(btn.getId())) {