IDEMPIERE-2230:Info Window - remember selection during pagination

This commit is contained in:
hieplq 2015-08-04 20:56:46 +08:00
parent 312cd4914e
commit c016319633
7 changed files with 468 additions and 69 deletions

View File

@ -0,0 +1,65 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- Nov 6, 2014 3:13:05 PM ICT
-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator
UPDATE AD_SysConfig SET Value='hieplq',Updated=TO_DATE('2014-11-06 15:13:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=50001
;
-- Nov 6, 2014 3:13:13 PM ICT
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,IsActive,Created,UpdatedBy,IsToolbarButton,IsAlwaysUpdateable,IsEncrypted,IsSecure,AD_Element_ID,AD_Reference_ID,AD_Table_ID,AD_Client_ID,AD_Org_ID,EntityType) VALUES (0,'N',0,211799,'N','N','N',0,'N',1,'N','N','N','Y','4ef802de-84a4-4ebc-a364-8ba9a27a39b5','Y','IsKey','This column is the key in this table','The key column must also be display sequence 0 in the field definition and may be hidden.','Key column','N',TO_DATE('2014-11-06 15:13:12','YYYY-MM-DD HH24:MI:SS'),100,'Y',TO_DATE('2014-11-06 15:13:12','YYYY-MM-DD HH24:MI:SS'),100,'N','N','N','N',389,20,897,0,0,'D')
;
-- Nov 6, 2014 3:13:25 PM ICT
ALTER TABLE AD_InfoColumn ADD IsKey CHAR(1) DEFAULT NULL CHECK (IsKey IN ('Y','N'))
;
-- Nov 6, 2014 3:14:19 PM ICT
INSERT INTO AD_Field (SortNo,IsEncrypted,AD_Tab_ID,DisplayLength,IsSameLine,IsHeading,SeqNo,IsCentrallyMaintained,AD_Field_ID,IsReadOnly,Help,EntityType,Description,Name,AD_Field_UU,IsDisplayed,IsFieldOnly,UpdatedBy,CreatedBy,Updated,IsActive,IsDisplayedGrid,SeqNoGrid,XPosition,IsQuickEntry,AD_Client_ID,ColumnSpan,NumLines,IsAdvancedField,IsDefaultFocus,AD_Column_ID,AD_Org_ID,Created) VALUES (0,'N',844,0,'N','N',260,'Y',203471,'N','The key column must also be display sequence 0 in the field definition and may be hidden.','D','This column is the key in this table','Key column','dd0b953a-d575-4eac-b435-87db841346c6','Y','N',100,100,TO_DATE('2014-11-06 15:14:18','YYYY-MM-DD HH24:MI:SS'),'Y','Y',170,1,'N',0,1,1,'N','N',211799,0,TO_DATE('2014-11-06 15:14:18','YYYY-MM-DD HH24:MI:SS'))
;
-- Nov 6, 2014 3:17:53 PM ICT
UPDATE AD_Field SET Help='In case data of info window come from a view, define a column contain unique value as key to keep selected record', Description='Define this column has unique value, play as key of table', Name='Is View Key',Updated=TO_DATE('2014-11-06 15:17:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203471
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=170, IsDisplayed='Y', XPosition=6,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203471
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=180,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201720
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=190,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201625
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=200,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203048
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=210,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201635
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=220,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201636
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=230,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13603
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=240,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201622
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=250,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201623
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=260,Updated=TO_DATE('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13597
;
SELECT register_migration_script('201411061604_IDEMPIERE-2230.sql') FROM dual
;

View File

@ -0,0 +1,62 @@
-- Nov 6, 2014 3:13:05 PM ICT
-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator
UPDATE AD_SysConfig SET Value='hieplq',Updated=TO_TIMESTAMP('2014-11-06 15:13:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=50001
;
-- Nov 6, 2014 3:13:13 PM ICT
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,IsActive,Created,UpdatedBy,IsToolbarButton,IsAlwaysUpdateable,IsEncrypted,IsSecure,AD_Element_ID,AD_Reference_ID,AD_Table_ID,AD_Client_ID,AD_Org_ID,EntityType) VALUES (0,'N',0,211799,'N','N','N',0,'N',1,'N','N','N','Y','4ef802de-84a4-4ebc-a364-8ba9a27a39b5','Y','IsKey','This column is the key in this table','The key column must also be display sequence 0 in the field definition and may be hidden.','Key column','N',TO_TIMESTAMP('2014-11-06 15:13:12','YYYY-MM-DD HH24:MI:SS'),100,'Y',TO_TIMESTAMP('2014-11-06 15:13:12','YYYY-MM-DD HH24:MI:SS'),100,'N','N','N','N',389,20,897,0,0,'D')
;
-- Nov 6, 2014 3:13:25 PM ICT
ALTER TABLE AD_InfoColumn ADD COLUMN IsKey CHAR(1) DEFAULT NULL CHECK (IsKey IN ('Y','N'))
;
-- Nov 6, 2014 3:14:19 PM ICT
INSERT INTO AD_Field (SortNo,IsEncrypted,AD_Tab_ID,DisplayLength,IsSameLine,IsHeading,SeqNo,IsCentrallyMaintained,AD_Field_ID,IsReadOnly,Help,EntityType,Description,Name,AD_Field_UU,IsDisplayed,IsFieldOnly,UpdatedBy,CreatedBy,Updated,IsActive,IsDisplayedGrid,SeqNoGrid,XPosition,IsQuickEntry,AD_Client_ID,ColumnSpan,NumLines,IsAdvancedField,IsDefaultFocus,AD_Column_ID,AD_Org_ID,Created) VALUES (0,'N',844,0,'N','N',260,'Y',203471,'N','The key column must also be display sequence 0 in the field definition and may be hidden.','D','This column is the key in this table','Key column','dd0b953a-d575-4eac-b435-87db841346c6','Y','N',100,100,TO_TIMESTAMP('2014-11-06 15:14:18','YYYY-MM-DD HH24:MI:SS'),'Y','Y',170,1,'N',0,1,1,'N','N',211799,0,TO_TIMESTAMP('2014-11-06 15:14:18','YYYY-MM-DD HH24:MI:SS'))
;
-- Nov 6, 2014 3:17:53 PM ICT
UPDATE AD_Field SET Help='In case data of info window come from a view, define a column contain unique value as key to keep selected record', Description='Define this column has unique value, play as key of table', Name='Is View Key',Updated=TO_TIMESTAMP('2014-11-06 15:17:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203471
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=170, IsDisplayed='Y', XPosition=6,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203471
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=180,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201720
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=190,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201625
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=200,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203048
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=210,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201635
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=220,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201636
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=230,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13603
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=240,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201622
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=250,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201623
;
-- Nov 6, 2014 3:18:15 PM ICT
UPDATE AD_Field SET SeqNo=260,Updated=TO_TIMESTAMP('2014-11-06 15:18:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=13597
;
SELECT register_migration_script('201411061604_IDEMPIERE-2230.sql') FROM dual
;

View File

@ -309,6 +309,19 @@ public interface I_AD_InfoColumn
*/ */
public boolean isIdentifier(); public boolean isIdentifier();
/** Column name IsKey */
public static final String COLUMNNAME_IsKey = "IsKey";
/** Set Key column.
* This column is the key in this table
*/
public void setIsKey (boolean IsKey);
/** Get Key column.
* This column is the key in this table
*/
public boolean isKey();
/** Column name IsMandatory */ /** Column name IsMandatory */
public static final String COLUMNNAME_IsMandatory = "IsMandatory"; public static final String COLUMNNAME_IsMandatory = "IsMandatory";

View File

@ -20,6 +20,7 @@ import java.sql.ResultSet;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.model.IInfoColumn;
import org.compiere.model.AccessSqlParser.TableInfo; import org.compiere.model.AccessSqlParser.TableInfo;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Evaluatee; import org.compiere.util.Evaluatee;
@ -31,7 +32,7 @@ import org.compiere.util.Evaluator;
* @author Jorg Janke * @author Jorg Janke
* @version $Id: MInfoColumn.java,v 1.2 2006/07/30 00:51:03 jjanke Exp $ * @version $Id: MInfoColumn.java,v 1.2 2006/07/30 00:51:03 jjanke Exp $
*/ */
public class MInfoColumn extends X_AD_InfoColumn public class MInfoColumn extends X_AD_InfoColumn implements IInfoColumn
{ {
/** /**
* *
@ -176,4 +177,14 @@ public class MInfoColumn extends X_AD_InfoColumn
getParent().saveEx(get_TrxName()); getParent().saveEx(get_TrxName());
return super.afterDelete(success); return super.afterDelete(success);
} }
@Override
public int getInfoColumnID() {
return get_ID();
}
@Override
public MInfoColumn getAD_InfoColumn() {
return this;
}
} // MInfoColumn } // MInfoColumn

View File

@ -30,7 +30,7 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent
/** /**
* *
*/ */
private static final long serialVersionUID = 20141030L; private static final long serialVersionUID = 20141106L;
/** Standard Constructor */ /** Standard Constructor */
public X_AD_InfoColumn (Properties ctx, int AD_InfoColumn_ID, String trxName) public X_AD_InfoColumn (Properties ctx, int AD_InfoColumn_ID, String trxName)
@ -442,6 +442,30 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent
return false; return false;
} }
/** Set Key column.
@param IsKey
This column is the key in this table
*/
public void setIsKey (boolean IsKey)
{
set_Value (COLUMNNAME_IsKey, Boolean.valueOf(IsKey));
}
/** Get Key column.
@return This column is the key in this table
*/
public boolean isKey ()
{
Object oo = get_Value(COLUMNNAME_IsKey);
if (oo != null)
{
if (oo instanceof Boolean)
return ((Boolean)oo).booleanValue();
return "Y".equals(oo);
}
return false;
}
/** Set Mandatory. /** Set Mandatory.
@param IsMandatory @param IsMandatory
Data entry is required in this column Data entry is required in this column

View File

@ -206,6 +206,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
processQueryValue(); processQueryValue();
} }
} }
} }
/** /**
@ -507,7 +508,10 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
infoColumns = infoWindow.getInfoColumns(tableInfos); infoColumns = infoWindow.getInfoColumns(tableInfos);
gridFields = new ArrayList<GridField>(); gridFields = new ArrayList<GridField>();
for(MInfoColumn infoColumn : infoColumns) { for(MInfoColumn infoColumn : infoColumns) {
if (infoColumn.isKey())
keyColumnOfView = infoColumn;
String columnName = infoColumn.getColumnName(); String columnName = infoColumn.getColumnName();
/*!m_lookup && infoColumn.isMandatory():apply Mandatory only case open as window and only for criteria field*/ /*!m_lookup && infoColumn.isMandatory():apply Mandatory only case open as window and only for criteria field*/
boolean isMandatory = !m_lookup && infoColumn.isMandatory() && infoColumn.isQueryCriteria(); boolean isMandatory = !m_lookup && infoColumn.isMandatory() && infoColumn.isQueryCriteria();
@ -686,11 +690,21 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
} }
columnInfo.setColDescription(infoColumn.get_Translation("Description")); columnInfo.setColDescription(infoColumn.get_Translation("Description"));
columnInfo.setGridField(gridFields.get(i)); columnInfo.setGridField(gridFields.get(i));
list.add(columnInfo); list.add(columnInfo);
if (keyColumnOfView == infoColumn){
if (columnInfo.getColClass().equals(IDColumn.class))
isIDColumnKeyOfView = true;
indexKeyOfView = list.size() - 1;
}
} }
i++; i++;
} }
if (keyColumnOfView == null){
isIDColumnKeyOfView = true;// because use main key
}
columnInfos = list.toArray(new ColumnInfo[0]); columnInfos = list.toArray(new ColumnInfo[0]);
prepareTable(columnInfos, infoWindow.getFromClause(), p_whereClause, infoWindow.getOrderByClause()); prepareTable(columnInfos, infoWindow.getFromClause(), p_whereClause, infoWindow.getOrderByClause());
@ -974,7 +988,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
} }
addViewIDToQuery(); addViewIDToQuery();
addKeyViewToQuery();
if (m_sqlMain.length() > 0 && infoWindow.isDistinct()) { if (m_sqlMain.length() > 0 && infoWindow.isDistinct()) {
m_sqlMain = m_sqlMain.substring("SELECT ".length()); m_sqlMain = m_sqlMain.substring("SELECT ".length());
@ -999,6 +1013,19 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
m_sqlMain = addMoreColumnToQuery (m_sqlMain, infoProcessList); m_sqlMain = addMoreColumnToQuery (m_sqlMain, infoProcessList);
} }
/**
* if {@link #keyColumnOfView} not null and not display, add query to query it's value
*/
protected void addKeyViewToQuery () {
if (isNeedAppendKeyViewData()){
m_sqlMain = addMoreColumnToQuery (m_sqlMain, new IInfoColumn [] {keyColumnOfView});
}
}
@Override
public boolean isNeedAppendKeyViewData() {
return (keyColumnOfView != null && !keyColumnOfView.isDisplayed(infoContext, p_WindowNo));
}
/** /**
* because data of infoColumn have isDisplay = false not load, * because data of infoColumn have isDisplay = false not load,

View File

@ -30,9 +30,11 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector; import java.util.Vector;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.model.IInfoColumn; import org.adempiere.model.IInfoColumn;
import org.adempiere.model.MInfoProcess; import org.adempiere.model.MInfoProcess;
import org.adempiere.model.MInfoRelated; import org.adempiere.model.MInfoRelated;
@ -131,6 +133,41 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
// Num of page preload, default is 2 page before current and 2 page after current // Num of page preload, default is 2 page before current and 2 page after current
protected int numPagePreLoad = MSysConfig.getIntValue(MSysConfig.ZK_INFO_NUM_PAGE_RELOAD, DEFAULT_PAGE_RELOAD); protected int numPagePreLoad = MSysConfig.getIntValue(MSysConfig.ZK_INFO_NUM_PAGE_RELOAD, DEFAULT_PAGE_RELOAD);
/**
* MInfoColumn has isKey = true, play as key column in case non column has
* isKey = true, this column is null and we use {@link #p_keyColumn}
*/
protected MInfoColumn keyColumnOfView = null;
/**
* index of {@link #keyColumnOfView} in data model, set when prepare listbox
*/
protected int indexKeyOfView = -1;
protected boolean isIDColumnKeyOfView = false;
/**
* store selected record info
* key of map is value of column play as keyView
* in case has no key coloumn of view, use value of {@link #p_keyColumn}
* zk6.x listview don't provide event when click to checkbox select all,
* so we can't manage selectedRecord time by time.
* each time change page we will update this list with current
* selected record of this page by call function
* {@link #updateListSelected()} when move to zk7, just enough handle
* onclick. because don't direct use recordSelectedData, call
* {@link #getSelectedRowInfo()}
*/
protected Map<Integer, List<Object>> recordSelectedData = new HashMap<Integer, List<Object>>();
/**
* when requery but don't clear selected record (example after run process)
* set flag to true to run sync selected record, also
* {@link #syncSelectedAfterRequery()}
*/
protected boolean isRequeryByRunSuccessProcess = false;
public static InfoPanel create (int WindowNo, public static InfoPanel create (int WindowNo,
String tableName, String keyColumn, String value, String tableName, String keyColumn, String value,
boolean multiSelection, String whereClause) boolean multiSelection, String whereClause)
@ -552,6 +589,8 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
appendDataForViewID(rs, data, lsReadedColumn); appendDataForViewID(rs, data, lsReadedColumn);
appendDataForParentLink(rs, data, lsReadedColumn); appendDataForParentLink(rs, data, lsReadedColumn);
appendDataForKeyView (rs, data, lsReadedColumn);
} }
/** /**
@ -580,6 +619,20 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
appendInfoColumnData(rs, data, relatedInfoList, listReadedColumn); appendInfoColumnData(rs, data, relatedInfoList, listReadedColumn);
} }
/**
* save data of all viewID column in infoProcessList to end of data line
* when override {@link #readData(ResultSet)} consider call this method
* IDEMPIERE-1970
* @param rs record set to read data
* @param data data line to append
* @param listReadedColumn list column is appended
* @throws SQLException
*/
protected void appendDataForKeyView(ResultSet rs, List<Object> data, List<Integer> listReadedColumn) throws SQLException {
if (isNeedAppendKeyViewData())
appendInfoColumnData(rs, data, new IInfoColumn [] {keyColumnOfView}, listReadedColumn);
}
/** /**
* save data of all infoColumn in listModelHaveInfoColumn to end of data line * save data of all infoColumn in listModelHaveInfoColumn to end of data line
* @param rs record set to read data * @param rs record set to read data
@ -678,6 +731,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
model.setMultiple(p_multipleSelection); model.setMultiple(p_multipleSelection);
contentPanel.setData(model, null); contentPanel.setData(model, null);
} }
restoreSelectedInPage();
int no = m_count; int no = m_count;
setStatusLine(Integer.toString(no) + " " + Msg.getMsg(Env.getCtx(), "SearchRows_EnterQuery"), false); setStatusLine(Integer.toString(no) + " " + Msg.getMsg(Env.getCtx(), "SearchRows_EnterQuery"), false);
setStatusDB(Integer.toString(no)); setStatusDB(Integer.toString(no));
@ -957,47 +1011,24 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
/** /**
* Get the keys of selected row/s based on layout defined in prepareTable * Get the keys of selected row/s based on layout defined in prepareTable
* @deprecated this function should deprecated and replace with {@link #getListKeyValueOfSelectedRow()} to support view at infoWindow
* @return IDs if selection present * @return IDs if selection present
* @author ashley * @author ashley
*/ */
protected ArrayList<Integer> getSelectedRowKeys() protected ArrayList<Integer> getSelectedRowKeys()
{ {
ArrayList<Integer> selectedDataList = new ArrayList<Integer>(); ArrayList<Integer> selectedDataList = new ArrayList<Integer>();
Collection<Integer> lsKeyValueOfSelectedRow = getSelectedRowInfo().keySet();
if (contentPanel.getKeyColumnIndex() == -1) if (lsKeyValueOfSelectedRow.size() == 0)
{ {
return selectedDataList; return selectedDataList;
} }
if (p_multipleSelection) if (p_multipleSelection)
{ {
int[] rows = contentPanel.getSelectedIndices(); for (Integer key : lsKeyValueOfSelectedRow){
for (int row = 0; row < rows.length; row++) selectedDataList.add(key);
{ }
Object data = contentPanel.getModel().getValueAt(rows[row], contentPanel.getKeyColumnIndex());
if (data instanceof IDColumn)
{
IDColumn dataColumn = (IDColumn)data;
selectedDataList.add(dataColumn.getRecord_ID());
}
else
{
log.severe("For multiple selection, IDColumn should be key column for selection");
}
}
}
if (selectedDataList.size() == 0)
{
int row = contentPanel.getSelectedRow();
if (row != -1 && contentPanel.getKeyColumnIndex() != -1)
{
Object data = contentPanel.getModel().getValueAt(row, contentPanel.getKeyColumnIndex());
if (data instanceof IDColumn)
selectedDataList.add(((IDColumn)data).getRecord_ID());
if (data instanceof Integer)
selectedDataList.add((Integer)data);
}
} }
return selectedDataList; return selectedDataList;
@ -1026,39 +1057,24 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
if (p_multipleSelection) if (p_multipleSelection)
{ {
int[] rows = contentPanel.getSelectedIndices(); Map <Integer, List<Object>> selectedRow = getSelectedRowInfo();
// this flag to just check key column in first record for (Entry<Integer, List<Object>> selectedInfo : selectedRow.entrySet())
boolean isCheckedKeyType = false;
for (int row = 0; row < rows.length; row++)
{ {
// get key data column // get key data column
Object keyData = contentPanel.getModel().getValueAt(rows[row], contentPanel.getKeyColumnIndex()); Integer keyData = selectedInfo.getKey();
// check key data must is IDColumn
if (!isCheckedKeyType){
if (keyData instanceof IDColumn){
isCheckedKeyType = true;
}else{
log.severe("For multiple selection, IDColumn should be key column for selection");
break;
}
}
IDColumn dataColumn = (IDColumn)keyData;
if (infoCulumnId > 0){ if (infoCulumnId > 0){
// have viewID, get it // have viewID, get it
int dataIndex = columnDataIndex.get(infoCulumnId) + p_layout.length; int dataIndex = columnDataIndex.get(infoCulumnId) + p_layout.length;
// get row data from model // get row data from model
Object viewIDValue = contentPanel.getModel().getDataAt(rows[row], dataIndex); Object viewIDValue = selectedInfo.getValue().get(dataIndex);
m_viewIDMap.add (new KeyNamePair(dataColumn.getRecord_ID(), viewIDValue == null?null:viewIDValue.toString())); m_viewIDMap.add (new KeyNamePair(keyData, viewIDValue == null?null:viewIDValue.toString()));
}else{ }else{
// hasn't viewID, set viewID value is null // hasn't viewID, set viewID value is null
m_viewIDMap.add (new KeyNamePair(dataColumn.getRecord_ID(), null)); m_viewIDMap.add (new KeyNamePair(keyData, null));
} }
} }
@ -1070,7 +1086,180 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
} }
} }
/**
* need overrider at infoWindow to check isDisplay
* @return
*/
protected boolean isNeedAppendKeyViewData (){
return false;
}
/**
* Check type of object is IDColumn
* @param keyData
* @param isCheckNull when true, raise exception when data is null
* @return
*/
protected boolean isIDColumn(Object keyData, boolean isCheckNull){
if (isCheckNull && keyData == null){
AdempiereException ex = getKeyNullException();
log.severe(ex.getMessage());
throw ex;
}
if (keyData != null && keyData instanceof IDColumn){
return true;
}
return false;
}
/**
* call {@link #isIDColumn(Object, boolean)} without check null value
* @param keyData
* @return
*/
protected boolean isIDColumn(Object keyData){
return isIDColumn(keyData, false);
}
/**
* get all selected record of current page and update to {@link #recordSelectedData}
* remove unselected record and add new selected record
* we maintain value of key, and extra value append by {@link #appendInfoColumnData(ResultSet, List, IInfoColumn[], List)}
*/
protected void updateListSelected (){
if (!p_multipleSelection){
return;
}
for (int rowIndex = 0; rowIndex < contentPanel.getModel().getRowCount(); rowIndex++){
Integer keyCandidate = getColumnValue(rowIndex);
@SuppressWarnings("unchecked")
List<Object> candidateRecord = (List<Object>)contentPanel.getModel().get(rowIndex);
if (contentPanel.getModel().isSelected(candidateRecord)){
recordSelectedData.put(keyCandidate, candidateRecord);// add or update selected record info
}else{
if (recordSelectedData.containsKey(keyCandidate)){// unselected record
recordSelectedData.remove(keyCandidate);
}
}
}
}
/**
* get data index of keyView
* @return
*/
protected int getIndexKeyColumnOfView (){
if (keyColumnOfView == null){
return contentPanel.getKeyColumnIndex();
}else if (isNeedAppendKeyViewData()){
return columnDataIndex.get(keyColumnOfView.getInfoColumnID()) + p_layout.length;
}else{
return indexKeyOfView;
}
}
/**
* go through all data record, in case key value is in {@link #recordSelectedData}, mark it as selected record
*/
protected void restoreSelectedInPage (){
if (!p_multipleSelection)
return;
Collection<Object> lsSelectionRecord = new ArrayList<Object>();
for (int rowIndex = 0; rowIndex < contentPanel.getModel().getRowCount(); rowIndex++){
Integer keyViewValue = getColumnValue(rowIndex);
if (recordSelectedData.containsKey(keyViewValue)){
// TODO: maybe add logic to check value of current record (focus only to viewKeys value) is same as value save in lsSelectedKeyValue
// because record can change by other user
lsSelectionRecord.add(contentPanel.getModel().get(rowIndex));
}
}
contentPanel.getModel().setSelection(lsSelectionRecord);
}
protected AdempiereException getKeyNullException (){
String errorMessage = String.format("has null value at column %1$s use as key of view in info window %2$s",
keyColumnOfView == null ? p_keyColumn : keyColumnOfView, infoWindow.getName());
return new AdempiereException(errorMessage);
}
/**
* get keyView value at rowIndex and clumnIndex
* also check in case value is null will rise a exception
* @param rowIndex
* @param columnIndex
* @return
*/
protected Integer getColumnValue (int rowIndex){
int keyIndex = getIndexKeyColumnOfView();
Integer keyValue = null;
// get row data from model
Object keyColumValue = contentPanel.getModel().getDataAt(rowIndex, keyIndex);
// throw exception when value is null
if (keyColumValue == null){
AdempiereException ex = getKeyNullException();
log.severe(ex.getMessage());
throw ex;
}
// IDColumn is recreate after change page, because use value of IDColumn
if (keyColumValue != null && keyColumValue instanceof IDColumn){
keyColumValue = ((IDColumn)keyColumValue).getRecord_ID();
}
if (keyColumValue instanceof Integer){
keyValue = (Integer)keyColumValue;
}else {
String msg = "column play keyView should is integer";
AdempiereException ex = new AdempiereException (msg);
log.severe(msg);
throw ex;
}
return (Integer)keyValue;
}
/**
* in case requery data, but want store selected record (example when run success a process)
* we must sync selected row, because some selected row maybe not at data list (process make it change not map with query)
* current 1000 line cache
* because in case query get more 1000 record we can't sync or maintain selected record (ever maintain for current page will make user confuse).
* just clear selection
* in case < 1000 record is ok
* TODO:rewrite
*/
protected void syncSelectedAfterRequery (){
if (isRequeryByRunSuccessProcess){
isRequeryByRunSuccessProcess = false;
//TODO:it's hard to ensure in case use keyViewId we can re-sync. some issue:
// + after RunSuccessProcess maybe key of record is change.
// + after RunSuccessProcess maybe value of viewID change.
// + after RunSuccessProcess maybe some record is out of query result
// + when load many page, sync at one time effect to performance
// maybe make two list, just sync for first page, old list use for reference,
// when user change page will use it for restore selected record, synced record will copy to new list
}
}
/**
* update list column key value of selected record and return this list
* @return {@link #recordSelectedData} after update
*/
public Map<Integer, List<Object>> getSelectedRowInfo (){
updateListSelected();
return recordSelectedData;
}
/** /**
* Get selected Keys * Get selected Keys
* @return selected keys (Integers) * @return selected keys (Integers)
@ -1173,7 +1362,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
* enable all control button or disable all rely to selected record * enable all control button or disable all rely to selected record
*/ */
protected void enableButtons (){ protected void enableButtons (){
boolean enable = (contentPanel.getSelectedCount() > 0); boolean enable = (contentPanel.getSelectedCount() > 0 || getSelectedRowInfo().size() > 0);
enableButtons(enable); enableButtons(enable);
} }
@ -1276,6 +1465,9 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
/** /**
* Save Selection Details * Save Selection Details
* To be overwritten by concrete classes * To be overwritten by concrete classes
* this function call when close info window.
* default infoWindow will set value of all column of current selected record to environment variable with {@link Env.TAB_INF}
* class extends can do more by override it.
*/ */
protected void saveSelectionDetail() {} protected void saveSelectionDetail() {}
@ -1425,6 +1617,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
// IDEMPIERE-1334 handle event click into process button end // IDEMPIERE-1334 handle event click into process button end
else if (event.getTarget() == paging) else if (event.getTarget() == paging)
{ {
updateListSelected();
int pgNo = paging.getActivePage(); int pgNo = paging.getActivePage();
if (pageNo != pgNo) if (pageNo != pgNo)
{ {
@ -1442,7 +1635,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
model.addTableModelListener(this); model.addTableModelListener(this);
model.setMultiple(p_multipleSelection); model.setMultiple(p_multipleSelection);
contentPanel.setData(model, null); contentPanel.setData(model, null);
restoreSelectedInPage();
//contentPanel.setSelectedIndex(0); //contentPanel.setSelectedIndex(0);
} }
} }
@ -1570,6 +1763,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
public void onEvent(Event event) throws Exception { public void onEvent(Event event) throws Exception {
ProcessModalDialog processModalDialog = (ProcessModalDialog)event.getTarget(); ProcessModalDialog processModalDialog = (ProcessModalDialog)event.getTarget();
if (DialogEvents.ON_BEFORE_RUN_PROCESS.equals(event.getName())){ if (DialogEvents.ON_BEFORE_RUN_PROCESS.equals(event.getName())){
updateListSelected();
// store in T_Selection table selected rows for Execute Process that retrieves from T_Selection in code. // store in T_Selection table selected rows for Execute Process that retrieves from T_Selection in code.
DB.createT_SelectionNew(pInstanceID, getSaveKeys(getInfoColumnIDFromProcess(processModalDialog.getAD_Process_ID())), DB.createT_SelectionNew(pInstanceID, getSaveKeys(getInfoColumnIDFromProcess(processModalDialog.getAD_Process_ID())),
null); null);
@ -1585,7 +1779,8 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
enableButtons(); enableButtons();
}else if (!m_pi.isError()){ }else if (!m_pi.isError()){
ProcessInfoDialog.showProcessInfo(m_pi, p_WindowNo, InfoPanel.this, true); ProcessInfoDialog.showProcessInfo(m_pi, p_WindowNo, InfoPanel.this, true);
Clients.response(new AuEcho(InfoPanel.this, "onQueryCallback", m_results)); isRequeryByRunSuccessProcess = true;
Clients.response(new AuEcho(InfoPanel.this, "onQueryCallback", null));
} }
} }
@ -1638,17 +1833,18 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
} }
m_sqlUserOrder=""; m_sqlUserOrder="";
executeQuery(); executeQuery();
renderItems(); renderItems();
// IDEMPIERE-1334 after refresh, restore prev selected item start // IDEMPIERE-1334 after refresh, restore prev selected item start
if (event != null && event.getData() != null){
@SuppressWarnings("unchecked")
List<Integer> lsSelectedKey = (List<Integer>)event.getData();
contentPanel.setSelectedByKeys(lsSelectedKey);
m_results.clear();
}
// just evaluate display logic of process button when requery by use click requery button // just evaluate display logic of process button when requery by use click requery button
if (isQueryByUser){ if (isQueryByUser){
bindInfoProcess(); bindInfoProcess();
// reset selected list
recordSelectedData.clear();
isRequeryByRunSuccessProcess = false;
}
if (isRequeryByRunSuccessProcess){
syncSelectedAfterRequery();
restoreSelectedInPage();
} }
// IDEMPIERE-1334 after refresh, restore prev selected item end // IDEMPIERE-1334 after refresh, restore prev selected item end
updateSubcontent (); updateSubcontent ();
@ -1668,7 +1864,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
protected void onOk() protected void onOk()
{ {
if (!contentPanel.getChildren().isEmpty() && contentPanel.getSelectedRowKey()!=null) if (!contentPanel.getChildren().isEmpty() && getSelectedRowInfo().size() > 0)
{ {
dispose(true); dispose(true);
} }
@ -1763,6 +1959,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
} // dispose } // dispose
public void sort(Comparator<Object> cmpr, boolean ascending) { public void sort(Comparator<Object> cmpr, boolean ascending) {
updateListSelected();
WListItemRenderer.ColumnComparator lsc = (WListItemRenderer.ColumnComparator) cmpr; WListItemRenderer.ColumnComparator lsc = (WListItemRenderer.ColumnComparator) cmpr;
if (m_useDatabasePaging) if (m_useDatabasePaging)
{ {