From 5e52d7407ba447706bbb6461d9e6fcaa4c21a0cf Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Fri, 1 Dec 2006 08:02:44 +0000 Subject: [PATCH] * Implemented my proposal in http://sourceforge.net/forum/forum.php?thread_id=1617252&forum_id=610548 * Implemented workaround for http://sourceforge.net/forum/forum.php?thread_id=1623567&forum_id=610546 * Report viewer needs to be track in the open window manager * Fixed range editor layout bug in ParameterPanel --- .../src/org/compiere/apps/AMenuStartItem.java | 2 + client/src/org/compiere/apps/ProcessCtl.java | 50 +- .../src/org/compiere/apps/ProcessDialog.java | 69 ++- .../org/compiere/apps/ProcessParameter.java | 6 + .../compiere/apps/ProcessParameterPanel.java | 449 ++++++++++++++++++ client/src/org/compiere/print/ReportCtl.java | 15 +- 6 files changed, 573 insertions(+), 18 deletions(-) create mode 100644 client/src/org/compiere/apps/ProcessParameterPanel.java diff --git a/client/src/org/compiere/apps/AMenuStartItem.java b/client/src/org/compiere/apps/AMenuStartItem.java index 2b9273a0a3..f86a7bff02 100644 --- a/client/src/org/compiere/apps/AMenuStartItem.java +++ b/client/src/org/compiere/apps/AMenuStartItem.java @@ -270,6 +270,8 @@ public class AMenuStartItem extends Thread implements ActionListener m_menu.getWindowManager().add(pd); SwingUtilities.invokeLater(m_updatePB); // 2 + pd.getContentPane().invalidate(); + pd.getContentPane().validate(); pd.pack(); // Center the window SwingUtilities.invokeLater(m_updatePB); // 3 diff --git a/client/src/org/compiere/apps/ProcessCtl.java b/client/src/org/compiere/apps/ProcessCtl.java index def43fea97..85e48c796a 100644 --- a/client/src/org/compiere/apps/ProcessCtl.java +++ b/client/src/org/compiere/apps/ProcessCtl.java @@ -49,8 +49,8 @@ public class ProcessCtl extends Thread * Creates a ProcessCtl instance, which calls * lockUI and unlockUI if parent is a ASyncProcess *
- * Called from ProcessCtl.startProcess, ProcessDialog.actionPerformed, - * APanel.cmd_print, APanel.actionButton, VPaySelect.cmd_generate + * Called from ProcessCtl.startProcess, APanel.cmd_print, + * APanel.actionButton, VPaySelect.cmd_generate * * @param parent ASyncProcess & Container * @param WindowNo window no @@ -89,6 +89,52 @@ public class ProcessCtl extends Thread worker.start(); // MUST be start! return worker; } // execute + + /** + * Async Process - Do it all. + * + * - Get Instance ID + * - Get Parameters + * - execute (lock - start process - unlock) + * + * Creates a ProcessCtl instance, which calls + * lockUI and unlockUI if parent is a ASyncProcess + *
+ * Called from ProcessDialog.actionPerformed + * + * @param parent ASyncProcess & Container + * @param WindowNo window no + * @param paraPanel Process Parameter Panel + * @param pi ProcessInfo process info + * @param trx Transaction + * @return worker started ProcessCtl instance or null for workflow + */ + public static ProcessCtl process(ASyncProcess parent, int WindowNo, ProcessParameterPanel paraPanel, ProcessInfo pi, Trx trx) + { + log.fine("WindowNo=" + WindowNo + " - " + pi); + + MPInstance instance = new MPInstance(Env.getCtx(), pi.getAD_Process_ID(), pi.getRecord_ID()); + if (!instance.save()) + { + pi.setSummary (Msg.getMsg(Env.getCtx(), "ProcessNoInstance")); + pi.setError (true); + return null; + } + pi.setAD_PInstance_ID (instance.getAD_PInstance_ID()); + + // Get Parameters + if (!paraPanel.saveParameters()) + { + pi.setSummary (Msg.getMsg(Env.getCtx(), "ProcessCancelled")); + pi.setError (true); + return null; + } + + // execute + ProcessCtl worker = new ProcessCtl(parent, pi, trx); + worker.start(); // MUST be start! + return worker; + } // execute diff --git a/client/src/org/compiere/apps/ProcessDialog.java b/client/src/org/compiere/apps/ProcessDialog.java index 13a7c72be5..46a009bdb7 100644 --- a/client/src/org/compiere/apps/ProcessDialog.java +++ b/client/src/org/compiere/apps/ProcessDialog.java @@ -77,14 +77,45 @@ public class ProcessDialog extends CFrame private static CLogger log = CLogger.getCLogger(ProcessDialog.class); // - private CPanel dialog = new CPanel(); + private CPanel dialog = new CPanel() + { + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + Dimension m = getMinimumSize(); + if ( d.height < m.height || d.width < m.width ) { + Dimension d1 = new Dimension(); + d1.height = Math.max(d.height, m.height); + d1.width = Math.max(d.width, m.width); + return d1; + } else + return d; + } + }; private BorderLayout mainLayout = new BorderLayout(); private CPanel southPanel = new CPanel(); private CButton bOK = ConfirmPanel.createOKButton(true); private FlowLayout southLayout = new FlowLayout(); - private JEditorPane message = new JEditorPane(); + private JEditorPane message = new JEditorPane() + { + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + Dimension m = getMaximumSize(); + if ( d.height > m.height || d.width > m.width ) { + Dimension d1 = new Dimension(); + d1.height = Math.min(d.height, m.height); + d1.width = Math.min(d.width, m.width); + return d1; + } else + return d; + } + }; private JScrollPane messagePane = new JScrollPane(message); private CButton bPrint = ConfirmPanel.createPrintButton(true); + + private CPanel centerPanel = null; + private ProcessParameterPanel parameterPanel = null; + private JSeparator separator = new JSeparator(); + private ProcessInfo m_pi = null; /** * Static Layout @@ -95,21 +126,27 @@ public class ProcessDialog extends CFrame setIconImage(Env.getImage("mProcess.gif")); // dialog.setLayout(mainLayout); + dialog.setMinimumSize(new Dimension(500, 200)); bOK.addActionListener(this); bPrint.addActionListener(this); // southPanel.setLayout(southLayout); southLayout.setAlignment(FlowLayout.RIGHT); - dialog.setPreferredSize(new Dimension(500, 150)); message.setContentType("text/html"); message.setEditable(false); - message.setBackground(AdempierePLAF.getFieldBackground_Inactive()); + message.setBackground(Color.white); message.setFocusable(false); getContentPane().add(dialog); dialog.add(southPanel, BorderLayout.SOUTH); southPanel.add(bPrint, null); southPanel.add(bOK, null); - dialog.add(messagePane, BorderLayout.CENTER); + dialog.add(messagePane, BorderLayout.NORTH); + messagePane.setBorder(null); + message.setMaximumSize(new Dimension(600, 300)); + centerPanel = new CPanel(); + centerPanel.setBorder(null); + centerPanel.setLayout(new BorderLayout()); + dialog.add(centerPanel, BorderLayout.CENTER); // this.getRootPane().setDefaultButton(bOK); } // jbInit @@ -122,8 +159,9 @@ public class ProcessDialog extends CFrame public void setVisible (boolean visible) { super.setVisible(visible); - if (visible) + if (visible) { bOK.requestFocus(); + } } // setVisible /** @@ -200,6 +238,17 @@ public class ProcessDialog extends CFrame return false; // don't show } **/ + // Similar to APanel.actionButton + m_pi = new ProcessInfo(m_Name, m_AD_Process_ID); + m_pi.setAD_User_ID (Env.getAD_User_ID(Env.getCtx())); + m_pi.setAD_Client_ID(Env.getAD_Client_ID(Env.getCtx())); + parameterPanel = new ProcessParameterPanel(m_WindowNo, m_pi); + centerPanel.removeAll(); + if (parameterPanel.init()) { + centerPanel.add(separator, BorderLayout.NORTH); + centerPanel.add(parameterPanel, BorderLayout.CENTER); + } + dialog.revalidate(); return true; } // init @@ -215,14 +264,8 @@ public class ProcessDialog extends CFrame dispose(); else { - // Similar to APanel.actionButton - ProcessInfo pi = new ProcessInfo(m_Name, m_AD_Process_ID); - pi.setAD_User_ID (Env.getAD_User_ID(Env.getCtx())); - pi.setAD_Client_ID(Env.getAD_Client_ID(Env.getCtx())); - m_messageText.append("

** ").append(m_Name).append("

"); - message.setText(m_messageText.toString()); // Trx trx = Trx.get(Trx.createTrxName("ProcessDialog"), true); - ProcessCtl.process(this, m_WindowNo, pi, null); + ProcessCtl.process(this, m_WindowNo, parameterPanel, m_pi, null); } } diff --git a/client/src/org/compiere/apps/ProcessParameter.java b/client/src/org/compiere/apps/ProcessParameter.java index f90ecb257d..b3a1835318 100644 --- a/client/src/org/compiere/apps/ProcessParameter.java +++ b/client/src/org/compiere/apps/ProcessParameter.java @@ -265,10 +265,16 @@ public class ProcessParameter extends CDialog { // To Label gbc.gridx = 2; + gbc.weightx = 0; + gbc.fill = GridBagConstraints.NONE; centerPanel.add (new JLabel(" - "), gbc); // To Field gbc.gridx = 3; gbc.insets = fieldInsetRight; + gbc.weightx = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.anchor = GridBagConstraints.WEST; + // GridFieldVO voF2 = GridFieldVO.createParameter(voF); GridField mField2 = new GridField (voF2); diff --git a/client/src/org/compiere/apps/ProcessParameterPanel.java b/client/src/org/compiere/apps/ProcessParameterPanel.java new file mode 100644 index 0000000000..50c3f41b8f --- /dev/null +++ b/client/src/org/compiere/apps/ProcessParameterPanel.java @@ -0,0 +1,449 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. 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., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.compiere.apps; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.logging.Level; + +import javax.swing.Box; +import javax.swing.JLabel; + +import org.compiere.grid.ed.VEditor; +import org.compiere.grid.ed.VEditorFactory; +import org.compiere.model.GridField; +import org.compiere.model.GridFieldVO; +import org.compiere.model.MPInstancePara; +import org.compiere.process.ProcessInfo; +import org.compiere.swing.CPanel; +import org.compiere.util.CLogger; +import org.compiere.util.DB; +import org.compiere.util.Env; + +/** + * Process Parameter Panel, based on existing ProcessParameter dialog. + * - Embedded in ProcessDialog + * - checks, if parameters exist and inquires and saves them + * + * @author Low Heng Sin + * @version 2006-12-01 + */ +@SuppressWarnings("serial") +public class ProcessParameterPanel extends CPanel implements VetoableChangeListener { + /** + * Dynamic generated Parameter panel. + * @param WindowNo window + * @param pi process info + */ + public ProcessParameterPanel(int WindowNo, ProcessInfo pi) + { + try + { + jbInit(); + } + catch(Exception ex) + { + log.log(Level.SEVERE, ex.getMessage()); + } + // + m_WindowNo = WindowNo; + m_processInfo = pi; + // + } // ProcessParameterPanel + + private int m_WindowNo; + private ProcessInfo m_processInfo; + /** Logger */ + private static CLogger log = CLogger.getCLogger(ProcessParameterPanel.class); + // + private GridBagConstraints gbc = new GridBagConstraints(); + private Insets nullInset = new Insets(0,0,0,0); + private Insets labelInset = new Insets(2,12,2,0); // top,left,bottom,right + private Insets fieldInset = new Insets(2,5,2,0); // top,left,bottom,right + private Insets fieldInsetRight = new Insets(2,5,2,12); // top,left,bottom,right + private int m_line = 0; + // + private ArrayList m_vEditors = new ArrayList(); + private ArrayList m_vEditors2 = new ArrayList(); // for ranges + private ArrayList m_mFields = new ArrayList(); + private ArrayList m_mFields2 = new ArrayList(); + // + private BorderLayout mainLayout = new BorderLayout(); + private CPanel centerPanel = new CPanel(); + private GridBagLayout centerLayout = new GridBagLayout(); + + /** + * Static Layout + * @throws Exception + */ + void jbInit() throws Exception + { + this.setLayout(mainLayout); + centerPanel.setLayout(centerLayout); + this.add(centerPanel, BorderLayout.CENTER); + } // jbInit + + /** + * Dispose + */ + public void dispose() + { + m_vEditors.clear(); + m_vEditors2.clear(); + m_mFields.clear(); + m_mFields2.clear(); + this.removeAll(); + } // dispose + + /** + * Read Fields to display + * @return true if loaded OK + */ + public boolean init() + { + log.config(""); + + // Prepare panel + gbc.anchor = GridBagConstraints.NORTHWEST; + gbc.weightx = 0; + gbc.weighty = 0; + gbc.gridy = m_line++; + gbc.gridx = 0; + gbc.gridwidth = 1; + gbc.insets = nullInset; + gbc.fill = GridBagConstraints.HORIZONTAL; + centerPanel.add(Box.createVerticalStrut(10), gbc); // top gap 10+2=12 + + // + String sql = null; + if (Env.isBaseLanguage(Env.getCtx(), "AD_Process_Para")) + sql = "SELECT p.Name, p.Description, p.Help, " + + "p.AD_Reference_ID, p.AD_Process_Para_ID, " + + "p.FieldLength, p.IsMandatory, p.IsRange, p.ColumnName, " + + "p.DefaultValue, p.DefaultValue2, p.VFormat, p.ValueMin, p.ValueMax, " + + "p.SeqNo, p.AD_Reference_Value_ID, vr.Code AS ValidationCode " + + "FROM AD_Process_Para p" + + " LEFT OUTER JOIN AD_Val_Rule vr ON (p.AD_Val_Rule_ID=vr.AD_Val_Rule_ID) " + + "WHERE p.AD_Process_ID=?" // 1 + + " AND p.IsActive='Y' " + + "ORDER BY SeqNo"; + else + sql = "SELECT t.Name, t.Description, t.Help, " + + "p.AD_Reference_ID, p.AD_Process_Para_ID, " + + "p.FieldLength, p.IsMandatory, p.IsRange, p.ColumnName, " + + "p.DefaultValue, p.DefaultValue2, p.VFormat, p.ValueMin, p.ValueMax, " + + "p.SeqNo, p.AD_Reference_Value_ID, vr.Code AS ValidationCode " + + "FROM AD_Process_Para p" + + " INNER JOIN AD_Process_Para_Trl t ON (p.AD_Process_Para_ID=t.AD_Process_Para_ID)" + + " LEFT OUTER JOIN AD_Val_Rule vr ON (p.AD_Val_Rule_ID=vr.AD_Val_Rule_ID) " + + "WHERE p.AD_Process_ID=?" // 1 + + " AND t.AD_Language='" + Env.getAD_Language(Env.getCtx()) + "'" + + " AND p.IsActive='Y' " + + "ORDER BY SeqNo"; + + // Create Fields + boolean hasFields = false; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, m_processInfo.getAD_Process_ID()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + { + hasFields = true; + createField (rs); + } + rs.close(); + pstmt.close(); + } + catch(SQLException e) + { + log.log(Level.SEVERE, sql, e); + } + + // both vectors the same? + if (m_mFields.size() != m_mFields2.size() + || m_mFields.size() != m_vEditors.size() + || m_mFields2.size() != m_vEditors2.size()) + log.log(Level.SEVERE, "View & Model vector size is different"); + + // clean up + if (hasFields) + { + gbc.gridy = m_line++; + centerPanel.add(Box.createVerticalStrut(10), gbc); // bottom gap + gbc.gridx = 3; + centerPanel.add(Box.createHorizontalStrut(12), gbc); // right gap + } + else + dispose(); + return hasFields; + } // initDialog + + + /** + * Create Field. + * - creates Fields and adds it to m_mFields list + * - creates Editor and adds it to m_vEditors list + * Handeles Ranges by adding additional mField/vEditor. + *

+ * mFields are used for default value and mandatory checking; + * vEditors are used to retrieve the value (no data binding) + * + * @param rs result set + */ + private void createField (ResultSet rs) + { + // Create Field + GridFieldVO voF = GridFieldVO.createParameter(Env.getCtx(), m_WindowNo, rs); + GridField mField = new GridField (voF); + m_mFields.add(mField); // add to Fields + + // Label Preparation + gbc.gridy = m_line++; + gbc.gridwidth = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; // required for right justified + gbc.gridx = 0; + gbc.weightx = 0; + JLabel label = VEditorFactory.getLabel(mField); + if (label == null) + { + gbc.insets = nullInset; + centerPanel.add(Box.createHorizontalStrut(12), gbc); // left gap + } + else + { + gbc.insets = labelInset; + centerPanel.add(label, gbc); + } + + // Field Preparation + gbc.insets = fieldInset; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.gridwidth = 1; + gbc.gridx = 1; + gbc.weightx = 1; + + // The Editor + VEditor vEditor = VEditorFactory.getEditor(mField, false); + vEditor.addVetoableChangeListener(this); + // MField => VEditor - New Field value to be updated to editor + mField.addPropertyChangeListener(vEditor); + // Set Default + Object defaultObject = mField.getDefault(); + mField.setValue (defaultObject, true); + // + centerPanel.add ((Component)vEditor, gbc); + m_vEditors.add (vEditor); // add to Editors + // + if (voF.isRange) + { + // To Label + gbc.gridx = 2; + gbc.weightx = 0; + gbc.fill = GridBagConstraints.NONE; + centerPanel.add (new JLabel(" - "), gbc); + // To Field + gbc.gridx = 3; + gbc.insets = fieldInsetRight; + gbc.weightx = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.anchor = GridBagConstraints.WEST; + // + GridFieldVO voF2 = GridFieldVO.createParameter(voF); + GridField mField2 = new GridField (voF2); + m_mFields2.add (mField2); + // The Editor + VEditor vEditor2 = VEditorFactory.getEditor(mField2, false); + // New Field value to be updated to editor + mField2.addPropertyChangeListener(vEditor2); + // Set Default + Object defaultObject2 = mField2.getDefault(); + mField2.setValue (defaultObject2, true); + // + centerPanel.add ((Component)vEditor2, gbc); + m_vEditors2.add (vEditor2); + } + else + { + m_mFields2.add (null); + m_vEditors2.add (null); + } + } // createField + + /** + * Editor Listener + * @param evt Event + * @exception PropertyVetoException if the recipient wishes to roll back. + */ + public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException + { + // log.fine( "ProcessParameterPanel.vetoableChange"); + String value = evt.getNewValue() == null ? "" : evt.getNewValue().toString(); + Env.setContext(Env.getCtx(), m_WindowNo, evt.getPropertyName(), value); + } // vetoableChange + + /** + * Save Parameter values + * @return true if parameters saved + */ + public boolean saveParameters() + { + log.config(""); + + /** + * Mandatory fields + * see - MTable.getMandatory + */ + StringBuffer sb = new StringBuffer(); + int size = m_mFields.size(); + for (int i = 0; i < size; i++) + { + GridField field = (GridField)m_mFields.get(i); + if (field.isMandatory(true)) // check context + { + VEditor vEditor = (VEditor)m_vEditors.get(i); + Object data = vEditor.getValue(); + if (data == null || data.toString().length() == 0) + { + field.setInserting (true); // set editable (i.e. updateable) otherwise deadlock + field.setError(true); + if (sb.length() > 0) + sb.append(", "); + sb.append(field.getHeader()); + } + else + field.setError(false); + // Check for Range + VEditor vEditor2 = (VEditor)m_vEditors2.get(i); + if (vEditor2 != null) + { + Object data2 = vEditor.getValue(); + GridField field2 = (GridField)m_mFields2.get(i); + if (data2 == null || data2.toString().length() == 0) + { + field.setInserting (true); // set editable (i.e. updateable) otherwise deadlock + field2.setError(true); + if (sb.length() > 0) + sb.append(", "); + sb.append(field.getHeader()); + } + else + field2.setError(false); + } // range field + } // mandatory + } // field loop + + + if (sb.length() != 0) + { + ADialog.error(m_WindowNo, this, "FillMandatory", sb.toString()); + return false; + } + + /********************************************************************** + * Save Now + */ + for (int i = 0; i < m_mFields.size(); i++) + { + // Get Values + VEditor editor = (VEditor)m_vEditors.get(i); + VEditor editor2 = (VEditor)m_vEditors2.get(i); + Object result = editor.getValue(); + Object result2 = null; + if (editor2 != null) + result2 = editor2.getValue(); + + // Don't save NULL values + if (result == null && result2 == null) + continue; + + // Create Parameter + MPInstancePara para = new MPInstancePara (Env.getCtx(), m_processInfo.getAD_PInstance_ID(), i); + GridField mField = (GridField)m_mFields.get(i); + para.setParameterName(mField.getColumnName()); + + // Date + if (result instanceof Timestamp || result2 instanceof Timestamp) + { + para.setP_Date((Timestamp)result); + if (editor2 != null && result2 != null) + para.setP_Date_To((Timestamp)result2); + } + // Integer + else if (result instanceof Integer || result2 instanceof Integer) + { + if (result != null) + { + Integer ii = (Integer)result; + para.setP_Number(ii.intValue()); + } + if (editor2 != null && result2 != null) + { + Integer ii = (Integer)result2; + para.setP_Number_To(ii.intValue()); + } + } + // BigDecimal + else if (result instanceof BigDecimal || result2 instanceof BigDecimal) + { + para.setP_Number ((BigDecimal)result); + if (editor2 != null && result2 != null) + para.setP_Number_To ((BigDecimal)result2); + } + // Boolean + else if (result instanceof Boolean) + { + Boolean bb = (Boolean)result; + String value = bb.booleanValue() ? "Y" : "N"; + para.setP_String (value); + // to does not make sense + } + // String + else + { + if (result != null) + para.setP_String (result.toString()); + if (editor2 != null && result2 != null) + para.setP_String_To (result2.toString()); + } + + // Info + para.setInfo (editor.getDisplay()); + if (editor2 != null) + para.setInfo_To (editor2.getDisplay()); + // + para.save(); + log.fine(para.toString()); + } // for every parameter + + return true; + } // saveParameters + } // ProcessParameterPanel + diff --git a/client/src/org/compiere/print/ReportCtl.java b/client/src/org/compiere/print/ReportCtl.java index e99f1e875c..40adef9e82 100644 --- a/client/src/org/compiere/print/ReportCtl.java +++ b/client/src/org/compiere/print/ReportCtl.java @@ -17,6 +17,9 @@ package org.compiere.print; import java.util.logging.*; + +import javax.swing.JFrame; + import org.compiere.apps.*; import org.compiere.model.*; import org.compiere.process.*; @@ -108,7 +111,7 @@ public class ReportCtl re.print(); } else - new Viewer(re); + preview(re); return true; } // startStandardReport @@ -137,7 +140,7 @@ public class ReportCtl PrintInfo info = new PrintInfo(pi); ReportEngine re = new ReportEngine(Env.getCtx(), format, query, info); - new Viewer(re); + preview(re); return true; } // startFinReport @@ -164,7 +167,7 @@ public class ReportCtl ReportEngine.printConfirm (type, Record_ID); } else - new Viewer(re); + preview(re); return true; } // StartDocumentPrint @@ -190,4 +193,10 @@ public class ReportCtl return startDocumentPrint (ReportEngine.CHECK, C_PaySelectionCheck_ID, IsDirectPrint); } // startCheckPrint + private static void preview(ReportEngine re) { + Viewer viewer = new Viewer(re); + JFrame top = Env.getWindow(0); + if (top instanceof AMenu) + ((AMenu)top).getWindowManager().add(viewer); + } } // ReportCtl