IDEMPIERE-1972:extend - Info window - process - by display logic field

This commit is contained in:
hieplq 2014-06-11 14:23:01 +07:00
parent b5e7d9aec8
commit e27b957666
7 changed files with 344 additions and 28 deletions

View File

@ -0,0 +1,63 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- May 31, 2014 10:33:25 AM ICT
-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator
INSERT INTO AD_Column (SeqNoSelection,IsSyncDatabase,Version,AD_Column_ID,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsParent,FieldLength,IsSelectionColumn,IsKey,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsUpdateable,ColumnName,Description,Help,Name,IsAllowCopy,Updated,CreatedBy,AD_Org_ID,IsActive,Created,UpdatedBy,IsToolbarButton,IsAlwaysUpdateable,AD_Client_ID,EntityType,IsEncrypted,IsSecure,AD_Element_ID,AD_Reference_ID,AD_Table_ID) VALUES (0,'N',0,211274,'N','N','N',0,'N',2000,'N','N','N','Y','f39fb481-a7f3-477b-924f-653478cf27b5','Y','DisplayLogic','If the Field is displayed, the result determines if the field is actually displayed','format := {expression} [{logic} {expression}]<br>
expression := @{context}@{operand}{value} or @{context}@{operand}{value}<br>
logic := {|}|{&}<br>
context := any global or window context <br>
value := strings or numbers<br>
logic operators := AND or OR with the previous result from left to right <br>
operand := eq{=}, gt{&gt;}, le{&lt;}, not{~^!} <br>
Examples: <br>
@AD_Table_ID@=14 | @Language@!GERGER <br>
@PriceLimit@>10 | @PriceList@>@PriceActual@<br>
@Name@>J<br>
Strings may be in single quotes (optional)','Display Logic','Y',TO_DATE('2014-05-31 10:33:19','YYYY-MM-DD HH24:MI:SS'),100,0,'Y',TO_DATE('2014-05-31 10:33:19','YYYY-MM-DD HH24:MI:SS'),100,'N','N',0,'D','N','N',283,14,200129)
;
-- May 31, 2014 10:33:35 AM ICT
ALTER TABLE AD_InfoProcess ADD DisplayLogic VARCHAR2(2000) DEFAULT NULL
;
-- May 31, 2014 10:35:29 AM ICT
INSERT INTO AD_Field (SortNo,IsEncrypted,AD_Tab_ID,DisplayLength,IsSameLine,IsHeading,SeqNo,IsCentrallyMaintained,AD_Field_ID,IsReadOnly,Help,Description,Name,AD_Field_UU,IsDisplayed,IsFieldOnly,UpdatedBy,AD_Org_ID,CreatedBy,Updated,IsActive,IsDisplayedGrid,SeqNoGrid,XPosition,IsQuickEntry,AD_Client_ID,ColumnSpan,NumLines,IsAdvancedField,IsDefaultFocus,AD_Column_ID,EntityType,Created) VALUES (0,'N',200142,0,'N','N',120,'Y',203050,'N','format := {expression} [{logic} {expression}]<br>
expression := @{context}@{operand}{value} or @{context}@{operand}{value}<br>
logic := {|}|{&}<br>
context := any global or window context <br>
value := strings or numbers<br>
logic operators := AND or OR with the previous result from left to right <br>
operand := eq{=}, gt{&gt;}, le{&lt;}, not{~^!} <br>
Examples: <br>
@AD_Table_ID@=14 | @Language@!GERGER <br>
@PriceLimit@>10 | @PriceList@>@PriceActual@<br>
@Name@>J<br>
Strings may be in single quotes (optional)','If the Field is displayed, the result determines if the field is actually displayed','Display Logic','c6112319-f905-4614-a2ee-f27945e414be','Y','N',100,0,100,TO_DATE('2014-05-31 10:35:23','YYYY-MM-DD HH24:MI:SS'),'Y','Y',60,1,'N',0,1,1,'N','N',211274,'D',TO_DATE('2014-05-31 10:35:23','YYYY-MM-DD HH24:MI:SS'))
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=50,Updated=TO_DATE('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203035
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=60,Updated=TO_DATE('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203036
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=70,Updated=TO_DATE('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203037
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=80,Updated=TO_DATE('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203038
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=90, ColumnSpan=5,Updated=TO_DATE('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203050
;
-- May 31, 2014 10:39:24 AM ICT
UPDATE AD_Field SET SeqNo=90, NumLines=2,Updated=TO_DATE('2014-05-31 10:39:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203050
;
SELECT register_migration_script('201405311604_IDEMPIERE-1972.sql') FROM dual
;

View File

@ -0,0 +1,60 @@
-- May 31, 2014 10:33:25 AM ICT
-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator
INSERT INTO AD_Column (SeqNoSelection,IsSyncDatabase,Version,AD_Column_ID,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsParent,FieldLength,IsSelectionColumn,IsKey,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsUpdateable,ColumnName,Description,Help,Name,IsAllowCopy,Updated,CreatedBy,AD_Org_ID,IsActive,Created,UpdatedBy,IsToolbarButton,IsAlwaysUpdateable,AD_Client_ID,EntityType,IsEncrypted,IsSecure,AD_Element_ID,AD_Reference_ID,AD_Table_ID) VALUES (0,'N',0,211274,'N','N','N',0,'N',2000,'N','N','N','Y','f39fb481-a7f3-477b-924f-653478cf27b5','Y','DisplayLogic','If the Field is displayed, the result determines if the field is actually displayed','format := {expression} [{logic} {expression}]<br>
expression := @{context}@{operand}{value} or @{context}@{operand}{value}<br>
logic := {|}|{&}<br>
context := any global or window context <br>
value := strings or numbers<br>
logic operators := AND or OR with the previous result from left to right <br>
operand := eq{=}, gt{&gt;}, le{&lt;}, not{~^!} <br>
Examples: <br>
@AD_Table_ID@=14 | @Language@!GERGER <br>
@PriceLimit@>10 | @PriceList@>@PriceActual@<br>
@Name@>J<br>
Strings may be in single quotes (optional)','Display Logic','Y',TO_TIMESTAMP('2014-05-31 10:33:19','YYYY-MM-DD HH24:MI:SS'),100,0,'Y',TO_TIMESTAMP('2014-05-31 10:33:19','YYYY-MM-DD HH24:MI:SS'),100,'N','N',0,'D','N','N',283,14,200129)
;
-- May 31, 2014 10:33:35 AM ICT
ALTER TABLE AD_InfoProcess ADD COLUMN DisplayLogic VARCHAR(2000) DEFAULT NULL
;
-- May 31, 2014 10:35:29 AM ICT
INSERT INTO AD_Field (SortNo,IsEncrypted,AD_Tab_ID,DisplayLength,IsSameLine,IsHeading,SeqNo,IsCentrallyMaintained,AD_Field_ID,IsReadOnly,Help,Description,Name,AD_Field_UU,IsDisplayed,IsFieldOnly,UpdatedBy,AD_Org_ID,CreatedBy,Updated,IsActive,IsDisplayedGrid,SeqNoGrid,XPosition,IsQuickEntry,AD_Client_ID,ColumnSpan,NumLines,IsAdvancedField,IsDefaultFocus,AD_Column_ID,EntityType,Created) VALUES (0,'N',200142,0,'N','N',120,'Y',203050,'N','format := {expression} [{logic} {expression}]<br>
expression := @{context}@{operand}{value} or @{context}@{operand}{value}<br>
logic := {|}|{&}<br>
context := any global or window context <br>
value := strings or numbers<br>
logic operators := AND or OR with the previous result from left to right <br>
operand := eq{=}, gt{&gt;}, le{&lt;}, not{~^!} <br>
Examples: <br>
@AD_Table_ID@=14 | @Language@!GERGER <br>
@PriceLimit@>10 | @PriceList@>@PriceActual@<br>
@Name@>J<br>
Strings may be in single quotes (optional)','If the Field is displayed, the result determines if the field is actually displayed','Display Logic','c6112319-f905-4614-a2ee-f27945e414be','Y','N',100,0,100,TO_TIMESTAMP('2014-05-31 10:35:23','YYYY-MM-DD HH24:MI:SS'),'Y','Y',60,1,'N',0,1,1,'N','N',211274,'D',TO_TIMESTAMP('2014-05-31 10:35:23','YYYY-MM-DD HH24:MI:SS'))
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=50,Updated=TO_TIMESTAMP('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203035
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=60,Updated=TO_TIMESTAMP('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203036
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=70,Updated=TO_TIMESTAMP('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203037
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=80,Updated=TO_TIMESTAMP('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203038
;
-- May 31, 2014 10:36:44 AM ICT
UPDATE AD_Field SET SeqNo=90, ColumnSpan=5,Updated=TO_TIMESTAMP('2014-05-31 10:36:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203050
;
-- May 31, 2014 10:39:24 AM ICT
UPDATE AD_Field SET SeqNo=90, NumLines=2,Updated=TO_TIMESTAMP('2014-05-31 10:39:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203050
;
SELECT register_migration_script('201405311604_IDEMPIERE-1972.sql') FROM dual
;

View File

@ -15,8 +15,12 @@ package org.adempiere.model;
import java.sql.ResultSet;
import java.util.Properties;
import java.util.logging.Level;
import org.compiere.model.MProcess;
import org.compiere.model.X_AD_InfoProcess;
import org.compiere.util.Env;
import org.compiere.util.Evaluatee;
import org.compiere.util.Evaluator;
/**
* Contain info of process in info window
@ -52,4 +56,34 @@ public class MInfoProcess extends X_AD_InfoProcess {
}
/**************************************************************************
* Is the Column Visible ? Evaluater base in display logic expression and context of this po
* @return true, if visible
*/
public boolean isDisplayed (final int windowNo)
{
return isDisplayed(this.getCtx(), windowNo);
}
/**************************************************************************
* Is the Column Visible ? Evaluater base in display logic expression and context
* @param ctx
* @return
*/
public boolean isDisplayed(final Properties ctx, final int windowNo) {
if (getDisplayLogic() == null || getDisplayLogic().trim().length() == 0)
return true;
Evaluatee evaluatee = new Evaluatee() {
public String get_ValueAsString(String variableName) {
return Env.getContext (ctx, windowNo, variableName, true);
}
};
boolean retValue = Evaluator.evaluateLogic(evaluatee, getDisplayLogic());
if (log.isLoggable(Level.FINEST)) log.finest(MProcess.get(getCtx(), getAD_Process_ID()).getName()
+ " (" + getDisplayLogic() + ") => " + retValue);
return retValue;
}
}

View File

@ -126,6 +126,19 @@ public interface I_AD_InfoProcess
*/
public int getCreatedBy();
/** Column name DisplayLogic */
public static final String COLUMNNAME_DisplayLogic = "DisplayLogic";
/** Set Display Logic.
* If the Field is displayed, the result determines if the field is actually displayed
*/
public void setDisplayLogic (String DisplayLogic);
/** Get Display Logic.
* If the Field is displayed, the result determines if the field is actually displayed
*/
public String getDisplayLogic();
/** Column name ImageURL */
public static final String COLUMNNAME_ImageURL = "ImageURL";

View File

@ -30,7 +30,7 @@ public class X_AD_InfoProcess extends PO implements I_AD_InfoProcess, I_Persiste
/**
*
*/
private static final long serialVersionUID = 20140529L;
private static final long serialVersionUID = 20140531L;
/** Standard Constructor */
public X_AD_InfoProcess (Properties ctx, int AD_InfoProcess_ID, String trxName)
@ -174,6 +174,23 @@ public class X_AD_InfoProcess extends PO implements I_AD_InfoProcess, I_Persiste
return new KeyNamePair(get_ID(), String.valueOf(getAD_Process_ID()));
}
/** Set Display Logic.
@param DisplayLogic
If the Field is displayed, the result determines if the field is actually displayed
*/
public void setDisplayLogic (String DisplayLogic)
{
set_Value (COLUMNNAME_DisplayLogic, DisplayLogic);
}
/** Get Display Logic.
@return If the Field is displayed, the result determines if the field is actually displayed
*/
public String getDisplayLogic ()
{
return (String)get_Value(COLUMNNAME_DisplayLogic);
}
/** Set Image URL.
@param ImageURL
URL of image

View File

@ -78,7 +78,6 @@ import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ComboitemRenderer;
import org.zkoss.zul.Div;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.North;
@ -123,7 +122,30 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
private List<GridField> gridFields;
private int AD_InfoWindow_ID;
private Checkbox checkAND;
/**
* All info process of this infoWindow
*/
protected MInfoProcess [] infoProcessList;
/**
* flag detect exists info process
*/
protected boolean haveProcess = false;
/**
* Info process have style is button
*/
protected List<MInfoProcess> infoProcessBtList;
/**
* Info process have style is drop down list
*/
protected List<MInfoProcess> infoProcessDropList;
/**
* Info process have style is menu
*/
protected List<MInfoProcess> infoProcessMenuList;
/**
* Menu contail process menu item
*/
protected Menupopup ipMenu;
/**
* @param WindowNo
* @param tableName
@ -169,7 +191,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
// make process button only in windown mode
if (!m_lookup){
// IDEMPIERE-1334
boolean haveProcess = initInfoProcess();
initInfoProcess();
// when have a process, force multi select mode
if (haveProcess)
p_multipleSelection = true;
@ -194,29 +216,38 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
/**
* IDEMPIERE-1334
* load info process info
* layout each info process as button or dropdown item
* separate by layout type
* init drop list and menu control
* set status of haveProcess flag
* @return true when have process, false when no process
*/
protected boolean initInfoProcess() {
protected void initInfoProcess() {
if (infoWindow == null){
return false;
return;
}
MInfoProcess [] infoProcessList = infoWindow.getInfoProcess(false);
infoProcessList = infoWindow.getInfoProcess(false);
if (infoProcessList.length == 0)
return;
haveProcess = true;
// ** layout info process flow order (button list, drop down, dialog,...)
// each layout type in a loop to ensure this order
// get info from process (name, help, des), set to name of button, item menu,...
MProcess process = null;
// make list process button
for (MInfoProcess infoProcess : infoProcessList){
// just add info process have layout is button
if (!MInfoProcess.LAYOUTTYPE_Button.equals(infoProcess.getLayoutType())){
if (!MInfoProcess.LAYOUTTYPE_Button.equals(infoProcess.getLayoutType()))
continue;
}
process = MProcess.get(Env.getCtx(), infoProcess.getAD_Process_ID());
if (infoProcessBtList == null)
infoProcessBtList = new ArrayList<MInfoProcess> ();
infoProcessBtList.add(infoProcess);
// make process button
MProcess process = MProcess.get(Env.getCtx(), infoProcess.getAD_Process_ID());
Button btProcess = confirmPanel.addProcessButton(process.get_Translation(MProcess.COLUMNNAME_Name), infoProcess.getImageURL());
if (Util.isEmpty(infoProcess.getImageURL(), true)) {
btProcess.setImage(null);
@ -233,18 +264,21 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
btProcessList.add(btProcess);
}
// filte just infoprocess have layout type is drop list for model of combobox
List<MInfoProcess> infoProcessDropList = new ArrayList<MInfoProcess>();
// make list process for drop down
for (MInfoProcess infoProcess : infoProcessList){
if (!MInfoProcess.LAYOUTTYPE_List.equals(infoProcess.getLayoutType())){
if (!MInfoProcess.LAYOUTTYPE_List.equals(infoProcess.getLayoutType()))
continue;
}
if (infoProcessDropList == null)
infoProcessDropList = new ArrayList<MInfoProcess>();
infoProcessDropList.add(infoProcess);
}
// make combobox contain list info process
if (infoProcessDropList.size() > 0){
// init combobox control
if (infoProcessDropList != null && infoProcessDropList.size() > 0){
cbbProcess = new Combobox ();
ListModel<MInfoProcess> infoProccessModel = new ListModelList<MInfoProcess>(infoProcessDropList);
// render item, use name to display
cbbProcess.setItemRenderer(new ComboitemRenderer<MInfoProcess>() {
public void render(Comboitem item, MInfoProcess data, int index){
@ -260,22 +294,24 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
// update tooltip hepl when select a item
cbbProcess.addEventListener(Events.ON_SELECT, this);
cbbProcess.setModel(infoProccessModel);
confirmPanel.addComponentsCenter(cbbProcess);
btCbbProcess = confirmPanel.addProcessButton(Msg.getMsg(Env.getCtx(), ConfirmPanel.A_PROCESS), null);
btCbbProcess.addEventListener(Events.ON_CLICK, this);
}
// make menu button
Menupopup ipMenu = null;
// make list process for menu
for (MInfoProcess infoProcess : infoProcessList){
// just add info process have layout is bt_menu
if (!MInfoProcess.LAYOUTTYPE_Menu.equals(infoProcess.getLayoutType())){
continue;
}
process = MProcess.get(Env.getCtx(), infoProcess.getAD_Process_ID());
if (infoProcessMenuList == null)
infoProcessMenuList = new ArrayList<MInfoProcess>();
infoProcessMenuList.add(infoProcess);
// init popup menu
if (ipMenu == null){
@ -287,7 +323,88 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
btMenuProcess = confirmPanel.addProcessButton("ProcessMenu", null);
btMenuProcess.setPopup("ipMenu, before_start");
}
}
}
/**
* {@inheritDoc}
*/
@Override
protected void bindInfoProcess (){
bindInfoProcessBt ();
bindInfoProcessDropDown ();
bindInfoProcessMenu ();
}
/**
* evel display logic of process info button
* set visible of button base in display logic
* when two button set for same process, two button can hiden too, or display too.
* this is bug of implementor by never have this case
*/
protected void bindInfoProcessBt (){
if (infoProcessBtList == null){
return;
}
// display process in button style
for (MInfoProcess infoProcessBt : infoProcessBtList){
// eval display logic
for (Button evlBt: btProcessList){
Integer processId = (Integer)evlBt.getAttribute(PROCESS_ID_KEY);
if (processId.intValue() == infoProcessBt.getAD_Process_ID()){
// display or hiden button
evlBt.setVisible(infoProcessBt.isDisplayed(infoContext, p_WindowNo));
break;
}
}
}
}
/**
* recreate drop down item by recreate model to set hiden, display of drop down item
* when all item is hiden, hiden combobox and process button too
*/
protected void bindInfoProcessDropDown (){
if (infoProcessDropList == null || infoProcessDropList.size() == 0){
return;
}
// list info process after eval display logic
List<MInfoProcess> infoProcessDropListTmp = new ArrayList<MInfoProcess> ();
// filter item not display
for (MInfoProcess infoProcessDropDown : infoProcessDropList){
if (infoProcessDropDown.isDisplayed(infoContext, p_WindowNo)){
infoProcessDropListTmp.add(infoProcessDropDown);
}
}
// when item is filter out all. don't show combobox
cbbProcess.setVisible(infoProcessDropListTmp.size() > 0);
btCbbProcess.setVisible(infoProcessDropListTmp.size() > 0);
if (infoProcessDropListTmp.size() > 0){
ListModelList<MInfoProcess> infoProccessModel = new ListModelList<MInfoProcess>(infoProcessDropListTmp);
cbbProcess.setModel(infoProccessModel);
}
}
/**
* recreate menu item by set hiden, display of menu item
* when all menu item is hiden, hiden process menu button too
*/
protected void bindInfoProcessMenu (){
if (infoProcessMenuList == null || infoProcessMenuList == null)
return;
ipMenu.getChildren().clear();
for (MInfoProcess infoProcess : infoProcessMenuList){
if (!infoProcess.isDisplayed(infoContext, p_WindowNo)){
continue;
}
MProcess process = MProcess.get(Env.getCtx(), infoProcess.getAD_Process_ID());
// make menu item for each info process
Menuitem ipMenuItem = new Menuitem();
ipMenuItem.setLabel(process.get_Translation(MProcess.COLUMNNAME_Name));
@ -299,7 +416,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
ipMenu.appendChild(ipMenuItem);
}
return infoProcessList.length > 0;
btMenuProcess.setVisible(ipMenu.getChildren().size() > 0);
}
private void processQueryValue() {
@ -837,6 +954,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
confirmPanel.getButton(ConfirmPanel.A_ZOOM).setDisabled(true);
// IDEMPIERE-1334 start when init all button process is disable because nothing record is selected
for (Button btProcess : btProcessList){
btProcess.setDisabled(true);
}
@ -993,6 +1111,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
editor.getLabel().setVisible(true);
}
}
}
/**

View File

@ -1350,6 +1350,10 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
contentPanel.setSelectedByKeys(lsSelectedKey);
m_results.clear();
}
// just evaluate display logic of process button when requery by use click requery button
if (isQueryByUser){
bindInfoProcess();
}
// IDEMPIERE-1334 after refresh, restore prev selected item end
}
finally
@ -1358,6 +1362,12 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
}
}
/**
* evaluate display logic of button process
* empty method. implement at child class extend
*/
protected void bindInfoProcess (){}
private void onOk()
{
if (!contentPanel.getChildren().isEmpty() && contentPanel.getSelectedRowKey()!=null)