From dff85c45dedfc87ea33c6a42734583554473a15b Mon Sep 17 00:00:00 2001 From: hengsin Date: Wed, 15 Feb 2023 19:33:18 +0800 Subject: [PATCH] IDEMPIERE-5570 Zk: Improve readability of code (#1675) * IDEMPIERE-5570 Zk: Improve readability of code * IDEMPIERE-5570 Zk: Improve readability of code - Improve readability for org.adempiere.webui.apps package. --- .../webui/adwindow/AbstractADTabbox.java | 8 +- .../src/org/adempiere/webui/apps/AEnv.java | 161 +++++--- .../webui/apps/AbstractProcessDialog.java | 357 +++++++++++++++--- .../org/adempiere/webui/apps/BusyDialog.java | 15 +- .../webui/apps/BusyDialogTemplate.java | 48 +++ .../adempiere/webui/apps/CalloutDialog.java | 6 +- .../adempiere/webui/apps/DesktopRunnable.java | 39 +- .../webui/apps/DocumentSearchController.java | 67 +++- .../webui/apps/FeedbackRequestWindow.java | 34 +- .../adempiere/webui/apps/GlobalSearch.java | 74 ++-- .../org/adempiere/webui/apps/HelpWindow.java | 39 +- .../webui/apps/IProcessParameterListener.java | 2 +- .../adempiere/webui/apps/LabelsSearch.java | 63 ++-- .../webui/apps/LabelsSearchController.java | 27 +- .../org/adempiere/webui/apps/MenuItem.java | 38 +- .../webui/apps/MenuSearchController.java | 137 ++++++- .../adempiere/webui/apps/ProcessDialog.java | 110 ++++-- .../webui/apps/ProcessModalDialog.java | 36 +- .../webui/apps/ProcessParameterPanel.java | 159 +++++--- .../adempiere/webui/apps/WDrillReport.java | 64 +++- .../org/adempiere/webui/apps/WProcessCtl.java | 118 +++--- .../src/org/adempiere/webui/apps/WReport.java | 46 ++- 22 files changed, 1265 insertions(+), 383 deletions(-) diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADTabbox.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADTabbox.java index 9d813d9a4f..3774de5996 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADTabbox.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADTabbox.java @@ -33,7 +33,7 @@ import org.compiere.util.Evaluator; import org.compiere.util.Util; /** - * Abstract model and controller for AD_Tab+AD_Field. UI part is implemented in sub class. + * Abstract base class for header+details AD_Tabs UI for AD_Window. * @author Ashley G Ramdass * @author Low Heng Sin * @date Feb 25, 2007 @@ -41,12 +41,12 @@ import org.compiere.util.Util; */ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabbox { - /** Logger */ + /** Logger **/ private static final CLogger log = CLogger.getCLogger (AbstractADTabbox.class); - /** List of dependent Variables */ + /** List of variables/columnName that's reference by one or more gridTab logic expression **/ private ArrayList m_dependents = new ArrayList(); - /** AD tab panels associated to this tab box */ + /** List of {@link IADTabpanel} instance manage by this AbstractADTabbox instance **/ protected List tabPanelList = new ArrayList(); /** Parent part, the content part of AD Window **/ protected AbstractADWindowContent adWindowPanel; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/AEnv.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/AEnv.java index 9ca76e94c5..251a40c6ce 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/AEnv.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/AEnv.java @@ -39,6 +39,7 @@ import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.adwindow.ADWindow; import org.adempiere.webui.component.Mask; import org.adempiere.webui.component.Window; +import org.adempiere.webui.desktop.IDesktop; import org.adempiere.webui.editor.WTableDirEditor; import org.adempiere.webui.event.DialogEvents; import org.adempiere.webui.event.DrillEvent.DrillData; @@ -86,7 +87,7 @@ import org.zkoss.zul.impl.InputElement; import com.lowagie.text.DocumentException; /** - * ZK Application Environment and utilities + * Static application environment and utilities methods. * * @author Jorg Janke * @version $Id: AEnv.java,v 1.2 2006/07/30 00:51:27 jjanke Exp $ @@ -95,11 +96,11 @@ import com.lowagie.text.DocumentException; */ public final class AEnv { + /** Environment context attribute for Locale **/ public static final String LOCALE = Env.LOCALE; /** - * Show in the center of the screen. - * (pack, set location and set visibility) + * Show window in the center of screen. * @param window Window to position */ public static void showCenterScreen(Window window) @@ -120,8 +121,7 @@ public final class AEnv } // showCenterScreen /** - * Show in the center of the screen. - * (pack, set location and set visibility) + * Set window position ({@link org.zkoss.zul.Window#setPosition(String)}) and show it. * @param window Window to position * @param position */ @@ -131,8 +131,7 @@ public final class AEnv } // showScreen /** - * Position in center of the parent window. - * (pack, set location and set visibility) + * Position window in center of the parent window. * @param parent Parent Window * @param window Window to position */ @@ -145,7 +144,7 @@ public final class AEnv /** * Get Mnemonic character from text. * @param text text with '&' - * @return Mnemonic or 0 + * @return Mnemonic character or 0 */ public static char getMnemonic (String text) { @@ -159,7 +158,7 @@ public final class AEnv /************************************************************************* - * Zoom + * Zoom to AD Window by AD_Table_ID and Record_ID. * @param AD_Table_ID * @param Record_ID */ @@ -178,10 +177,11 @@ public final class AEnv } // zoom /************************************************************************* - * Zoom + * Zoom to AD Window by AD_Table_ID and Record_ID. * @param AD_Table_ID * @param Record_ID - * @param query + * @param query initial query for destination AD Window + * @param windowNo */ public static void zoom (int AD_Table_ID, int Record_ID, MQuery query, int windowNo) { @@ -192,21 +192,28 @@ public final class AEnv zoom(AD_Window_ID, query); } // zoom + /** + * Call {@link #zoom(int, int, MQuery, int)} + * @param AD_Table_ID + * @param Record_ID + * @param query + */ public static void zoom (int AD_Table_ID, int Record_ID, MQuery query) { zoom (AD_Table_ID, Record_ID, query, 0); } /** - * Exit System + * Exit System. * @param status System exit status (usually 0 for no error) */ + @Deprecated(forRemoval = true, since = "11") public static void exit (int status) { Env.exitEnv(status); } // exit /** - * logout AD_Session + * Logout AD_Session and clear {@link #windowCache}. */ public static void logout() { @@ -228,13 +235,12 @@ public final class AEnv session.logout(); Env.setContext(Env.getCtx(), Env.AD_SESSION_ID, (String)null); - // } /** - * Start Workflow Process Window - * @param AD_Table_ID optional table - * @param Record_ID optional record + * Open Workflow Process Window for AD_Table_ID and Record_ID + * @param AD_Table_ID + * @param Record_ID */ public static void startWorkflowProcess (int AD_Table_ID, int Record_ID) { @@ -253,28 +259,24 @@ public final class AEnv AEnv.zoom(s_workflow_Window_ID, query); } // startWorkflowProcess - - /*************************************************************************/ - - /** Workflow Window */ + /** Cache Workflow Window ID **/ private static int s_workflow_Window_ID = 0; /** Logger */ private static final CLogger log = CLogger.getCLogger(AEnv.class); - /** Window Cache */ + /** Register AD Window Cache **/ private static Map> windowCache = new HashMap>(); /** - * Get Window Model + * Get VO for AD_Window * * @param WindowNo Window No * @param AD_Window_ID window * @param AD_Menu_ID menu - * @return Model Window Value Obkect + * @return {@link GridWindowVO} instance for AD_Window_ID */ public static GridWindowVO getMWindowVO (int WindowNo, int AD_Window_ID, int AD_Menu_ID) { - if (log.isLoggable(Level.CONFIG)) log.config("Window=" + WindowNo + ", AD_Window_ID=" + AD_Window_ID); GridWindowVO mWindowVO = null; String sessionID = Env.getContext(Env.getCtx(), Env.AD_SESSION_ID); @@ -299,7 +301,8 @@ public final class AEnv // Create Window Model on Client if (mWindowVO == null) { - log.config("create local"); + if (log.isLoggable(Level.CONFIG)) + log.config("create local"); mWindowVO = GridWindowVO.create (Env.getCtx(), WindowNo, AD_Window_ID, AD_Menu_ID); if (mWindowVO != null && Ini.isCacheWindow()) { @@ -318,10 +321,9 @@ public final class AEnv if (mWindowVO == null) return null; - // Check (remote) context + // Check context if (!mWindowVO.ctx.equals(Env.getCtx())) { - // Remote Context is called by value, not reference // Add Window properties to context Enumeration keyEnum = mWindowVO.ctx.keys(); while (keyEnum.hasMoreElements()) @@ -341,12 +343,13 @@ public final class AEnv } // getWindow /** - * Post Immediate + * Post Immediate. + * Call {@link Doc#manualPosting(int, int, int, int, boolean)}. * @param WindowNo window * @param AD_Table_ID Table ID of Document * @param AD_Client_ID Client ID of Document - * @param Record_ID Record ID of this document - * @param force force posting + * @param Record_ID Record ID of Document + * @param force force posting. if false, only post if (Processing='N' OR Processing IS NULL) * @return null if success, otherwise error */ public static String postImmediate (int WindowNo, int AD_Client_ID, @@ -373,6 +376,13 @@ public final class AEnv CacheMgt.get().reset(tableName, Record_ID); } // cacheReset + /** + * Refresh lookup + * @param lookup + * @param value + * @param mandatory + * @param shortList + */ public static void actionRefresh(Lookup lookup, Object value, boolean mandatory, boolean shortList) // IDEMPIERE 90 { if (lookup == null) @@ -385,9 +395,9 @@ public final class AEnv lookup.fillComboBox(mandatory, true, false, false, shortList); // IDEMPIERE 90 } /** - * - * @param lookup - * @param value + * zoom to AD Window + * @param lookup lookup for zoom destination table + * @param value record key */ public static void actionZoom(Lookup lookup, Object value) { @@ -492,7 +502,7 @@ public final class AEnv } /** - * Zoom to a window with the provided window id and filters according to the + * Zoom to AD window with the provided window id and filters according to the * query * @param AD_Window_ID Window on which to zoom * @param query Filter to be applied on the records. @@ -503,17 +513,27 @@ public final class AEnv showZoomWindow(zoomId > 0 ? zoomId : AD_Window_ID, query); } + /** + * Call {@link #zoom(int, MQuery, int)} + * @param AD_Window_ID + * @param query + */ public static void zoom(int AD_Window_ID, MQuery query) { zoom(AD_Window_ID, query, 0); } + /** + * Show window in desktop. + * Call {@link IDesktop#showWindow(Window)}. + * @param win + */ public static void showWindow(Window win) { SessionManager.getAppDesktop().showWindow(win); } /** - * Zoom + * Zoom to AD Window with details from query * @param query query */ public static void zoom (MQuery query) @@ -537,7 +557,7 @@ public final class AEnv * Get ImageIcon. * * @param fileNameInImageDir full file name in imgaes folder (e.g. Bean16.png) - * @return image + * @return image {@link URI} */ public static URI getImage(String fileNameInImageDir) { @@ -555,8 +575,7 @@ public final class AEnv } // getImageIcon /** - * - * @return boolean + * @return true if client browser is firefox 2+ */ public static boolean isFirefox2() { Execution execution = Executions.getCurrent(); @@ -626,10 +645,9 @@ public final class AEnv } /** - * * @param parent * @param child - * @return boolean + * @return true if parent == child or parent is ancestor of child. */ public static boolean contains(Component parent, Component child) { if (child == parent) @@ -646,7 +664,7 @@ public final class AEnv } /** - * + * Merge pdfList to outFile * @param pdfList * @param outFile * @throws IOException @@ -687,7 +705,7 @@ public final class AEnv /** * @param ctx - * @return Language + * @return {@link Language} */ public static Language getLanguage(Properties ctx) { return Env.getLocaleLanguage(ctx); @@ -695,7 +713,7 @@ public final class AEnv /** * @param ctx - * @return Locale + * @return {@link Locale} */ public static Locale getLocale(Properties ctx) { return Env.getLocale(ctx); @@ -741,12 +759,19 @@ public final class AEnv return header; } + /** + * Call {@link #getDialogHeader(Properties, int, String)} + * @param ctx + * @param windowNo + * @return dialog header + */ public static String getDialogHeader(Properties ctx, int windowNo) { return getDialogHeader(ctx, windowNo, null); } /** * Execute synchronous task in UI thread. + * Use {@link Executions#activate(Desktop)} and {@link Executions#deactivate(Desktop)} pair if current thread is not UI/Listener thread. * @param runnable */ public static void executeDesktopTask(final Runnable runnable) { @@ -777,7 +802,7 @@ public final class AEnv /** * Get current desktop - * @return Desktop + * @return {@link Desktop} */ public static Desktop getDesktop() { boolean inUIThread = Executions.getCurrent() != null; @@ -793,6 +818,7 @@ public final class AEnv * @deprecated replace by ClientInfo.isMobile() * @return true if running on a tablet */ + @Deprecated(forRemoval = true, since = "11") public static boolean isTablet() { return ClientInfo.isMobile(); } @@ -822,6 +848,12 @@ public final class AEnv return adWindowID; } + /** + * + * @param client + * @return {@link WTableDirEditor} for Language if client is with IsMultiLingualDocument=Y + * @throws Exception + */ public static WTableDirEditor getListDocumentLanguage (MClient client) throws Exception { WTableDirEditor fLanguageType = null; if (client.isMultiLingualDocument()){ @@ -834,6 +866,10 @@ public final class AEnv } private static String m_ApplicationUrl = null; + + /** + * @return URL to access application from browser + */ public static String getApplicationUrl() { String url = MSysConfig.getValue(MSysConfig.APPLICATION_URL, Env.getAD_Client_ID(Env.getCtx())); if (!Util.isEmpty(url) && !url.equals("USE_HARDCODED")) @@ -851,20 +887,26 @@ public final class AEnv return m_ApplicationUrl; } - /** Return the link for direct access to the record using tableID */ + /** + * @param po + * @return URL link for direct access to the record using AD_Table_ID+Record_ID + */ public static String getZoomUrlTableID(PO po) { return getApplicationUrl() + "?Action=Zoom&AD_Table_ID=" + po.get_Table_ID() + "&Record_ID=" + po.get_ID(); } - /** Return the link for direct access to the record using tablename */ + /** + * @param po + * @return URL link for direct access to the record using TableName+Record_ID + */ public static String getZoomUrlTableName(PO po) { return getApplicationUrl() + "?Action=Zoom&TableName" + po.get_TableName() + "&Record_ID=" + po.get_ID(); } /** - * + * Set attribute value to Boolean.TRUE if attribute doesn't exists in current execution yet. * @param attribute * @return true if attribute have been set for current executions */ @@ -878,17 +920,22 @@ public final class AEnv } /** - * Workaround for detached HTML input element leak - * @param c + * Workaround for detached HTML input element leak. + *
+ * Detach all InputElement and Button that's the immediate or not immediate child of parent. + *
+ * Note that to remedy the detached HTML element leak issue, we must defer the detach of parent + * with {@link Executions#schedule(Desktop, EventListener, Event)}. + * @param parent {@link Component} */ - public static void detachInputElement(Component c) { - if (c instanceof InputElement || c instanceof Button) { - c.detach(); + public static void detachInputElement(Component parent) { + if (parent instanceof InputElement || parent instanceof Button) { + parent.detach(); } - if (c.getChildren().size() > 0) { - Component[] childs = c.getChildren().toArray(new Component[0]); - for(Component c1 : childs) { - detachInputElement(c1); + if (parent.getChildren().size() > 0) { + Component[] childs = parent.getChildren().toArray(new Component[0]); + for(Component child : childs) { + detachInputElement(child); } } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/AbstractProcessDialog.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/AbstractProcessDialog.java index 22bcf69b1b..3990bf751e 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/AbstractProcessDialog.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/AbstractProcessDialog.java @@ -73,6 +73,7 @@ import org.compiere.model.MUser; import org.compiere.model.MUserDefProc; import org.compiere.model.Query; import org.compiere.model.SystemIDs; +import org.compiere.model.X_AD_PInstance; import org.compiere.print.MPrintFormat; import org.compiere.process.ProcessInfo; import org.compiere.process.ProcessInfoUtil; @@ -101,15 +102,22 @@ import org.zkoss.zul.Html; import org.zkoss.zul.Space; import org.zkoss.zul.Vlayout; +/** + * Abstract dialog base class for execution of process/report. + * @see ProcessModalDialog + * @see ProcessDialog + */ public abstract class AbstractProcessDialog extends Window implements IProcessUI, EventListener { /** - * + * generated serial id */ private static final long serialVersionUID = 484056046177205235L; - private static final String ON_COMPLETE = "onComplete"; - private static final String ON_STATUS_UPDATE = "onStatusUpdate"; + /** Event to fire on complete of execution of process/report **/ + private static final String ON_COMPLETE_EVENT = "onComplete"; + /** Event to update status text of process dialog. Event data: status text message. **/ + private static final String ON_STATUS_UPDATE_EVENT = "onStatusUpdate"; private static final CLogger log = CLogger.getCLogger(AbstractProcessDialog.class); @@ -118,29 +126,47 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI private Properties m_ctx; private int m_AD_Process_ID; private ProcessInfo m_pi = null; + /** if true, auto call {@link #dispose()} in {@link #ON_COMPLETE_EVENT} handler. **/ private boolean m_disposeOnComplete; - + /** Panel for process paramters **/ private ProcessParameterPanel parameterPanel = null; + /** Checkbox to toggle running process/report as background job **/ private Checkbox runAsJobField = null; private Label notificationTypeLabel = null; + /** + * Drop down editor for {@link X_AD_PInstance#NOTIFICATIONTYPE_AD_Reference_ID} list. + * For background job notification when {@link #runAsJobField} is checked. + */ private WTableDirEditor notificationTypeField = null; private BusyDialog progressWindow; + /** translated process name */ private String m_Name = null; + /** translated process description */ private String m_Description = null; + /** translated process help */ private String m_Help = null; - private String m_ShowHelp = null; // Determine if a Help Process Window is shown + /** Determine if a Help Process Window is shown **/ + private String m_ShowHelp = null; + /** initial panel header message **/ private String initialMessage; - + /** true if dialog is still valid, i.e not dispose yet **/ private boolean m_valid = true; + /** true if dialog have been cancelled by user **/ private boolean m_cancel = false; - + + /** Reference to process thread/task **/ private Future future; + /** files for download by user **/ private List downloadFiles; + /** true when UI have been locked, i.e busy **/ private boolean m_locked = false; private String m_AD_Process_UU = ""; + /** + * default constructor + */ protected AbstractProcessDialog() { super(); @@ -163,7 +189,7 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } /** - * layout as below + * layout dialog * * @param ctx * @param WindowNo @@ -172,7 +198,7 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI * @param pi * @param autoStart * @param isDisposeOnComplete - * @return + * @return true if init is ok. */ protected boolean init(Properties ctx, int WindowNo, int TabNo, int AD_Process_ID, ProcessInfo pi, boolean autoStart, boolean isDisposeOnComplete) { @@ -183,7 +209,8 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI setProcessInfo(pi); m_disposeOnComplete = isDisposeOnComplete; - log.config(""); + if (log.isLoggable(Level.CONFIG)) + log.config(""); // StringBuilder buildMsg = new StringBuilder(); boolean trl = !Env.isBaseLanguage(m_ctx, "AD_Process"); @@ -222,7 +249,6 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI // this.setTitle(m_Name); - // Move from APanel.actionButton if (m_pi == null) { m_pi = new WProcessInfo(m_Name, AD_Process_ID); // Set Replace Tab Content @@ -233,8 +259,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI m_pi.setTitle(m_Name); m_pi.setAD_Process_UU(m_AD_Process_UU); - parameterPanel = new ProcessParameterPanel(m_WindowNo, m_TabNo, m_pi); + parameterPanel = new ProcessParameterPanel(m_WindowNo, m_TabNo, m_pi); if ( !parameterPanel.init() ) { + //auto start if no parameters and DonTShowHelp. if (m_ShowHelp != null && MProcess.SHOWHELP_DonTShowHelp.equals(m_ShowHelp)) autoStart = true; @@ -263,21 +290,33 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI return true; } + /** top part of {@link #mainParameterLayout} **/ protected HtmlBasedComponent topParameterLayout; + /** bottom part of {@link #mainParameterLayout} **/ protected HtmlBasedComponent bottomParameterLayout; + /** main content layout **/ protected HtmlBasedComponent mainParameterLayout; protected WTableDirEditor fPrintFormat; private WEditor fLanguageType; protected Listbox freportType; private Checkbox chbIsSummary; + /** ok button to run process/report **/ protected Button bOK; + /** cancel button to dismiss dialog **/ protected Button bCancel; + /** List of name/label for save process parameters **/ protected Combobox fSavedName=new Combobox(); + /** button to save process parameters **/ private Button bSave=ButtonFactory.createNamedButton("Save"); + /** button to delete saved process parameters **/ private Button bDelete=ButtonFactory.createNamedButton("Delete"); + /** List of save parameters **/ private List savedParams; private Label lSaved; + /** + * layout dialog + */ protected void layout(){ overalLayout(); topLayout(topParameterLayout); @@ -285,6 +324,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } + /** + * Layout {@link #mainParameterLayout}, {@link #topParameterLayout} and {@link #bottomParameterLayout}. + */ protected void overalLayout(){ mainParameterLayout = new Div(); mainParameterLayout.setSclass("main-parameter-layout"); @@ -300,6 +342,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI mainParameterLayout.appendChild(bottomParameterLayout); } + /** + * Layout content of {@link #topParameterLayout} + * @param topParameterLayout + */ protected void topLayout(HtmlBasedComponent topParameterLayout) { // message setHeadMessage (topParameterLayout, initialMessage); @@ -313,6 +359,12 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI inputParameterLayout(inputParameterLayout); } + /** + * Create header message of {@link #topParameterLayout} + * @param parent + * @param contentMsg + * @return content component for contentMsg + */ protected HtmlBasedComponent setHeadMessage (HtmlBasedComponent parent, String contentMsg){ // message HtmlBasedComponent messageParameterLayout = new Vlayout(); @@ -332,6 +384,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI return content; } + /** + * Layout parameter part of {@link #topParameterLayout}. + * {@link #parameterPanel}, {@link #runAsJobField} and {@link #notificationTypeField}. + * @param parent + */ protected void inputParameterLayout (HtmlBasedComponent parent) { parent.appendChild(parameterPanel); @@ -403,6 +460,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } } + /** + * Layout content of {@link #bottomParameterLayout}. + * Report option, save parameter and action buttons. + * @param bottomParameterLayout + */ protected void bottomLayout(HtmlBasedComponent bottomParameterLayout) { reportOptionLayout(bottomParameterLayout); @@ -418,6 +480,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI buttonLayout (bottomContainer); } + /** + * Render report option part of {@link #bottomParameterLayout}. + * @param bottomParameterLayout + */ protected void reportOptionLayout(HtmlBasedComponent bottomParameterLayout) { if (!isReport() && !isJasperReport()) return;//if not a report not need show this pannel @@ -428,6 +494,7 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI reportOptionLayout.setValign("middle"); bottomParameterLayout.appendChild(reportOptionLayout); + //output type: html, pdf, etc Label lreportType = new Label(Msg.translate(Env.getCtx(), "view.report")); lreportType.setSclass("option-input-parameter view-report-label"); freportType = new Listbox(); @@ -440,6 +507,8 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI if (!isReport()) return; + + //summary option chbIsSummary = new Checkbox(); chbIsSummary.setSclass("option-input-parameter"); Label lPrintFormat = new Label(Msg.translate(Env.getCtx(), "AD_PrintFormat_ID")); @@ -447,11 +516,13 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI Label lIsSummary = new Label(Msg.translate(Env.getCtx(), "Summary")); lIsSummary.setSclass("option-input-parameter"); + //print formats MClient client = MClient.get(m_ctx); listPrintFormat(client); reportOptionLayout.appendChild(lPrintFormat); reportOptionLayout.appendChild(fPrintFormat.getComponent()); + //selection of language if (client.isMultiLingualDocument()){ Label lLanguageType = new Label(Msg.translate(Env.getCtx(), MLanguage.COLUMNNAME_AD_Language_ID)); reportOptionLayout.appendChild(lLanguageType); @@ -464,16 +535,26 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI reportOptionLayout.appendChild(chbIsSummary); } + /** + * @return true if current process is with IsReport=Y AND JasperReport Is NULL. + */ protected boolean isReport () { MProcess pr = MProcess.get(m_ctx, m_AD_Process_ID); return pr.isReport() && pr.getJasperReport() == null; } + /** + * @return true if current process is with IsReport=Y AND JasperReport Is Not NULL. + */ protected boolean isJasperReport () { MProcess pr = MProcess.get(m_ctx, m_AD_Process_ID); return pr.isReport() && pr.getJasperReport() != null; } + /** + * Layout UI to load/save process parameters + * @param bottomParameterLayout + */ protected void savePrameterLayout(HtmlBasedComponent bottomParameterLayout) { Hlayout savePrameterLayout = new Hlayout(); savePrameterLayout.setSclass("save-parameter-container"); @@ -503,6 +584,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI querySaved(); } + /** + * Load saved process parameters + */ protected void querySaved() { //user query @@ -517,6 +601,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI fSavedName.setValue(""); } + /** + * Action buttons for dialog + * @param bottomParameterLayout + */ protected void buttonLayout (HtmlBasedComponent bottomParameterLayout) { HtmlBasedComponent confParaPanel =new Div(); confParaPanel.setSclass("button-container"); @@ -536,6 +624,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } + /** + * Fill {@link #fPrintFormat} + * @param client + */ private void listPrintFormat(MClient client) { int AD_Column_ID = 0; @@ -590,6 +682,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI setReportTypeAndPrintFormat(getLastRun()); } + /** + * Fill {@link #freportType} for Jasper Report. + */ private void listReportTypeJasper() { boolean m_isCanExport = MRole.getDefault().isCanExport(); @@ -598,6 +693,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI setReportTypeAndPrintFormat(getLastRun()); } + /** + * @return Last run {@link MPInstance} record for current logged in user. + */ protected MPInstance getLastRun() { final String where = "AD_Process_ID = ? AND AD_User_ID = ? AND Name IS NULL "; return new Query(Env.getCtx(), MPInstance.Table_Name, where, null) @@ -607,6 +705,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI .first(); } + /** + * Fill {@link #freportType} + * @param m_isCanExport true to include excel and csv. + */ private void fillReportType(boolean m_isCanExport) { freportType.removeAllItems(); freportType.setMold("select"); @@ -623,6 +725,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI freportType.setSelectedIndex(-1); } + /** + * Set value for {@link #fPrintFormat}, {@link #fLanguageType}, {@link #freportType} and {@link #chbIsSummary} from instance. + * @param instance + */ private void setReportTypeAndPrintFormat(MPInstance instance) { if (fPrintFormat != null && instance != null @@ -645,6 +751,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI chbIsSummary.setSelected(instance.isSummary()); } + /** + * Update process info ({@link ProcessInfo}) with selected report options ({@link #freportType}, + * {@link #fPrintFormat}, {@link #fLanguageType} and {@link #chbIsSummary}). + */ protected void saveReportOption (){ if (!isReport() && !isJasperReport()){ return; @@ -669,11 +779,16 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI getProcessInfo().setLanguageID(MLanguage.get(getCtx(), Env.getLanguage(getCtx())).getAD_Language_ID()); } + /** + * Auto start process upon instantiation of process dialog. + * Delegate to {@link #startProcess0()}. + */ protected void autoStart() { startProcess0(); } + @Override public void onEvent(Event event) { Component component = event.getTarget(); @@ -683,9 +798,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI mainParameterLayout.invalidate(); } - else if (event.getName().equals(ON_COMPLETE)) + else if (event.getName().equals(ON_COMPLETE_EVENT)) onComplete(); - else if (event.getName().equals(ON_STATUS_UPDATE)) + else if (event.getName().equals(ON_STATUS_UPDATE_EVENT)) onStatusUpdate(event); else if (event.getTarget().equals(bSave) || event.getTarget().equals(bDelete) || event.getTarget().equals(fSavedName)){ String saveName = null; @@ -708,52 +823,62 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } } + /** + * Save process parameters and report options. + * Set MPInstance.Name = saveName. + * @param saveName + */ protected void updateSaveParameter(String saveName) { - // Update existing - if (fSavedName.getSelectedIndex() > -1 && savedParams != null) { - for (int i = 0; i < savedParams.size(); i++) { - if (savedParams.get(i).getName().equals(saveName)) { - getProcessInfo().setAD_PInstance_ID(savedParams.get(i) - .getAD_PInstance_ID()); - for (MPInstancePara para : savedParams.get(i) - .getParameters()) { - para.deleteEx(true); - } - getParameterPanel().saveParameters(); - - saveReportOptionToInstance(savedParams.get(i)); - - savedParams.get(i).saveEx(); - - getProcessInfo().setAD_PInstance_ID(0); + // Update existing + if (fSavedName.getSelectedIndex() > -1 && savedParams != null) { + for (int i = 0; i < savedParams.size(); i++) { + if (savedParams.get(i).getName().equals(saveName)) { + getProcessInfo().setAD_PInstance_ID(savedParams.get(i) + .getAD_PInstance_ID()); + for (MPInstancePara para : savedParams.get(i) + .getParameters()) { + para.deleteEx(true); } + getParameterPanel().saveParameters(); + + saveReportOptionToInstance(savedParams.get(i)); + + savedParams.get(i).saveEx(); + + getProcessInfo().setAD_PInstance_ID(0); } } - // create new - else { - MPInstance instance = null; - try { - instance = new MPInstance(Env.getCtx(), - getProcessInfo().getAD_Process_ID(), getProcessInfo().getRecord_ID()); - instance.setName(saveName); - saveReportOptionToInstance(instance); - instance.saveEx(); - getProcessInfo().setAD_PInstance_ID(instance.getAD_PInstance_ID()); - // Get Parameters - if (getParameterPanel() != null) { - if (!getParameterPanel().saveParameters()) { - throw new AdempiereSystemError(Msg.getMsg( - Env.getCtx(), "SaveParameterError")); - } + } + // create new + else { + MPInstance instance = null; + try { + instance = new MPInstance(Env.getCtx(), + getProcessInfo().getAD_Process_ID(), getProcessInfo().getRecord_ID()); + instance.setName(saveName); + saveReportOptionToInstance(instance); + instance.saveEx(); + getProcessInfo().setAD_PInstance_ID(instance.getAD_PInstance_ID()); + // Get Parameters + if (getParameterPanel() != null) { + if (!getParameterPanel().saveParameters()) { + throw new AdempiereSystemError(Msg.getMsg( + Env.getCtx(), "SaveParameterError")); } - } catch (Exception ex) { - log.log(Level.SEVERE, ex.getLocalizedMessage(), ex); } + } catch (Exception ex) { + log.log(Level.SEVERE, ex.getLocalizedMessage(), ex); } - querySaved(); - fSavedName.setSelectedItem(getComboItem(saveName)); + } + //reload fSavedName + querySaved(); + fSavedName.setSelectedItem(getComboItem(saveName)); } + /** + * Save report options (output type, print format, language and IsSummary) to instance. + * @param instance {@link MPInstance} + */ protected void saveReportOptionToInstance (MPInstance instance){ if (!isReport() && !isJasperReport()) return; @@ -782,6 +907,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI instance.setIsSummary(chbIsSummary.isSelected()); } + /** + * Find {@link #fSavedName} item for value. + * @param value + * @return {@link Comboitem} found. + */ public Comboitem getComboItem( String value) { Comboitem item = null; for (int i = 0; i < fSavedName.getItems().size(); i++) { @@ -794,7 +924,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } return item; } - + + /** + * Delete saved MPInstance by saveName. + * @param saveName + */ protected void deleteSaveParameter(String saveName) { Object o = fSavedName.getSelectedItem(); if (savedParams != null && o != null) { @@ -808,6 +942,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI querySaved(); } + /** + * Load MPInstance by saveName. + * @param saveName + * @param lastRun + */ protected void chooseSaveParameter(String saveName, boolean lastRun) { if (savedParams != null && saveName != null) { for (int i = 0; i < savedParams.size(); i++) { @@ -819,15 +958,22 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI boolean enabled = !Util.isEmpty(saveName); bSave.setEnabled(enabled && !lastRun); bDelete.setEnabled(enabled && fSavedName.getSelectedIndex() > -1 - && !lastRun); - + && !lastRun); } + /** + * Load parameter values and report options from instance. + * @param instance {@link MPInstance} + */ protected void loadSavedParams(MPInstance instance) { getParameterPanel().loadParameters(instance); setReportTypeAndPrintFormat(instance); } + /** + * Run process. + * Delegate to {@link #startProcess0()}. + */ protected void startProcess() { if (!parameterPanel.validateParameters()) @@ -842,12 +988,19 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI startProcess0(); } + /** + * Cancel/dismiss process dialog. + */ protected void cancelProcess() { m_cancel = true; this.dispose(); } + /** + * Create new {@link #progressWindow}. + * @return {@link BusyDialog} + */ protected BusyDialog createBusyDialog() { progressWindow = new BusyDialog(); @@ -855,6 +1008,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI return progressWindow; } + /** + * Close {@link #progressWindow}. + */ protected void closeBusyDialog() { if (progressWindow != null) { @@ -869,6 +1025,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI m_valid = false; } // dispose + /** + * Run process. + */ private void startProcess0() { if (!isBackgroundJob()) @@ -882,12 +1041,20 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI Clients.response(new AuEcho(this, isBackgroundJob() ? "runBackgroundJob" : "runProcess", this)); } + /** + * Run process. Echo event from {@link #startProcess0()}. + */ public void runProcess() { Events.sendEvent(DialogEvents.ON_BEFORE_RUN_PROCESS, this, null); future = Adempiere.getThreadPoolExecutor().submit(new DesktopRunnable(new ProcessDialogRunnable(null), getDesktop())); } + /** + * Run process as background job (runBackgroundJob event echo from {@link #startProcess0()}). + *
+ * The different with {@link #runProcess()} is this method doesn't wait for completion of process. + */ public void runBackgroundJob() { Properties m_ctx = getCtx(); @@ -959,6 +1126,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } } + /** + * Handle {@link #ON_COMPLETE_EVENT} + */ private void onComplete() { ProcessInfo m_pi = getProcessInfo(); @@ -986,6 +1156,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI dispose(); } + /** + * Handle {@link #ON_STATUS_UPDATE_EVENT} + * @param event + */ private void onStatusUpdate(Event event) { String message = (String) event.getData(); @@ -993,6 +1167,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI progressWindow.statusUpdate(message); } + /** + * Lock UI by showing of busy dialog ({@link #progressWindow}). + */ @Override public void lockUI(ProcessInfo pi) { if (m_locked || Executions.getCurrent() == null) @@ -1001,8 +1178,14 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI showBusyDialog(); } + /** + * Show process in progress dialog. + */ public abstract void showBusyDialog(); + /** + * Unlock dialog upon completion of process (or upon submission of job if process is running as background job). + */ @Override public void unlockUI(ProcessInfo pi) { if (!m_locked) @@ -1026,14 +1209,23 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } } + /** + * Close process in progress dialog and update UI with the result of process execution. + */ private void doUnlockUI() { hideBusyDialog(); updateUI(); } + /** + * Close process in progress dialog. + */ public abstract void hideBusyDialog(); + /** + * Update UI with the result of process execution. + */ public abstract void updateUI(); @Override @@ -1045,7 +1237,7 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI public void statusUpdate(String message) { Desktop desktop = getDesktop(); if (desktop != null && desktop.isAlive()) - Executions.schedule(desktop, this, new Event(ON_STATUS_UPDATE, this, message)); + Executions.schedule(desktop, this, new Event(ON_STATUS_UPDATE_EVENT, this, message)); } @Override @@ -1064,20 +1256,21 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI } /** - * - * @return ProcessInfo + * @return {@link ProcessInfo} */ public ProcessInfo getProcessInfo() { return m_pi; } + /** + * @param pi + */ public void setProcessInfo(ProcessInfo pi) { m_pi = pi; } /** - * is dialog still valid - * @return boolean + * @return true if dialog is still valid (i.e not completed and not cancel). */ public boolean isValid() { @@ -1092,60 +1285,97 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI return m_cancel; } + /** + * @return cache environment context reference + */ public Properties getCtx() { return m_ctx; } + /** + * @return register window number. + */ public int getWindowNo() { return m_WindowNo; } + /** + * @return AD_Process_ID + */ public int getAD_Process_ID() { return m_AD_Process_ID; } + /** + * @return {@link ProcessParameterPanel} instance + */ public ProcessParameterPanel getParameterPanel() { return parameterPanel; } + /** + * @return translated process name + */ public String getName() { return m_Name; } + /** + * @return DonTShowHelp, ShowHelp or Silent. + */ public String getShowHelp() { return m_ShowHelp; } + /** + * @return initial panel header message + */ public String getInitialMessage() { return initialMessage; } + /** + * @return true if run process as background job. + */ public boolean isBackgroundJob() { return runAsJobField != null && runAsJobField.isChecked(); } + /** + * @return Notification type - None, Email, Notice or Email+Notice. + */ public String getNotificationType() { return (String) notificationTypeField.getValue(); } + /** + * @return list of files for user download + */ public List getDownloadFiles() { return downloadFiles; } + /** + * Runnable to run process in background thread. + * Notify process dialog with {@link AbstractProcessDialog#ON_COMPLETE_EVENT} event. + */ private class ProcessDialogRunnable extends ZkContextRunnable { private Trx m_trx; + /** + * @param trx + */ private ProcessDialogRunnable(Trx trx) { super(); @@ -1164,11 +1394,15 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI m_pi.setSummary(ex.getLocalizedMessage()); log.log(Level.SEVERE, ex.getLocalizedMessage(), ex); } finally { - Executions.schedule(getDesktop(), AbstractProcessDialog.this, new Event(ON_COMPLETE, AbstractProcessDialog.this, null)); + Executions.schedule(getDesktop(), AbstractProcessDialog.this, new Event(ON_COMPLETE_EVENT, AbstractProcessDialog.this, null)); } } } + /** + * Runnable to run process as background job. + * Send email or notice notification to user upon completion of job. + */ private class BackgroundJobRunnable implements Runnable { private Properties m_ctx; @@ -1313,6 +1547,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI Dialog.askForInput(message, lookup, editorType, callback, getDesktop(), m_WindowNo); } + /** + * Merge pdfList and show with {@link SimplePDFViewer}. + */ @Override public void showReports(List pdfList) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/BusyDialog.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/BusyDialog.java index 45e0e6a699..cc2832a469 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/BusyDialog.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/BusyDialog.java @@ -23,15 +23,24 @@ import org.zkoss.zul.Div; import org.zkoss.zul.Span; /** - * + * Blocking in progress dialog. * @author hengsin * */ public class BusyDialog extends Window { + /** + * generated serial id + */ private static final long serialVersionUID = -779475945298887887L; + /** + * Label component to display in progress message (default is Processing...). + */ private Label label; + /** + * Default constructor + */ public BusyDialog() { super(); LayoutUtils.addSclass("busy-dialog", this); @@ -55,6 +64,10 @@ public class BusyDialog extends Window { setShadow(true); } + /** + * Update in progress message. + * @param message + */ public void statusUpdate(String message) { if (label != null) { label.setText(message); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/BusyDialogTemplate.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/BusyDialogTemplate.java index 77dc017261..283748cda2 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/BusyDialogTemplate.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/BusyDialogTemplate.java @@ -1,3 +1,28 @@ +/*********************************************************************** + * 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 * + * - Richard Morales * + **********************************************************************/ package org.adempiere.webui.apps; import org.adempiere.webui.component.Window; @@ -5,18 +30,31 @@ import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; +/** + * Show {@link BusyDialog} and invoke {@link Runnable} task. + *
+ * Usage: new BusyDialogTemplate(runnable).run(); or with Lambda,new BusyDialogTemplate(() -> {your code}).run(); + */ public class BusyDialogTemplate implements Runnable, EventListener { + /** Event to call {@link #runnable} **/ private static final String EVENT_NAME = "onRun"; + /** Task to be invoked **/ private Runnable runnable; private BusyDialog busyDialog; + /** + * @param runnable + */ public BusyDialogTemplate(Runnable runnable) { this.runnable = runnable; } + /** + * Hide/dispose busy dialog + */ private void hideBusyDialog() { if (busyDialog != null) { @@ -25,12 +63,19 @@ public class BusyDialogTemplate implements Runnable, EventListener { } } + /** + * Show busy dialog in highlighted mode. + */ private void showBusyDialog() { busyDialog = new BusyDialog(); busyDialog.setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED); AEnv.showCenterScreen(busyDialog); } + /** + * Call {@link #runnable} and close busy dialog. + */ + @Override public void onEvent(Event event) throws Exception { try { if (event.getName().equals(EVENT_NAME)) { @@ -41,6 +86,9 @@ public class BusyDialogTemplate implements Runnable, EventListener { } } + /** + * Show busy dialog and echo {@link #EVENT_NAME} to call {@link #runnable} + */ public void run() { showBusyDialog(); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/CalloutDialog.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/CalloutDialog.java index 302c18511f..3488fb2ebc 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/CalloutDialog.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/CalloutDialog.java @@ -21,7 +21,7 @@ import org.compiere.model.MLookup; import org.zkoss.zk.ui.Desktop; /** - * Callout Dialog used for Ask For Input + * Callout Dialog used to ask for input from user. * * @author Murilo H. Torquato (devCoffee, http://devcoffee.com.br) * @@ -31,6 +31,10 @@ public class CalloutDialog implements ICalloutUI { private Desktop desktop; private int m_windowNo; + /** + * @param desktop + * @param windowNo + */ public CalloutDialog(Desktop desktop, int windowNo) { this.desktop = desktop; this.m_windowNo = windowNo; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/DesktopRunnable.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/DesktopRunnable.java index ca1a1a9bf5..977673f147 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/DesktopRunnable.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/DesktopRunnable.java @@ -1,6 +1,27 @@ -/** - * - */ +/*********************************************************************** + * 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.webui.apps; import java.lang.ref.WeakReference; @@ -14,10 +35,12 @@ import org.zkoss.zk.ui.Desktop; * */ public class DesktopRunnable implements Runnable { - + /** wrapped runnable **/ private Runnable runnable; + /** weak reference to Desktop **/ private WeakReference desktopWeakRef; + /** ThreadLocal weak reference to Desktop **/ private static ThreadLocal> threadLocalDesktop = new ThreadLocal>() { protected WeakReference initialValue() { @@ -25,13 +48,17 @@ public class DesktopRunnable implements Runnable { } }; + /** + * @param runnable + * @param desktop + */ public DesktopRunnable(Runnable runnable, Desktop desktop) { this.runnable = runnable; this.desktopWeakRef = new WeakReference(desktop); } - /* (non-Javadoc) - * @see java.lang.Runnable#run() + /** + * Set thread local Desktop reference and call {@link #runnable}. */ @Override public void run() { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/DocumentSearchController.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/DocumentSearchController.java index c9d2a16057..5fca715073 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/DocumentSearchController.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/DocumentSearchController.java @@ -53,20 +53,29 @@ import org.zkoss.zul.Vlayout; */ public class DocumentSearchController implements EventListener{ + /** {@link A} component attribute to hold reference to corresponding {@link #SEARCH_RESULT} **/ private static final String SEARCH_RESULT = "search.result"; - private static final String ON_SEARCH_DOCUMENTS = "onSearchDocuments"; + /** onSearchDocuments event **/ + private static final String ON_SEARCH_DOCUMENTS_EVENT = "onSearchDocuments"; private int MAX_RESULTS_PER_SEARCH_IN_DOCUMENT_CONTROLLER = 3; + /** layout to show links ({@link A}) for each {@link #SEARCH_RESULT} in {@link #list} **/ private Vlayout layout; + /** results from execution of search **/ private ArrayList list; + /** Current selected index of {@link #list} **/ private int selected = -1; /** - * + * default constructor */ public DocumentSearchController() { MAX_RESULTS_PER_SEARCH_IN_DOCUMENT_CONTROLLER = MSysConfig.getIntValue(MSysConfig.MAX_RESULTS_PER_SEARCH_IN_DOCUMENT_CONTROLLER, 3, Env.getAD_Client_ID(Env.getCtx())); } + /** + * Create {@link #layout} for search result + * @param parent + */ public void create(Component parent) { layout = new Vlayout(); layout.setStyle("padding: 3px; overflow:auto;"); @@ -75,14 +84,23 @@ public class DocumentSearchController implements EventListener{ parent.appendChild(layout); - layout.addEventListener(ON_SEARCH_DOCUMENTS, this); + layout.addEventListener(ON_SEARCH_DOCUMENTS_EVENT, this); } + /** + * Echo {@link #ON_SEARCH_DOCUMENTS_EVENT} with value as event data. + * @param value + */ public void search(String value) { layout.getChildren().clear(); - Events.echoEvent(ON_SEARCH_DOCUMENTS, layout, value); + Events.echoEvent(ON_SEARCH_DOCUMENTS_EVENT, layout, value); } + /** + * Handle {@link #ON_SEARCH_DOCUMENTS_EVENT} event. + * Delegate execution of search to {@link #doSearch(String)}. + * @param searchString + */ private void onSearchDocuments(String searchString) { list = new ArrayList(); if (Util.isEmpty(searchString)) { @@ -119,6 +137,11 @@ public class DocumentSearchController implements EventListener{ } } + /** + * Perform search with searchString using definition from AD_SearchDefinition. + * @param searchString + * @return List of {@link SearchResult} + */ private List doSearch(String searchString) { final MRole role = MRole.get(Env.getCtx(), Env.getAD_Role_ID(Env.getCtx()), Env.getAD_User_ID(Env.getCtx()), true); @@ -199,6 +222,17 @@ public class DocumentSearchController implements EventListener{ return list; } + /** + * Execute query and output result to list. + * @param msd + * @param builder + * @param params + * @param lookup + * @param window + * @param tableName + * @param extraWhereClase + * @param list + */ private void doRetrieval(MSearchDefinition msd, StringBuilder builder, List params, MLookup lookup, MWindow window, String tableName, String extraWhereClase, List list) { PreparedStatement pstmt = null; @@ -250,17 +284,24 @@ public class DocumentSearchController implements EventListener{ SearchResult result = (SearchResult) event.getTarget().getAttribute(SEARCH_RESULT); doZoom(result); } - } else if (event.getName().equals(ON_SEARCH_DOCUMENTS)) { + } else if (event.getName().equals(ON_SEARCH_DOCUMENTS_EVENT)) { onSearchDocuments((String)event.getData()); } } + /** + * Zoom to AD Window + * @param result + */ private void doZoom(SearchResult result) { MQuery query = new MQuery(); query.addRestriction(result.getTableName()+"_ID", "=", result.getRecordId()); AEnv.zoom(result.getWindowId(), query); } + /** + * Value class to hold search result + */ public static class SearchResult { private String windowName; private int windowId; @@ -344,6 +385,13 @@ public class DocumentSearchController implements EventListener{ } } + /** + * Find {@link SearchResult} link from {@link #layout} that matches text from textbox. + *
+ * Call {@link #doZoom(SearchResult)} if a match is found. + * @param textbox + * @return true if a match is found + */ public boolean onOk(Textbox textbox) { String text = textbox.getText(); if (Util.isEmpty(text)) @@ -374,11 +422,16 @@ public class DocumentSearchController implements EventListener{ result = (SearchResult) firstStart.getAttribute(SEARCH_RESULT); if (result != null) { doZoom(result); + return true; } return false; } + /** + * Select and return {@link SearchResult} that comes before the current selected {@link SearchResult} link in {@link #layout}. + * @return {@link SearchResult} + */ public SearchResult selectPrior() { if (selected > 0) { selected--; @@ -399,6 +452,10 @@ public class DocumentSearchController implements EventListener{ return null; } + /** + * Select and return {@link SearchResult} that comes after the current selected {@link SearchResult} link in {@link #layout}. + * @return {@link SearchResult} + */ public SearchResult selectNext() { if (selected < (list.size()-1)) { selected++; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/FeedbackRequestWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/FeedbackRequestWindow.java index 40d7ea30c2..ee6584510c 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/FeedbackRequestWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/FeedbackRequestWindow.java @@ -64,7 +64,7 @@ import org.zkoss.zul.Div; import org.zkoss.zul.South; /** - * + * Window to capture feedback request from user. * @author hengsin * */ @@ -77,13 +77,19 @@ public class FeedbackRequestWindow extends Window implements EventListener attachments = new ArrayList(); + /** Div to host list of {@link AttachmentItem} **/ protected Div attachmentBox; + /** + * Default constructor + */ public FeedbackRequestWindow() { super(); @@ -114,6 +120,7 @@ public class FeedbackRequestWindow extends Window implements EventListener { - private static final String ON_ENTER_KEY = "onEnterKey"; + /** {@link #bandbox} attribute to store value from last {@link Events#ON_CHANGING} event **/ + private static final String LAST_ONCHANGING_ATTR = "last.onchanging"; - private static final String ON_POST_ENTER_KEY = "onPostEnterKey"; + /** Event send from client side upon keyDown of enter key **/ + private static final String ON_ENTER_KEY_EVENT = "onEnterKey"; - private static final String ON_CREATE_ECHO = "onCreateEcho"; + /** Event echo from ON_ENTER_KEY_EVENT to allow showing of in progress dialog before execution of search **/ + private static final String ON_POST_ENTER_KEY_EVENT = "onPostEnterKey"; - private static final String ON_SEARCH = "onSearch"; + /** Event echo from {@link #onPageAttached(Page, Page)} **/ + private static final String ON_CREATE_ECHO_EVENT = "onCreateEcho"; + /** Event to execute search. **/ + private static final String ON_SEARCH_EVENT = "onSearch"; + + /** Prefix to start document search using definition from {@link MSearchDefinition} **/ private static final String PREFIX_DOCUMENT_SEARCH = "/"; /** @@ -57,15 +66,20 @@ public class GlobalSearch extends Div implements EventListener { */ private static final long serialVersionUID = -8793878697269469837L; + /** Bandbox to capture search text from user and display result in popup **/ private Bandbox bandbox; + /** controller to search AD_Menu **/ private MenuSearchController menuController; + + /** controller to search tables **/ private DocumentSearchController docController; + /** tabbox to host menu and document search tab **/ private Tabbox tabbox; /** - * + * @param menuController */ public GlobalSearch(MenuSearchController menuController) { this.menuController = menuController; @@ -73,11 +87,13 @@ public class GlobalSearch extends Div implements EventListener { init(); } + /** + * Layout UI and setup listeners + */ private void init() { bandbox = new Bandbox(); bandbox.setSclass("global-search-box"); appendChild(bandbox); -// ZKUpdateUtil.setWidth(bandbox, "100%"); bandbox.setAutodrop(true); bandbox.setId("globalSearchBox"); bandbox.addEventListener(Events.ON_CHANGING, this); @@ -114,22 +130,24 @@ public class GlobalSearch extends Div implements EventListener { tabPanels.appendChild(tabPanel); docController.create(tabPanel); - addEventListener(ON_SEARCH, this); - addEventListener(ON_CREATE_ECHO, this); - bandbox.addEventListener(ON_ENTER_KEY, this); - addEventListener(ON_POST_ENTER_KEY, this); + addEventListener(ON_SEARCH_EVENT, this); + addEventListener(ON_CREATE_ECHO_EVENT, this); + bandbox.addEventListener(ON_ENTER_KEY_EVENT, this); + addEventListener(ON_POST_ENTER_KEY_EVENT, this); } @Override public void onEvent(Event event) throws Exception { - if (Events.ON_CHANGING.equals(event.getName())) { + if (Events.ON_CHANGING.equals(event.getName())) { + //post ON_SEARCH_EVENT for ON_CHANGING from bandbox InputEvent inputEvent = (InputEvent) event; String value = inputEvent.getValue(); - bandbox.setAttribute("last.onchanging", value); - Events.postEvent(ON_SEARCH, this, value); + bandbox.setAttribute(LAST_ONCHANGING_ATTR, value); + Events.postEvent(ON_SEARCH_EVENT, this, value); } else if (Events.ON_CHANGE.equals(event.getName())) { - bandbox.removeAttribute("last.onchanging"); + bandbox.removeAttribute(LAST_ONCHANGING_ATTR); } else if (Events.ON_CTRL_KEY.equals(event.getName())) { + //handle keyboard navigation for bandbox items KeyEvent ke = (KeyEvent) event; if (ke.getKeyCode() == KeyEvent.UP) { if (bandbox.getFirstChild().isVisible()) { @@ -160,28 +178,30 @@ public class GlobalSearch extends Div implements EventListener { } } } - } else if (event.getName().equals(ON_SEARCH)) { + } else if (event.getName().equals(ON_SEARCH_EVENT)) { String value = (String) event.getData(); if (tabbox.getSelectedIndex()==0) menuController.search(value); else docController.search(value); bandbox.focus(); - } else if (event.getName().equals(ON_CREATE_ECHO)) { + } else if (event.getName().equals(ON_CREATE_ECHO_EVENT)) { + //setup client side listener for enter key StringBuilder script = new StringBuilder("jq('#") .append(bandbox.getUuid()) .append("').bind('keydown', function(e) {let code=e.keyCode||e.which;if(code==13){") .append("let widget=zk.Widget.$(this);") .append("let event=new zk.Event(widget,'") - .append(ON_ENTER_KEY) + .append(ON_ENTER_KEY_EVENT) .append("',{},{toServer:true});") .append("zAu.send(event);") .append("}});"); Clients.evalJavaScript(script.toString()); - } else if (event.getName().equals(ON_ENTER_KEY)) { + } else if (event.getName().equals(ON_ENTER_KEY_EVENT)) { Clients.showBusy(bandbox, null); - Events.echoEvent(ON_POST_ENTER_KEY, this, null); - } else if (event.getName().equals(ON_POST_ENTER_KEY)) { + Events.echoEvent(ON_POST_ENTER_KEY_EVENT, this, null); + } else if (event.getName().equals(ON_POST_ENTER_KEY_EVENT)) { + //execute search trigger by press of enter key Clients.clearBusy(bandbox); if (bandbox.getValue() != null && bandbox.getValue().startsWith(PREFIX_DOCUMENT_SEARCH)) { DocumentSearch search = new DocumentSearch(); @@ -195,11 +215,11 @@ public class GlobalSearch extends Div implements EventListener { } } } else if (event.getName().equals(Events.ON_SELECT)) { - String value = (String) bandbox.getAttribute("last.onchanging"); + String value = (String) bandbox.getAttribute(LAST_ONCHANGING_ATTR); if (value == null) { value = bandbox.getValue(); } - Events.postEvent(ON_SEARCH, this, value); + Events.postEvent(ON_SEARCH_EVENT, this, value); } } @@ -209,15 +229,21 @@ public class GlobalSearch extends Div implements EventListener { @Override public void onPageAttached(Page newpage, Page oldpage) { super.onPageAttached(newpage, oldpage); - Events.echoEvent(ON_CREATE_ECHO, this, null); + Events.echoEvent(ON_CREATE_ECHO_EVENT, this, null); } + /** + * Close {@link #bandbox} popup. + */ public void closePopup() { if (bandbox != null) { bandbox.close(); } } + /** + * Handle client info event from browser. + */ public void onClientInfo() { ZKUpdateUtil.setWindowHeightX(bandbox.getDropdown(), ClientInfo.get().desktopHeight-50); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/HelpWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/HelpWindow.java index 1d732cf7dd..e4348bbfe2 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/HelpWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/HelpWindow.java @@ -38,15 +38,21 @@ import org.zkoss.zul.Center; import org.zkoss.zul.Div; import org.zkoss.zul.Html; +/** + * Help for AD Window with contents generated from AD definition. + */ public class HelpWindow extends Window { /** - * + * generated serial id */ private static final long serialVersionUID = -7353411576541612026L; private GridWindow gridWindow; private String winpref; + /** + * @param gridWindow + */ public HelpWindow(GridWindow gridWindow) { super(); @@ -95,6 +101,9 @@ public class HelpWindow extends Window { html.setContent(doc.toString()); } + /** + * @return header {@link table} + */ private table getHeader() { table table = new table("0", "0", "0", "100%", null); @@ -180,6 +189,9 @@ public class HelpWindow extends Window { return table; } + /** + * @return content {@link table} + */ private table getContent() { table table = new table("0", "0", "0", "100%", null); @@ -202,6 +214,9 @@ public class HelpWindow extends Window { return table; } + /** + * @return content {@link table} for left pane + */ private table getLeftContent() { table table = new table("0", "0", "0", "100%", null); @@ -223,6 +238,9 @@ public class HelpWindow extends Window { return table; } + /** + * @return content {@link table} for right pane + */ private table getRightContent() { table table = new table("0", "0", "0", "100%", null); @@ -273,6 +291,12 @@ public class HelpWindow extends Window { return table; } + /** + * Name, description and help text for AD_Tab + * @param tab + * @param tabIndex + * @return {@link table} with name, description and help text + */ private table getTabBox(GridTab tab, int tabIndex) { table table = new table("0", "0", "0", "100%", null); @@ -326,6 +350,12 @@ public class HelpWindow extends Window { return table; } + /** + * Links for all display field + * @param tab + * @param tabIndex + * @return {@link table} with link for all display fields + */ private table getFieldsBox(GridTab tab, int tabIndex) { table table = new table("0", "0", "0", "100%", null); @@ -383,6 +413,13 @@ public class HelpWindow extends Window { return table; } + /** + * header/label, description and help text for a field. + * @param field + * @param tabIndex + * @param fieldIndex + * @return {@link table} with header/label, description and help text + */ private table getFieldBox(GridField field, int tabIndex, int fieldIndex) { table table = new table("0", "0", "0", "100%", null); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/IProcessParameterListener.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/IProcessParameterListener.java index 6da7eabd59..6efe5c9d80 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/IProcessParameterListener.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/IProcessParameterListener.java @@ -17,7 +17,7 @@ import org.adempiere.webui.editor.WEditor; /** * Listener interface for process parameter panel. - * Implementation must be thread safe + * Implementation must be thread safe. * @author hengsin * */ diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/LabelsSearch.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/LabelsSearch.java index 3b6f103f64..43e443186f 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/LabelsSearch.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/LabelsSearch.java @@ -42,16 +42,29 @@ import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.Bandpopup; import org.zkoss.zul.Div; -public class LabelsSearch extends Div implements EventListener { +/** + * Component to search AD_Label* records. + */ +public class LabelsSearch extends Div implements EventListener { + /** + * generated serial id + */ private static final long serialVersionUID = -8793878697269469837L; - private static final String ON_ENTER_KEY = "onEnterKey"; - private static final String ON_CREATE_ECHO = "onCreateEcho"; - private static final String ON_SEARCH = "onSearch"; - private Bandbox bandbox; + /** Event send from client side upon keyDown of enter key **/ + private static final String ON_ENTER_KEY_EVENT = "onEnterKey"; + /** Event echo from {@link #onPageAttached(Page, Page)} **/ + private static final String ON_CREATE_ECHO_EVENT = "onCreateEcho"; + /** Event to execute search. **/ + private static final String ON_SEARCH_EVENT = "onSearch"; + /** {@link #bandbox} attribute to store value from last {@link Events#ON_CHANGING} event **/ + private static final String LAST_ONCHANGING_ATTR = "last.onchanging"; + /** Bandbox to capture search text from user and display result in popup **/ + private Bandbox bandbox; + /** Controller to perform search on AD_Label* records **/ private LabelsSearchController controller; /** - * Standard constructot + * Standard constructor * @param controller */ public LabelsSearch(LabelsSearchController controller) { @@ -59,6 +72,9 @@ public class LabelsSearch extends Div implements EventListener { init(); } + /** + * Layout UI and setup listeners + */ private void init() { bandbox = new Bandbox(); appendChild(bandbox); @@ -77,22 +93,24 @@ public class LabelsSearch extends Div implements EventListener { bandbox.appendChild(popup); controller.create(popup); - addEventListener(ON_SEARCH, this); - addEventListener(ON_CREATE_ECHO, this); + addEventListener(ON_SEARCH_EVENT, this); + addEventListener(ON_CREATE_ECHO_EVENT, this); addEventListener(LabelsSearchController.ON_POST_SELECT_LABELITEM_EVENT, this); - bandbox.addEventListener(ON_ENTER_KEY, this); + bandbox.addEventListener(ON_ENTER_KEY_EVENT, this); } @Override public void onEvent(Event event) throws Exception { - if (Events.ON_CHANGING.equals(event.getName())) { + if (Events.ON_CHANGING.equals(event.getName())) { + //post ON_SEARCH_EVENT for ON_CHANGING event from bandbox InputEvent inputEvent = (InputEvent) event; String value = inputEvent.getValue(); - bandbox.setAttribute("last.onchanging", value); - Events.postEvent(ON_SEARCH, this, value); + bandbox.setAttribute(LAST_ONCHANGING_ATTR, value); + Events.postEvent(ON_SEARCH_EVENT, this, value); } else if (Events.ON_CHANGE.equals(event.getName())) { - bandbox.removeAttribute("last.onchanging"); + bandbox.removeAttribute(LAST_ONCHANGING_ATTR); } else if (Events.ON_CTRL_KEY.equals(event.getName())) { + //handle keyboard navigation for bandbox items KeyEvent ke = (KeyEvent) event; if (ke.getKeyCode() == KeyEvent.UP) { if (bandbox.getFirstChild().isVisible()) { @@ -111,32 +129,33 @@ public class LabelsSearch extends Div implements EventListener { } } } - } else if (event.getName().equals(ON_SEARCH)) { + } else if (event.getName().equals(ON_SEARCH_EVENT)) { String value = (String) event.getData(); controller.search(value); bandbox.focus(); - } else if (event.getName().equals(ON_CREATE_ECHO)) { + } else if (event.getName().equals(ON_CREATE_ECHO_EVENT)) { + //setup client side keyDown listener for enter key StringBuilder script = new StringBuilder("jq('#") .append(bandbox.getUuid()) .append("').bind('keydown', function(e) {var code=e.keyCode||e.which;if(code==13){") .append("var widget=zk.Widget.$(this);") .append("var event=new zk.Event(widget,'") - .append(ON_ENTER_KEY) + .append(ON_ENTER_KEY_EVENT) .append("',{},{toServer:true});") .append("zAu.send(event);") .append("}});"); Clients.evalJavaScript(script.toString()); - } else if (event.getName().equals(ON_ENTER_KEY)) { + } else if (event.getName().equals(ON_ENTER_KEY_EVENT)) { if (event.getTarget() instanceof Bandbox) { controller.onSelect(controller.getSelectedItem()); } } else if (event.getName().equals(Events.ON_SELECT)) { - String value = (String) bandbox.getAttribute("last.onchanging"); + String value = (String) bandbox.getAttribute(LAST_ONCHANGING_ATTR); if (value == null) { value = bandbox.getValue(); } - Events.postEvent(ON_SEARCH, this, value); + Events.postEvent(ON_SEARCH_EVENT, this, value); } if (event.getName().equals(LabelsSearchController.ON_POST_SELECT_LABELITEM_EVENT)) { @@ -150,11 +169,11 @@ public class LabelsSearch extends Div implements EventListener { @Override public void onPageAttached(Page newpage, Page oldpage) { super.onPageAttached(newpage, oldpage); - Events.echoEvent(ON_CREATE_ECHO, this, null); + Events.echoEvent(ON_CREATE_ECHO_EVENT, this, null); } /** - * Close the search dropdown + * Close {@link #bandbox} popup */ public void closePopup() { if (bandbox != null) { @@ -163,7 +182,7 @@ public class LabelsSearch extends Div implements EventListener { } /** - * Set height of the search dropdown + * Set height {@link #bandbox} dropdown */ public void onClientInfo() { ZKUpdateUtil.setWindowHeightX(bandbox.getDropdown(), ClientInfo.get().desktopHeight-50); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/LabelsSearchController.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/LabelsSearchController.java index ccee4ae55e..b70cf9234d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/LabelsSearchController.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/LabelsSearchController.java @@ -56,14 +56,25 @@ import org.zkoss.zul.ListitemRenderer; import org.zkoss.zul.ListitemRendererExt; import org.zkoss.zul.Vlayout; +/** + * Controller for search on AD_Label* records. + */ public class LabelsSearchController implements EventListener{ + /** Event echo from {@link #onSelect(LabelItem)} **/ public static final String ON_POST_SELECT_LABELITEM_EVENT = "onPostSelectLabelitem"; - private static final String ON_SEARCH_ECHO = "onSearchEcho"; - private static final String ON_LOAD_MORE = "onLoadMore"; + /** Event echo to initiate search for a given input text **/ + private static final String ON_SEARCH_ECHO_EVENT = "onSearchEcho"; + /** TODO: not used, candidate for removal **/ + private static final String ON_LOAD_MORE_EVENT = "onLoadMore"; + /** parent of {@link #layout} **/ private Component parent; + /** Listbox to display search result **/ private Listbox listbox; + /** model for {@link #listbox} **/ private ListModelList model; + /** main layout **/ private Vlayout layout; + /** label window panel, provider for AD_Table_ID and Record_ID **/ private LabelsPanel labelsPanel; /** @@ -103,13 +114,13 @@ public class LabelsSearchController implements EventListener{ ZKUpdateUtil.setWidth(listheader, "30px"); listhead.appendChild(listheader); - layout.addEventListener(ON_SEARCH_ECHO, this); - layout.addEventListener(ON_LOAD_MORE, this); + layout.addEventListener(ON_SEARCH_ECHO_EVENT, this); + layout.addEventListener(ON_LOAD_MORE_EVENT, this); } @Override public void onEvent(Event event) throws Exception { - if (event.getName().equals(ON_SEARCH_ECHO)) { + if (event.getName().equals(ON_SEARCH_ECHO_EVENT)) { onSearchEcho((String) event.getData()); } else if (Events.ON_CLICK.equals(event.getName())) { if (event.getTarget() instanceof ListItem) { @@ -121,16 +132,16 @@ public class LabelsSearchController implements EventListener{ } /** - * Search for a given text + * Echo {@link #ON_SEARCH_ECHO_EVENT} to initiate search for value * @param value */ public void search(String value) { listbox.setModel((ListModel)null); - Events.echoEvent(ON_SEARCH_ECHO, layout, value); + Events.echoEvent(ON_SEARCH_ECHO_EVENT, layout, value); } /** - * Search for a given text + * Handle {@link #ON_SEARCH_ECHO_EVENT} to execute search for a given text * @param value */ public void onSearchEcho(String value) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuItem.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuItem.java index a795046c54..59782824b5 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuItem.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuItem.java @@ -1,22 +1,50 @@ -/** - * - */ +/*********************************************************************** + * 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.webui.apps; +import org.zkoss.zul.DefaultTreeNode; +import org.zkoss.zul.Treeitem; + /** + * Value object for AD_Menu. + *
+ * Use by {@link GlobalSearch} and {@link MenuSearchController}. * @author hengsin - * */ public class MenuItem { private String label; private String description; private String image; + /** report, process, workflow, form, info or window **/ private String type; + /** Corresponding {@link Treeitem} or {@link DefaultTreeNode} **/ private Object data; /** - * + * default constructor */ public MenuItem() { } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuSearchController.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuSearchController.java index 70e281be20..e764f2c83a 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuSearchController.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuSearchController.java @@ -55,41 +55,60 @@ import org.zkoss.zul.Textbox; import org.zkoss.zul.Tree; import org.zkoss.zul.Treechildren; import org.zkoss.zul.Treeitem; +import org.zkoss.zul.Treerow; import org.zkoss.zul.Vlayout; import org.zkoss.zul.impl.LabelElement; import org.zkoss.zul.impl.LabelImageElement; /** + * Controller for search on AD_Menu records. * @author hengsin - * */ public class MenuSearchController implements EventListener{ + /** Component attribute to hold reference of {@link MTreeNode} **/ public static final String M_TREE_NODE_ATTR = "MTreeNode"; + /** font icon sclass for already added to favourite menu item **/ private static final String Z_ICON_STAR_O = "z-icon-star-o"; + /** font icon sclass for not yet added to favourite menu item **/ private static final String Z_ICON_STAR = "z-icon-star"; - private static final String ON_SEARCH_ECHO = "onSearchEcho"; - private static final String ON_LOAD_MORE = "onLoadMore"; - private static final String ONSELECT_TIMESTAMP = "onselect.timestamp"; + /** Event echo from {@link #search(String)} to initiate search action **/ + private static final String ON_SEARCH_ECHO_EVENT = "onSearchEcho"; + /** Event to load all menu items into {@link #listbox}. Default is to load the first 50 only. **/ + private static final String ON_LOAD_MORE_EVENT = "onLoadMore"; + /** {@link Listitem} attribute to store the last timestamp of ON_CLICK or ON_SELECT event **/ + private static final String ONSELECT_TIMESTAMP_ATTR = "onselect.timestamp"; + /** name of star button **/ private static final String STAR_BUTTON_NAME = "Star"; + /** name of new button **/ private static final String NEW_BUTTON_NAME = "New"; + /** tree for AD_Menu **/ private Tree tree; + /** list box for menu items **/ private Listbox listbox; + /** model for all menu items **/ private ListModelList model; + /** main layout component. parent of {@link #listbox}. **/ private Vlayout layout; + /** model for all menu items **/ private ListModelList fullModel; + /** true when controller is handling event from Star/Favourite button **/ private boolean inStarEvent; + /** Event post from {@link #selectTreeitem(Object, Boolean)} **/ private static final String ON_POST_SELECT_TREEITEM_EVENT = "onPostSelectTreeitem"; /** - * + * @param tree */ public MenuSearchController(Tree tree) { this.tree = tree; } + /** + * Populate {@link #model} from {@link #tree} + */ public void refreshModel() { final List list = new ArrayList(); if (tree.getModel() == null) { @@ -116,6 +135,11 @@ public class MenuSearchController implements EventListener{ }, true); } + /** + * Add treeNode to list + * @param list + * @param treeNode + */ private void addTreeItem(List list, DefaultTreeNode treeNode) { MTreeNode mNode = (MTreeNode) treeNode.getData(); if (!mNode.isLeaf()) @@ -129,6 +153,10 @@ public class MenuSearchController implements EventListener{ list.add(item); } + /** + * @param treeItem + * @return true if treeItem is a folder + */ private boolean isFolder(Treeitem treeItem) { List list = treeItem.getChildren(); for (Component c : list) { @@ -139,6 +167,11 @@ public class MenuSearchController implements EventListener{ return false; } + /** + * Add treeItem to list + * @param list + * @param treeItem + */ private void addTreeItem(List list, Treeitem treeItem) { if (isFolder(treeItem)) return; @@ -158,6 +191,10 @@ public class MenuSearchController implements EventListener{ item.setType((String) treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE)); } + /** + * @param treeItem + * @return label for treeItem + */ private String getLabel(Treeitem treeItem) { String label = treeItem.getLabel(); if (label == null || label.trim().length() == 0) @@ -172,6 +209,10 @@ public class MenuSearchController implements EventListener{ return label; } + /** + * @param treeItem + * @return image url or font icon sclass (start with z-icon) + */ private String getImage(Treeitem treeItem) { String image = treeItem.getImage(); if (image == null || image.trim().length() == 0) @@ -189,6 +230,10 @@ public class MenuSearchController implements EventListener{ return image != null ? image.intern() : null; } + /** + * Call {@link #refreshModel()} and layout UI. + * @param parent + */ public void create(Component parent) { refreshModel(); @@ -220,8 +265,8 @@ public class MenuSearchController implements EventListener{ ZKUpdateUtil.setWidth(listheader, "28px"); listhead.appendChild(listheader); - layout.addEventListener(ON_SEARCH_ECHO, this); - layout.addEventListener(ON_LOAD_MORE, this); + layout.addEventListener(ON_SEARCH_ECHO_EVENT, this); + layout.addEventListener(ON_LOAD_MORE_EVENT, this); updateListboxModel(model); FavouriteController controller = FavouriteController.getInstance(Executions.getCurrent().getSession()); @@ -240,7 +285,7 @@ public class MenuSearchController implements EventListener{ } else if (Events.ON_CLICK.equals(event.getName())) { if (event.getTarget() instanceof ListItem) { ListItem item = (ListItem) event.getTarget(); - Long onSelect = (Long) item.getAttribute(ONSELECT_TIMESTAMP); + Long onSelect = (Long) item.getAttribute(ONSELECT_TIMESTAMP_ATTR); if (onSelect == null) { onSelect(item, Boolean.FALSE); } else if (System.currentTimeMillis() - onSelect.longValue() > 1000) { @@ -276,9 +321,9 @@ public class MenuSearchController implements EventListener{ inStarEvent = false; } } - } else if (event.getName().equals(ON_SEARCH_ECHO)) { + } else if (event.getName().equals(ON_SEARCH_ECHO_EVENT)) { onSearchEcho((String) event.getData()); - } else if (event.getName().equals(ON_LOAD_MORE)) { + } else if (event.getName().equals(ON_LOAD_MORE_EVENT)) { loadMore(); } } @@ -297,13 +342,19 @@ public class MenuSearchController implements EventListener{ listbox.setModel(t); } + /** + * Echo {@link #ON_LOAD_MORE_EVENT} if selected is of type "...". + * Otherwise delegate to {@link #selectTreeitem(Object, Boolean)}. + * @param selected + * @param newRecord true if event is originated from new record button + */ private void onSelect(ListItem selected, Boolean newRecord) { MenuItem item = selected.getValue(); if (item == null) return; if ("...".equals(item.getType())) { - selected.setAttribute(ONSELECT_TIMESTAMP, System.currentTimeMillis()); + selected.setAttribute(ONSELECT_TIMESTAMP_ATTR, System.currentTimeMillis()); Clients.showBusy(selected, null); - Events.echoEvent(ON_LOAD_MORE, layout, null); + Events.echoEvent(ON_LOAD_MORE_EVENT, layout, null); } else { if (newRecord) { Treeitem ti = (Treeitem)item.getData(); @@ -312,10 +363,14 @@ public class MenuSearchController implements EventListener{ newRecord = false; } selectTreeitem(item.getData(), newRecord); - selected.setAttribute(ONSELECT_TIMESTAMP, System.currentTimeMillis()); + selected.setAttribute(ONSELECT_TIMESTAMP_ATTR, System.currentTimeMillis()); } } + /** + * Load {@link #fullModel} to {@link #listbox}. + * Only first 50 loaded to {@link #listbox} initially. + */ private void loadMore() { ListModel listModel = listbox.getModel(); ListModelList lml = (ListModelList) listModel; @@ -327,6 +382,11 @@ public class MenuSearchController implements EventListener{ Clients.scrollIntoView(listbox.getSelectedItem()); } + /** + * Call {@link #select(Treeitem)} and post {@link #ON_POST_SELECT_TREEITEM_EVENT} event. + * @param node {@link Treeitem} or {@link DefaultTreeNode} + * @param newRecord + */ private void selectTreeitem(Object node, Boolean newRecord) { if (Executions.getCurrent().getAttribute(listbox.getUuid()+".selectTreeitem") != null) return; @@ -350,6 +410,10 @@ public class MenuSearchController implements EventListener{ } } + /** + * Make sure all parent node is open and ensure tree selected item is selectedItem + * @param selectedItem + */ private void select(Treeitem selectedItem) { Treeitem parent = selectedItem.getParentItem(); while (parent != null) { @@ -361,6 +425,11 @@ public class MenuSearchController implements EventListener{ selectedItem.getTree().setSelectedItem(selectedItem); } + /** + * Handle {@link #ON_POST_SELECT_TREEITEM_EVENT} event. + * Post ON_CLICK event to link ({@link A} or {@link Treerow}). + * @param newRecord + */ private void onPostSelectTreeitem(Boolean newRecord) { Event event = null; if (tree.getSelectedItem().getTreerow().getFirstChild().getFirstChild() instanceof A) @@ -374,11 +443,19 @@ public class MenuSearchController implements EventListener{ Events.postEvent(event); } + /** + * Echo {@link #ON_SEARCH_ECHO_EVENT} to initial search with value. + * @param value + */ public void search(String value) { listbox.setModel((ListModel)null); - Events.echoEvent(ON_SEARCH_ECHO, layout, value); + Events.echoEvent(ON_SEARCH_ECHO_EVENT, layout, value); } + /** + * Handle {@link #ON_SEARCH_ECHO_EVENT} event. + * @param value + */ public void onSearchEcho(String value) { ListModelList newModel = null; if (Util.isEmpty(value)) { @@ -391,6 +468,12 @@ public class MenuSearchController implements EventListener{ updateListboxModel(newModel); } + /** + * Update {@link #listbox} with newModel. + * If newModel has > 50 items, only first 50 is loaded into {@link #listbox}. + * User has to click the load more link (...) to load the rest of the items into {@link #listbox}. + * @param newModel + */ private void updateListboxModel(ListModelList newModel) { fullModel = null; if (newModel.size() > 50) { @@ -406,10 +489,20 @@ public class MenuSearchController implements EventListener{ listbox.setModel(newModel); } + /** + * Comparator to help filter menu items with a filter value. + */ private class MenuListComparator implements Comparator { + /** + * Text to filter menu items by label. + * Use startsWith if length of compare is < 3, otherwise use contains for filter. + */ private String compare; + /** + * @param compare filter text + */ private MenuListComparator(String compare) { this.compare = Util.deleteAccents(compare.toLowerCase().trim()); } @@ -431,6 +524,10 @@ public class MenuSearchController implements EventListener{ } + /** + * select ListItem that comes before the current selected ListItem. + * @return new selected {@link MenuItem} + */ public MenuItem selectPrior() { int i = listbox.getSelectedIndex(); if (i > 0) { @@ -444,6 +541,10 @@ public class MenuSearchController implements EventListener{ return null; } + /** + * select ListItem that comes after the current selected ListItem. + * @return new selected {@link MenuItem} + */ public MenuItem selectNext() { int i = listbox.getSelectedIndex(); if (i < 0 && listbox.getItemCount() > 0) { @@ -467,6 +568,11 @@ public class MenuSearchController implements EventListener{ return null; } + /** + * Handle ON_OK event + * @param textbox + * @return true if there's partial or exact match for textbox value + */ public boolean onOk(Textbox textbox) { String text = textbox.getText(); if (Util.isEmpty(text)) @@ -498,6 +604,9 @@ public class MenuSearchController implements EventListener{ return false; } + /** + * {@link ListitemRenderer} for {@link #listbox} + */ private class MenuItemRenderer implements ListitemRenderer, ListitemRendererExt { private static final String REMOVE_FROM_FAVOURITES_MSG = "RemoveFromFavourites"; private static final String ADD_TO_FAVOURITES_MSG = "AddToFavourites"; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessDialog.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessDialog.java index 2a8caacac6..ce5d7ca336 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessDialog.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessDialog.java @@ -78,7 +78,7 @@ import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.PdfWriter; /** - * Dialog to Start process or report. + * Embedded Dialog to Start process or report. * Displays information about the process * and lets the user decide to start it * and displays results (optionally print them). @@ -90,30 +90,42 @@ import com.lowagie.text.pdf.PdfWriter; public class ProcessDialog extends AbstractProcessDialog implements EventListener, IHelpContext { /** - * + * generated serial id */ private static final long serialVersionUID = -6728929130788829223L; public static final String ON_INITIAL_FOCUS_EVENT = "onInitialFocus"; - private static final String ON_OK_ECHO = "onOkEcho"; + /** + * Event echo form {@link #onOk()} to defer execution of {@link #onOk()}. + * Execution is defer to happens after the dismiss of modal dialog (usually info window) blocking parameter panel. + */ + private static final String ON_OK_ECHO_EVENT = "onOkEcho"; /** Logger */ private static final CLogger log = CLogger.getCLogger(ProcessDialog.class); // - - private Table logMessageTable; - private int[] m_ids = null; - + /** message from {@link ProcessInfoLog} **/ + private Table logMessageTable; + /** record ids from {@link ProcessInfo} **/ + private int[] m_ids = null; + /** true if dialog is showing process parameters **/ private boolean isParameterPage = true; private Mask mask; + /** layout for process execution result **/ private HtmlBasedComponent resultPanelLayout; + /** process message content of {@link #resultPanelLayout} **/ private HtmlBasedComponent messageResultContent; + /** process log content of {@link #resultPanelLayout}, host {@link #logMessageTable} **/ private HtmlBasedComponent infoResultContent; /** Window No */ - private int m_WindowNo = -1; + private int m_WindowNo = -1; + /** timestamp of previous key event **/ private long prevKeyEventTime = 0; + /** + * Previous key event. use together with {@link #prevKeyEventTime} to detect double firing of key event from browser. + */ private KeyEvent prevKeyEvent; /** @@ -134,7 +146,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene */ public ProcessDialog (int AD_Process_ID, boolean isSOTrx, String predefinedContextVariables) { - log.info("Process=" + AD_Process_ID ); + if (log.isLoggable(Level.INFO)) log.info("Process=" + AD_Process_ID ); m_WindowNo = SessionManager.getAppDesktop().registerWindow(this); this.setAttribute(IDesktop.WINDOWNO_ATTRIBUTE, m_WindowNo); Env.setContext(Env.getCtx(), m_WindowNo, "IsSOTrx", isSOTrx ? "Y" : "N"); @@ -145,7 +157,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene querySaved(); addEventListener(WindowContainer.ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT, this); addEventListener(ON_INITIAL_FOCUS_EVENT, this); - addEventListener(ON_OK_ECHO, this); + addEventListener(ON_OK_ECHO_EVENT, this); } catch(Exception ex) { @@ -188,7 +200,8 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene super.dispose(); SessionManager.getAppDesktop().closeWindow(getWindowNo()); }// dispose - + + @Override public void onEvent(Event event) { Component component = event.getTarget(); @@ -198,7 +211,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene super.onEvent(event); onOk(); - } else if (event.getName().equals(ON_OK_ECHO)) { + } else if (event.getName().equals(ON_OK_ECHO_EVENT)) { onOk(); }else if (bCancel.equals(component)){ super.onEvent(event); @@ -236,12 +249,15 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene } } + /** + * Handle ON_Click event from {@link #bOK} + */ private void onOk() { if (isParameterPage) { if (getParameterPanel().isWaitingForDialog()) { - Events.echoEvent(ON_OK_ECHO, this, null); + Events.echoEvent(ON_OK_ECHO_EVENT, this, null); return; } startProcess(); @@ -250,6 +266,10 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene restart(); } + /** + * Handle shortcut key event + * @param keyEvent + */ private void onCtrlKeyEvent(KeyEvent keyEvent) { if (keyEvent.isAltKey() && keyEvent.getKeyCode() == 0x58) { // Alt-X if (m_WindowNo > 0) { @@ -261,6 +281,10 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene } } + /** + * Handle on click event for record link. + * @param btn + */ private void doOnClick(A btn) { int Record_ID = 0; int AD_Table_ID =0; @@ -272,8 +296,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene catch (Exception e) { } - if (Record_ID > 0 && AD_Table_ID > 0) { - + if (Record_ID > 0 && AD_Table_ID > 0) { AEnv.zoom(AD_Table_ID, Record_ID); } } @@ -286,6 +309,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene LayoutUtils.openOverlappedWindow(this, progressWindow, "middle_center"); } + /** + * @return in progress mask + */ private Div getMask() { if (mask == null) { mask = new Mask(); @@ -293,9 +319,14 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene return mask; } + /** + * show in progress mask + * @param window + */ private void showBusyMask(Window window) { if (getParent() != null) { getParent().appendChild(getMask()); + //to prevent focus to components beneath the in progress mask (see canActivate in web/js/org/idempiere/commons/window.js) StringBuilder script = new StringBuilder("(function(){let w=zk.Widget.$('#"); script.append(getParent().getUuid()).append("');"); if (window != null) { @@ -308,6 +339,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene } } + /** + * close in progress mask + */ private void hideBusyMask() { if (mask != null && mask.getParent() != null) { @@ -333,6 +367,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene swithToFinishScreen(); } + /** + * Switch to process execution result panel. + */ protected void swithToFinishScreen() { ProcessInfo pi = getProcessInfo(); ProcessInfoUtil.setLogFromDB(pi); @@ -375,6 +412,10 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene Clients.response(new AuEcho(this, "onAfterProcess", null)); } + /** + * layout process execution result panel + * @param topParameterLayout + */ private void layoutResultPanel (HtmlBasedComponent topParameterLayout){ if (resultPanelLayout == null){ resultPanelLayout = new Vlayout(); @@ -388,11 +429,21 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene } } + /** + * replace oldComponent with newComponent + * @param newComponent + * @param oldComponent + */ protected void replaceComponent(HtmlBasedComponent newComponent, HtmlBasedComponent oldComponent) { oldComponent.getParent().insertBefore(newComponent, oldComponent); oldComponent.detach(); } + /** + * append m_logs content to {@link #logMessageTable} + * @param m_logs + * @param infoResultContent + */ private void appendRecordLogInfo(ProcessInfoLog[] m_logs, HtmlBasedComponent infoResultContent) { if (m_logs == null) return; @@ -466,9 +517,11 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene tr.appendChild(td); } } - //messageDiv.appendChild(logMessageTable); } + /** + * Move back from process execution result panel to process parameter panel + */ private void restart() { replaceComponent (topParameterLayout, resultPanelLayout); @@ -500,6 +553,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene invalidate(); } + /** + * Handle onAfterProcess event echo from {@link #swithToFinishScreen()} + */ public void onAfterProcess() { // @@ -510,15 +566,15 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene } } - /************************************************************************** - * Optional Processing Task + /** + * Optional after/post process execution task */ private boolean afterProcessTask() { // something to do? if (m_ids != null && m_ids.length > 0) { - log.config(""); + if (log.isLoggable(Level.CONFIG)) log.config(""); // Print invoices if (getAD_Process_ID() == PROCESS_C_INVOICE_GENERATE) { @@ -538,8 +594,8 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene return false; } // afterProcessTask - /************************************************************************** - * Print Shipments + /** + * Print Shipments */ private void printShipments() { @@ -557,8 +613,11 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene } } }); - } // printInvoices + } + /** + * Handle onPrintShipments event echo by {@link #printShipments()} + */ public void onPrintShipments() { // Loop through all items @@ -629,7 +688,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene } /** - * Print Invoices + * Print Invoices */ private void printInvoices() { @@ -649,8 +708,11 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene } } }); - } // printInvoices + } + /** + * Handle onPrintInvoices event echo by {@link #printInvoices()} + */ public void onPrintInvoices() { // Loop through all items diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessModalDialog.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessModalDialog.java index b0d4db2296..e8689ad6b8 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessModalDialog.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessModalDialog.java @@ -48,15 +48,22 @@ import org.zkoss.zk.ui.event.Events; public class ProcessModalDialog extends AbstractProcessDialog implements EventListener, DialogEvents { /** - * + * generated serial id */ private static final long serialVersionUID = -6227339628038418701L; - private static final String ON_OK_ECHO = "onOkEcho"; + /** + * Event echo form {@link #onOk()} to defer execution of {@link #onOk()}. + * Execution is defer to happens after the dismiss of modal dialog (usually info window) blocking parameter panel. + */ + private static final String ON_OK_ECHO_EVENT = "onOkEcho"; /** Logger */ private static final CLogger log = CLogger.getCLogger(ProcessModalDialog.class); - // + /** + * Store screen orientation from last onClientInfo event. + * Use to detect change of screen orientation and adapt layout accordingly. + */ private String orientation; /** @@ -172,10 +179,17 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi { log.log(Level.SEVERE, "", ex); } - addEventListener(ON_OK_ECHO, this); + addEventListener(ON_OK_ECHO_EVENT, this); addEventListener(Events.ON_CANCEL, e -> onCancel()); } + /** + * @param WindowNo + * @param AD_Process_ID + * @param tableId + * @param recordId + * @param autoStart + */ public ProcessModalDialog (int WindowNo, int AD_Process_ID, int tableId, int recordId, boolean autoStart) { this(null, WindowNo, AD_Process_ID, tableId, recordId, autoStart); @@ -265,12 +279,13 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi /** * handle events */ + @Override public void onEvent(Event event) { Component component = event.getTarget(); if (component.equals(bOK)) { super.onEvent(event); onOk(); - } else if (event.getName().equals(ON_OK_ECHO)) { + } else if (event.getName().equals(ON_OK_ECHO_EVENT)) { onOk(); } else if (component.equals(bCancel)) { super.onEvent(event); @@ -280,14 +295,20 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi } } + /** + * Handle ON_Click event from {@link #bCancel} + */ private void onCancel() { cancelProcess(); } + /** + * Handle ON_Click event from {@link #bOK} + */ private void onOk() { if (getParameterPanel().isWaitingForDialog()) { - Events.echoEvent(ON_OK_ECHO, this, null); + Events.echoEvent(ON_OK_ECHO_EVENT, this, null); return; } if(fPrintFormat != null && fPrintFormat.getValue() != null) { @@ -302,6 +323,9 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi startProcess(); } + /** + * Handle client info event from browser + */ protected void onClientInfo() { if (getPage() != null) { String newOrientation = ClientInfo.get().orientation; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessParameterPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessParameterPanel.java index fa8fdd6b92..fb28718451 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessParameterPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/ProcessParameterPanel.java @@ -84,9 +84,9 @@ import org.zkoss.zul.impl.InputElement; import org.zkoss.zul.impl.XulElement; /** - * Process Parameter Panel, based on existing ProcessParameter dialog. - - * Embedded in ProcessDialog - checks, if parameters exist and inquires and - * saves them + * Process Parameter Panel. + * Embedded in {@link ProcessDialog} and {@link ProcessModalDialog}. + * Capture parameters input, validate and save to DB. * * @author Low Heng Sin * @version 2006-12-01 @@ -94,17 +94,18 @@ import org.zkoss.zul.impl.XulElement; public class ProcessParameterPanel extends Panel implements ValueChangeListener, IProcessParameter, EventListener { /** - * + * generated serial id */ private static final long serialVersionUID = -6099317911368929787L; + /** Event post from {@link #valueChange(ValueChangeEvent)} **/ + private static final String ON_POST_EDITOR_VALUE_CHANGE_EVENT = "onPostEditorValueChange"; + /** * Dynamic generated Parameter panel. * - * @param WindowNo - * window - * @param pi - * process info + * @param WindowNo register window number + * @param pi process info */ public ProcessParameterPanel(int WindowNo, ProcessInfo pi) { this(WindowNo, 0, pi); @@ -113,12 +114,9 @@ public class ProcessParameterPanel extends Panel implements /** * Dynamic generated Parameter panel. * - * @param WindowNo - * window - * @param tabNo - * tabNo - * @param pi - * process info + * @param WindowNo register window number + * @param tabNo tabNo + * @param pi process info */ public ProcessParameterPanel(int WindowNo,int tabNo, ProcessInfo pi) { // @@ -130,9 +128,12 @@ public class ProcessParameterPanel extends Panel implements // initComponent(); addEventListener("onDynamicDisplay", this); - addEventListener("onPostEditorValueChange", this); + addEventListener(ON_POST_EDITOR_VALUE_CHANGE_EVENT, this); } // ProcessParameterPanel + /** + * Layout UI + */ private void initComponent() { centerPanel = GridFactory.newGridLayout(); this.appendChild(centerPanel); @@ -151,27 +152,36 @@ public class ProcessParameterPanel extends Panel implements private int m_WindowNo; private int m_TabNo; private ProcessInfo m_processInfo; - // AD_Window of window below this dialog in case show parameter dialog panel + /** AD_Window_ID if process dialog is launch by AD_Window **/ private int m_AD_Window_ID = 0; - // infoWindowID of infoWindow below this dialog in case call process from infoWindow + /** Info_Window_ID if process dialog is launch by Info Window **/ private int m_InfoWindowID = 0; /** Logger */ private static final CLogger log = CLogger .getCLogger(ProcessParameterPanel.class); - - // + + /** parameter editor list **/ private ArrayList m_wEditors = new ArrayList(); - private ArrayList m_wEditors2 = new ArrayList(); // for ranges + /** to parameter editor list for range parameter **/ + private ArrayList m_wEditors2 = new ArrayList(); + /** parameter field list **/ private ArrayList m_mFields = new ArrayList(); + /** to parameter field list for range parameter **/ private ArrayList m_mFields2 = new ArrayList(); private ArrayList m_separators = new ArrayList(); + /** all rows of {@link #centerPanel} **/ private ArrayList m_Rows = new ArrayList(); - // + /** layout grid for parameter fields **/ private Grid centerPanel = null; + /** Group Name:Rows for parameter field **/ private Map> fieldGroupContents = new HashMap>(); + /** Group Name:Rows for group header **/ private Map> fieldGroupHeaders = new HashMap>(); + /** rows of current rendering group **/ private ArrayList rowList; + /** all groups of field type collapsible or tab **/ private List allCollapsibleGroups = new ArrayList(); + /** current rendering group **/ private Group currentGroup; /** @@ -186,12 +196,12 @@ public class ProcessParameterPanel extends Panel implements } // dispose /** - * Read Fields to display + * Render all visible fields * * @return true if loaded OK */ public boolean init() { - log.config(""); + if (log.isLoggable(Level.CONFIG)) log.config(""); // ASP MClient client = MClient.get(Env.getCtx()); @@ -385,12 +395,13 @@ public class ProcessParameterPanel extends Panel implements } // 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. + * Create editor and adds it to {@link #m_wEditors}. + *
+ * For range type field, create the to field and add it to {@link #m_mFields2} and + * create the to editor and adds it to {@link #m_wEditors2}. *

- * mFields are used for default value and mandatory checking; vEditors are - * used to retrieve the value (no data binding) + * mField is used for default value and mandatory checking and editor is + * used to capture input value from user (no data binding). * * @param voF GridFieldVO * @param mField @@ -403,7 +414,7 @@ public class ProcessParameterPanel extends Panel implements editor.getComponent().addEventListener(Events.ON_FOCUS, this); editor.addValueChangeListener(this); editor.dynamicDisplay(); - // MField => VEditor - New Field value to be updated to editor + // MField => editor - New Field value to be updated to editor mField.addPropertyChangeListener(editor); // Set Default Object defaultObject = mField.getDefaultForPanel(); @@ -446,6 +457,7 @@ public class ProcessParameterPanel extends Panel implements Div box = new Div(); box.setStyle("display: flex; align-items: center;"); ZKUpdateUtil.setWidth(box, "100%"); + //create to field and editor if (voF.isRange) { box.appendChild(editor.getComponent()); ZKUpdateUtil.setWidth((HtmlBasedComponent) editor.getComponent(), "49%"); @@ -492,6 +504,7 @@ public class ProcessParameterPanel extends Panel implements m_mFields2.add(null); m_wEditors2.add(null); m_separators.add(null); + //add not in support for multi selection field if(DisplayType.isChosenMultipleSelection(mField.getDisplayType())) { Button bNegate = ButtonFactory.createButton("", null, null); bNegate.setTooltiptext(Msg.translate(Env.getCtx(), "IncludeSelectedValues")); @@ -507,6 +520,11 @@ public class ProcessParameterPanel extends Panel implements row.appendChild(box); } // createField + /** + * set place holder message + * @param editor + * @param msg + */ private void setEditorPlaceHolder(WEditor editor, String msg) { Component c = editor.getComponent(); if (c instanceof InputElement) { @@ -528,17 +546,15 @@ public class ProcessParameterPanel extends Panel implements * @return true if parameters are valid */ public boolean validateParameters() { - log.config(""); + if (log.isLoggable(Level.CONFIG)) log.config(""); - /** - * Mandatory fields see - MTable.getMandatory - */ + //mandatory fields validation StringBuilder sb = new StringBuilder(); 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 - { + { WEditor wEditor = (WEditor) m_wEditors.get(i); Object data = wEditor.getValue(); if (data == null || data.toString().length() == 0) { @@ -577,6 +593,7 @@ public class ProcessParameterPanel extends Panel implements return false; } + /** call {@link IProcessParameterListener} validate(ProcessParameterPanel) **/ if (m_processInfo.getAD_Process_ID() > 0) { String className = MProcess.get(Env.getCtx(), m_processInfo.getAD_Process_ID()).getClassname(); List listeners = Extensions.getProcessParameterListeners(className, null); @@ -592,12 +609,13 @@ public class ProcessParameterPanel extends Panel implements return true; } // validateParameters - /* + /** * load parameters from saved instance + * @param instance */ public boolean loadParameters(MPInstance instance) { - log.config(""); + if (log.isLoggable(Level.CONFIG)) log.config(""); MPInstancePara[] params = instance.getParameters(); for (int j = 0; j < m_mFields.size(); j++) @@ -688,12 +706,13 @@ public class ProcessParameterPanel extends Panel implements return true; } // loadParameters - /* + /** * Load parameters from Process Info + * @param pi */ public boolean loadParametersFromProcessInfo(ProcessInfo pi) { - log.config(""); + if (log.isLoggable(Level.CONFIG)) log.config(""); ProcessInfoParameter[] params = pi.getParameter(); for (int j = 0; j < m_mFields.size(); j++) @@ -742,12 +761,12 @@ public class ProcessParameterPanel extends Panel implements } // loadParameters /** - * Save Parameter values + * Save parameter values to {@link MPInstancePara}. * * @return true if parameters saved */ public boolean saveParameters() { - log.config(""); + if (log.isLoggable(Level.CONFIG)) log.config(""); if (!validateParameters()) return false; @@ -839,21 +858,19 @@ public class ProcessParameterPanel extends Panel implements } // saveParameters /** - * Get Parameter values without saving + * Get parameter values from editors without saving to DB. * - * @return list of parameter values + * @return MPInstancePara[], list of parameter values. */ public MPInstancePara[] getParameters() { - log.config(""); + if (log.isLoggable(Level.CONFIG)) log.config(""); if (!validateParameters()) return new MPInstancePara[0]; List paras = new ArrayList(); - /********************************************************************** - * Save Now - */ + /** create MPInstancePara from editors and add to paras (without saving MPInstancePara to DB) **/ for (int i = 0; i < m_mFields.size(); i++) { // Get Values WEditor editor = (WEditor) m_wEditors.get(i); @@ -928,12 +945,10 @@ public class ProcessParameterPanel extends Panel implements /** - * Editor Listener + * Editor value change listener. * - * @param evt - * ValueChangeEvent + * @param evt ValueChangeEvent */ - public void valueChange(ValueChangeEvent evt) { String propName = evt.getPropertyName(); if (evt.getSource() instanceof WEditor) { @@ -947,7 +962,7 @@ public class ProcessParameterPanel extends Panel implements processDependencies (changedField); // future processCallout (changedField); } - Events.postEvent("onPostEditorValueChange", this, evt.getSource()); + Events.postEvent(ON_POST_EDITOR_VALUE_CHANGE_EVENT, this, evt.getSource()); } processNewValue(evt.getNewValue(), propName); } @@ -955,6 +970,7 @@ public class ProcessParameterPanel extends Panel implements @Override public void onEvent(Event event) throws Exception { if (event.getName().equals(Events.ON_FOCUS)) { + //update tooltip text inside desktop help panel. for (WEditor editor : m_wEditors) { if (editor.isComponentOfEditor(event.getTarget())) @@ -976,7 +992,7 @@ public class ProcessParameterPanel extends Panel implements else if (event.getName().equals("onDynamicDisplay")) { dynamicDisplay(); } - else if (event.getName().equals("onPostEditorValueChange")) { + else if (event.getName().equals(ON_POST_EDITOR_VALUE_CHANGE_EVENT)) { WEditor editor = (WEditor)event.getData(); onPostEditorValueChange(editor); if(editor.getComponent() != null) { @@ -996,6 +1012,7 @@ public class ProcessParameterPanel extends Panel implements } else if (event.getName().equals(Events.ON_CLICK)) { if(event.getTarget() instanceof Button) { + //from not in button of multi selection field Button bNegate = (Button)event.getTarget(); boolean isSelected = !(boolean)bNegate.getAttribute("isSelected"); if(isSelected) { @@ -1013,6 +1030,12 @@ public class ProcessParameterPanel extends Panel implements } } + /** + * Handle ON_POST_EDITOR_VALUE_CHANGE_EVENT event. + *
+ * Call {@link IProcessParameterListener#validate(ProcessParameterPanel)}. + * @param editor + */ private void onPostEditorValueChange(WEditor editor) { if (m_processInfo.getAD_Process_ID() > 0) { String className = MProcess.get(Env.getCtx(), m_processInfo.getAD_Process_ID()).getClassname(); @@ -1029,7 +1052,7 @@ public class ProcessParameterPanel extends Panel implements } /** - * Evaluate Dependencies + * Notify dependent fields. * @param changedField changed field */ private void processDependencies (GridField changedField) @@ -1048,6 +1071,11 @@ public class ProcessParameterPanel extends Panel implements } } // processDependencies + /** + * Reset field value to null if field depends on columnName. + * @param field + * @param columnName column name of changed field + */ private void verifyChangedField(GridField field, String columnName) { ArrayList list = field.getDependentOn(); if (list.contains(columnName)) { @@ -1066,6 +1094,11 @@ public class ProcessParameterPanel extends Panel implements } } + /** + * Process new value from {@link #valueChange(ValueChangeEvent)}. + * @param value + * @param name + */ private void processNewValue(Object value, String name) { if (value == null) value = new String(""); @@ -1086,6 +1119,9 @@ public class ProcessParameterPanel extends Panel implements Events.postEvent("onDynamicDisplay", this, (Object)null); } + /** + * Dynamic update the UI state and properties of all fields. + */ private void dynamicDisplay() { for (int i = 0; i < m_wEditors.size(); i++) { WEditor editor = m_wEditors.get(i); @@ -1172,6 +1208,10 @@ public class ProcessParameterPanel extends Panel implements m_processInfo = processInfo; } + /** + * focus to first visible field editor. + * @return true if there is at least one visible field editor. + */ public boolean focusToFirstEditor() { if (m_wEditors.isEmpty()) return false; @@ -1184,6 +1224,9 @@ public class ProcessParameterPanel extends Panel implements return false; } + /** + * @param toFocus + */ private void focusToEditor(WEditor toFocus) { Component c = toFocus.getComponent(); if (c instanceof EditorBox) { @@ -1211,7 +1254,7 @@ public class ProcessParameterPanel extends Panel implements } /** - * Get parameter field value to editor by column name + * Get parameter field to editor by column name * @param columnName * @return editor */ @@ -1225,7 +1268,7 @@ public class ProcessParameterPanel extends Panel implements } /** - * @return true if editor is showing dialog awaiting user action + * @return true if editor is showing dialog awaiting user action (usually info window). */ public boolean isWaitingForDialog() { for (int i = 0; i < m_mFields.size(); i++) { @@ -1244,6 +1287,9 @@ public class ProcessParameterPanel extends Panel implements return false; } + /** + * Field label ON_CLICK listener for {@link IZoomableEditor}. + */ static class ZoomListener implements EventListener { private IZoomableEditor searchEditor; @@ -1261,6 +1307,9 @@ public class ProcessParameterPanel extends Panel implements } + /** + * @return register window number. + */ public int getWindowNo() { return m_WindowNo; } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WDrillReport.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WDrillReport.java index f8f5ea1e80..d2078d6b09 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WDrillReport.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WDrillReport.java @@ -70,14 +70,14 @@ import org.zkoss.zul.Center; import org.zkoss.zul.Div; /** - * + * Drill assistant dialog * @author Igor Pojzl, Cloudempiere * */ public class WDrillReport extends Window implements EventListener { /** - * + * generated serial id */ private static final long serialVersionUID = 5143424676962140799L; @@ -88,10 +88,14 @@ public class WDrillReport extends Window implements EventListener { private static final String DRILL_REPORT_TABLE_NAME = "TableName"; private DrillReportCtl drillReportCtl; + /** generated unique window name prefix **/ private String winpref; + /** tabpanel for related table drill **/ private Tabpanel tabPanel; + /** tab for related table drill **/ private Tab tableTab; + /** true if {@link #tabPanel} loaded **/ private boolean tablesLoaded = false; private int windowNo = 0; @@ -150,6 +154,10 @@ public class WDrillReport extends Window implements EventListener { td.appendChild(getContent()); } + /** + * Header text + * @return {@link Table} + */ private Table getHeader() { Table table = new Table(); @@ -202,6 +210,10 @@ public class WDrillReport extends Window implements EventListener { return table; } + /** + * Tabbox with Drill Rules and Related Tables tab. + * @return {@link Tabbox} + */ private Tabbox getContent() { @@ -236,6 +248,14 @@ public class WDrillReport extends Window implements EventListener { return tabbox; } + /** + * Table with links for all process and nested table for print formats for each process. + * @param tabIndex + * @param drillTables [AD_Process_ID,Process Name] + * @param drillPrintFormatMap AD_Process_ID:[AD_Process_DrillRule_ID,Name] + * @param isDrillProcessRule true for drill rules, false for related tables + * @return {@link Table} + */ private Table getTabContent(int tabIndex, KeyNamePair[] drillTables, HashMap drillPrintFormatMap, boolean isDrillProcessRule) { Table table = new Table(); @@ -276,7 +296,6 @@ public class WDrillReport extends Window implements EventListener { td.appendChild(getTablesBox(tabIndex, drillTables)); for (int i = 0; i < size; i++) { - KeyNamePair drillTable = drillTables[i]; // tab @@ -292,6 +311,15 @@ public class WDrillReport extends Window implements EventListener { return table; } + /** + * Table with process name and print formats + * @param drillTable [AD_Process_ID,Process Name] + * @param tabIndex + * @param groupIndex + * @param drillPrintFormatMap AD_Process_ID:[AD_Process_DrillRule_ID,Name] + * @param isDrillProcessRule + * @return {@link Table} + */ private Table getDrillTableBox(KeyNamePair drillTable, int tabIndex, int groupIndex, HashMap drillPrintFormatMap, boolean isDrillProcessRule) { Table table = new Table(); @@ -325,11 +353,14 @@ public class WDrillReport extends Window implements EventListener { a.appendChild(new Text("..")); header.appendChild(a); + //[AD_Process_DrillRule_ID,Name] KeyNamePair[] drillRules = drillPrintFormatMap != null ? drillPrintFormatMap.get(drillTable.getKey()) : new KeyNamePair[]{findTablePrintFormat(drillTable)}; for (int j = 0; j < drillRules.length; j++) { + //(AD_Process_DrillRule_ID,Name) or (AD_PrintFormat_ID,Name) KeyNamePair drillRule = drillRules[j]; + //[AD_PrintFormat_ID,Name] KeyNamePair[] printFormats = isDrillProcessRule ? drillReportCtl.getDrillProcessRulesPrintFormatMap(drillRule.getKey()) : new KeyNamePair[] {drillRule} ; // create new Print Format @@ -376,7 +407,10 @@ public class WDrillReport extends Window implements EventListener { return table; } - + /** + * @param drillTable KeyNamePair(AD_Process_ID,Process Name) + * @return KeyNamePair(AD_PrintFormat_ID,Name) + */ private KeyNamePair findTablePrintFormat(KeyNamePair drillTable) { Integer printFormatID = new Query(Env.getCtx(), MPrintFormat.Table_Name, " AD_Table_ID = ? AND AD_Client_ID IN (0,?) ", null) @@ -385,7 +419,12 @@ public class WDrillReport extends Window implements EventListener { return new KeyNamePair((printFormatID != null && printFormatID > 0) ? printFormatID : 0, drillTable.getName()); } - + /** + * Link for process in drillTables + * @param tabIndex + * @param drillTables [AD_Process_ID,Process Name] + * @return {@link Table} + */ private Table getTablesBox(int tabIndex, KeyNamePair[] drillTables) { Table table = new Table(); @@ -436,6 +475,17 @@ public class WDrillReport extends Window implements EventListener { return table; } + /** + * Link and description for print format. + * @param drillPrintFormat KeyNamePair(AD_PrintFormat_ID,Name) + * @param reportIndex + * @param formatIndex + * @param groupIndex + * @param drillTable KeyNamePair(AD_Process_ID,Name) + * @param drillRule KeyNamePair(AD_Process_DrillRule_ID,Name) + * @param isSinglePrintFormat + * @return {@link Tr} + */ private Tr getPrintFormatBox(KeyNamePair drillPrintFormat, int reportIndex, int formatIndex, int groupIndex, KeyNamePair drillTable, KeyNamePair drillRule, boolean isSinglePrintFormat) { @@ -451,7 +501,6 @@ public class WDrillReport extends Window implements EventListener { H4 h4 = new H4(); h4.appendChild(new Text(drillPrintFormat.getName())); - td.appendChild(h4); a = new A(); a.setHref("#"+winpref+"Rep"+reportIndex+"-"+groupIndex); @@ -459,8 +508,6 @@ public class WDrillReport extends Window implements EventListener { a.appendChild(new Text("..")); td.appendChild(a); - - td = new Td(); td.setStyle("width: 10%"); tr.appendChild(td); @@ -495,7 +542,6 @@ public class WDrillReport extends Window implements EventListener { } } - td = new Td(); td.setStyle("width: 60"); tr.appendChild(td); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WProcessCtl.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WProcessCtl.java index c407f590d7..1a881f2289 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WProcessCtl.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WProcessCtl.java @@ -40,7 +40,8 @@ import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; /** - * Ported from org.compiere.apps.ProcessCtl + * Zk client controller for execution of process. + * * @author hengsin * @contributor red1 IDEMPIERE-1711 with final review by Hengsin * @@ -50,25 +51,28 @@ public class WProcessCtl extends AbstractProcessCtl { /** Logger */ private static final CLogger log = CLogger.getCLogger(WProcessCtl.class); + /** + * Call {@link #process(int, ProcessInfo, Trx, EventListener)} + * @param WindowNo + * @param pi + * @param trx + */ public static void process (int WindowNo, ProcessInfo pi, Trx trx) { process(WindowNo, pi, trx, null); } /** - * Process Control - * - * - Get Instance ID - * - Get Parameters - * - execute (lock - start process - unlock) - * - * Creates a ProcessCtl instance, which calls - * lockUI and unlockUI if parent is a ASyncProcess - *
- * - * @param WindowNo window no - * @param pi ProcessInfo process info - * @param trx Transaction + * Open ProcessModalDialog to run process. + *

+	 * - Create and save {@link MPInstance} if no pi.AD_PInstance_ID.
+	 * - Use {@link ProcessModalDialog} to capture process parameters and run process.
+	 * 
+ * + * @param WindowNo window no + * @param pi ProcessInfo process info + * @param trx Transaction + * @param listener listener for {@link ProcessModalDialog} */ public static void process (int WindowNo, ProcessInfo pi, Trx trx, EventListener listener) { @@ -104,7 +108,6 @@ public class WProcessCtl extends AbstractProcessCtl { ProcessModalDialog para = new ProcessModalDialog(listener, WindowNo, pi, false); if (para.isValid()) { - //para.setWidth("500px"); para.setVisible(true); Object window = SessionManager.getAppDesktop().findWindow(WindowNo); @@ -116,7 +119,7 @@ public class WProcessCtl extends AbstractProcessCtl { parent.hideMask(); } }); - }else if (window != null && window instanceof Component){ + } else if (window != null && window instanceof Component){ final Mask mask = LayoutUtils.showWindowWithMask(para, (Component)window, null); para.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener() { @Override @@ -124,7 +127,7 @@ public class WProcessCtl extends AbstractProcessCtl { mask.hideMask(); } }); - }else{ + } else { para.setPosition("center"); para.setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED); AEnv.showWindow(para); @@ -134,57 +137,54 @@ public class WProcessCtl extends AbstractProcessCtl { } // 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 + * Save parameters and execute process. + *
+	 *  - Create and save {@link MPInstance} if no pi.AD_PInstance_ID.
+	 *  - Call parameter.saveParameters ({@link IProcessParameter#saveParameters()}) to save process parameters.
+	 *  - Save pi.getRecord_IDs() to T_Selections ({@link DB#createT_Selection(int, java.util.Collection, String)}).
+	 *  - Call {@link WProcessCtl#run()} to execute process.
+	 *  
* - * @param aProcessUI ASyncProcess and Container + * @param aProcessUI {@link IProcessUI} * @param WindowNo window no * @param parameter Process Parameter Panel - * @param pi ProcessInfo process info + * @param pi {@link ProcessInfo} * @param trx Transaction */ public static void process(IProcessUI aProcessUI, int WindowNo, IProcessParameter parameter, ProcessInfo pi, Trx trx) { - if (log.isLoggable(Level.FINE)) log.fine("WindowNo=" + WindowNo + " - " + pi); + if (log.isLoggable(Level.FINE)) log.fine("WindowNo=" + WindowNo + " - " + pi); - MPInstance instance = null; - if (pi.getAD_PInstance_ID() < 1) { //red1 bypass if PInstance exists - try - { - instance = new MPInstance(Env.getCtx(), pi.getAD_Process_ID(), pi.getRecord_ID()); + MPInstance instance = null; + if (pi.getAD_PInstance_ID() < 1) { //red1 bypass if PInstance exists + try + { + instance = new MPInstance(Env.getCtx(), pi.getAD_Process_ID(), pi.getRecord_ID()); + } + catch (Exception e) + { + pi.setSummary (e.getLocalizedMessage()); + pi.setError (true); + log.warning(pi.toString()); + return; + } + catch (Error e) + { + pi.setSummary (e.getLocalizedMessage()); + pi.setError (true); + log.warning(pi.toString()); + return; + } + if (!instance.save()) + { + pi.setSummary (Msg.getMsg(Env.getCtx(), "ProcessNoInstance")); + pi.setError (true); + return; + } + pi.setAD_PInstance_ID (instance.getAD_PInstance_ID()); + } else { + instance = new MPInstance(Env.getCtx(), pi.getAD_PInstance_ID(), null); } - catch (Exception e) - { - pi.setSummary (e.getLocalizedMessage()); - pi.setError (true); - log.warning(pi.toString()); - return; - } - catch (Error e) - { - pi.setSummary (e.getLocalizedMessage()); - pi.setError (true); - log.warning(pi.toString()); - return; - } - if (!instance.save()) - { - pi.setSummary (Msg.getMsg(Env.getCtx(), "ProcessNoInstance")); - pi.setError (true); - return; - } - pi.setAD_PInstance_ID (instance.getAD_PInstance_ID()); - } else { - instance = new MPInstance(Env.getCtx(), pi.getAD_PInstance_ID(), null); - } // Get Parameters if (parameter != null) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WReport.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WReport.java index 9437d392b6..82629a423d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WReport.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/WReport.java @@ -40,15 +40,15 @@ import org.zkoss.zul.Menuitem; import org.zkoss.zul.Menupopup; /** - * Base on org.compiere.print.AReport + * Launch report for table (immediate or through popup menu, depends on number of print format discover + * for AD_Table_ID and AD_Window_ID). * @author Low Heng Sin * */ public class WReport implements EventListener { /** - * Constructor - * + * Call {@link #WReport(int, MQuery, Component, int)} * @param AD_Table_ID table * @param query query */ @@ -58,11 +58,10 @@ public class WReport implements EventListener { } /** - * Constructor - * + * Call {@link #WReport(int, MQuery, Component, int, String)} * @param AD_Table_ID table * @param query query - * @param parent The invoking parent window + * @param parent The invoking parent component * @param WindowNo The invoking parent window number */ public WReport (int AD_Table_ID, MQuery query, Component parent, @@ -72,7 +71,8 @@ public class WReport implements EventListener { } /** - * Constructor + * Launch report immediately (if only one print format found) or show menu popup + * for the list of print formats discover for AD_Table_ID and AD_Window_ID (from WindowNo). * * @param AD_Table_ID table * @param query query @@ -103,25 +103,26 @@ public class WReport implements EventListener { getPrintFormats (AD_Table_ID, AD_Window_ID); } // AReport - /** The Query */ + /** Query parameter **/ private MQuery m_query; + /** menu popup to show the list of print formats discover **/ private Menupopup m_popup; - /** The Option List */ + /** List of KeyNamePair(AD_PrintFormat_ID,Name) **/ private List m_list = new ArrayList(); - /** Logger */ + /** Logger **/ private static final CLogger log = CLogger.getCLogger(WReport.class); - /** The parent window for locking/unlocking during process execution */ - Component parent; - /** The parent window number */ - int WindowNo; - /** The filter to apply to this report */ + /** The invoking parent component **/ + protected Component parent; + /** The parent window number **/ + protected int WindowNo; + /** The filter to apply to this report **/ private String whereExtended; /** - * Get the Print Formats for the table. - * Fill the list and the popup menu + * Get Print Formats for table and window. + * If there's only 1 print format found, call {@link #launchReport(KeyNamePair)}, otherwise call {@link #showPopup()}. * @param AD_Table_ID table - * @param invoker component to display popup (optional) + * @param AD_Window_ID */ private void getPrintFormats (int AD_Table_ID, int AD_Window_ID) { @@ -134,6 +135,9 @@ public class WReport implements EventListener { showPopup(); // below button } // getPrintFormats + /** + * Show popup menu for the list of print formats found. + */ private void showPopup() { m_popup = new Menupopup(); for(int i = 0; i < m_list.size(); i++) @@ -150,7 +154,7 @@ public class WReport implements EventListener { /** * Launch Report - * @param pp Key=AD_PrintFormat_ID + * @param pp KeyNamePair(AD_PrintFormat_ID,Name) */ private void launchReport (KeyNamePair pp) { @@ -202,7 +206,7 @@ public class WReport implements EventListener { } } // launchReport - /************************************************************************** + /** * Get AD_Table_ID for Table Name * @param tableName table name * @return AD_Table_ID or 0 @@ -212,9 +216,11 @@ public class WReport implements EventListener { return MTable.getTable_ID(tableName); } // getAD_Table_ID + @Override public void onEvent(Event event) { if(event.getTarget() instanceof Menuitem) { + //ON_CLICK event from showPopup() menu item. Menuitem mi = (Menuitem) event.getTarget(); launchReport(m_list.get(Integer.parseInt(mi.getValue().toString()))); }