IDEMPIERE-5624 Implement export data as SQL insert statement (#1721)

This commit is contained in:
hengsin 2023-03-13 22:57:45 +08:00 committed by GitHub
parent efe0e14e57
commit b188775e9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 467 additions and 122 deletions

View File

@ -0,0 +1,14 @@
-- IDEMPIERE-5624 Implement export data as SQL insert statement
SELECT register_migration_script('202303111206_IDEMPIERE-5624.sql') FROM dual;
SET SQLBLANKLINES ON
SET DEFINE OFF
-- Mar 11, 2023, 12:06:48 PM MYT
INSERT INTO AD_Message (MsgType,MsgText,MsgTip,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','zip - SQL zip file','Zip archive of Oracle and PostgreSQL Insert SQL scripts',0,0,'Y',TO_TIMESTAMP('2023-03-11 12:06:46','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-03-11 12:06:46','YYYY-MM-DD HH24:MI:SS'),100,200825,'FileSQLInsertZip','D','9308f542-5ab1-4462-90a3-c0d70b2eb009')
;
-- Mar 11, 2023, 12:11:29 PM MYT
UPDATE AD_Message SET MsgText='zip - SQL Insert scripts zip archive', MsgTip=NULL,Updated=TO_TIMESTAMP('2023-03-11 12:11:29','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200825
;

View File

@ -0,0 +1,11 @@
-- IDEMPIERE-5624 Implement export data as SQL insert statement
SELECT register_migration_script('202303111206_IDEMPIERE-5624.sql') FROM dual;
-- Mar 11, 2023, 12:06:48 PM MYT
INSERT INTO AD_Message (MsgType,MsgText,MsgTip,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','zip - SQL zip file','Zip archive of Oracle and PostgreSQL Insert SQL scripts',0,0,'Y',TO_TIMESTAMP('2023-03-11 12:06:46','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-03-11 12:06:46','YYYY-MM-DD HH24:MI:SS'),100,200825,'FileSQLInsertZip','D','9308f542-5ab1-4462-90a3-c0d70b2eb009')
;
-- Mar 11, 2023, 12:11:29 PM MYT
UPDATE AD_Message SET MsgText='zip - SQL Insert scripts zip archive', MsgTip=NULL,Updated=TO_TIMESTAMP('2023-03-11 12:11:29','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200825
;

View File

@ -119,4 +119,13 @@
priority="0"> priority="0">
</exporter> </exporter>
</extension> </extension>
<extension
id="org.adempiere.impexp.GridTabSQLInsertExporter"
name="Export data as SQL insert statement"
point="org.adempiere.base.IGridTabExporter">
<exporter
class="org.adempiere.impexp.GridTabSQLInsertExporter"
priority="0">
</exporter>
</extension>
</plugin> </plugin>

View File

@ -19,9 +19,8 @@ import java.util.List;
import org.compiere.model.GridTab; import org.compiere.model.GridTab;
/** /**
* * Interface to export data from {@link GridTab}
* @author hengsin * @author hengsin
*
*/ */
public interface IGridTabExporter { public interface IGridTabExporter {
@ -31,21 +30,22 @@ public interface IGridTabExporter {
* @param childs * @param childs
* @param isCurrentRowOnly * @param isCurrentRowOnly
* @param file * @param file
* @param indxDetailSelected index of selected child tab
*/ */
public void export(GridTab gridTab, List<GridTab> childs, boolean isCurrentRowOnly, File file, int indxDetailSelected); public void export(GridTab gridTab, List<GridTab> childs, boolean isCurrentRowOnly, File file, int indxDetailSelected);
/** /**
* @return file extension * @return file extension (csv, zip, ect)
*/ */
public String getFileExtension(); public String getFileExtension();
/** /**
* @return description for file extension * @return label for file extension
*/ */
public String getFileExtensionLabel(); public String getFileExtensionLabel();
/** /**
* @return mime type * @return mime content type
*/ */
public String getContentType(); public String getContentType();
@ -55,9 +55,31 @@ public interface IGridTabExporter {
public String getSuggestedFileName(GridTab gridTab); public String getSuggestedFileName(GridTab gridTab);
/** /**
* Check a tab (detail tab) is support to export in this exporter * Check if exported support the export of a child tab
* @param gridTab * @param childTab
* @return * @return true if export is supported, false otherwise
*/ */
public boolean isExportableTab (GridTab gridTab); public boolean isExportableTab (GridTab childTab);
/**
* @return true if exporter is available to role with advanced access only
*/
default boolean isAdvanced() {
return false;
}
/**
* @return true if export of child tabs is supported only when current row only is on.
*/
default boolean isExportChildTabsForCurrentRowOnly() {
return false;
}
/**
* Maximum deep of child tab supported by the exporter
* @return > 0 for maximum level of deep, <= 0 for unlimited level of deep
*/
default int maxDeepOfChildTab() {
return 0;
}
} }

View File

@ -0,0 +1,207 @@
/***********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Contributors: *
* - hengsin *
**********************************************************************/
package org.adempiere.impexp;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.adempiere.base.IGridTabExporter;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.db.Database;
import org.compiere.model.GridTab;
import org.compiere.model.MTable;
import org.compiere.model.PO;
import org.compiere.util.Env;
import org.compiere.util.Msg;
/**
* Export data as SQL insert statement
* @author hengsin
*/
public class GridTabSQLInsertExporter implements IGridTabExporter {
/**
* Default constructor
*/
public GridTabSQLInsertExporter() {
}
@Override
public void export(GridTab gridTab, List<GridTab> childs, boolean isCurrentRowOnly, File file,
int indxDetailSelected) {
try (FileOutputStream fos = new FileOutputStream (file); ZipOutputStream zos = new ZipOutputStream(fos);){
// create directory "oracle"
ZipEntry directoryEntry = new ZipEntry("oracle/");
zos.putNextEntry(directoryEntry);
zos.closeEntry();
// create directory "postgresql"
directoryEntry = new ZipEntry("postgresql/");
zos.putNextEntry(directoryEntry);
zos.closeEntry();
//export header tab
MTable table = MTable.get(gridTab.getAD_Table_ID());
List<String> oracles = new ArrayList<>();
List<String> pgs = new ArrayList<>();
if (isCurrentRowOnly) {
PO po = getPO(gridTab, table, gridTab.getCurrentRow());
if (po != null)
addSQLInsert(po, oracles, pgs);
} else {
for(int i = 0; i < gridTab.getRowCount(); i++) {
PO po = getPO(gridTab, table, i);
if (po != null)
addSQLInsert(po, oracles, pgs);
}
}
ZipEntry fileEntry = new ZipEntry("oracle/" + table.getTableName() + ".sql");
zos.putNextEntry(fileEntry);
for(String oracle : oracles)
zos.write((oracle+"\n;\n").getBytes());
zos.closeEntry();
fileEntry = new ZipEntry("postgresql/" + table.getTableName() + ".sql");
zos.putNextEntry(fileEntry);
for(String pg : pgs)
zos.write((pg+"\n;\n").getBytes());
zos.closeEntry();
//export child tabs
if (isCurrentRowOnly) {
for(GridTab childTab : childs) {
if (!childTab.isLoadComplete()){
childTab.initTab(false);
childTab.query(false, 0, 0);
}
if (childTab.getRowCount() == 0)
continue;
table = MTable.get(childTab.getAD_Table_ID());
oracles = new ArrayList<>();
pgs = new ArrayList<>();
for(int i = 0; i < childTab.getRowCount(); i++) {
PO po = getPO(childTab, table, i);
if (po != null)
addSQLInsert(po, oracles, pgs);
}
fileEntry = new ZipEntry("oracle/" + table.getTableName() + ".sql");
zos.putNextEntry(fileEntry);
for(String oracle : oracles)
zos.write((oracle+"\n;\n").getBytes());
zos.closeEntry();
fileEntry = new ZipEntry("postgresql/" + table.getTableName() + ".sql");
zos.putNextEntry(fileEntry);
for(String pg : pgs)
zos.write((pg+"\n;\n").getBytes());
zos.closeEntry();
}
}
} catch (Exception e) {
throw new AdempiereException(e);
}
}
/**
* Create SQL insert script for po
* @param po
* @param oracles list to add oracle insert script
* @param pgs list to add postgresql insert script
*/
protected void addSQLInsert(PO po, List<String> oracles, List<String> pgs) {
String sql = po.toInsertSQL();
String oracle = Database.getDatabase(Database.DB_ORACLE).convertStatement(sql);
String pg = Database.getDatabase(Database.DB_POSTGRESQL).convertStatement(sql);
oracles.add(oracle);
pgs.add(pg);
}
/**
* Load PO by record ID or UUID
* @param gridTab
* @param table
* @param row
* @return PO
*/
protected PO getPO(GridTab gridTab, MTable table, int row) {
int recordId = gridTab.getKeyID(row);
if (recordId >= 0) {
return table.getPO(gridTab.getKeyID(row), null);
} else {
UUID uuid = gridTab.getTableModel().getUUID(row);
if (uuid != null)
return table.getPOByUU(uuid.toString(), null);
}
return null;
}
@Override
public String getFileExtension() {
return "zip";
}
@Override
public String getFileExtensionLabel() {
return Msg.getMsg(Env.getCtx(), "FileSQLInsertZip");
}
@Override
public String getContentType() {
return "application/zip";
}
@Override
public String getSuggestedFileName(GridTab gridTab) {
return gridTab.getName() + "." + getFileExtension();
}
@Override
public boolean isExportableTab(GridTab gridTab) {
if (!gridTab.isDisplayed())
return false;
return true;
}
@Override
public boolean isAdvanced() {
return true;
}
@Override
public boolean isExportChildTabsForCurrentRowOnly() {
return true;
}
@Override
public int maxDeepOfChildTab() {
return 1;
}
}

View File

@ -1579,9 +1579,6 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
return true; return true;
// ** dynamic content ** // ** dynamic content **
String parsed = Env.parseContext (m_vo.ctx, 0, dl, false, false).trim();
if (parsed.length() == 0)
return true;
boolean retValue = Evaluator.evaluateLogic(this, dl); boolean retValue = Evaluator.evaluateLogic(this, dl);
if (log.isLoggable(Level.CONFIG)) log.config(m_vo.Name + " (" + dl + ") => " + retValue); if (log.isLoggable(Level.CONFIG)) log.config(m_vo.Name + " (" + dl + ") => " + retValue);
return retValue; return retValue;

View File

@ -3177,7 +3177,6 @@ public abstract class PO
} // saveNew } // saveNew
private boolean doInsert(boolean withValues) { private boolean doInsert(boolean withValues) {
int index;
lobReset(); lobReset();
// Change Log // Change Log
@ -3190,7 +3189,92 @@ public abstract class PO
List<Object> params = new ArrayList<Object>(); List<Object> params = new ArrayList<Object>();
// SQL // SQL
StringBuilder sqlInsert = new StringBuilder("INSERT INTO "); StringBuilder sqlInsert = new StringBuilder();
AD_ChangeLog_ID = buildInsertSQL(sqlInsert, withValues, params, session, AD_ChangeLog_ID, false);
//
int no = withValues ? DB.executeUpdate(sqlInsert.toString(), m_trxName)
: DB.executeUpdate(sqlInsert.toString(), params.toArray(), false, m_trxName);
boolean ok = no == 1;
if (ok)
{
if (withValues && m_IDs.length == 1 && p_info.hasKeyColumn()
&& m_KeyColumns[0].endsWith("_ID") && !Env.isUseCentralizedId(p_info.getTableName()))
{
int id = DB.getSQLValueEx(get_TrxName(), "SELECT " + m_KeyColumns[0] + " FROM "
+ p_info.getTableName() + " WHERE " + getUUIDColumnName() + "=?", get_ValueAsString(getUUIDColumnName()));
m_IDs[0] = Integer.valueOf(id);
set_ValueNoCheck(m_KeyColumns[0], m_IDs[0]);
int ki = p_info.getColumnIndex(m_KeyColumns[0]);
// Change Log - Only
String insertLog = MSysConfig.getValue(MSysConfig.SYSTEM_INSERT_CHANGELOG, "Y", getAD_Client_ID());
if ( session != null
&& m_IDs.length == 1
&& p_info.isAllowLogging(ki) // logging allowed
&& !p_info.isEncrypted(ki) // not encrypted
&& !p_info.isVirtualColumn(ki) // no virtual column
&& !"Password".equals(p_info.getColumnName(ki))
&& (insertLog.equalsIgnoreCase("Y")
|| (insertLog.equalsIgnoreCase("K") && p_info.getColumn(ki).IsKey))
)
{
// change log on new
MChangeLog cLog = session.changeLog (
m_trxName, AD_ChangeLog_ID,
p_info.getAD_Table_ID(), p_info.getColumn(ki).AD_Column_ID,
get_ID(), getAD_Client_ID(), getAD_Org_ID(), null, id, MChangeLog.EVENTCHANGELOG_Insert);
if (cLog != null)
AD_ChangeLog_ID = cLog.getAD_ChangeLog_ID();
}
}
ok = lobSave();
if (!load(m_trxName)) // re-read Info
{
if (m_trxName == null)
log.log(Level.SEVERE, "reloading");
else
log.log(Level.SEVERE, "[" + m_trxName + "] - reloading");
ok = false;;
}
}
else
{
String msg = "Not inserted - ";
if (CLogMgt.isLevelFiner())
msg += sqlInsert.toString();
else
msg += get_TableName();
if (m_trxName == null)
log.log(Level.WARNING, msg);
else
log.log(Level.WARNING, "[" + m_trxName + "]" + msg);
}
return ok;
}
/**
* Export data as insert SQL statement
*/
public String toInsertSQL()
{
StringBuilder sqlInsert = new StringBuilder();
buildInsertSQL(sqlInsert, true, null, null, 0, true);
return sqlInsert.toString();
}
/**
* Build insert SQL statement and capture change log
* @param sqlInsert
* @param withValues true to create statement with column values, false to use parameter binding (i.e with ?)
* @param params statement parameters when withValues is false
* @param session to capture change log. null when call from toInsertSQL (i.e to build sql only, not for real insert to DB)
* @param AD_ChangeLog_ID initial change log id
* @param generateScriptOnly true if it is to generate sql script only, false for real DB insert
* @return last AD_ChangeLog_ID
*/
protected int buildInsertSQL(StringBuilder sqlInsert, boolean withValues, List<Object> params, MSession session,
int AD_ChangeLog_ID, boolean generateScriptOnly) {
sqlInsert.append("INSERT INTO ");
sqlInsert.append(p_info.getTableName()).append(" ("); sqlInsert.append(p_info.getTableName()).append(" (");
StringBuilder sqlValues = new StringBuilder(") VALUES ("); StringBuilder sqlValues = new StringBuilder(") VALUES (");
int size = get_ColumnCount(); int size = get_ColumnCount();
@ -3212,6 +3296,13 @@ public abstract class PO
continue; continue;
} }
//do not export secure column
if (generateScriptOnly)
{
if (p_info.isEncrypted(i) || p_info.isSecure(i) || "Password".equalsIgnoreCase(p_info.getColumnName(i)))
continue;
}
// ** add column ** // ** add column **
if (doComma) if (doComma)
{ {
@ -3229,11 +3320,18 @@ public abstract class PO
try try
{ {
if (m_IDs.length == 1 && p_info.hasKeyColumn() if (m_IDs.length == 1 && p_info.hasKeyColumn()
&& m_KeyColumns[0].endsWith("_ID") && m_KeyColumns[0].equals(p_info.getColumnName(i)) && !Env.isUseCentralizedId(p_info.getTableName())) && m_KeyColumns[0].endsWith("_ID") && m_KeyColumns[0].equals(p_info.getColumnName(i)) && (generateScriptOnly || !Env.isUseCentralizedId(p_info.getTableName())))
{
if (generateScriptOnly && get_ID() > 0 && get_ID() <= MTable.MAX_OFFICIAL_ID)
{
sqlValues.append(value);
}
else
{ {
MSequence sequence = MSequence.get(Env.getCtx(), p_info.getTableName(), get_TrxName(), true); MSequence sequence = MSequence.get(Env.getCtx(), p_info.getTableName(), get_TrxName(), true);
sqlValues.append("nextidfunc("+sequence.getAD_Sequence_ID()+",'N')"); sqlValues.append("nextidfunc("+sequence.getAD_Sequence_ID()+",'N')");
} }
}
else if (c == Object.class) // may have need to deal with null values differently else if (c == Object.class) // may have need to deal with null values differently
sqlValues.append (saveNewSpecial (value, i)); sqlValues.append (saveNewSpecial (value, i));
else if (value == null || value.equals (Null.NULL)) else if (value == null || value.equals (Null.NULL))
@ -3379,11 +3477,11 @@ public abstract class PO
} }
} }
if (!withValues || Env.isUseCentralizedId(p_info.getTableName())) if (session != null && (!withValues || Env.isUseCentralizedId(p_info.getTableName())))
{ {
// Change Log - Only // Change Log - Only
String insertLog = MSysConfig.getValue(MSysConfig.SYSTEM_INSERT_CHANGELOG, "Y", getAD_Client_ID()); String insertLog = MSysConfig.getValue(MSysConfig.SYSTEM_INSERT_CHANGELOG, "Y", getAD_Client_ID());
if ( session != null if (!generateScriptOnly && session != null
&& m_IDs.length == 1 && m_IDs.length == 1
&& p_info.isAllowLogging(i) // logging allowed && p_info.isAllowLogging(i) // logging allowed
&& !p_info.isEncrypted(i) // not encrypted && !p_info.isEncrypted(i) // not encrypted
@ -3410,7 +3508,7 @@ public abstract class PO
while (it.hasNext()) while (it.hasNext())
{ {
String column = (String)it.next(); String column = (String)it.next();
index = p_info.getColumnIndex(column); int index = p_info.getColumnIndex(column);
String value = (String)m_custom.get(column); String value = (String)m_custom.get(column);
if (value == null) if (value == null)
continue; continue;
@ -3443,65 +3541,7 @@ public abstract class PO
} }
sqlInsert.append(sqlValues) sqlInsert.append(sqlValues)
.append(")"); .append(")");
// return AD_ChangeLog_ID;
int no = withValues ? DB.executeUpdate(sqlInsert.toString(), m_trxName)
: DB.executeUpdate(sqlInsert.toString(), params.toArray(), false, m_trxName);
boolean ok = no == 1;
if (ok)
{
if (withValues && m_IDs.length == 1 && p_info.hasKeyColumn()
&& m_KeyColumns[0].endsWith("_ID") && !Env.isUseCentralizedId(p_info.getTableName()))
{
int id = DB.getSQLValueEx(get_TrxName(), "SELECT " + m_KeyColumns[0] + " FROM "
+ p_info.getTableName() + " WHERE " + getUUIDColumnName() + "=?", get_ValueAsString(getUUIDColumnName()));
m_IDs[0] = Integer.valueOf(id);
set_ValueNoCheck(m_KeyColumns[0], m_IDs[0]);
int ki = p_info.getColumnIndex(m_KeyColumns[0]);
// Change Log - Only
String insertLog = MSysConfig.getValue(MSysConfig.SYSTEM_INSERT_CHANGELOG, "Y", getAD_Client_ID());
if ( session != null
&& m_IDs.length == 1
&& p_info.isAllowLogging(ki) // logging allowed
&& !p_info.isEncrypted(ki) // not encrypted
&& !p_info.isVirtualColumn(ki) // no virtual column
&& !"Password".equals(p_info.getColumnName(ki))
&& (insertLog.equalsIgnoreCase("Y")
|| (insertLog.equalsIgnoreCase("K") && p_info.getColumn(ki).IsKey))
)
{
// change log on new
MChangeLog cLog = session.changeLog (
m_trxName, AD_ChangeLog_ID,
p_info.getAD_Table_ID(), p_info.getColumn(ki).AD_Column_ID,
get_ID(), getAD_Client_ID(), getAD_Org_ID(), null, id, MChangeLog.EVENTCHANGELOG_Insert);
if (cLog != null)
AD_ChangeLog_ID = cLog.getAD_ChangeLog_ID();
}
}
ok = lobSave();
if (!load(m_trxName)) // re-read Info
{
if (m_trxName == null)
log.log(Level.SEVERE, "reloading");
else
log.log(Level.SEVERE, "[" + m_trxName + "] - reloading");
ok = false;;
}
}
else
{
String msg = "Not inserted - ";
if (CLogMgt.isLevelFiner())
msg += sqlInsert.toString();
else
msg += get_TableName();
if (m_trxName == null)
log.log(Level.WARNING, msg);
else
log.log(Level.WARNING, "[" + m_trxName + "]" + msg);
}
return ok;
} }
/** /**

View File

@ -657,6 +657,17 @@ public class POInfo implements Serializable
return m_columns[index].IsEncrypted; return m_columns[index].IsEncrypted;
} // isEncrypted } // isEncrypted
/**
* @param index
* @return true if column is secure
*/
public boolean isSecure(int index)
{
if (index < 0 || index >= m_columns.length)
return false;
return MColumn.get(m_columns[index].AD_Column_ID).isSecure();
}
/** /**
* Is allowed logging on this column * Is allowed logging on this column
* *

View File

@ -15,6 +15,7 @@ package org.adempiere.webui.panel.action;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -44,6 +45,7 @@ import org.adempiere.webui.event.DialogEvents;
import org.adempiere.webui.util.ZKUpdateUtil; import org.adempiere.webui.util.ZKUpdateUtil;
import org.adempiere.webui.window.Dialog; import org.adempiere.webui.window.Dialog;
import org.compiere.model.GridTab; import org.compiere.model.GridTab;
import org.compiere.model.MRole;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Msg; import org.compiere.util.Msg;
import org.zkoss.util.media.AMedia; import org.zkoss.util.media.AMedia;
@ -56,26 +58,30 @@ import org.zkoss.zul.Vbox;
import org.zkoss.zul.Vlayout; import org.zkoss.zul.Vlayout;
/** /**
* * Action to export data from {@link GridTab}
* @author hengsin * @author hengsin
*
*/ */
public class ExportAction implements EventListener<Event> public class ExportAction implements EventListener<Event>
{ {
private AbstractADWindowContent panel; private AbstractADWindowContent panel;
/** Exporter Label:IGridTabExporter */
private Map<String, IGridTabExporter> exporterMap = null; private Map<String, IGridTabExporter> exporterMap = null;
/** Exporter Label:Exporter File Extension */
private Map<String, String> extensionMap = null; private Map<String, String> extensionMap = null;
/** Export file dialog */
private Window winExportFile = null; private Window winExportFile = null;
private ConfirmPanel confirmPanel = new ConfirmPanel(true); private ConfirmPanel confirmPanel = new ConfirmPanel(true);
/** List of exporters */
private Listbox cboType = new Listbox(); private Listbox cboType = new Listbox();
private Checkbox chkCurrentRow = new Checkbox(); private Checkbox chkCurrentRow = new Checkbox();
private int indxDetailSelected = 0; private int selectedChildTabIndex = 0;
private List<GridTab> childs; private List<GridTab> childTabs;
private Row selectionTabRow = null; private Row childTabSelectionRow = null;
private List<Checkbox> chkSelectionTabForExport = null; private List<Checkbox> chkSelectChildTabs = null;
private IGridTabExporter exporter; private IGridTabExporter exporter;
/** /**
* @param panel * @param panel
*/ */
@ -92,13 +98,17 @@ public class ExportAction implements EventListener<Event>
exporterMap = new HashMap<String, IGridTabExporter>(); exporterMap = new HashMap<String, IGridTabExporter>();
extensionMap = new HashMap<String, String>(); extensionMap = new HashMap<String, String>();
List<IGridTabExporter> exporterList = EquinoxExtensionLocator.instance().list(IGridTabExporter.class).getExtensions(); List<IGridTabExporter> exporterList = EquinoxExtensionLocator.instance().list(IGridTabExporter.class).getExtensions();
MRole role = MRole.getDefault();
for(IGridTabExporter exporter : exporterList) for(IGridTabExporter exporter : exporterList)
{ {
if (exporter.isAdvanced() && !role.isAccessAdvanced())
continue;
String extension = exporter.getFileExtension(); String extension = exporter.getFileExtension();
if (!extensionMap.containsKey(extension)) if (!extensionMap.containsKey(exporter.getFileExtensionLabel()))
{ {
extensionMap.put(extension, exporter.getFileExtensionLabel()); extensionMap.put(exporter.getFileExtensionLabel(), extension);
exporterMap.put(extension, exporter); exporterMap.put(exporter.getFileExtensionLabel(), exporter);
} }
} }
@ -116,9 +126,11 @@ public class ExportAction implements EventListener<Event>
cboType.setMold("select"); cboType.setMold("select");
cboType.getItems().clear(); cboType.getItems().clear();
for(Map.Entry<String, String> entry : extensionMap.entrySet()) List<String> keys = new ArrayList<>(extensionMap.keySet());
Collections.sort(keys);
for(String key : keys)
{ {
cboType.appendItem(entry.getKey() + " - " + entry.getValue(), entry.getKey()); cboType.appendItem(key, key);
} }
cboType.setSelectedIndex(0); cboType.setSelectedIndex(0);
@ -159,9 +171,10 @@ public class ExportAction implements EventListener<Event>
chkCurrentRow.setLabel(Msg.getMsg(Env.getCtx(), "ExportCurrentRowOnly")); chkCurrentRow.setLabel(Msg.getMsg(Env.getCtx(), "ExportCurrentRowOnly"));
chkCurrentRow.setSelected(true); chkCurrentRow.setSelected(true);
row.appendChild(chkCurrentRow); row.appendChild(chkCurrentRow);
chkCurrentRow.addActionListener(this);
selectionTabRow = new Row(); childTabSelectionRow = new Row();
rows.appendChild(selectionTabRow); rows.appendChild(childTabSelectionRow);
LayoutUtils.addSclass("dialog-footer", confirmPanel); LayoutUtils.addSclass("dialog-footer", confirmPanel);
vb.appendChild(confirmPanel); vb.appendChild(confirmPanel);
@ -179,51 +192,61 @@ public class ExportAction implements EventListener<Event>
} }
/** /**
* Show list tab can export for user selection * Show child tabs for user selection
*/ */
protected void displayExportTabSelection() { protected void displayExportTabSelection() {
initTabInfo (); initTabInfo ();
int tabLevel = panel.getActiveGridTab().getTabLevel();
exporter = getExporter (); exporter = getExporter ();
if (exporter == null){ if (exporter == null){
Events.echoEvent("onExporterException", winExportFile, null); Events.echoEvent("onExporterException", winExportFile, null);
} }
// clear list checkbox selection to recreate with new reporter // clear list checkbox selection to recreate with new reporter
selectionTabRow.getChildren().clear(); childTabSelectionRow.getChildren().clear();
if (exporter.isExportChildTabsForCurrentRowOnly() && !chkCurrentRow.isChecked())
return;
Vlayout vlayout = new Vlayout(); Vlayout vlayout = new Vlayout();
selectionTabRow.appendChild(new Space()); childTabSelectionRow.appendChild(new Space());
selectionTabRow.appendChild(vlayout); childTabSelectionRow.appendChild(vlayout);
vlayout.appendChild(new Label(Msg.getMsg(Env.getCtx(), "SelectTabToExport"))); vlayout.appendChild(new Label(Msg.getMsg(Env.getCtx(), "SelectTabToExport")));
chkSelectionTabForExport = new ArrayList<Checkbox> (); chkSelectChildTabs = new ArrayList<Checkbox> ();
boolean isHasSelectionTab = false; boolean isHasSelectionTab = false;
boolean isSelectTabDefault = false; boolean selectAllChildTabs = false;
// with 2Pack, default is export all child tab // with 2Pack, default is export all child tab
if (exporter.getClass().getName().equals("org.adempiere.pipo2.GridTab2PackExporter")){ if (exporter.getClass().getName().equals("org.adempiere.pipo2.GridTab2PackExporter")){
isSelectTabDefault = true; selectAllChildTabs = true;
} }
// for to make each export tab with one checkbox // for to make each export tab with one checkbox
for (GridTab child : childs){ for (GridTab child : childTabs){
Checkbox chkSelectionTab = new Checkbox(); Checkbox chkSelectionTab = new Checkbox();
chkSelectionTab.setLabel(child.getName()); chkSelectionTab.setLabel(child.getName());
// just allow selection tab can export // check with exporter
if (!exporter.isExportableTab(child)){ if (!exporter.isExportableTab(child)){
continue; continue;
} }
if (child.getTabNo() == indxDetailSelected || isSelectTabDefault){ if (exporter.maxDeepOfChildTab() > 0) {
int deep = child.getTabLevel() - tabLevel;
if (deep > exporter.maxDeepOfChildTab())
continue;
}
if (child.getTabNo() == selectedChildTabIndex || selectAllChildTabs){
chkSelectionTab.setSelected(true); chkSelectionTab.setSelected(true);
} }
chkSelectionTab.setAttribute("tabBinding", child); chkSelectionTab.setAttribute("tabBinding", child);
vlayout.appendChild(chkSelectionTab); vlayout.appendChild(chkSelectionTab);
chkSelectionTabForExport.add(chkSelectionTab); chkSelectChildTabs.add(chkSelectionTab);
chkSelectionTab.addEventListener(Events.ON_CHECK, this); chkSelectionTab.addEventListener(Events.ON_CHECK, this);
isHasSelectionTab = true; isHasSelectionTab = true;
} }
// in case no child tab can export. clear selection area // in case no child tab can export. clear selection area
if (isHasSelectionTab == false){ if (isHasSelectionTab == false){
selectionTabRow.getChildren().clear(); childTabSelectionRow.getChildren().clear();
} }
} }
@ -238,12 +261,17 @@ public class ExportAction implements EventListener<Event>
panel.focusToLastFocusEditor(); panel.focusToLastFocusEditor();
} else if (event.getTarget().equals(cboType) && event.getName().equals(Events.ON_SELECT)) { } else if (event.getTarget().equals(cboType) && event.getName().equals(Events.ON_SELECT)) {
displayExportTabSelection(); displayExportTabSelection();
} else if (event.getTarget() == chkCurrentRow) {
exporter = getExporter();
if (exporter != null && exporter.isExportChildTabsForCurrentRowOnly()) {
displayExportTabSelection();
}
} else if (event.getTarget() instanceof Checkbox) { } else if (event.getTarget() instanceof Checkbox) {
// A child is not exportable without its parent // A child is not exportable without its parent
Checkbox cbSel = (Checkbox) event.getTarget(); Checkbox cbSel = (Checkbox) event.getTarget();
GridTab gtSel = (GridTab)cbSel.getAttribute("tabBinding"); GridTab gtSel = (GridTab)cbSel.getAttribute("tabBinding");
boolean found = false; boolean found = false;
for (Checkbox cb : chkSelectionTabForExport) { for (Checkbox cb : chkSelectChildTabs) {
if (cb == cbSel) { if (cb == cbSel) {
found = true; found = true;
continue; continue;
@ -264,20 +292,23 @@ public class ExportAction implements EventListener<Event>
} }
} }
/**
* Close export file dialog
*/
private void onCancel() { private void onCancel() {
winExportFile.onClose(); winExportFile.onClose();
} }
/** /**
* get info of window export, * Get GridTabs info from calling AD window,
* index of active tab, list child tab * index of active detail tab, child tabs
*/ */
protected void initTabInfo() { protected void initTabInfo() {
IADTabbox adTab = panel.getADTab(); IADTabbox adTab = panel.getADTab();
int selected = adTab.getSelectedIndex(); int selected = adTab.getSelectedIndex();
int tabLevel = panel.getActiveGridTab().getTabLevel(); int tabLevel = panel.getActiveGridTab().getTabLevel();
Set<String> tables = new HashSet<String>(); Set<String> tables = new HashSet<String>();
childs = new ArrayList<GridTab>(); childTabs = new ArrayList<GridTab>();
List<GridTab> includedList = panel.getActiveGridTab().getIncludedTabs(); List<GridTab> includedList = panel.getActiveGridTab().getIncludedTabs();
for(GridTab included : includedList) for(GridTab included : includedList)
{ {
@ -285,7 +316,7 @@ public class ExportAction implements EventListener<Event>
if (tables.contains(tableName)) if (tables.contains(tableName))
continue; continue;
tables.add(tableName); tables.add(tableName);
childs.add(included); childTabs.add(included);
} }
for(int i = selected+1; i < adTab.getTabCount(); i++) for(int i = selected+1; i < adTab.getTabCount(); i++)
{ {
@ -298,18 +329,18 @@ public class ExportAction implements EventListener<Event>
if (tables.contains(tableName)) if (tables.contains(tableName))
continue; continue;
tables.add(tableName); tables.add(tableName);
childs.add(adTabPanel.getGridTab()); childTabs.add(adTabPanel.getGridTab());
} }
indxDetailSelected = 0; selectedChildTabIndex = 0;
if( adTab.getSelectedDetailADTabpanel()!=null ) if( adTab.getSelectedDetailADTabpanel()!=null )
indxDetailSelected = adTab.getSelectedDetailADTabpanel().getGridTab().getTabNo(); selectedChildTabIndex = adTab.getSelectedDetailADTabpanel().getGridTab().getTabNo();
} }
/** /**
* Get selected exporter * Get selected exporter
* @return * @return IGridTabExporter
*/ */
protected IGridTabExporter getExporter() { protected IGridTabExporter getExporter() {
ListItem li = cboType.getSelectedItem(); ListItem li = cboType.getSelectedItem();
@ -323,18 +354,21 @@ public class ExportAction implements EventListener<Event>
return exporter; return exporter;
} }
/**
* Invoke exporter and prompt user to download exported data file
*/
private void exportFile() { private void exportFile() {
try { try {
boolean currentRowOnly = chkCurrentRow.isSelected(); boolean currentRowOnly = chkCurrentRow.isSelected();
File file = File.createTempFile("Export", "."+cboType.getSelectedItem().getValue().toString()); File file = File.createTempFile("Export", "."+cboType.getSelectedItem().getValue().toString());
childs.clear(); List<GridTab> selectedChildTabs = new ArrayList<>();
for (Checkbox chkSeletionTab : chkSelectionTabForExport){ for (Checkbox chkSeletionTab : chkSelectChildTabs){
if (chkSeletionTab.isChecked()){ if (chkSeletionTab.isChecked()){
childs.add((GridTab)chkSeletionTab.getAttribute("tabBinding")); selectedChildTabs.add((GridTab)chkSeletionTab.getAttribute("tabBinding"));
} }
} }
exporter.export(panel.getActiveGridTab(), childs, currentRowOnly,file,indxDetailSelected); exporter.export(panel.getActiveGridTab(), selectedChildTabs, currentRowOnly, file, selectedChildTabIndex);
winExportFile.onClose(); winExportFile.onClose();
winExportFile = null; winExportFile = null;