IDEMPIERE-2709 Adding support for editable field on info window / thanks to Deepak Pansheriya (Logilite) and Silvano Trinchero (FreePath)

This commit is contained in:
Carlos Ruiz 2018-08-28 12:54:07 +02:00
parent 588eed01e3
commit 2180fc3524
12 changed files with 1265 additions and 36 deletions

View File

@ -0,0 +1,35 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-2709: Adding support for editable field on info window
-- Jul 3, 2015 6:10:42 PM IST
INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,Help,AD_Table_ID,ColumnName,DefaultValue,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,IsToolbarButton,IsSecure) VALUES (212216,0,'Read Only','Field is read only','The Read Only indicates that this field may only be Read. It may not be updated.',897,'IsReadOnly','Y',1,'N','N','Y','N','N',0,'N',20,0,0,'Y',TO_DATE('2015-07-03 18:10:41','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2015-07-03 18:10:41','YYYY-MM-DD HH24:MI:SS'),100,405,'Y','N','D','N','N','N','Y','3a94dcce-25f4-4382-9547-a8f18949bbe7','Y','N','N')
;
-- Jul 3, 2015 6:10:49 PM IST
ALTER TABLE AD_InfoColumn ADD IsReadOnly CHAR(1) DEFAULT 'Y' CHECK (IsReadOnly IN ('Y','N')) NOT NULL
;
-- Jul 3, 2015 6:15:02 PM IST
INSERT INTO AD_Field (AD_Field_ID,Name,Description,Help,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField) VALUES (203829,'Read Only','Field is read only','The Read Only indicates that this field may only be Read. It may not be updated.',844,212216,'Y',0,165,0,'N','N','N','N',0,0,'Y',TO_DATE('2015-07-03 18:14:59','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2015-07-03 18:14:59','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','ebc3464e-96a2-447d-a846-b964ede1b66f','Y',170,1,1,1,'N','N','N')
;
-- Table: t_selection_infowindow
-- DROP TABLE t_selection_infowindow;
CREATE TABLE t_selection_infowindow
(
ad_pinstance_id NUMBER(10,0) NOT NULL,
t_selection_id NUMBER(10,0) NOT NULL,
viewid VARCHAR2(30),
columnname VARCHAR2(255) NOT NULL,
value_string VARCHAR2(255),
value_date date,
value_number NUMBER,
info VARCHAR2(60),
CONSTRAINT t_selection_infowindow_key PRIMARY KEY (ad_pinstance_id, t_selection_id, columnname)
);
SELECT register_migration_script('201507032015_IDEMPIERE-2709.sql') FROM dual
;

View File

@ -0,0 +1,54 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- InfoWindow selection editable fields
-- 18-giu-2018 16.11.33 CEST
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203216,0,0,'Y',TO_DATE('2018-06-18 16:11:32','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-06-18 16:11:32','YYYY-MM-DD HH24:MI:SS'),100,'InputFieldValidation','Input field validation','Input field validaton query','Input field validaton query','Input field validation','D','b457c250-ced2-415f-aaae-9bc7e545cb01')
;
-- 18-giu-2018 16.12.33 CEST
INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,Help,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure) VALUES (213525,0,'Input field validation','Input field validaton query','Input field validaton query',897,'InputFieldValidation',2000,'N','N','N','N','N',0,'N',14,0,0,'Y',TO_DATE('2018-06-18 16:12:33','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-06-18 16:12:33','YYYY-MM-DD HH24:MI:SS'),100,203216,'Y','N','D','N','N','N','Y','d0a5e559-7621-496c-9269-715b1040395b','Y',0,'N','N')
;
-- 18-giu-2018 16.12.49 CEST
UPDATE AD_Column SET EntityType='D',Updated=TO_DATE('2018-06-18 16:12:49','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=213525
;
-- 18-giu-2018 16.21.51 CEST
INSERT INTO AD_Field (AD_Field_ID,Name,Description,Help,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField) VALUES (205588,'Input field validation','Input field validaton query','Input field validaton query',844,213525,'Y',0,280,0,'N','N','N','N',0,0,'Y',TO_DATE('2018-06-18 16:21:50','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-06-18 16:21:50','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','26da27d1-b040-49dc-a3e6-ecd9f273636f','Y',190,1,1,1,'N','N','N')
;
-- 18-giu-2018 16.22.23 CEST
UPDATE AD_Field SET SeqNo=290, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2018-06-18 16:22:23','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588
;
-- 18-giu-2018 16.24.44 CEST
UPDATE AD_Field SET AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, ColumnSpan=5, NumLines=3, IsToolbarButton=NULL,Updated=TO_DATE('2018-06-18 16:24:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588
;
-- 18-giu-2018 16.25.24 CEST
UPDATE AD_Field SET AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsDisplayedGrid='N', IsToolbarButton=NULL,Updated=TO_DATE('2018-06-18 16:25:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588
;
-- 18-giu-2018 16.26.02 CEST
ALTER TABLE AD_InfoColumn ADD InputFieldValidation VARCHAR2(2000) DEFAULT NULL
;
-- 18-giu-2018 17.39.36 CEST
UPDATE AD_Field SET DisplayLogic='@IsReadOnly@=N', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2018-06-18 17:39:36','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588
;
-- 18-giu-2018 18.00.13 CEST
UPDATE AD_Column SET EntityType='D',Updated=TO_DATE('2018-06-18 18:00:13','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=212216
;
-- 18-giu-2018 18.04.58 CEST
UPDATE AD_Field SET EntityType='D', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=2, ColumnSpan=2, IsToolbarButton=NULL,Updated=TO_DATE('2018-06-18 18:04:58','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203829
;
-- 18-giu-2018 18.05.07 CEST
UPDATE AD_Column SET Help='Input field validaton query. If this query returns at least a row, an error will be displayed and the new value will be refused. The query can use all the fields in row as context fields (using the usual @...@ syntax). The error messages is composed appending the first column of every rows of the result, and its then translated, so the message can contains traslatable parts in the form @<MessageValue>@ and/or @<ElementValue>@',Updated=TO_DATE('2018-06-18 18:05:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=213525
;
SELECT register_migration_script('201806181810_IDEMPIERE-2709.sql') FROM dual
;

View File

@ -0,0 +1,32 @@
-- IDEMPIERE-2709: Adding support for editable field on info window
-- Jul 3, 2015 6:10:42 PM IST
INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,Help,AD_Table_ID,ColumnName,DefaultValue,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,IsToolbarButton,IsSecure) VALUES (212216,0,'Read Only','Field is read only','The Read Only indicates that this field may only be Read. It may not be updated.',897,'IsReadOnly','Y',1,'N','N','Y','N','N',0,'N',20,0,0,'Y',TO_TIMESTAMP('2015-07-03 18:10:41','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2015-07-03 18:10:41','YYYY-MM-DD HH24:MI:SS'),100,405,'Y','N','D','N','N','N','Y','3a94dcce-25f4-4382-9547-a8f18949bbe7','Y','N','N')
;
-- Jul 3, 2015 6:10:49 PM IST
ALTER TABLE AD_InfoColumn ADD COLUMN IsReadOnly CHAR(1) DEFAULT 'Y' CHECK (IsReadOnly IN ('Y','N')) NOT NULL
;
-- Jul 3, 2015 6:15:02 PM IST
INSERT INTO AD_Field (AD_Field_ID,Name,Description,Help,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField) VALUES (203829,'Read Only','Field is read only','The Read Only indicates that this field may only be Read. It may not be updated.',844,212216,'Y',0,165,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2015-07-03 18:14:59','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2015-07-03 18:14:59','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','ebc3464e-96a2-447d-a846-b964ede1b66f','Y',170,1,1,1,'N','N','N')
;
-- Table: t_selection_infowindow
-- DROP TABLE t_selection_infowindow;
CREATE TABLE t_selection_infowindow
(
ad_pinstance_id numeric(10) NOT NULL,
t_selection_id numeric(10) NOT NULL,
viewid varchar(30),
columnname varchar(255) NOT NULL,
value_string varchar(255),
value_date timestamp,
value_number numeric,
info varchar(60),
CONSTRAINT t_selection_infowindow_key PRIMARY KEY (ad_pinstance_id, t_selection_id, columnname)
);
SELECT register_migration_script('201507032015_IDEMPIERE-2709.sql') FROM dual
;

View File

@ -0,0 +1,51 @@
-- InfoWindow selection editable fields
-- 18-giu-2018 16.11.33 CEST
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203216,0,0,'Y',TO_TIMESTAMP('2018-06-18 16:11:32','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-06-18 16:11:32','YYYY-MM-DD HH24:MI:SS'),100,'InputFieldValidation','Input field validation','Input field validaton query','Input field validaton query','Input field validation','D','b457c250-ced2-415f-aaae-9bc7e545cb01')
;
-- 18-giu-2018 16.12.33 CEST
INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,Help,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure) VALUES (213525,0,'Input field validation','Input field validaton query','Input field validaton query',897,'InputFieldValidation',2000,'N','N','N','N','N',0,'N',14,0,0,'Y',TO_TIMESTAMP('2018-06-18 16:12:33','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-06-18 16:12:33','YYYY-MM-DD HH24:MI:SS'),100,203216,'Y','N','D','N','N','N','Y','d0a5e559-7621-496c-9269-715b1040395b','Y',0,'N','N')
;
-- 18-giu-2018 16.12.49 CEST
UPDATE AD_Column SET EntityType='D',Updated=TO_TIMESTAMP('2018-06-18 16:12:49','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=213525
;
-- 18-giu-2018 16.21.51 CEST
INSERT INTO AD_Field (AD_Field_ID,Name,Description,Help,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField) VALUES (205588,'Input field validation','Input field validaton query','Input field validaton query',844,213525,'Y',0,280,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2018-06-18 16:21:50','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-06-18 16:21:50','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','26da27d1-b040-49dc-a3e6-ecd9f273636f','Y',190,1,1,1,'N','N','N')
;
-- 18-giu-2018 16.22.23 CEST
UPDATE AD_Field SET SeqNo=290, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-06-18 16:22:23','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588
;
-- 18-giu-2018 16.24.44 CEST
UPDATE AD_Field SET AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, ColumnSpan=5, NumLines=3, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-06-18 16:24:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588
;
-- 18-giu-2018 16.25.24 CEST
UPDATE AD_Field SET AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsDisplayedGrid='N', IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-06-18 16:25:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588
;
-- 18-giu-2018 16.26.02 CEST
ALTER TABLE AD_InfoColumn ADD COLUMN InputFieldValidation VARCHAR(2000) DEFAULT NULL
;
-- 18-giu-2018 17.39.36 CEST
UPDATE AD_Field SET DisplayLogic='@IsReadOnly@=N', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-06-18 17:39:36','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205588
;
-- 18-giu-2018 18.00.13 CEST
UPDATE AD_Column SET EntityType='D',Updated=TO_TIMESTAMP('2018-06-18 18:00:13','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=212216
;
-- 18-giu-2018 18.04.58 CEST
UPDATE AD_Field SET EntityType='D', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=2, ColumnSpan=2, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2018-06-18 18:04:58','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=203829
;
-- 18-giu-2018 18.05.07 CEST
UPDATE AD_Column SET Help='Input field validaton query. If this query returns at least a row, an error will be displayed and the new value will be refused. The query can use all the fields in row as context fields (using the usual @...@ syntax). The error messages is composed appending the first column of every rows of the result, and its then translated, so the message can contains traslatable parts in the form @<MessageValue>@ and/or @<ElementValue>@',Updated=TO_TIMESTAMP('2018-06-18 18:05:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=213525
;
SELECT register_migration_script('201806181810_IDEMPIERE-2709.sql') FROM dual
;

View File

@ -257,6 +257,19 @@ public interface I_AD_InfoColumn
*/
public String getHelp();
/** Column name InputFieldValidation */
public static final String COLUMNNAME_InputFieldValidation = "InputFieldValidation";
/** Set Input field validation.
* Input field validaton query
*/
public void setInputFieldValidation (String InputFieldValidation);
/** Get Input field validation.
* Input field validaton query
*/
public String getInputFieldValidation();
/** Column name IsActive */
public static final String COLUMNNAME_IsActive = "IsActive";
@ -348,6 +361,19 @@ public interface I_AD_InfoColumn
*/
public boolean isQueryCriteria();
/** Column name IsReadOnly */
public static final String COLUMNNAME_IsReadOnly = "IsReadOnly";
/** Set Read Only.
* Field is read only
*/
public void setIsReadOnly (boolean IsReadOnly);
/** Get Read Only.
* Field is read only
*/
public boolean isReadOnly();
/** Column name Name */
public static final String COLUMNNAME_Name = "Name";

View File

@ -30,7 +30,7 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent
/**
*
*/
private static final long serialVersionUID = 20180719L;
private static final long serialVersionUID = 20180828L;
/** Standard Constructor */
public X_AD_InfoColumn (Properties ctx, int AD_InfoColumn_ID, String trxName)
@ -369,6 +369,23 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent
{
return (String)get_Value(COLUMNNAME_Help);
}
/** Set Input field validation.
@param InputFieldValidation
Input field validaton query
*/
public void setInputFieldValidation (String InputFieldValidation)
{
set_Value (COLUMNNAME_InputFieldValidation, InputFieldValidation);
}
/** Get Input field validation.
@return Input field validaton query
*/
public String getInputFieldValidation ()
{
return (String)get_Value(COLUMNNAME_InputFieldValidation);
}
/** Set Centrally maintained.
@param IsCentrallyMaintained
@ -417,6 +434,31 @@ public class X_AD_InfoColumn extends PO implements I_AD_InfoColumn, I_Persistent
}
return false;
}
/**
* Set Read Only.
*
* @param IsReadOnly
* Determines, if this field is Read Only
*/
public void setIsReadOnly(boolean IsReadOnly) {
set_Value(COLUMNNAME_IsReadOnly, Boolean.valueOf(IsReadOnly));
}
/**
* Get Read Only.
*
* @return Determines, if this field is Read Only
*/
public boolean isReadOnly() {
Object oo = get_Value(COLUMNNAME_IsReadOnly);
if (oo != null) {
if (oo instanceof Boolean)
return ((Boolean) oo).booleanValue();
return "Y".equals(oo);
}
return false;
}
/** Set Identifier.
@param IsIdentifier

View File

@ -0,0 +1,130 @@
/**********************************************************************
* 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. *
**********************************************************************/
package org.adempiere.webui.component;
import java.util.List;
import org.adempiere.webui.editor.WEditor;
import org.adempiere.webui.editor.WebEditorFactory;
import org.adempiere.webui.event.ValueChangeEvent;
import org.adempiere.webui.event.ValueChangeListener;
import org.adempiere.webui.info.InfoWindow;
import org.compiere.minigrid.IDColumn;
import org.compiere.model.GridField;
import org.compiere.model.MInfoColumn;
import org.compiere.util.KeyNamePair;
import org.zkoss.zul.Listcell;
public class WInfoWindowListItemRenderer extends WListItemRenderer
{
private MInfoColumn[] infoColumns;
private GridField[] gridFields;
private int gridFieldsOffset = -1; // There are added columns in front of the first real gridField, instead of a fixed +1 we use an offset
private InfoWindow infoWindow;
public WInfoWindowListItemRenderer(InfoWindow infoWindow, MInfoColumn[] infoColumns, List<GridField> gridFields)
{
this.infoColumns = infoColumns;
this.gridFields = gridFields.toArray(new GridField[infoColumns.length]);
this.infoWindow = infoWindow;
}
public WInfoWindowListItemRenderer(InfoWindow infoWindow, MInfoColumn[] infoColumns, List<GridField> gridFields, List<? extends String> columnNames)
{
super(columnNames);
this.infoColumns = infoColumns;
this.gridFields = gridFields.toArray(new GridField[infoColumns.length]);
this.infoWindow = infoWindow;
}
private void calculateFieldOffest()
{
int colCount = getTableColumns().size();
if(colCount > infoColumns.length) // Added columns: selecetion
gridFieldsOffset = colCount - infoColumns.length;
}
@Override
protected Listcell getCellComponent(WListbox table, Object field,
final int rowIndex, final int columnIndex)
{
if(gridFieldsOffset < 0) // Just do it once, this assumes this rendered is not shared between grids
calculateFieldOffest();
Listcell listcell = null;
ListModelTable model = table.getModel();
Object obj = model.get(rowIndex);
int effectiveFieldIndex = columnIndex - gridFieldsOffset;
if(effectiveFieldIndex >= 0
&& model.isSelected(obj) )
{
MInfoColumn infoColumn = infoColumns[effectiveFieldIndex];
if(infoColumn.isReadOnly() == false
&& columnIndex > 0)
{
ListCell listCell = new ListCell();
final GridField gridField = gridFields[effectiveFieldIndex];
final WEditor editor = WebEditorFactory.getEditor(gridField, false);
// Set editor value
Object value = table.getValueAt(rowIndex, columnIndex);
if(value instanceof IDColumn)
{
IDColumn idc = (IDColumn)value;
value = idc.getRecord_ID();
}
else if(value instanceof KeyNamePair)
{
KeyNamePair knp = (KeyNamePair)value;
value = knp.getKey();
}
editor.setValue(value);
editor.addValueChangeListener(new ValueChangeListener()
{
@Override
public void valueChange(ValueChangeEvent evt)
{
infoWindow.onCellEditCallback(evt, rowIndex, columnIndex, editor, gridField);
}
});
listCell.appendChild(editor.getComponent());
listcell = listCell;
}
}
if(listcell == null)
listcell = super.getCellComponent(table, field, rowIndex, columnIndex);
return listcell;
}
}

View File

@ -25,6 +25,7 @@ import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
@ -197,7 +198,7 @@ public class WListItemRenderer implements ListitemRenderer<Object>, EventListene
* @param columnIndex The column in which the cell is to be placed.
* @return The list cell component.
*/
private Listcell getCellComponent(WListbox table, Object field,
protected Listcell getCellComponent(WListbox table, Object field,
int rowIndex, int columnIndex)
{
ListCell listcell = new ListCell();
@ -864,6 +865,10 @@ public class WListItemRenderer implements ListitemRenderer<Object>, EventListene
m_tableColumns.get(index).setColumnClass(classType);
}
}
public List<WTableColumn> getTableColumns() {
return Collections.unmodifiableList(m_tableColumns);
}
class CellListener implements EventListener<Event> {

View File

@ -81,6 +81,9 @@ public class WListbox extends Listbox implements IMiniTable, TableValueChangeLis
private int m_colorColumnIndex = -1;
/** Color Column compare data. */
private Object m_colorDataCompare = Env.ZERO;
// F3P: support IDColumn for selection
private boolean allowIDColumnForReadWrite = false;
/**
* Default constructor.
@ -194,12 +197,27 @@ public class WListbox extends Listbox implements IMiniTable, TableValueChangeLis
public boolean isCellEditable(int row, int column)
{
// if the first column holds a boolean and it is false, it is not editable
if (column != 0
&& (getValueAt(row, 0) instanceof Boolean)
&& !((Boolean)getValueAt(row, 0)).booleanValue())
// F3P: If allowed, use idcolumn as a switch for read/write
if (column != 0)
return false;
Object val = getValueAt(row, 0);
if ((val instanceof Boolean)
&& !((Boolean)val).booleanValue())
{
return false;
}
if(val instanceof IDColumn)
{
IDColumn idc = (IDColumn)val;
if(!idc.isSelected())
return false;
}
// is the column read/write?
if (m_readWriteColumn.contains(new Integer(column)))
@ -1228,4 +1246,14 @@ public class WListbox extends Listbox implements IMiniTable, TableValueChangeLis
}
}
public boolean isAllowIDColumnForReadWrite()
{
return allowIDColumnForReadWrite;
}
public void setAllowIDColumnForReadWrite(boolean allowIDColumnForReadWrite)
{
this.allowIDColumnForReadWrite = allowIDColumnForReadWrite;
}
}

View File

@ -3,6 +3,7 @@
*/
package org.adempiere.webui.info;
import java.io.File;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -11,10 +12,13 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.TreeMap;
import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.impexp.AbstractExcelExporter;
import org.adempiere.model.IInfoColumn;
import org.adempiere.model.MInfoProcess;
import org.adempiere.model.MInfoRelated;
@ -33,6 +37,7 @@ import org.adempiere.webui.component.EditorBox;
import org.adempiere.webui.component.Grid;
import org.adempiere.webui.component.GridFactory;
import org.adempiere.webui.component.Label;
import org.adempiere.webui.component.ListModelTable;
import org.adempiere.webui.component.Menupopup;
import org.adempiere.webui.component.Row;
import org.adempiere.webui.component.Rows;
@ -41,6 +46,7 @@ import org.adempiere.webui.component.Tabbox;
import org.adempiere.webui.component.Tabpanel;
import org.adempiere.webui.component.Tabpanels;
import org.adempiere.webui.component.Tabs;
import org.adempiere.webui.component.WInfoWindowListItemRenderer;
import org.adempiere.webui.component.WListbox;
import org.adempiere.webui.editor.WEditor;
import org.adempiere.webui.editor.WSearchEditor;
@ -49,6 +55,8 @@ import org.adempiere.webui.editor.WebEditorFactory;
import org.adempiere.webui.event.DialogEvents;
import org.adempiere.webui.event.ValueChangeEvent;
import org.adempiere.webui.event.ValueChangeListener;
import org.adempiere.webui.event.WTableModelEvent;
import org.adempiere.webui.factory.ButtonFactory;
import org.adempiere.webui.grid.WQuickEntry;
import org.adempiere.webui.panel.InfoPanel;
import org.adempiere.webui.session.SessionManager;
@ -63,6 +71,7 @@ import org.compiere.model.AccessSqlParser.TableInfo;
import org.compiere.model.GridField;
import org.compiere.model.GridFieldVO;
import org.compiere.model.GridWindow;
import org.compiere.model.Lookup;
import org.compiere.model.MInfoColumn;
import org.compiere.model.MInfoWindow;
import org.compiere.model.MLookupFactory;
@ -77,14 +86,17 @@ import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg;
import org.compiere.util.Trx;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
import org.zkoss.util.media.AMedia;
import org.zkoss.zk.au.out.AuEcho;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zk.ui.event.SwipeEvent;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.Center;
@ -92,7 +104,9 @@ import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ComboitemRenderer;
import org.zkoss.zul.Div;
import org.zkoss.zul.Filedownload;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.North;
import org.zkoss.zul.Paging;
@ -138,6 +152,16 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
private List<GridField> gridFields;
private Checkbox checkAND;
// F3P: Keep original values: when a row is unselected, restore original values
private boolean hasEditable = false;
private Map<Integer, List<Object>> cacheOriginalValues = new HashMap<>();
private Map<Integer, List<Object>> temporarySelectedData = new HashMap<>();
// F3P: export
private Button exportButton = null;
/**
* Menu contail process menu item
@ -188,7 +212,21 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
//Xolali IDEMPIERE-1045
contentPanel.addActionListener(new EventListener<Event>() {
public void onEvent(Event event) throws Exception {
updateSubcontent();
int row = -1;
if(event instanceof SelectEvent<?, ?>)
{
@SuppressWarnings("unchecked")
SelectEvent<Listitem, List<Object>> selEvent = (SelectEvent<Listitem, List<Object>>)event;
if(selEvent.getReference() != null)
{
row = selEvent.getReference().getIndex();
}
}
updateSubcontent(row);
}
}); //xolali --end-
@ -223,14 +261,21 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
ClientInfo.onClientInfo(this, this::onClientInfo);
}
// F3P: add export button
initExport();
}
/**
/**
*
* {@inheritDoc}
*/
@Override
protected void updateSubcontent (){
int row = contentPanel.getSelectedRow();
protected void updateSubcontent (int row){ // F3P: For multi-selection info, using selected row blocks the dislay to the first selected
if(row < 0)
row = contentPanel.getSelectedRow();
if (row >= 0) {
for (EmbedWinInfo embed : embeddedWinList) {
// default link column is key column
@ -562,6 +607,36 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
gridFields.add(gridField);
}
// If we have a process and at least one process and an editable field, change to the info window rendered
int processCount = 0;
if(infoWindow != null)
{
MInfoProcess processes[] = infoWindow.getInfoProcess(false);
processCount = processes.length;
}
if(processCount > 0)
{
for(MInfoColumn infoColumn:infoColumns)
{
if(infoColumn.isReadOnly() == false)
{
hasEditable = true;
break;
}
}
if(hasEditable)
{
WInfoWindowListItemRenderer renderer = new WInfoWindowListItemRenderer(this, infoColumns, gridFields);
contentPanel.setItemRenderer(renderer);
contentPanel.setAllowIDColumnForReadWrite(true);
renderer.addTableValueChangeListener(contentPanel); // Replicated from WListbox constructor
}
}
StringBuilder builder = new StringBuilder(p_whereClause != null ? p_whereClause.trim() : "");
String infoWhereClause = infoWindow.getWhereClause();
if (infoWhereClause != null && infoWhereClause.indexOf("@") >= 0) {
@ -689,8 +764,10 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
: tableInfos[0].getTableName();
String keySelectClause = keyTableAlias+"."+p_keyColumn;
list.add(new ColumnInfo(" ", keySelectClause, IDColumn.class));
list.add(new ColumnInfo(" ", keySelectClause, IDColumn.class, true, false, null, p_keyColumn));
boolean haveNotProcess = !haveProcess; // A field is editabile only if is not readonly and theres a process
int i = 0;
for(MInfoColumn infoColumn : infoColumns)
{
@ -705,7 +782,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
if (infoColumn.getSelectClause().equalsIgnoreCase(keySelectClause))
continue;
columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, DisplayType.getClass(infoColumn.getAD_Reference_ID(), true));
columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, DisplayType.getClass(infoColumn.getAD_Reference_ID(), true), infoColumn.isReadOnly() || haveNotProcess);
}
else if (DisplayType.isLookup(infoColumn.getAD_Reference_ID()))
{
@ -716,7 +793,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
editor.setMandatory(false);
editor.setReadWrite(false);
editorMap.put(colSQL, editor);
columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, ValueNamePair.class, (String)null);
columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, ValueNamePair.class, (String)null, infoColumn.isReadOnly() || haveNotProcess);
}
else
{
@ -725,11 +802,12 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
}
else
{
columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, DisplayType.getClass(infoColumn.getAD_Reference_ID(), true));
columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, DisplayType.getClass(infoColumn.getAD_Reference_ID(), true), infoColumn.isReadOnly() || haveNotProcess);
}
columnInfo.setColDescription(infoColumn.get_Translation("Description"));
columnInfo.setAD_Reference_ID(infoColumn.getAD_Reference_ID());
columnInfo.setGridField(gridFields.get(i));
columnInfo.setColumnName(infoColumn.getColumnName());
list.add(columnInfo);
if (keyColumnOfView == infoColumn){
@ -757,6 +835,8 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
MLookupInfo lookupInfo = MLookupFactory.getLookupInfo(Env.getCtx(), p_WindowNo, 0, infoColumn.getAD_Reference_ID(), Env.getLanguage(Env.getCtx()), columnName, infoColumn.getAD_Reference_Value_ID(), false, validationCode);
String displayColumn = lookupInfo.DisplayColumn;
boolean haveNotProcess = !haveProcess; // A field is editabile only if is not readonly and theres a process;
int index = infoColumn.getSelectClause().indexOf(".");
if (index == infoColumn.getSelectClause().lastIndexOf("."))
{
@ -768,7 +848,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
if (tableInfo.getTableName().equalsIgnoreCase(lookupInfo.TableName))
{
displayColumn = displayColumn.replace(lookupInfo.TableName+".", tableInfo.getSynonym()+".");
ColumnInfo columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), displayColumn, KeyNamePair.class, infoColumn.getSelectClause());
ColumnInfo columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), displayColumn, KeyNamePair.class, infoColumn.getSelectClause(), infoColumn.isReadOnly() || haveNotProcess);
return columnInfo;
}
break;
@ -785,7 +865,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
if (! colSQL.toUpperCase().contains(" AS "))
colSQL += " AS " + infoColumn.getColumnName();
editorMap.put(colSQL, editor);
ColumnInfo columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, KeyNamePair.class, (String)null);
ColumnInfo columnInfo = new ColumnInfo(infoColumn.get_Translation("Name"), colSQL, KeyNamePair.class, (String)null, infoColumn.isReadOnly() || haveNotProcess);
return columnInfo;
}
@ -1577,6 +1657,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
if (!isRequeryByRunSuccessProcess)
prepareTable();
super.executeQuery();
cacheOriginalValues.clear(); // F3P: Clear original values
if (ClientInfo.maxHeight(ClientInfo.SMALL_HEIGHT-1) ||
ClientInfo.maxWidth(ClientInfo.SMALL_WIDTH-1)) {
layout.getNorth().setOpen(false);
@ -1954,7 +2035,6 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
return gridField;
}
/**
* {@inheritDoc}
@ -2069,5 +2149,504 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
}
}
}
// Edit Callback method and original values management
public Properties getRowaAsCtx(int row, int editingColumn, Object editingValue)
{
ListModelTable model = contentPanel.getModel();
Properties ctx = new Properties(Env.getCtx()); // Allow session values
// Parameter dditors
for(WEditor e:editors)
{
Object val = e.getValue();
String column = e.getColumnName();
if(val != null)
{
if(val instanceof Integer)
Env.setContext(ctx, 0, column, (Integer)val);
else if(val instanceof Timestamp)
Env.setContext(ctx, 0, column, (Timestamp)val);
else if(val instanceof Boolean)
Env.setContext(ctx, 0, column, (Boolean)val);
else
Env.setContext(ctx, 0, column, val.toString());
}
}
for(int i=0; i < p_layout.length; i++)
{
String column = p_layout[i].getColumnName();
Object val = null;
if(i != editingColumn)
val = model.getValueAt(row, i);
else
val = editingValue;
// Get id from 'complex' types
if(val != null)
{
if(val instanceof IDColumn)
{
IDColumn idc = (IDColumn)val;
val = idc.getRecord_ID();
}
else if(val instanceof KeyNamePair)
{
KeyNamePair knp = (KeyNamePair)val;
val = knp.getKey();
}
if(val instanceof Integer)
Env.setContext(ctx, 0, column, (Integer)val);
else if(val instanceof Timestamp)
Env.setContext(ctx, 0, column, (Timestamp)val);
else if(val instanceof Boolean)
Env.setContext(ctx, 0, column, (Boolean)val);
else
Env.setContext(ctx, 0, column, val.toString());
}
}
return ctx;
}
public void onCellEditCallback(ValueChangeEvent event, int rowIndex, int colIndex, WEditor editor, GridField field)
{
Object val = event.getNewValue();
if(val != null && columnInfos[colIndex].getColClass().equals(KeyNamePair.class))
{
Integer iVal = (Integer)val;
String display = editor.getDisplay();
KeyNamePair kdc = new KeyNamePair(iVal, display);
val = kdc;
}
MInfoColumn infoColumn = infoColumns[colIndex - 1];
boolean changeIsValid = true;
String validationSQL = null;
if(!Util.isEmpty(infoColumn.getInputFieldValidation(), true)) // Run validation
{
changeIsValid = false;
Properties ctx = getRowaAsCtx(rowIndex, colIndex, val);
String rawSQL = infoColumn.getInputFieldValidation();
validationSQL = Env.parseContext(ctx, 0, rawSQL, false);
try
{
List<List<Object>> errors = DB.getSQLArrayObjectsEx(null, validationSQL);
if(errors != null && errors.size() > 0)
{
StringBuilder sbError = new StringBuilder();
for(List<Object> line:errors)
{
if(line.size() > 0)
{
if(sbError.length() > 0)
sbError.append('\n');
sbError.append(line.get(0));
}
}
String msg = Msg.translate(ctx, sbError.toString());
FDialog.error(0, this, "ValidationError", msg); // TODO messaggio
}
else
changeIsValid = true;
}
catch(Exception e)
{
log.log(Level.SEVERE, "Error executing validation SQL: " + validationSQL, e);
FDialog.error(0, this, "Error", validationSQL); // TODO messaggio
changeIsValid = false;
}
}
if(changeIsValid)
{
// Editing a row delesects it, make sure it stays selected
ListModelTable model = contentPanel.getModel();
Object row = model.get(rowIndex);
// Since the row object is a collection, we can update it safely, but the hash code will be different from the one stored
// in the selection. So we need to remove and re-add the row after to keep the selection in sync
model.removeFromSelection(row);
contentPanel.setValueAt(val, rowIndex, colIndex);
model.addToSelection(row);
Clients.resize(contentPanel);
}
else
{
editor.setValue(event.getOldValue());
}
}
protected void restoreOriginalValues(int rowIndex)
{
Integer viewIdKey = getColumnValue(rowIndex);
if(cacheOriginalValues.containsKey(viewIdKey)) // Only cache if not cached to avoid caching subsequent modifications
{
int colCount = contentPanel.getColumnCount();
List<Object> row = cacheOriginalValues.get(viewIdKey);
for(int i=1; i < colCount; i++) // Skip first row (selection)
{
Object val = row.get(i-1);
contentPanel.setValueAt(val, rowIndex, i);
}
}
}
protected void cacheOriginalValues(int rowIndex)
{
Integer viewIdKey = getColumnValue(rowIndex);
if(cacheOriginalValues.containsKey(viewIdKey) == false) // Only cache if not cached to avoid caching subsequent modifications
{
int colCount = contentPanel.getColumnCount();
List<Object> row = new ArrayList<>();
for(int i=1; i < colCount; i++) // Skip first row (selection)
{
Object val = contentPanel.getValueAt(rowIndex, i);
row.add(val);
}
cacheOriginalValues.put(viewIdKey, row);
}
}
@Override
public void tableChanged(WTableModelEvent event)
{
// Manage cache of values
if(hasEditable && event.getColumn() == 0)
{
for(int row=event.getFirstRow(); row <= event.getLastRow(); row++)
{
Object col0 = contentPanel.getValueAt(row, 0);
if(col0 instanceof IDColumn)
{
IDColumn idc = (IDColumn)col0;
if(idc.isSelected())
{
cacheOriginalValues(row);
}
else
{
restoreOriginalValues(row);
}
}
}
Clients.resize(contentPanel);
}
super.tableChanged(event);
}
@Override
public void onQueryCallback(Event event)
{
super.onQueryCallback(event);
enableExportButton();
}
@Override
protected void updateListSelected()
{
if(hasEditable)
{
temporarySelectedData = new HashMap<>();
// The list contents (rows) will be cleared during query, so we need a backup to restore the in-edit data
ListModelTable model = contentPanel.getModel();
for(int rowIndex:contentPanel.getSelectedIndices())
{
Integer keyViewValue = getColumnValue(rowIndex);
@SuppressWarnings("unchecked")
List<Object> row = (List<Object>)model.get(rowIndex);
ArrayList<Object> clonedRow = new ArrayList<>(row);
temporarySelectedData.put(keyViewValue, clonedRow);
}
for(Entry<Integer, List<Object>> entry: recordSelectedData.entrySet())
{
ArrayList<Object> clonedRow = new ArrayList<>(entry.getValue());
temporarySelectedData.put(entry.getKey(), clonedRow);
}
}
super.updateListSelected();
}
@Override
protected void restoreSelectedInPage()
{
super.restoreSelectedInPage();
if(temporarySelectedData != null)
{
temporarySelectedData.clear();
temporarySelectedData = null;
}
}
@Override
public boolean onRestoreSelectedItemIndexInPage(Integer keyViewValue, int rowIndex, Object oRow)
{
if(hasEditable && temporarySelectedData != null)
{
cacheOriginalValues(rowIndex);
int gridFieldsOffset = 1; // First column is the id, and its not on the infoColumns
@SuppressWarnings("unchecked")
List<Object> row = (List<Object>)oRow;
List<Object> originalSelectedRow = temporarySelectedData.get(keyViewValue);
ListModelTable model = contentPanel.getModel();
// While restoring values we dong want to trigger listeners
model.removeTableModelListener(this);
for(int i=0; i < infoColumns.length; i++)
{
if(infoColumns[i].isReadOnly() == false) // Only replace editable column, in case some other data changed on db
{
int colIndex = i + gridFieldsOffset;
Object obj = originalSelectedRow.get(colIndex);
model.setValueAt( obj, rowIndex, colIndex);
}
}
// Restore isSelected status on IDColumn
Object id = (IDColumn)row.get(0);
if(id instanceof IDColumn)
{
IDColumn idc = (IDColumn)id;
idc.setSelected(true);
}
// Restore listners
model.addTableModelListener(this);
}
return super.onRestoreSelectedItemIndexInPage(keyViewValue, rowIndex, oRow);
}
// F3P: Export function
protected void initExport()
{
exportButton = ButtonFactory.createNamedButton("Export", false, true);
exportButton.setId("Export");
exportButton.setEnabled(false);
exportButton.addEventListener(Events.ON_CLICK, new XlsExportAction());
confirmPanel.addComponentsLeft(exportButton);
}
protected void enableExportButton()
{
if(exportButton == null)
return;
exportButton.setEnabled(contentPanel.getRowCount() > 0);
}
private class XlsExportAction implements EventListener<Event>
{
@Override
public void onEvent(Event evt) throws Exception
{
if(evt.getTarget() == exportButton)
{
XlsExporter exporter = new XlsExporter();
exporter.doExport();
}
}
}
private class XlsExporter extends AbstractExcelExporter
{
private ResultSet m_rs = null;
private int rowCount = -1;
private int currentRow = -1;
public void doExport() throws Exception
{
int originalCount = m_count;
String dataSql = buildDataSQL(0, 0);
File file = File.createTempFile("Export", ".xls");
testCount();
rowCount = m_count;
m_count = originalCount;
if(rowCount > 0)
{
PreparedStatement pstmt = null;
Trx trx = null;
try
{
String trxName = Trx.createTrxName("InfoPanelLoad:");
trx = Trx.get(trxName, true);
trx.setDisplayName(getClass().getName()+"_exportXls");
pstmt = DB.prepareStatement(dataSql, trxName);
setParameters (pstmt, false); // no count
pstmt.setFetchSize(100);
m_rs = pstmt.executeQuery();
export(file, null);
}
catch(SQLException e)
{
log.log(Level.SEVERE, dataSql, e);
}
finally
{
DB.close(m_rs, pstmt);
trx.close();
m_rs = null;
currentRow = -1;
}
AMedia media = null;
media = new AMedia(file.getName(), null, "application/vnd.ms-excel", file, true);
Filedownload.save(media);
}
}
@Override
public boolean isFunctionRow()
{
return false;
}
@Override
public int getColumnCount()
{
return columnInfos.length;
}
@Override
public int getRowCount()
{
return rowCount;
}
@Override
protected void setCurrentRow(int row)
{
if(row > currentRow)
{
try
{
m_rs.next();
currentRow = row;
}
catch(SQLException e)
{
throw new AdempiereException(e);
}
}
}
@Override
protected int getCurrentRow()
{
return currentRow;
}
@Override
public boolean isColumnPrinted(int col)
{
return (columnInfos[col].getGridField() != null);
}
@Override
public String getHeaderName(int col)
{
return columnInfos[col].getColHeader();
}
@Override
public int getDisplayType(int row, int col)
{
int displayType = -1;
GridField gridField = columnInfos[col].getGridField();
displayType = gridField.getDisplayType();
return displayType;
}
@Override
public Object getValueAt(int row, int col)
{
Object val = null;
try
{
val = m_rs.getObject(col + 1); // Col are zero-based, while resultset col are 1 based
}
catch(SQLException e)
{
throw new AdempiereException(e);
}
GridField gridField = columnInfos[col].getGridField();
Lookup lookup = gridField.getLookup();
if (lookup != null)
{
val = lookup.getDisplay(val);
}
return val;
}
@Override
public boolean isPageBreak(int row, int col)
{
return false;
}
}
}

View File

@ -17,6 +17,7 @@
package org.adempiere.webui.panel;
import java.awt.event.MouseEvent;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -26,8 +27,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -89,7 +92,6 @@ import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zk.ui.event.MouseEvent;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.Comboitem;
@ -129,6 +131,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
// attribute key of info process
protected final static String ATT_INFO_PROCESS_KEY = "INFO_PROCESS";
protected int pageSize;
public LinkedHashMap<KeyNamePair,LinkedHashMap<String, Object>> m_values = null;
protected MInfoRelated[] relatedInfoList;
// for test disable load all record when num of record < 1000
protected boolean isIgnoreCacheAll = true;
@ -391,7 +394,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
private boolean m_useDatabasePaging = false;
private BusyDialog progressWindow;
// in case double click to item. this store clicked item (maybe it's un-select item)
private Listitem m_lastOnSelectItem;
private int m_lastSelectedIndex = -1;
protected GridField m_gridfield;
/**
@ -1348,14 +1351,28 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
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));
Object row = contentPanel.getModel().get(rowIndex);
if(onRestoreSelectedItemIndexInPage(keyViewValue, rowIndex, row)) // F3P: provide an hook for operations on restored index
lsSelectionRecord.add(row);
}
}
contentPanel.getModel().setSelection(lsSelectionRecord);
}
/** Hook to intercept 'restore selection' actions
*
* @param keyViewValue row view key
* @param rowIndex row index
* @param row row
* @return false to skip restore selection
*/
public boolean onRestoreSelectedItemIndexInPage(Integer keyViewValue, int rowIndex, Object row)
{
return true;
}
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());
@ -1697,11 +1714,14 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
else if (event.getTarget() == contentPanel && event.getName().equals(Events.ON_SELECT))
{
setStatusSelected ();
m_lastOnSelectItem = null;
SelectEvent<?, ?> selectEvent = (SelectEvent<?, ?>) event;
if (selectEvent.getReference() != null && selectEvent.getReference() instanceof Listitem)
m_lastOnSelectItem = (Listitem) selectEvent.getReference();
}else if (event.getTarget() == contentPanel && event.getName().equals("onAfterRender")){
{
Listitem m_lastOnSelectItem = (Listitem) selectEvent.getReference();
m_lastSelectedIndex = m_lastOnSelectItem.getIndex();
}
}else if (event.getTarget() == contentPanel && event.getName().equals("onAfterRender")){
//IDEMPIERE-1334 at this event selected item from listBox and model is sync
enableButtons();
}
@ -1710,18 +1730,34 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
if (event.getClass().equals(MouseEvent.class)){
return;
}
if (contentPanel.isMultiple()) {
//un-select all selected column
if (m_lastOnSelectItem != null){
contentPanel.getModel().clearSelection();
int clickItemIndex = contentPanel.getIndexOfItem(m_lastOnSelectItem);
Object selectedItemModle = contentPanel.getModel().get(clickItemIndex);
contentPanel.getModel().addToSelection(selectedItemModle);
}
// clean selected record in cache
recordSelectedData.clear();
if (contentPanel.isMultiple() && m_lastSelectedIndex >= 0) {
contentPanel.setSelectedIndex(m_lastSelectedIndex);
model.clearSelection();
List<Object> lsSelectedItem = new ArrayList<Object>();
lsSelectedItem.add(model.getElementAt(m_lastSelectedIndex));
model.setSelection(lsSelectedItem);
int m_keyColumnIndex = contentPanel.getKeyColumnIndex();
for (int i = 0; i < contentPanel.getRowCount(); i++) {
// Find the IDColumn Key
Object data = contentPanel.getModel().getValueAt(i, m_keyColumnIndex);
if (data instanceof IDColumn) {
IDColumn dataColumn = (IDColumn) data;
if (i == m_lastSelectedIndex) {
dataColumn.setSelected(true);
}
else {
dataColumn.setSelected(false);
}
}
}
}
onDoubleClick();
contentPanel.repaint();
m_lastSelectedIndex = -1;
}
else if (event.getTarget().equals(confirmPanel.getButton(ConfirmPanel.A_REFRESH)))
{
@ -1903,7 +1939,13 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
/**
* Update relate info when selection in main info change
*/
protected void updateSubcontent (){};
protected void updateSubcontent (){ updateSubcontent(-1);};
/**
* Update relate info for a specific row, if targetRow < 0 update using selected row
*/
protected void updateSubcontent (int targetRow){};
/**
* Reset parameter to default value or to empty value? implement at
@ -1950,8 +1992,10 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
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.
DB.createT_SelectionNew(pInstanceID, getSaveKeys(getInfoColumnIDFromProcess(processModalDialog.getAD_Process_ID())),
null);
DB.createT_SelectionNew(pInstanceID, getSaveKeys(getInfoColumnIDFromProcess(processModalDialog.getAD_Process_ID())),
null);
saveResultSelection(getInfoColumnIDFromProcess(processModalDialog.getAD_Process_ID()));
createT_Selection_InfoWindow(pInstanceID);
}else if (ProcessModalDialog.ON_WINDOW_CLOSE.equals(event.getName())){
if (processModalDialog.isCancel()){
//clear back
@ -1975,6 +2019,147 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
});
}
/**
* save result values
*/
protected void saveResultSelection(int infoColumnId) {
int m_keyColumnIndex = contentPanel.getKeyColumnIndex();
if (m_keyColumnIndex == -1) {
return;
}
m_values = new LinkedHashMap<KeyNamePair,LinkedHashMap<String,Object>>();
if (p_multipleSelection) {
Map <Integer, List<Object>> selectedRow = getSelectedRowInfo();
// for selected rows
for (Entry<Integer, List<Object>> selectedInfo : selectedRow.entrySet())
{
// get key and viewID
Integer keyData = selectedInfo.getKey();
KeyNamePair kp = null;
if (infoColumnId > 0){
int dataIndex = columnDataIndex.get(infoColumnId) + p_layout.length;
Object viewIDValue = selectedInfo.getValue().get(dataIndex);
kp = new KeyNamePair(keyData, viewIDValue == null ? null : viewIDValue.toString());
}else{
kp = new KeyNamePair(keyData, null);
}
// get Data
LinkedHashMap<String, Object> values = new LinkedHashMap<String, Object>();
for(int col = 0 ; col < p_layout.length; col ++)
{
// layout has same columns as selectedInfo
if (!p_layout[col].isReadOnly())
values.put(p_layout[col].getColumnName(), selectedInfo.getValue().get(col));
}
if(values.size() > 0)
m_values.put(kp, values);
}
}
} // saveResultSelection
/**
* Insert result values
* @param AD_PInstance_ID
*/
public void createT_Selection_InfoWindow(int AD_PInstance_ID)
{
StringBuilder insert = new StringBuilder();
insert.append("INSERT INTO T_Selection_InfoWindow (AD_PINSTANCE_ID, T_SELECTION_ID, COLUMNNAME , VALUE_STRING, VALUE_NUMBER , VALUE_DATE ) VALUES(?,?,?,?,?,?) ");
for (Entry<KeyNamePair,LinkedHashMap<String, Object>> records : m_values.entrySet()) {
//set Record ID
LinkedHashMap<String, Object> fields = records.getValue();
for(Entry<String, Object> field : fields.entrySet())
{
List<Object> parameters = new ArrayList<Object>();
parameters.add(AD_PInstance_ID);
Object key = records.getKey();
if(key instanceof KeyNamePair)
{
KeyNamePair knp = (KeyNamePair)key;
parameters.add(knp.getKey());
}
else
{
parameters.add(key);
}
parameters.add(field.getKey());
Object data = field.getValue();
// set Values
if (data instanceof IDColumn)
{
IDColumn id = (IDColumn) data;
parameters.add(null);
parameters.add(id.getRecord_ID());
parameters.add(null);
}
else if (data instanceof String)
{
parameters.add(data);
parameters.add(null);
parameters.add(null);
}
else if (data instanceof BigDecimal || data instanceof Integer || data instanceof Double)
{
parameters.add(null);
if(data instanceof Double)
{
BigDecimal value = BigDecimal.valueOf((Double)data);
parameters.add(value);
}
else
parameters.add(data);
parameters.add(null);
}
else if (data instanceof Integer)
{
parameters.add(null);
parameters.add((Integer)data);
parameters.add(null);
}
else if (data instanceof Timestamp || data instanceof Date)
{
parameters.add(null);
parameters.add(null);
if(data instanceof Date)
{
Timestamp value = new Timestamp(((Date)data).getTime());
parameters.add(value);
}
else
parameters.add(data);
}
else if(data instanceof KeyNamePair)
{
KeyNamePair knpData = (KeyNamePair)data;
parameters.add(null);
parameters.add(knpData.getKey());
parameters.add(null);
}
else
{
parameters.add(data);
parameters.add(null);
parameters.add(null);
}
DB.executeUpdateEx(insert.toString(),parameters.toArray() , null);
}
}
} // createT_Selection_InfoWindow
/**
* Get InfoColumnID of infoProcess have processID is processId
* @param processId

View File

@ -38,6 +38,19 @@ public class ColumnInfo
this(colHeader, colSQL, colClass, true, false, null);
} // ColumnInfo
/**
* Create Info Column (r/o and not color column)
*
* @param colHeader Column Header
* @param colSQL SQL select code for column
* @param colClass class of column - determines display
* @param readOnly column is read only
*/
public ColumnInfo (String colHeader, String colSQL, Class<?> colClass, boolean readOnly)
{
this(colHeader, colSQL, colClass, readOnly, false, null);
} // ColumnInfo
/**
* Create Info Column (r/o and not color column)
*
@ -51,6 +64,20 @@ public class ColumnInfo
this(colHeader, colSQL, colClass, true, false, keyPairColSQL);
} // ColumnInfo
/**
* Create Info Column (r/o and not color column)
*
* @param colHeader Column Header
* @param colSQL SQL select code for column
* @param colClass class of column - determines display
* @param keyPairColSQL SQL select for the ID of the for the displayed column
* @param readOnly column is read only
*/
public ColumnInfo (String colHeader, String colSQL, Class<?> colClass, String keyPairColSQL, boolean readOnly)
{
this(colHeader, colSQL, colClass, readOnly, false, keyPairColSQL);
} // ColumnInfo
/**
* Create Info Column
*
@ -63,17 +90,36 @@ public class ColumnInfo
*/
public ColumnInfo (String colHeader, String colSQL, Class<?> colClass,
boolean readOnly, boolean colorColumn, String keyPairColSQL)
{
this(colHeader, colSQL, colClass, readOnly, false, keyPairColSQL, null);
}
/**
* Create Info Column
*
* @param colHeader Column Header
* @param colSQL SQL select code for column
* @param colClass class of column - determines display
* @param readOnly column is read only
* @param colorColumn if true, value of column determines foreground color
* @param keyPairColSQL SQL select for the ID of the for the displayed column
* @param columnName Column Name
*/
public ColumnInfo (String colHeader, String colSQL, Class<?> colClass,
boolean readOnly, boolean colorColumn, String keyPairColSQL, String columnName)
{
setColHeader(colHeader);
setColSQL(colSQL);
setColClass(colClass);
setReadOnly(readOnly);
setColorColumn(colorColumn);
setColumnName(columnName);
setKeyPairColSQL(keyPairColSQL);
} // ColumnInfo
private String m_colHeader;
private String m_columnName;
private String m_colSQL;
private Class<?> m_colClass;
private boolean m_readOnly;
@ -100,6 +146,14 @@ public class ColumnInfo
{
return m_colHeader;
}
/**
* Get Column Name
* @return Column Name
*/
public String getColumnName()
{
return m_columnName;
}
/**
* Get Col SQL
* @return sql
@ -138,6 +192,14 @@ public class ColumnInfo
m_colHeader = colHeader.substring(0, index) + colHeader.substring(index+1);
}
}
/**
* Set Column Name
* @param columnName Column Name
*/
public void setColumnName(String columnName)
{
m_columnName = columnName;
}
/**
* Set Col SQL
* @param colSQL sql