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.
This commit is contained in:
hengsin 2023-02-15 19:33:18 +08:00 committed by GitHub
parent 17f1957d70
commit dff85c45de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1265 additions and 383 deletions

View File

@ -33,7 +33,7 @@ import org.compiere.util.Evaluator;
import org.compiere.util.Util; 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 <a href="mailto:agramdass@gmail.com">Ashley G Ramdass</a> * @author <a href="mailto:agramdass@gmail.com">Ashley G Ramdass</a>
* @author <a href="mailto:hengsin@gmail.com">Low Heng Sin</a> * @author <a href="mailto:hengsin@gmail.com">Low Heng Sin</a>
* @date Feb 25, 2007 * @date Feb 25, 2007
@ -41,12 +41,12 @@ import org.compiere.util.Util;
*/ */
public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabbox public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabbox
{ {
/** Logger */ /** Logger **/
private static final CLogger log = CLogger.getCLogger (AbstractADTabbox.class); 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<String> m_dependents = new ArrayList<String>(); private ArrayList<String> m_dependents = new ArrayList<String>();
/** AD tab panels associated to this tab box */ /** List of {@link IADTabpanel} instance manage by this AbstractADTabbox instance **/
protected List<IADTabpanel> tabPanelList = new ArrayList<IADTabpanel>(); protected List<IADTabpanel> tabPanelList = new ArrayList<IADTabpanel>();
/** Parent part, the content part of AD Window **/ /** Parent part, the content part of AD Window **/
protected AbstractADWindowContent adWindowPanel; protected AbstractADWindowContent adWindowPanel;

View File

@ -39,6 +39,7 @@ import org.adempiere.webui.LayoutUtils;
import org.adempiere.webui.adwindow.ADWindow; import org.adempiere.webui.adwindow.ADWindow;
import org.adempiere.webui.component.Mask; import org.adempiere.webui.component.Mask;
import org.adempiere.webui.component.Window; import org.adempiere.webui.component.Window;
import org.adempiere.webui.desktop.IDesktop;
import org.adempiere.webui.editor.WTableDirEditor; import org.adempiere.webui.editor.WTableDirEditor;
import org.adempiere.webui.event.DialogEvents; import org.adempiere.webui.event.DialogEvents;
import org.adempiere.webui.event.DrillEvent.DrillData; import org.adempiere.webui.event.DrillEvent.DrillData;
@ -86,7 +87,7 @@ import org.zkoss.zul.impl.InputElement;
import com.lowagie.text.DocumentException; import com.lowagie.text.DocumentException;
/** /**
* ZK Application Environment and utilities * Static application environment and utilities methods.
* *
* @author Jorg Janke * @author Jorg Janke
* @version $Id: AEnv.java,v 1.2 2006/07/30 00:51:27 jjanke Exp $ * @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 public final class AEnv
{ {
/** Environment context attribute for Locale **/
public static final String LOCALE = Env.LOCALE; public static final String LOCALE = Env.LOCALE;
/** /**
* Show in the center of the screen. * Show window in the center of screen.
* (pack, set location and set visibility)
* @param window Window to position * @param window Window to position
*/ */
public static void showCenterScreen(Window window) public static void showCenterScreen(Window window)
@ -120,8 +121,7 @@ public final class AEnv
} // showCenterScreen } // showCenterScreen
/** /**
* Show in the center of the screen. * Set window position ({@link org.zkoss.zul.Window#setPosition(String)}) and show it.
* (pack, set location and set visibility)
* @param window Window to position * @param window Window to position
* @param position * @param position
*/ */
@ -131,8 +131,7 @@ public final class AEnv
} // showScreen } // showScreen
/** /**
* Position in center of the parent window. * Position window in center of the parent window.
* (pack, set location and set visibility)
* @param parent Parent Window * @param parent Parent Window
* @param window Window to position * @param window Window to position
*/ */
@ -145,7 +144,7 @@ public final class AEnv
/** /**
* Get Mnemonic character from text. * Get Mnemonic character from text.
* @param text text with '&amp;' * @param text text with '&amp;'
* @return Mnemonic or 0 * @return Mnemonic character or 0
*/ */
public static char getMnemonic (String text) 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 AD_Table_ID
* @param Record_ID * @param Record_ID
*/ */
@ -178,10 +177,11 @@ public final class AEnv
} // zoom } // zoom
/************************************************************************* /*************************************************************************
* Zoom * Zoom to AD Window by AD_Table_ID and Record_ID.
* @param AD_Table_ID * @param AD_Table_ID
* @param Record_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) 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(AD_Window_ID, query);
} // zoom } // 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) { public static void zoom (int AD_Table_ID, int Record_ID, MQuery query) {
zoom (AD_Table_ID, Record_ID, query, 0); zoom (AD_Table_ID, Record_ID, query, 0);
} }
/** /**
* Exit System * Exit System.
* @param status System exit status (usually 0 for no error) * @param status System exit status (usually 0 for no error)
*/ */
@Deprecated(forRemoval = true, since = "11")
public static void exit (int status) public static void exit (int status)
{ {
Env.exitEnv(status); Env.exitEnv(status);
} // exit } // exit
/** /**
* logout AD_Session * Logout AD_Session and clear {@link #windowCache}.
*/ */
public static void logout() public static void logout()
{ {
@ -228,13 +235,12 @@ public final class AEnv
session.logout(); session.logout();
Env.setContext(Env.getCtx(), Env.AD_SESSION_ID, (String)null); Env.setContext(Env.getCtx(), Env.AD_SESSION_ID, (String)null);
//
} }
/** /**
* Start Workflow Process Window * Open Workflow Process Window for AD_Table_ID and Record_ID
* @param AD_Table_ID optional table * @param AD_Table_ID
* @param Record_ID optional record * @param Record_ID
*/ */
public static void startWorkflowProcess (int AD_Table_ID, int 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); AEnv.zoom(s_workflow_Window_ID, query);
} // startWorkflowProcess } // startWorkflowProcess
/** Cache Workflow Window ID **/
/*************************************************************************/
/** Workflow Window */
private static int s_workflow_Window_ID = 0; private static int s_workflow_Window_ID = 0;
/** Logger */ /** Logger */
private static final CLogger log = CLogger.getCLogger(AEnv.class); private static final CLogger log = CLogger.getCLogger(AEnv.class);
/** Window Cache */ /** Register AD Window Cache **/
private static Map<String, CCache<Integer,GridWindowVO>> windowCache = new HashMap<String, CCache<Integer,GridWindowVO>>(); private static Map<String, CCache<Integer,GridWindowVO>> windowCache = new HashMap<String, CCache<Integer,GridWindowVO>>();
/** /**
* Get Window Model * Get VO for AD_Window
* *
* @param WindowNo Window No * @param WindowNo Window No
* @param AD_Window_ID window * @param AD_Window_ID window
* @param AD_Menu_ID menu * @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) 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); if (log.isLoggable(Level.CONFIG)) log.config("Window=" + WindowNo + ", AD_Window_ID=" + AD_Window_ID);
GridWindowVO mWindowVO = null; GridWindowVO mWindowVO = null;
String sessionID = Env.getContext(Env.getCtx(), Env.AD_SESSION_ID); String sessionID = Env.getContext(Env.getCtx(), Env.AD_SESSION_ID);
@ -299,7 +301,8 @@ public final class AEnv
// Create Window Model on Client // Create Window Model on Client
if (mWindowVO == null) 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); mWindowVO = GridWindowVO.create (Env.getCtx(), WindowNo, AD_Window_ID, AD_Menu_ID);
if (mWindowVO != null && Ini.isCacheWindow()) if (mWindowVO != null && Ini.isCacheWindow())
{ {
@ -318,10 +321,9 @@ public final class AEnv
if (mWindowVO == null) if (mWindowVO == null)
return null; return null;
// Check (remote) context // Check context
if (!mWindowVO.ctx.equals(Env.getCtx())) if (!mWindowVO.ctx.equals(Env.getCtx()))
{ {
// Remote Context is called by value, not reference
// Add Window properties to context // Add Window properties to context
Enumeration<Object> keyEnum = mWindowVO.ctx.keys(); Enumeration<Object> keyEnum = mWindowVO.ctx.keys();
while (keyEnum.hasMoreElements()) while (keyEnum.hasMoreElements())
@ -341,12 +343,13 @@ public final class AEnv
} // getWindow } // getWindow
/** /**
* Post Immediate * Post Immediate.
* Call {@link Doc#manualPosting(int, int, int, int, boolean)}.
* @param WindowNo window * @param WindowNo window
* @param AD_Table_ID Table ID of Document * @param AD_Table_ID Table ID of Document
* @param AD_Client_ID Client ID of Document * @param AD_Client_ID Client ID of Document
* @param Record_ID Record ID of this document * @param Record_ID Record ID of Document
* @param force force posting * @param force force posting. if false, only post if (Processing='N' OR Processing IS NULL)
* @return null if success, otherwise error * @return null if success, otherwise error
*/ */
public static String postImmediate (int WindowNo, int AD_Client_ID, public static String postImmediate (int WindowNo, int AD_Client_ID,
@ -373,6 +376,13 @@ public final class AEnv
CacheMgt.get().reset(tableName, Record_ID); CacheMgt.get().reset(tableName, Record_ID);
} // cacheReset } // 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 public static void actionRefresh(Lookup lookup, Object value, boolean mandatory, boolean shortList) // IDEMPIERE 90
{ {
if (lookup == null) if (lookup == null)
@ -385,9 +395,9 @@ public final class AEnv
lookup.fillComboBox(mandatory, true, false, false, shortList); // IDEMPIERE 90 lookup.fillComboBox(mandatory, true, false, false, shortList); // IDEMPIERE 90
} }
/** /**
* * zoom to AD Window
* @param lookup * @param lookup lookup for zoom destination table
* @param value * @param value record key
*/ */
public static void actionZoom(Lookup lookup, Object value) 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 * query
* @param AD_Window_ID Window on which to zoom * @param AD_Window_ID Window on which to zoom
* @param query Filter to be applied on the records. * @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); 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) { public static void zoom(int AD_Window_ID, MQuery query) {
zoom(AD_Window_ID, query, 0); zoom(AD_Window_ID, query, 0);
} }
/**
* Show window in desktop.
* Call {@link IDesktop#showWindow(Window)}.
* @param win
*/
public static void showWindow(Window win) public static void showWindow(Window win)
{ {
SessionManager.getAppDesktop().showWindow(win); SessionManager.getAppDesktop().showWindow(win);
} }
/** /**
* Zoom * Zoom to AD Window with details from query
* @param query query * @param query query
*/ */
public static void zoom (MQuery query) public static void zoom (MQuery query)
@ -537,7 +557,7 @@ public final class AEnv
* Get ImageIcon. * Get ImageIcon.
* *
* @param fileNameInImageDir full file name in imgaes folder (e.g. Bean16.png) * @param fileNameInImageDir full file name in imgaes folder (e.g. Bean16.png)
* @return image * @return image {@link URI}
*/ */
public static URI getImage(String fileNameInImageDir) public static URI getImage(String fileNameInImageDir)
{ {
@ -555,8 +575,7 @@ public final class AEnv
} // getImageIcon } // getImageIcon
/** /**
* * @return true if client browser is firefox 2+
* @return boolean
*/ */
public static boolean isFirefox2() { public static boolean isFirefox2() {
Execution execution = Executions.getCurrent(); Execution execution = Executions.getCurrent();
@ -626,10 +645,9 @@ public final class AEnv
} }
/** /**
*
* @param parent * @param parent
* @param child * @param child
* @return boolean * @return true if parent == child or parent is ancestor of child.
*/ */
public static boolean contains(Component parent, Component child) { public static boolean contains(Component parent, Component child) {
if (child == parent) if (child == parent)
@ -646,7 +664,7 @@ public final class AEnv
} }
/** /**
* * Merge pdfList to outFile
* @param pdfList * @param pdfList
* @param outFile * @param outFile
* @throws IOException * @throws IOException
@ -687,7 +705,7 @@ public final class AEnv
/** /**
* @param ctx * @param ctx
* @return Language * @return {@link Language}
*/ */
public static Language getLanguage(Properties ctx) { public static Language getLanguage(Properties ctx) {
return Env.getLocaleLanguage(ctx); return Env.getLocaleLanguage(ctx);
@ -695,7 +713,7 @@ public final class AEnv
/** /**
* @param ctx * @param ctx
* @return Locale * @return {@link Locale}
*/ */
public static Locale getLocale(Properties ctx) { public static Locale getLocale(Properties ctx) {
return Env.getLocale(ctx); return Env.getLocale(ctx);
@ -741,12 +759,19 @@ public final class AEnv
return header; return header;
} }
/**
* Call {@link #getDialogHeader(Properties, int, String)}
* @param ctx
* @param windowNo
* @return dialog header
*/
public static String getDialogHeader(Properties ctx, int windowNo) { public static String getDialogHeader(Properties ctx, int windowNo) {
return getDialogHeader(ctx, windowNo, null); return getDialogHeader(ctx, windowNo, null);
} }
/** /**
* Execute synchronous task in UI thread. * 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 * @param runnable
*/ */
public static void executeDesktopTask(final Runnable runnable) { public static void executeDesktopTask(final Runnable runnable) {
@ -777,7 +802,7 @@ public final class AEnv
/** /**
* Get current desktop * Get current desktop
* @return Desktop * @return {@link Desktop}
*/ */
public static Desktop getDesktop() { public static Desktop getDesktop() {
boolean inUIThread = Executions.getCurrent() != null; boolean inUIThread = Executions.getCurrent() != null;
@ -793,6 +818,7 @@ public final class AEnv
* @deprecated replace by ClientInfo.isMobile() * @deprecated replace by ClientInfo.isMobile()
* @return true if running on a tablet * @return true if running on a tablet
*/ */
@Deprecated(forRemoval = true, since = "11")
public static boolean isTablet() { public static boolean isTablet() {
return ClientInfo.isMobile(); return ClientInfo.isMobile();
} }
@ -822,6 +848,12 @@ public final class AEnv
return adWindowID; 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 { public static WTableDirEditor getListDocumentLanguage (MClient client) throws Exception {
WTableDirEditor fLanguageType = null; WTableDirEditor fLanguageType = null;
if (client.isMultiLingualDocument()){ if (client.isMultiLingualDocument()){
@ -834,6 +866,10 @@ public final class AEnv
} }
private static String m_ApplicationUrl = null; private static String m_ApplicationUrl = null;
/**
* @return URL to access application from browser
*/
public static String getApplicationUrl() { public static String getApplicationUrl() {
String url = MSysConfig.getValue(MSysConfig.APPLICATION_URL, Env.getAD_Client_ID(Env.getCtx())); String url = MSysConfig.getValue(MSysConfig.APPLICATION_URL, Env.getAD_Client_ID(Env.getCtx()));
if (!Util.isEmpty(url) && !url.equals("USE_HARDCODED")) if (!Util.isEmpty(url) && !url.equals("USE_HARDCODED"))
@ -851,20 +887,26 @@ public final class AEnv
return m_ApplicationUrl; 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) public static String getZoomUrlTableID(PO po)
{ {
return getApplicationUrl() + "?Action=Zoom&AD_Table_ID=" + po.get_Table_ID() + "&Record_ID=" + po.get_ID(); 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) public static String getZoomUrlTableName(PO po)
{ {
return getApplicationUrl() + "?Action=Zoom&TableName" + po.get_TableName() + "&Record_ID=" + po.get_ID(); 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 * @param attribute
* @return true if attribute have been set for current executions * @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 * Workaround for detached HTML input element leak.
* @param c * <br/>
* Detach all InputElement and Button that's the immediate or not immediate child of parent.
* <br/>
* 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) { public static void detachInputElement(Component parent) {
if (c instanceof InputElement || c instanceof Button) { if (parent instanceof InputElement || parent instanceof Button) {
c.detach(); parent.detach();
} }
if (c.getChildren().size() > 0) { if (parent.getChildren().size() > 0) {
Component[] childs = c.getChildren().toArray(new Component[0]); Component[] childs = parent.getChildren().toArray(new Component[0]);
for(Component c1 : childs) { for(Component child : childs) {
detachInputElement(c1); detachInputElement(child);
} }
} }
} }

View File

@ -73,6 +73,7 @@ import org.compiere.model.MUser;
import org.compiere.model.MUserDefProc; import org.compiere.model.MUserDefProc;
import org.compiere.model.Query; import org.compiere.model.Query;
import org.compiere.model.SystemIDs; import org.compiere.model.SystemIDs;
import org.compiere.model.X_AD_PInstance;
import org.compiere.print.MPrintFormat; import org.compiere.print.MPrintFormat;
import org.compiere.process.ProcessInfo; import org.compiere.process.ProcessInfo;
import org.compiere.process.ProcessInfoUtil; import org.compiere.process.ProcessInfoUtil;
@ -101,15 +102,22 @@ import org.zkoss.zul.Html;
import org.zkoss.zul.Space; import org.zkoss.zul.Space;
import org.zkoss.zul.Vlayout; 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<Event> public abstract class AbstractProcessDialog extends Window implements IProcessUI, EventListener<Event>
{ {
/** /**
* * generated serial id
*/ */
private static final long serialVersionUID = 484056046177205235L; private static final long serialVersionUID = 484056046177205235L;
private static final String ON_COMPLETE = "onComplete"; /** Event to fire on complete of execution of process/report **/
private static final String ON_STATUS_UPDATE = "onStatusUpdate"; 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); 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 Properties m_ctx;
private int m_AD_Process_ID; private int m_AD_Process_ID;
private ProcessInfo m_pi = null; private ProcessInfo m_pi = null;
/** if true, auto call {@link #dispose()} in {@link #ON_COMPLETE_EVENT} handler. **/
private boolean m_disposeOnComplete; private boolean m_disposeOnComplete;
/** Panel for process paramters **/
private ProcessParameterPanel parameterPanel = null; private ProcessParameterPanel parameterPanel = null;
/** Checkbox to toggle running process/report as background job **/
private Checkbox runAsJobField = null; private Checkbox runAsJobField = null;
private Label notificationTypeLabel = 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 WTableDirEditor notificationTypeField = null;
private BusyDialog progressWindow; private BusyDialog progressWindow;
/** translated process name */
private String m_Name = null; private String m_Name = null;
/** translated process description */
private String m_Description = null; private String m_Description = null;
/** translated process help */
private String m_Help = null; 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; private String initialMessage;
/** true if dialog is still valid, i.e not dispose yet **/
private boolean m_valid = true; private boolean m_valid = true;
/** true if dialog have been cancelled by user **/
private boolean m_cancel = false; private boolean m_cancel = false;
/** Reference to process thread/task **/
private Future<?> future; private Future<?> future;
/** files for download by user **/
private List<File> downloadFiles; private List<File> downloadFiles;
/** true when UI have been locked, i.e busy **/
private boolean m_locked = false; private boolean m_locked = false;
private String m_AD_Process_UU = ""; private String m_AD_Process_UU = "";
/**
* default constructor
*/
protected AbstractProcessDialog() protected AbstractProcessDialog()
{ {
super(); super();
@ -163,7 +189,7 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
} }
/** /**
* layout as below * layout dialog
* *
* @param ctx * @param ctx
* @param WindowNo * @param WindowNo
@ -172,7 +198,7 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
* @param pi * @param pi
* @param autoStart * @param autoStart
* @param isDisposeOnComplete * @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) 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); setProcessInfo(pi);
m_disposeOnComplete = isDisposeOnComplete; m_disposeOnComplete = isDisposeOnComplete;
log.config(""); if (log.isLoggable(Level.CONFIG))
log.config("");
// //
StringBuilder buildMsg = new StringBuilder(); StringBuilder buildMsg = new StringBuilder();
boolean trl = !Env.isBaseLanguage(m_ctx, "AD_Process"); boolean trl = !Env.isBaseLanguage(m_ctx, "AD_Process");
@ -222,7 +249,6 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
// //
this.setTitle(m_Name); this.setTitle(m_Name);
// Move from APanel.actionButton
if (m_pi == null) { if (m_pi == null) {
m_pi = new WProcessInfo(m_Name, AD_Process_ID); m_pi = new WProcessInfo(m_Name, AD_Process_ID);
// Set Replace Tab Content // Set Replace Tab Content
@ -233,8 +259,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
m_pi.setTitle(m_Name); m_pi.setTitle(m_Name);
m_pi.setAD_Process_UU(m_AD_Process_UU); 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() ) { if ( !parameterPanel.init() ) {
//auto start if no parameters and DonTShowHelp.
if (m_ShowHelp != null && MProcess.SHOWHELP_DonTShowHelp.equals(m_ShowHelp)) if (m_ShowHelp != null && MProcess.SHOWHELP_DonTShowHelp.equals(m_ShowHelp))
autoStart = true; autoStart = true;
@ -263,21 +290,33 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
return true; return true;
} }
/** top part of {@link #mainParameterLayout} **/
protected HtmlBasedComponent topParameterLayout; protected HtmlBasedComponent topParameterLayout;
/** bottom part of {@link #mainParameterLayout} **/
protected HtmlBasedComponent bottomParameterLayout; protected HtmlBasedComponent bottomParameterLayout;
/** main content layout **/
protected HtmlBasedComponent mainParameterLayout; protected HtmlBasedComponent mainParameterLayout;
protected WTableDirEditor fPrintFormat; protected WTableDirEditor fPrintFormat;
private WEditor fLanguageType; private WEditor fLanguageType;
protected Listbox freportType; protected Listbox freportType;
private Checkbox chbIsSummary; private Checkbox chbIsSummary;
/** ok button to run process/report **/
protected Button bOK; protected Button bOK;
/** cancel button to dismiss dialog **/
protected Button bCancel; protected Button bCancel;
/** List of name/label for save process parameters **/
protected Combobox fSavedName=new Combobox(); protected Combobox fSavedName=new Combobox();
/** button to save process parameters **/
private Button bSave=ButtonFactory.createNamedButton("Save"); private Button bSave=ButtonFactory.createNamedButton("Save");
/** button to delete saved process parameters **/
private Button bDelete=ButtonFactory.createNamedButton("Delete"); private Button bDelete=ButtonFactory.createNamedButton("Delete");
/** List of save parameters **/
private List<MPInstance> savedParams; private List<MPInstance> savedParams;
private Label lSaved; private Label lSaved;
/**
* layout dialog
*/
protected void layout(){ protected void layout(){
overalLayout(); overalLayout();
topLayout(topParameterLayout); 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(){ protected void overalLayout(){
mainParameterLayout = new Div(); mainParameterLayout = new Div();
mainParameterLayout.setSclass("main-parameter-layout"); mainParameterLayout.setSclass("main-parameter-layout");
@ -300,6 +342,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
mainParameterLayout.appendChild(bottomParameterLayout); mainParameterLayout.appendChild(bottomParameterLayout);
} }
/**
* Layout content of {@link #topParameterLayout}
* @param topParameterLayout
*/
protected void topLayout(HtmlBasedComponent topParameterLayout) { protected void topLayout(HtmlBasedComponent topParameterLayout) {
// message // message
setHeadMessage (topParameterLayout, initialMessage); setHeadMessage (topParameterLayout, initialMessage);
@ -313,6 +359,12 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
inputParameterLayout(inputParameterLayout); inputParameterLayout(inputParameterLayout);
} }
/**
* Create header message of {@link #topParameterLayout}
* @param parent
* @param contentMsg
* @return content component for contentMsg
*/
protected HtmlBasedComponent setHeadMessage (HtmlBasedComponent parent, String contentMsg){ protected HtmlBasedComponent setHeadMessage (HtmlBasedComponent parent, String contentMsg){
// message // message
HtmlBasedComponent messageParameterLayout = new Vlayout(); HtmlBasedComponent messageParameterLayout = new Vlayout();
@ -332,6 +384,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
return content; return content;
} }
/**
* Layout parameter part of {@link #topParameterLayout}.
* {@link #parameterPanel}, {@link #runAsJobField} and {@link #notificationTypeField}.
* @param parent
*/
protected void inputParameterLayout (HtmlBasedComponent parent) { protected void inputParameterLayout (HtmlBasedComponent parent) {
parent.appendChild(parameterPanel); 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) { protected void bottomLayout(HtmlBasedComponent bottomParameterLayout) {
reportOptionLayout(bottomParameterLayout); reportOptionLayout(bottomParameterLayout);
@ -418,6 +480,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
buttonLayout (bottomContainer); buttonLayout (bottomContainer);
} }
/**
* Render report option part of {@link #bottomParameterLayout}.
* @param bottomParameterLayout
*/
protected void reportOptionLayout(HtmlBasedComponent bottomParameterLayout) { protected void reportOptionLayout(HtmlBasedComponent bottomParameterLayout) {
if (!isReport() && !isJasperReport()) if (!isReport() && !isJasperReport())
return;//if not a report not need show this pannel 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"); reportOptionLayout.setValign("middle");
bottomParameterLayout.appendChild(reportOptionLayout); bottomParameterLayout.appendChild(reportOptionLayout);
//output type: html, pdf, etc
Label lreportType = new Label(Msg.translate(Env.getCtx(), "view.report")); Label lreportType = new Label(Msg.translate(Env.getCtx(), "view.report"));
lreportType.setSclass("option-input-parameter view-report-label"); lreportType.setSclass("option-input-parameter view-report-label");
freportType = new Listbox(); freportType = new Listbox();
@ -440,6 +507,8 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
if (!isReport()) if (!isReport())
return; return;
//summary option
chbIsSummary = new Checkbox(); chbIsSummary = new Checkbox();
chbIsSummary.setSclass("option-input-parameter"); chbIsSummary.setSclass("option-input-parameter");
Label lPrintFormat = new Label(Msg.translate(Env.getCtx(), "AD_PrintFormat_ID")); 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")); Label lIsSummary = new Label(Msg.translate(Env.getCtx(), "Summary"));
lIsSummary.setSclass("option-input-parameter"); lIsSummary.setSclass("option-input-parameter");
//print formats
MClient client = MClient.get(m_ctx); MClient client = MClient.get(m_ctx);
listPrintFormat(client); listPrintFormat(client);
reportOptionLayout.appendChild(lPrintFormat); reportOptionLayout.appendChild(lPrintFormat);
reportOptionLayout.appendChild(fPrintFormat.getComponent()); reportOptionLayout.appendChild(fPrintFormat.getComponent());
//selection of language
if (client.isMultiLingualDocument()){ if (client.isMultiLingualDocument()){
Label lLanguageType = new Label(Msg.translate(Env.getCtx(), MLanguage.COLUMNNAME_AD_Language_ID)); Label lLanguageType = new Label(Msg.translate(Env.getCtx(), MLanguage.COLUMNNAME_AD_Language_ID));
reportOptionLayout.appendChild(lLanguageType); reportOptionLayout.appendChild(lLanguageType);
@ -464,16 +535,26 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
reportOptionLayout.appendChild(chbIsSummary); reportOptionLayout.appendChild(chbIsSummary);
} }
/**
* @return true if current process is with IsReport=Y AND JasperReport Is NULL.
*/
protected boolean isReport () { protected boolean isReport () {
MProcess pr = MProcess.get(m_ctx, m_AD_Process_ID); MProcess pr = MProcess.get(m_ctx, m_AD_Process_ID);
return pr.isReport() && pr.getJasperReport() == null; return pr.isReport() && pr.getJasperReport() == null;
} }
/**
* @return true if current process is with IsReport=Y AND JasperReport Is Not NULL.
*/
protected boolean isJasperReport () { protected boolean isJasperReport () {
MProcess pr = MProcess.get(m_ctx, m_AD_Process_ID); MProcess pr = MProcess.get(m_ctx, m_AD_Process_ID);
return pr.isReport() && pr.getJasperReport() != null; return pr.isReport() && pr.getJasperReport() != null;
} }
/**
* Layout UI to load/save process parameters
* @param bottomParameterLayout
*/
protected void savePrameterLayout(HtmlBasedComponent bottomParameterLayout) { protected void savePrameterLayout(HtmlBasedComponent bottomParameterLayout) {
Hlayout savePrameterLayout = new Hlayout(); Hlayout savePrameterLayout = new Hlayout();
savePrameterLayout.setSclass("save-parameter-container"); savePrameterLayout.setSclass("save-parameter-container");
@ -503,6 +584,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
querySaved(); querySaved();
} }
/**
* Load saved process parameters
*/
protected void querySaved() protected void querySaved()
{ {
//user query //user query
@ -517,6 +601,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
fSavedName.setValue(""); fSavedName.setValue("");
} }
/**
* Action buttons for dialog
* @param bottomParameterLayout
*/
protected void buttonLayout (HtmlBasedComponent bottomParameterLayout) { protected void buttonLayout (HtmlBasedComponent bottomParameterLayout) {
HtmlBasedComponent confParaPanel =new Div(); HtmlBasedComponent confParaPanel =new Div();
confParaPanel.setSclass("button-container"); 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) private void listPrintFormat(MClient client)
{ {
int AD_Column_ID = 0; int AD_Column_ID = 0;
@ -590,6 +682,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
setReportTypeAndPrintFormat(getLastRun()); setReportTypeAndPrintFormat(getLastRun());
} }
/**
* Fill {@link #freportType} for Jasper Report.
*/
private void listReportTypeJasper() private void listReportTypeJasper()
{ {
boolean m_isCanExport = MRole.getDefault().isCanExport(); boolean m_isCanExport = MRole.getDefault().isCanExport();
@ -598,6 +693,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
setReportTypeAndPrintFormat(getLastRun()); setReportTypeAndPrintFormat(getLastRun());
} }
/**
* @return Last run {@link MPInstance} record for current logged in user.
*/
protected MPInstance getLastRun() { protected MPInstance getLastRun() {
final String where = "AD_Process_ID = ? AND AD_User_ID = ? AND Name IS NULL "; final String where = "AD_Process_ID = ? AND AD_User_ID = ? AND Name IS NULL ";
return new Query(Env.getCtx(), MPInstance.Table_Name, where, null) return new Query(Env.getCtx(), MPInstance.Table_Name, where, null)
@ -607,6 +705,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
.first(); .first();
} }
/**
* Fill {@link #freportType}
* @param m_isCanExport true to include excel and csv.
*/
private void fillReportType(boolean m_isCanExport) { private void fillReportType(boolean m_isCanExport) {
freportType.removeAllItems(); freportType.removeAllItems();
freportType.setMold("select"); freportType.setMold("select");
@ -623,6 +725,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
freportType.setSelectedIndex(-1); freportType.setSelectedIndex(-1);
} }
/**
* Set value for {@link #fPrintFormat}, {@link #fLanguageType}, {@link #freportType} and {@link #chbIsSummary} from instance.
* @param instance
*/
private void setReportTypeAndPrintFormat(MPInstance instance) private void setReportTypeAndPrintFormat(MPInstance instance)
{ {
if (fPrintFormat != null && instance != null if (fPrintFormat != null && instance != null
@ -645,6 +751,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
chbIsSummary.setSelected(instance.isSummary()); 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 (){ protected void saveReportOption (){
if (!isReport() && !isJasperReport()){ if (!isReport() && !isJasperReport()){
return; return;
@ -669,11 +779,16 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
getProcessInfo().setLanguageID(MLanguage.get(getCtx(), Env.getLanguage(getCtx())).getAD_Language_ID()); 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() protected void autoStart()
{ {
startProcess0(); startProcess0();
} }
@Override
public void onEvent(Event event) public void onEvent(Event event)
{ {
Component component = event.getTarget(); Component component = event.getTarget();
@ -683,9 +798,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
mainParameterLayout.invalidate(); mainParameterLayout.invalidate();
} }
else if (event.getName().equals(ON_COMPLETE)) else if (event.getName().equals(ON_COMPLETE_EVENT))
onComplete(); onComplete();
else if (event.getName().equals(ON_STATUS_UPDATE)) else if (event.getName().equals(ON_STATUS_UPDATE_EVENT))
onStatusUpdate(event); onStatusUpdate(event);
else if (event.getTarget().equals(bSave) || event.getTarget().equals(bDelete) || event.getTarget().equals(fSavedName)){ else if (event.getTarget().equals(bSave) || event.getTarget().equals(bDelete) || event.getTarget().equals(fSavedName)){
String saveName = null; 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) { protected void updateSaveParameter(String saveName) {
// Update existing // Update existing
if (fSavedName.getSelectedIndex() > -1 && savedParams != null) { if (fSavedName.getSelectedIndex() > -1 && savedParams != null) {
for (int i = 0; i < savedParams.size(); i++) { for (int i = 0; i < savedParams.size(); i++) {
if (savedParams.get(i).getName().equals(saveName)) { if (savedParams.get(i).getName().equals(saveName)) {
getProcessInfo().setAD_PInstance_ID(savedParams.get(i) getProcessInfo().setAD_PInstance_ID(savedParams.get(i)
.getAD_PInstance_ID()); .getAD_PInstance_ID());
for (MPInstancePara para : savedParams.get(i) for (MPInstancePara para : savedParams.get(i)
.getParameters()) { .getParameters()) {
para.deleteEx(true); para.deleteEx(true);
}
getParameterPanel().saveParameters();
saveReportOptionToInstance(savedParams.get(i));
savedParams.get(i).saveEx();
getProcessInfo().setAD_PInstance_ID(0);
} }
getParameterPanel().saveParameters();
saveReportOptionToInstance(savedParams.get(i));
savedParams.get(i).saveEx();
getProcessInfo().setAD_PInstance_ID(0);
} }
} }
// create new }
else { // create new
MPInstance instance = null; else {
try { MPInstance instance = null;
instance = new MPInstance(Env.getCtx(), try {
getProcessInfo().getAD_Process_ID(), getProcessInfo().getRecord_ID()); instance = new MPInstance(Env.getCtx(),
instance.setName(saveName); getProcessInfo().getAD_Process_ID(), getProcessInfo().getRecord_ID());
saveReportOptionToInstance(instance); instance.setName(saveName);
instance.saveEx(); saveReportOptionToInstance(instance);
getProcessInfo().setAD_PInstance_ID(instance.getAD_PInstance_ID()); instance.saveEx();
// Get Parameters getProcessInfo().setAD_PInstance_ID(instance.getAD_PInstance_ID());
if (getParameterPanel() != null) { // Get Parameters
if (!getParameterPanel().saveParameters()) { if (getParameterPanel() != null) {
throw new AdempiereSystemError(Msg.getMsg( if (!getParameterPanel().saveParameters()) {
Env.getCtx(), "SaveParameterError")); 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){ protected void saveReportOptionToInstance (MPInstance instance){
if (!isReport() && !isJasperReport()) if (!isReport() && !isJasperReport())
return; return;
@ -782,6 +907,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
instance.setIsSummary(chbIsSummary.isSelected()); instance.setIsSummary(chbIsSummary.isSelected());
} }
/**
* Find {@link #fSavedName} item for value.
* @param value
* @return {@link Comboitem} found.
*/
public Comboitem getComboItem( String value) { public Comboitem getComboItem( String value) {
Comboitem item = null; Comboitem item = null;
for (int i = 0; i < fSavedName.getItems().size(); i++) { for (int i = 0; i < fSavedName.getItems().size(); i++) {
@ -794,7 +924,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
} }
return item; return item;
} }
/**
* Delete saved MPInstance by saveName.
* @param saveName
*/
protected void deleteSaveParameter(String saveName) { protected void deleteSaveParameter(String saveName) {
Object o = fSavedName.getSelectedItem(); Object o = fSavedName.getSelectedItem();
if (savedParams != null && o != null) { if (savedParams != null && o != null) {
@ -808,6 +942,11 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
querySaved(); querySaved();
} }
/**
* Load MPInstance by saveName.
* @param saveName
* @param lastRun
*/
protected void chooseSaveParameter(String saveName, boolean lastRun) { protected void chooseSaveParameter(String saveName, boolean lastRun) {
if (savedParams != null && saveName != null) { if (savedParams != null && saveName != null) {
for (int i = 0; i < savedParams.size(); i++) { 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); boolean enabled = !Util.isEmpty(saveName);
bSave.setEnabled(enabled && !lastRun); bSave.setEnabled(enabled && !lastRun);
bDelete.setEnabled(enabled && fSavedName.getSelectedIndex() > -1 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) { protected void loadSavedParams(MPInstance instance) {
getParameterPanel().loadParameters(instance); getParameterPanel().loadParameters(instance);
setReportTypeAndPrintFormat(instance); setReportTypeAndPrintFormat(instance);
} }
/**
* Run process.
* Delegate to {@link #startProcess0()}.
*/
protected void startProcess() protected void startProcess()
{ {
if (!parameterPanel.validateParameters()) if (!parameterPanel.validateParameters())
@ -842,12 +988,19 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
startProcess0(); startProcess0();
} }
/**
* Cancel/dismiss process dialog.
*/
protected void cancelProcess() protected void cancelProcess()
{ {
m_cancel = true; m_cancel = true;
this.dispose(); this.dispose();
} }
/**
* Create new {@link #progressWindow}.
* @return {@link BusyDialog}
*/
protected BusyDialog createBusyDialog() protected BusyDialog createBusyDialog()
{ {
progressWindow = new BusyDialog(); progressWindow = new BusyDialog();
@ -855,6 +1008,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
return progressWindow; return progressWindow;
} }
/**
* Close {@link #progressWindow}.
*/
protected void closeBusyDialog() protected void closeBusyDialog()
{ {
if (progressWindow != null) { if (progressWindow != null) {
@ -869,6 +1025,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
m_valid = false; m_valid = false;
} // dispose } // dispose
/**
* Run process.
*/
private void startProcess0() private void startProcess0()
{ {
if (!isBackgroundJob()) if (!isBackgroundJob())
@ -882,12 +1041,20 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
Clients.response(new AuEcho(this, isBackgroundJob() ? "runBackgroundJob" : "runProcess", this)); Clients.response(new AuEcho(this, isBackgroundJob() ? "runBackgroundJob" : "runProcess", this));
} }
/**
* Run process. Echo event from {@link #startProcess0()}.
*/
public void runProcess() public void runProcess()
{ {
Events.sendEvent(DialogEvents.ON_BEFORE_RUN_PROCESS, this, null); Events.sendEvent(DialogEvents.ON_BEFORE_RUN_PROCESS, this, null);
future = Adempiere.getThreadPoolExecutor().submit(new DesktopRunnable(new ProcessDialogRunnable(null), getDesktop())); future = Adempiere.getThreadPoolExecutor().submit(new DesktopRunnable(new ProcessDialogRunnable(null), getDesktop()));
} }
/**
* Run process as background job (runBackgroundJob event echo from {@link #startProcess0()}).
* <br/>
* The different with {@link #runProcess()} is this method doesn't wait for completion of process.
*/
public void runBackgroundJob() public void runBackgroundJob()
{ {
Properties m_ctx = getCtx(); Properties m_ctx = getCtx();
@ -959,6 +1126,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
} }
} }
/**
* Handle {@link #ON_COMPLETE_EVENT}
*/
private void onComplete() private void onComplete()
{ {
ProcessInfo m_pi = getProcessInfo(); ProcessInfo m_pi = getProcessInfo();
@ -986,6 +1156,10 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
dispose(); dispose();
} }
/**
* Handle {@link #ON_STATUS_UPDATE_EVENT}
* @param event
*/
private void onStatusUpdate(Event event) private void onStatusUpdate(Event event)
{ {
String message = (String) event.getData(); String message = (String) event.getData();
@ -993,6 +1167,9 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
progressWindow.statusUpdate(message); progressWindow.statusUpdate(message);
} }
/**
* Lock UI by showing of busy dialog ({@link #progressWindow}).
*/
@Override @Override
public void lockUI(ProcessInfo pi) { public void lockUI(ProcessInfo pi) {
if (m_locked || Executions.getCurrent() == null) if (m_locked || Executions.getCurrent() == null)
@ -1001,8 +1178,14 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
showBusyDialog(); showBusyDialog();
} }
/**
* Show process in progress dialog.
*/
public abstract void showBusyDialog(); public abstract void showBusyDialog();
/**
* Unlock dialog upon completion of process (or upon submission of job if process is running as background job).
*/
@Override @Override
public void unlockUI(ProcessInfo pi) { public void unlockUI(ProcessInfo pi) {
if (!m_locked) 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() private void doUnlockUI()
{ {
hideBusyDialog(); hideBusyDialog();
updateUI(); updateUI();
} }
/**
* Close process in progress dialog.
*/
public abstract void hideBusyDialog(); public abstract void hideBusyDialog();
/**
* Update UI with the result of process execution.
*/
public abstract void updateUI(); public abstract void updateUI();
@Override @Override
@ -1045,7 +1237,7 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
public void statusUpdate(String message) { public void statusUpdate(String message) {
Desktop desktop = getDesktop(); Desktop desktop = getDesktop();
if (desktop != null && desktop.isAlive()) 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 @Override
@ -1064,20 +1256,21 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
} }
/** /**
* * @return {@link ProcessInfo}
* @return ProcessInfo
*/ */
public ProcessInfo getProcessInfo() { public ProcessInfo getProcessInfo() {
return m_pi; return m_pi;
} }
/**
* @param pi
*/
public void setProcessInfo(ProcessInfo pi) { public void setProcessInfo(ProcessInfo pi) {
m_pi = pi; m_pi = pi;
} }
/** /**
* is dialog still valid * @return true if dialog is still valid (i.e not completed and not cancel).
* @return boolean
*/ */
public boolean isValid() public boolean isValid()
{ {
@ -1092,60 +1285,97 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
return m_cancel; return m_cancel;
} }
/**
* @return cache environment context reference
*/
public Properties getCtx() public Properties getCtx()
{ {
return m_ctx; return m_ctx;
} }
/**
* @return register window number.
*/
public int getWindowNo() public int getWindowNo()
{ {
return m_WindowNo; return m_WindowNo;
} }
/**
* @return AD_Process_ID
*/
public int getAD_Process_ID() public int getAD_Process_ID()
{ {
return m_AD_Process_ID; return m_AD_Process_ID;
} }
/**
* @return {@link ProcessParameterPanel} instance
*/
public ProcessParameterPanel getParameterPanel() public ProcessParameterPanel getParameterPanel()
{ {
return parameterPanel; return parameterPanel;
} }
/**
* @return translated process name
*/
public String getName() public String getName()
{ {
return m_Name; return m_Name;
} }
/**
* @return DonTShowHelp, ShowHelp or Silent.
*/
public String getShowHelp() public String getShowHelp()
{ {
return m_ShowHelp; return m_ShowHelp;
} }
/**
* @return initial panel header message
*/
public String getInitialMessage() public String getInitialMessage()
{ {
return initialMessage; return initialMessage;
} }
/**
* @return true if run process as background job.
*/
public boolean isBackgroundJob() public boolean isBackgroundJob()
{ {
return runAsJobField != null && runAsJobField.isChecked(); return runAsJobField != null && runAsJobField.isChecked();
} }
/**
* @return Notification type - None, Email, Notice or Email+Notice.
*/
public String getNotificationType() public String getNotificationType()
{ {
return (String) notificationTypeField.getValue(); return (String) notificationTypeField.getValue();
} }
/**
* @return list of files for user download
*/
public List<File> getDownloadFiles() public List<File> getDownloadFiles()
{ {
return downloadFiles; 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 class ProcessDialogRunnable extends ZkContextRunnable
{ {
private Trx m_trx; private Trx m_trx;
/**
* @param trx
*/
private ProcessDialogRunnable(Trx trx) private ProcessDialogRunnable(Trx trx)
{ {
super(); super();
@ -1164,11 +1394,15 @@ public abstract class AbstractProcessDialog extends Window implements IProcessUI
m_pi.setSummary(ex.getLocalizedMessage()); m_pi.setSummary(ex.getLocalizedMessage());
log.log(Level.SEVERE, ex.getLocalizedMessage(), ex); log.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
} finally { } 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 class BackgroundJobRunnable implements Runnable
{ {
private Properties m_ctx; 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); Dialog.askForInput(message, lookup, editorType, callback, getDesktop(), m_WindowNo);
} }
/**
* Merge pdfList and show with {@link SimplePDFViewer}.
*/
@Override @Override
public void showReports(List<File> pdfList) { public void showReports(List<File> pdfList) {

View File

@ -23,15 +23,24 @@ import org.zkoss.zul.Div;
import org.zkoss.zul.Span; import org.zkoss.zul.Span;
/** /**
* * Blocking in progress dialog.
* @author hengsin * @author hengsin
* *
*/ */
public class BusyDialog extends Window { public class BusyDialog extends Window {
/**
* generated serial id
*/
private static final long serialVersionUID = -779475945298887887L; private static final long serialVersionUID = -779475945298887887L;
/**
* Label component to display in progress message (default is Processing...).
*/
private Label label; private Label label;
/**
* Default constructor
*/
public BusyDialog() { public BusyDialog() {
super(); super();
LayoutUtils.addSclass("busy-dialog", this); LayoutUtils.addSclass("busy-dialog", this);
@ -55,6 +64,10 @@ public class BusyDialog extends Window {
setShadow(true); setShadow(true);
} }
/**
* Update in progress message.
* @param message
*/
public void statusUpdate(String message) { public void statusUpdate(String message) {
if (label != null) { if (label != null) {
label.setText(message); label.setText(message);

View File

@ -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; package org.adempiere.webui.apps;
import org.adempiere.webui.component.Window; 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.EventListener;
import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.event.Events;
/**
* Show {@link BusyDialog} and invoke {@link Runnable} task.
* <br/>
* Usage: new BusyDialogTemplate(runnable).run(); or with Lambda,new BusyDialogTemplate(() -> {your code}).run();
*/
public class BusyDialogTemplate implements Runnable, EventListener<Event> { public class BusyDialogTemplate implements Runnable, EventListener<Event> {
/** Event to call {@link #runnable} **/
private static final String EVENT_NAME = "onRun"; private static final String EVENT_NAME = "onRun";
/** Task to be invoked **/
private Runnable runnable; private Runnable runnable;
private BusyDialog busyDialog; private BusyDialog busyDialog;
/**
* @param runnable
*/
public BusyDialogTemplate(Runnable runnable) { public BusyDialogTemplate(Runnable runnable) {
this.runnable = runnable; this.runnable = runnable;
} }
/**
* Hide/dispose busy dialog
*/
private void hideBusyDialog() { private void hideBusyDialog() {
if (busyDialog != null) if (busyDialog != null)
{ {
@ -25,12 +63,19 @@ public class BusyDialogTemplate implements Runnable, EventListener<Event> {
} }
} }
/**
* Show busy dialog in highlighted mode.
*/
private void showBusyDialog() { private void showBusyDialog() {
busyDialog = new BusyDialog(); busyDialog = new BusyDialog();
busyDialog.setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED); busyDialog.setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED);
AEnv.showCenterScreen(busyDialog); AEnv.showCenterScreen(busyDialog);
} }
/**
* Call {@link #runnable} and close busy dialog.
*/
@Override
public void onEvent(Event event) throws Exception { public void onEvent(Event event) throws Exception {
try { try {
if (event.getName().equals(EVENT_NAME)) { if (event.getName().equals(EVENT_NAME)) {
@ -41,6 +86,9 @@ public class BusyDialogTemplate implements Runnable, EventListener<Event> {
} }
} }
/**
* Show busy dialog and echo {@link #EVENT_NAME} to call {@link #runnable}
*/
public void run() { public void run() {
showBusyDialog(); showBusyDialog();

View File

@ -21,7 +21,7 @@ import org.compiere.model.MLookup;
import org.zkoss.zk.ui.Desktop; 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) * @author Murilo H. Torquato (devCoffee, http://devcoffee.com.br)
* *
@ -31,6 +31,10 @@ public class CalloutDialog implements ICalloutUI {
private Desktop desktop; private Desktop desktop;
private int m_windowNo; private int m_windowNo;
/**
* @param desktop
* @param windowNo
*/
public CalloutDialog(Desktop desktop, int windowNo) { public CalloutDialog(Desktop desktop, int windowNo) {
this.desktop = desktop; this.desktop = desktop;
this.m_windowNo = windowNo; this.m_windowNo = windowNo;

View File

@ -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; package org.adempiere.webui.apps;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -14,10 +35,12 @@ import org.zkoss.zk.ui.Desktop;
* *
*/ */
public class DesktopRunnable implements Runnable { public class DesktopRunnable implements Runnable {
/** wrapped runnable **/
private Runnable runnable; private Runnable runnable;
/** weak reference to Desktop **/
private WeakReference<Desktop> desktopWeakRef; private WeakReference<Desktop> desktopWeakRef;
/** ThreadLocal weak reference to Desktop **/
private static ThreadLocal<WeakReference<Desktop>> threadLocalDesktop = new ThreadLocal<WeakReference<Desktop>>() { private static ThreadLocal<WeakReference<Desktop>> threadLocalDesktop = new ThreadLocal<WeakReference<Desktop>>() {
protected WeakReference<Desktop> initialValue() protected WeakReference<Desktop> initialValue()
{ {
@ -25,13 +48,17 @@ public class DesktopRunnable implements Runnable {
} }
}; };
/**
* @param runnable
* @param desktop
*/
public DesktopRunnable(Runnable runnable, Desktop desktop) { public DesktopRunnable(Runnable runnable, Desktop desktop) {
this.runnable = runnable; this.runnable = runnable;
this.desktopWeakRef = new WeakReference<Desktop>(desktop); this.desktopWeakRef = new WeakReference<Desktop>(desktop);
} }
/* (non-Javadoc) /**
* @see java.lang.Runnable#run() * Set thread local Desktop reference and call {@link #runnable}.
*/ */
@Override @Override
public void run() { public void run() {

View File

@ -53,20 +53,29 @@ import org.zkoss.zul.Vlayout;
*/ */
public class DocumentSearchController implements EventListener<Event>{ public class DocumentSearchController implements EventListener<Event>{
/** {@link A} component attribute to hold reference to corresponding {@link #SEARCH_RESULT} **/
private static final String SEARCH_RESULT = "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; 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; private Vlayout layout;
/** results from execution of search **/
private ArrayList<SearchResult> list; private ArrayList<SearchResult> list;
/** Current selected index of {@link #list} **/
private int selected = -1; private int selected = -1;
/** /**
* * default constructor
*/ */
public DocumentSearchController() { 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())); 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) { public void create(Component parent) {
layout = new Vlayout(); layout = new Vlayout();
layout.setStyle("padding: 3px; overflow:auto;"); layout.setStyle("padding: 3px; overflow:auto;");
@ -75,14 +84,23 @@ public class DocumentSearchController implements EventListener<Event>{
parent.appendChild(layout); 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) { public void search(String value) {
layout.getChildren().clear(); 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) { private void onSearchDocuments(String searchString) {
list = new ArrayList<SearchResult>(); list = new ArrayList<SearchResult>();
if (Util.isEmpty(searchString)) { if (Util.isEmpty(searchString)) {
@ -119,6 +137,11 @@ public class DocumentSearchController implements EventListener<Event>{
} }
} }
/**
* Perform search with searchString using definition from AD_SearchDefinition.
* @param searchString
* @return List of {@link SearchResult}
*/
private List<SearchResult> doSearch(String searchString) { private List<SearchResult> doSearch(String searchString) {
final MRole role = MRole.get(Env.getCtx(), Env.getAD_Role_ID(Env.getCtx()), Env.getAD_User_ID(Env.getCtx()), true); 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<Event>{
return list; 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<Object> params, MLookup lookup, MWindow window, String tableName, private void doRetrieval(MSearchDefinition msd, StringBuilder builder, List<Object> params, MLookup lookup, MWindow window, String tableName,
String extraWhereClase, List<SearchResult> list) { String extraWhereClase, List<SearchResult> list) {
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
@ -250,17 +284,24 @@ public class DocumentSearchController implements EventListener<Event>{
SearchResult result = (SearchResult) event.getTarget().getAttribute(SEARCH_RESULT); SearchResult result = (SearchResult) event.getTarget().getAttribute(SEARCH_RESULT);
doZoom(result); doZoom(result);
} }
} else if (event.getName().equals(ON_SEARCH_DOCUMENTS)) { } else if (event.getName().equals(ON_SEARCH_DOCUMENTS_EVENT)) {
onSearchDocuments((String)event.getData()); onSearchDocuments((String)event.getData());
} }
} }
/**
* Zoom to AD Window
* @param result
*/
private void doZoom(SearchResult result) { private void doZoom(SearchResult result) {
MQuery query = new MQuery(); MQuery query = new MQuery();
query.addRestriction(result.getTableName()+"_ID", "=", result.getRecordId()); query.addRestriction(result.getTableName()+"_ID", "=", result.getRecordId());
AEnv.zoom(result.getWindowId(), query); AEnv.zoom(result.getWindowId(), query);
} }
/**
* Value class to hold search result
*/
public static class SearchResult { public static class SearchResult {
private String windowName; private String windowName;
private int windowId; private int windowId;
@ -344,6 +385,13 @@ public class DocumentSearchController implements EventListener<Event>{
} }
} }
/**
* Find {@link SearchResult} link from {@link #layout} that matches text from textbox.
* <br/>
* Call {@link #doZoom(SearchResult)} if a match is found.
* @param textbox
* @return true if a match is found
*/
public boolean onOk(Textbox textbox) { public boolean onOk(Textbox textbox) {
String text = textbox.getText(); String text = textbox.getText();
if (Util.isEmpty(text)) if (Util.isEmpty(text))
@ -374,11 +422,16 @@ public class DocumentSearchController implements EventListener<Event>{
result = (SearchResult) firstStart.getAttribute(SEARCH_RESULT); result = (SearchResult) firstStart.getAttribute(SEARCH_RESULT);
if (result != null) { if (result != null) {
doZoom(result); doZoom(result);
return true;
} }
return false; 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() { public SearchResult selectPrior() {
if (selected > 0) { if (selected > 0) {
selected--; selected--;
@ -399,6 +452,10 @@ public class DocumentSearchController implements EventListener<Event>{
return null; 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() { public SearchResult selectNext() {
if (selected < (list.size()-1)) { if (selected < (list.size()-1)) {
selected++; selected++;

View File

@ -64,7 +64,7 @@ import org.zkoss.zul.Div;
import org.zkoss.zul.South; import org.zkoss.zul.South;
/** /**
* * Window to capture feedback request from user.
* @author hengsin * @author hengsin
* *
*/ */
@ -77,13 +77,19 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
private static final CLogger log = CLogger.getCLogger(FeedbackRequestWindow.class); private static final CLogger log = CLogger.getCLogger(FeedbackRequestWindow.class);
/** Fields for {@link MRequest} **/
protected WTableDirEditor requestTypeField, priorityField, salesRepField; protected WTableDirEditor requestTypeField, priorityField, salesRepField;
protected Textbox txtSummary; protected Textbox txtSummary;
protected ConfirmPanel confirmPanel; protected ConfirmPanel confirmPanel;
/** attachments uploaded by user **/
protected List<DataSource> attachments = new ArrayList<DataSource>(); protected List<DataSource> attachments = new ArrayList<DataSource>();
/** Div to host list of {@link AttachmentItem} **/
protected Div attachmentBox; protected Div attachmentBox;
/**
* Default constructor
*/
public FeedbackRequestWindow() { public FeedbackRequestWindow() {
super(); super();
@ -114,6 +120,7 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
throw new RuntimeException(Msg.getMsg(Env.getCtx(), "AccessTableNoUpdate")); throw new RuntimeException(Msg.getMsg(Env.getCtx(), "AccessTableNoUpdate"));
} }
//layout window
Label lblRequestType = new Label(Msg.getElement(Env.getCtx(), "R_RequestType_ID")); Label lblRequestType = new Label(Msg.getElement(Env.getCtx(), "R_RequestType_ID"));
Label lblPriority = new Label(Msg.getElement(Env.getCtx(), "Priority")); Label lblPriority = new Label(Msg.getElement(Env.getCtx(), "Priority"));
Label lblSummary = new Label(Msg.getElement(Env.getCtx(), "Summary")); Label lblSummary = new Label(Msg.getElement(Env.getCtx(), "Summary"));
@ -236,6 +243,7 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
addAttachment(FeedbackManager.getLogAttachment(false), false); addAttachment(FeedbackManager.getLogAttachment(false), false);
} }
@Override
public void onEvent(Event e) throws Exception { public void onEvent(Event e) throws Exception {
if (e.getTarget() == confirmPanel.getButton(ConfirmPanel.A_OK)) { if (e.getTarget() == confirmPanel.getButton(ConfirmPanel.A_OK)) {
Clients.clearBusy(); Clients.clearBusy();
@ -271,6 +279,10 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
} }
} }
/**
* Save request
* @throws IOException
*/
protected void saveRequest() throws IOException { protected void saveRequest() throws IOException {
Trx trx = Trx.get(Trx.createTrxName("SaveNewRequest"), true); Trx trx = Trx.get(Trx.createTrxName("SaveNewRequest"), true);
trx.setDisplayName(getClass().getName()+"_saveRequest"); trx.setDisplayName(getClass().getName()+"_saveRequest");
@ -315,6 +327,11 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
} }
} }
/**
* Create new MRequest record.
* @param trx
* @return {@link MRequest}
*/
protected MRequest createMRequest(Trx trx) { protected MRequest createMRequest(Trx trx) {
MRequest request = new MRequest(Env.getCtx(), 0, trx.getTrxName()); MRequest request = new MRequest(Env.getCtx(), 0, trx.getTrxName());
request.setAD_Org_ID(Env.getAD_Org_ID(Env.getCtx())); request.setAD_Org_ID(Env.getAD_Org_ID(Env.getCtx()));
@ -325,6 +342,11 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
return request; return request;
} }
/**
* Add attachment from user.
* @param dataSource
* @param removable
*/
public void addAttachment(DataSource dataSource, boolean removable) { public void addAttachment(DataSource dataSource, boolean removable) {
attachments.add(dataSource); attachments.add(dataSource);
AttachmentItem item = new AttachmentItem(dataSource, attachments, removable); AttachmentItem item = new AttachmentItem(dataSource, attachments, removable);
@ -332,6 +354,11 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
getFirstChild().invalidate(); getFirstChild().invalidate();
} }
/**
* Get byte[] from media.
* @param media
* @return byte[]
*/
private byte[] getMediaData(Media media) { private byte[] getMediaData(Media media) {
byte[] bytes = null; byte[] bytes = null;
@ -358,6 +385,11 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
return bytes; return bytes;
} }
/**
* Get character set from contentType (i.e from charset=).
* @param contentType
* @return character set (default is UTF-8)
*/
private String getCharset(String contentType) { private String getCharset(String contentType) {
if (contentType != null) { if (contentType != null) {
int j = contentType.indexOf("charset="); int j = contentType.indexOf("charset=");

View File

@ -23,6 +23,7 @@ import org.adempiere.webui.component.Tabpanels;
import org.adempiere.webui.component.Tabs; import org.adempiere.webui.component.Tabs;
import org.adempiere.webui.util.DocumentSearch; import org.adempiere.webui.util.DocumentSearch;
import org.adempiere.webui.util.ZKUpdateUtil; import org.adempiere.webui.util.ZKUpdateUtil;
import org.compiere.model.MSearchDefinition;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Msg; import org.compiere.util.Msg;
import org.compiere.util.Util; import org.compiere.util.Util;
@ -37,19 +38,27 @@ import org.zkoss.zul.Bandpopup;
import org.zkoss.zul.Div; import org.zkoss.zul.Div;
/** /**
* Global search component at desktop header.
* @author hengsin * @author hengsin
*
*/ */
public class GlobalSearch extends Div implements EventListener<Event> { public class GlobalSearch extends Div implements EventListener<Event> {
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 = "/"; private static final String PREFIX_DOCUMENT_SEARCH = "/";
/** /**
@ -57,15 +66,20 @@ public class GlobalSearch extends Div implements EventListener<Event> {
*/ */
private static final long serialVersionUID = -8793878697269469837L; private static final long serialVersionUID = -8793878697269469837L;
/** Bandbox to capture search text from user and display result in popup **/
private Bandbox bandbox; private Bandbox bandbox;
/** controller to search AD_Menu **/
private MenuSearchController menuController; private MenuSearchController menuController;
/** controller to search tables **/
private DocumentSearchController docController; private DocumentSearchController docController;
/** tabbox to host menu and document search tab **/
private Tabbox tabbox; private Tabbox tabbox;
/** /**
* * @param menuController
*/ */
public GlobalSearch(MenuSearchController menuController) { public GlobalSearch(MenuSearchController menuController) {
this.menuController = menuController; this.menuController = menuController;
@ -73,11 +87,13 @@ public class GlobalSearch extends Div implements EventListener<Event> {
init(); init();
} }
/**
* Layout UI and setup listeners
*/
private void init() { private void init() {
bandbox = new Bandbox(); bandbox = new Bandbox();
bandbox.setSclass("global-search-box"); bandbox.setSclass("global-search-box");
appendChild(bandbox); appendChild(bandbox);
// ZKUpdateUtil.setWidth(bandbox, "100%");
bandbox.setAutodrop(true); bandbox.setAutodrop(true);
bandbox.setId("globalSearchBox"); bandbox.setId("globalSearchBox");
bandbox.addEventListener(Events.ON_CHANGING, this); bandbox.addEventListener(Events.ON_CHANGING, this);
@ -114,22 +130,24 @@ public class GlobalSearch extends Div implements EventListener<Event> {
tabPanels.appendChild(tabPanel); tabPanels.appendChild(tabPanel);
docController.create(tabPanel); docController.create(tabPanel);
addEventListener(ON_SEARCH, this); addEventListener(ON_SEARCH_EVENT, this);
addEventListener(ON_CREATE_ECHO, this); addEventListener(ON_CREATE_ECHO_EVENT, this);
bandbox.addEventListener(ON_ENTER_KEY, this); bandbox.addEventListener(ON_ENTER_KEY_EVENT, this);
addEventListener(ON_POST_ENTER_KEY, this); addEventListener(ON_POST_ENTER_KEY_EVENT, this);
} }
@Override @Override
public void onEvent(Event event) throws Exception { 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; InputEvent inputEvent = (InputEvent) event;
String value = inputEvent.getValue(); String value = inputEvent.getValue();
bandbox.setAttribute("last.onchanging", value); bandbox.setAttribute(LAST_ONCHANGING_ATTR, value);
Events.postEvent(ON_SEARCH, this, value); Events.postEvent(ON_SEARCH_EVENT, this, value);
} else if (Events.ON_CHANGE.equals(event.getName())) { } 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())) { } else if (Events.ON_CTRL_KEY.equals(event.getName())) {
//handle keyboard navigation for bandbox items
KeyEvent ke = (KeyEvent) event; KeyEvent ke = (KeyEvent) event;
if (ke.getKeyCode() == KeyEvent.UP) { if (ke.getKeyCode() == KeyEvent.UP) {
if (bandbox.getFirstChild().isVisible()) { if (bandbox.getFirstChild().isVisible()) {
@ -160,28 +178,30 @@ public class GlobalSearch extends Div implements EventListener<Event> {
} }
} }
} }
} else if (event.getName().equals(ON_SEARCH)) { } else if (event.getName().equals(ON_SEARCH_EVENT)) {
String value = (String) event.getData(); String value = (String) event.getData();
if (tabbox.getSelectedIndex()==0) if (tabbox.getSelectedIndex()==0)
menuController.search(value); menuController.search(value);
else else
docController.search(value); docController.search(value);
bandbox.focus(); 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('#") StringBuilder script = new StringBuilder("jq('#")
.append(bandbox.getUuid()) .append(bandbox.getUuid())
.append("').bind('keydown', function(e) {let code=e.keyCode||e.which;if(code==13){") .append("').bind('keydown', function(e) {let code=e.keyCode||e.which;if(code==13){")
.append("let widget=zk.Widget.$(this);") .append("let widget=zk.Widget.$(this);")
.append("let event=new zk.Event(widget,'") .append("let event=new zk.Event(widget,'")
.append(ON_ENTER_KEY) .append(ON_ENTER_KEY_EVENT)
.append("',{},{toServer:true});") .append("',{},{toServer:true});")
.append("zAu.send(event);") .append("zAu.send(event);")
.append("}});"); .append("}});");
Clients.evalJavaScript(script.toString()); 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); Clients.showBusy(bandbox, null);
Events.echoEvent(ON_POST_ENTER_KEY, this, null); Events.echoEvent(ON_POST_ENTER_KEY_EVENT, this, null);
} else if (event.getName().equals(ON_POST_ENTER_KEY)) { } else if (event.getName().equals(ON_POST_ENTER_KEY_EVENT)) {
//execute search trigger by press of enter key
Clients.clearBusy(bandbox); Clients.clearBusy(bandbox);
if (bandbox.getValue() != null && bandbox.getValue().startsWith(PREFIX_DOCUMENT_SEARCH)) { if (bandbox.getValue() != null && bandbox.getValue().startsWith(PREFIX_DOCUMENT_SEARCH)) {
DocumentSearch search = new DocumentSearch(); DocumentSearch search = new DocumentSearch();
@ -195,11 +215,11 @@ public class GlobalSearch extends Div implements EventListener<Event> {
} }
} }
} else if (event.getName().equals(Events.ON_SELECT)) { } 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) { if (value == null) {
value = bandbox.getValue(); 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<Event> {
@Override @Override
public void onPageAttached(Page newpage, Page oldpage) { public void onPageAttached(Page newpage, Page oldpage) {
super.onPageAttached(newpage, 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() { public void closePopup() {
if (bandbox != null) { if (bandbox != null) {
bandbox.close(); bandbox.close();
} }
} }
/**
* Handle client info event from browser.
*/
public void onClientInfo() { public void onClientInfo() {
ZKUpdateUtil.setWindowHeightX(bandbox.getDropdown(), ClientInfo.get().desktopHeight-50); ZKUpdateUtil.setWindowHeightX(bandbox.getDropdown(), ClientInfo.get().desktopHeight-50);
} }

View File

@ -38,15 +38,21 @@ import org.zkoss.zul.Center;
import org.zkoss.zul.Div; import org.zkoss.zul.Div;
import org.zkoss.zul.Html; import org.zkoss.zul.Html;
/**
* Help for AD Window with contents generated from AD definition.
*/
public class HelpWindow extends Window { public class HelpWindow extends Window {
/** /**
* * generated serial id
*/ */
private static final long serialVersionUID = -7353411576541612026L; private static final long serialVersionUID = -7353411576541612026L;
private GridWindow gridWindow; private GridWindow gridWindow;
private String winpref; private String winpref;
/**
* @param gridWindow
*/
public HelpWindow(GridWindow gridWindow) public HelpWindow(GridWindow gridWindow)
{ {
super(); super();
@ -95,6 +101,9 @@ public class HelpWindow extends Window {
html.setContent(doc.toString()); html.setContent(doc.toString());
} }
/**
* @return header {@link table}
*/
private table getHeader() private table getHeader()
{ {
table table = new table("0", "0", "0", "100%", null); table table = new table("0", "0", "0", "100%", null);
@ -180,6 +189,9 @@ public class HelpWindow extends Window {
return table; return table;
} }
/**
* @return content {@link table}
*/
private table getContent() private table getContent()
{ {
table table = new table("0", "0", "0", "100%", null); table table = new table("0", "0", "0", "100%", null);
@ -202,6 +214,9 @@ public class HelpWindow extends Window {
return table; return table;
} }
/**
* @return content {@link table} for left pane
*/
private table getLeftContent() private table getLeftContent()
{ {
table table = new table("0", "0", "0", "100%", null); table table = new table("0", "0", "0", "100%", null);
@ -223,6 +238,9 @@ public class HelpWindow extends Window {
return table; return table;
} }
/**
* @return content {@link table} for right pane
*/
private table getRightContent() private table getRightContent()
{ {
table table = new table("0", "0", "0", "100%", null); table table = new table("0", "0", "0", "100%", null);
@ -273,6 +291,12 @@ public class HelpWindow extends Window {
return table; 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) private table getTabBox(GridTab tab, int tabIndex)
{ {
table table = new table("0", "0", "0", "100%", null); table table = new table("0", "0", "0", "100%", null);
@ -326,6 +350,12 @@ public class HelpWindow extends Window {
return table; 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) private table getFieldsBox(GridTab tab, int tabIndex)
{ {
table table = new table("0", "0", "0", "100%", null); table table = new table("0", "0", "0", "100%", null);
@ -383,6 +413,13 @@ public class HelpWindow extends Window {
return table; 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) private table getFieldBox(GridField field, int tabIndex, int fieldIndex)
{ {
table table = new table("0", "0", "0", "100%", null); table table = new table("0", "0", "0", "100%", null);

View File

@ -17,7 +17,7 @@ import org.adempiere.webui.editor.WEditor;
/** /**
* Listener interface for process parameter panel. * Listener interface for process parameter panel.
* Implementation must be thread safe * Implementation must be thread safe.
* @author hengsin * @author hengsin
* *
*/ */

View File

@ -42,16 +42,29 @@ import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.Bandpopup; import org.zkoss.zul.Bandpopup;
import org.zkoss.zul.Div; import org.zkoss.zul.Div;
public class LabelsSearch extends Div implements EventListener<Event> { /**
* Component to search AD_Label* records.
*/
public class LabelsSearch extends Div implements EventListener<Event> {
/**
* generated serial id
*/
private static final long serialVersionUID = -8793878697269469837L; private static final long serialVersionUID = -8793878697269469837L;
private static final String ON_ENTER_KEY = "onEnterKey"; /** Event send from client side upon keyDown of enter key **/
private static final String ON_CREATE_ECHO = "onCreateEcho"; private static final String ON_ENTER_KEY_EVENT = "onEnterKey";
private static final String ON_SEARCH = "onSearch"; /** Event echo from {@link #onPageAttached(Page, Page)} **/
private Bandbox bandbox; 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; private LabelsSearchController controller;
/** /**
* Standard constructot * Standard constructor
* @param controller * @param controller
*/ */
public LabelsSearch(LabelsSearchController controller) { public LabelsSearch(LabelsSearchController controller) {
@ -59,6 +72,9 @@ public class LabelsSearch extends Div implements EventListener<Event> {
init(); init();
} }
/**
* Layout UI and setup listeners
*/
private void init() { private void init() {
bandbox = new Bandbox(); bandbox = new Bandbox();
appendChild(bandbox); appendChild(bandbox);
@ -77,22 +93,24 @@ public class LabelsSearch extends Div implements EventListener<Event> {
bandbox.appendChild(popup); bandbox.appendChild(popup);
controller.create(popup); controller.create(popup);
addEventListener(ON_SEARCH, this); addEventListener(ON_SEARCH_EVENT, this);
addEventListener(ON_CREATE_ECHO, this); addEventListener(ON_CREATE_ECHO_EVENT, this);
addEventListener(LabelsSearchController.ON_POST_SELECT_LABELITEM_EVENT, this); addEventListener(LabelsSearchController.ON_POST_SELECT_LABELITEM_EVENT, this);
bandbox.addEventListener(ON_ENTER_KEY, this); bandbox.addEventListener(ON_ENTER_KEY_EVENT, this);
} }
@Override @Override
public void onEvent(Event event) throws Exception { 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; InputEvent inputEvent = (InputEvent) event;
String value = inputEvent.getValue(); String value = inputEvent.getValue();
bandbox.setAttribute("last.onchanging", value); bandbox.setAttribute(LAST_ONCHANGING_ATTR, value);
Events.postEvent(ON_SEARCH, this, value); Events.postEvent(ON_SEARCH_EVENT, this, value);
} else if (Events.ON_CHANGE.equals(event.getName())) { } 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())) { } else if (Events.ON_CTRL_KEY.equals(event.getName())) {
//handle keyboard navigation for bandbox items
KeyEvent ke = (KeyEvent) event; KeyEvent ke = (KeyEvent) event;
if (ke.getKeyCode() == KeyEvent.UP) { if (ke.getKeyCode() == KeyEvent.UP) {
if (bandbox.getFirstChild().isVisible()) { if (bandbox.getFirstChild().isVisible()) {
@ -111,32 +129,33 @@ public class LabelsSearch extends Div implements EventListener<Event> {
} }
} }
} }
} else if (event.getName().equals(ON_SEARCH)) { } else if (event.getName().equals(ON_SEARCH_EVENT)) {
String value = (String) event.getData(); String value = (String) event.getData();
controller.search(value); controller.search(value);
bandbox.focus(); 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('#") StringBuilder script = new StringBuilder("jq('#")
.append(bandbox.getUuid()) .append(bandbox.getUuid())
.append("').bind('keydown', function(e) {var code=e.keyCode||e.which;if(code==13){") .append("').bind('keydown', function(e) {var code=e.keyCode||e.which;if(code==13){")
.append("var widget=zk.Widget.$(this);") .append("var widget=zk.Widget.$(this);")
.append("var event=new zk.Event(widget,'") .append("var event=new zk.Event(widget,'")
.append(ON_ENTER_KEY) .append(ON_ENTER_KEY_EVENT)
.append("',{},{toServer:true});") .append("',{},{toServer:true});")
.append("zAu.send(event);") .append("zAu.send(event);")
.append("}});"); .append("}});");
Clients.evalJavaScript(script.toString()); 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) { if (event.getTarget() instanceof Bandbox) {
controller.onSelect(controller.getSelectedItem()); controller.onSelect(controller.getSelectedItem());
} }
} else if (event.getName().equals(Events.ON_SELECT)) { } 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) { if (value == null) {
value = bandbox.getValue(); 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)) { if (event.getName().equals(LabelsSearchController.ON_POST_SELECT_LABELITEM_EVENT)) {
@ -150,11 +169,11 @@ public class LabelsSearch extends Div implements EventListener<Event> {
@Override @Override
public void onPageAttached(Page newpage, Page oldpage) { public void onPageAttached(Page newpage, Page oldpage) {
super.onPageAttached(newpage, 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() { public void closePopup() {
if (bandbox != null) { if (bandbox != null) {
@ -163,7 +182,7 @@ public class LabelsSearch extends Div implements EventListener<Event> {
} }
/** /**
* Set height of the search dropdown * Set height {@link #bandbox} dropdown
*/ */
public void onClientInfo() { public void onClientInfo() {
ZKUpdateUtil.setWindowHeightX(bandbox.getDropdown(), ClientInfo.get().desktopHeight-50); ZKUpdateUtil.setWindowHeightX(bandbox.getDropdown(), ClientInfo.get().desktopHeight-50);

View File

@ -56,14 +56,25 @@ import org.zkoss.zul.ListitemRenderer;
import org.zkoss.zul.ListitemRendererExt; import org.zkoss.zul.ListitemRendererExt;
import org.zkoss.zul.Vlayout; import org.zkoss.zul.Vlayout;
/**
* Controller for search on AD_Label* records.
*/
public class LabelsSearchController implements EventListener<Event>{ public class LabelsSearchController implements EventListener<Event>{
/** Event echo from {@link #onSelect(LabelItem)} **/
public static final String ON_POST_SELECT_LABELITEM_EVENT = "onPostSelectLabelitem"; public static final String ON_POST_SELECT_LABELITEM_EVENT = "onPostSelectLabelitem";
private static final String ON_SEARCH_ECHO = "onSearchEcho"; /** Event echo to initiate search for a given input text **/
private static final String ON_LOAD_MORE = "onLoadMore"; 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; private Component parent;
/** Listbox to display search result **/
private Listbox listbox; private Listbox listbox;
/** model for {@link #listbox} **/
private ListModelList<LabelItem> model; private ListModelList<LabelItem> model;
/** main layout **/
private Vlayout layout; private Vlayout layout;
/** label window panel, provider for AD_Table_ID and Record_ID **/
private LabelsPanel labelsPanel; private LabelsPanel labelsPanel;
/** /**
@ -103,13 +114,13 @@ public class LabelsSearchController implements EventListener<Event>{
ZKUpdateUtil.setWidth(listheader, "30px"); ZKUpdateUtil.setWidth(listheader, "30px");
listhead.appendChild(listheader); listhead.appendChild(listheader);
layout.addEventListener(ON_SEARCH_ECHO, this); layout.addEventListener(ON_SEARCH_ECHO_EVENT, this);
layout.addEventListener(ON_LOAD_MORE, this); layout.addEventListener(ON_LOAD_MORE_EVENT, this);
} }
@Override @Override
public void onEvent(Event event) throws Exception { 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()); onSearchEcho((String) event.getData());
} else if (Events.ON_CLICK.equals(event.getName())) { } else if (Events.ON_CLICK.equals(event.getName())) {
if (event.getTarget() instanceof ListItem) { if (event.getTarget() instanceof ListItem) {
@ -121,16 +132,16 @@ public class LabelsSearchController implements EventListener<Event>{
} }
/** /**
* Search for a given text * Echo {@link #ON_SEARCH_ECHO_EVENT} to initiate search for value
* @param value * @param value
*/ */
public void search(String value) { public void search(String value) {
listbox.setModel((ListModel<?>)null); 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 * @param value
*/ */
public void onSearchEcho(String value) { public void onSearchEcho(String value) {

View File

@ -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; package org.adempiere.webui.apps;
import org.zkoss.zul.DefaultTreeNode;
import org.zkoss.zul.Treeitem;
/** /**
* Value object for AD_Menu.
* <br/>
* Use by {@link GlobalSearch} and {@link MenuSearchController}.
* @author hengsin * @author hengsin
*
*/ */
public class MenuItem { public class MenuItem {
private String label; private String label;
private String description; private String description;
private String image; private String image;
/** report, process, workflow, form, info or window **/
private String type; private String type;
/** Corresponding {@link Treeitem} or {@link DefaultTreeNode} **/
private Object data; private Object data;
/** /**
* * default constructor
*/ */
public MenuItem() { public MenuItem() {
} }

View File

@ -55,41 +55,60 @@ import org.zkoss.zul.Textbox;
import org.zkoss.zul.Tree; import org.zkoss.zul.Tree;
import org.zkoss.zul.Treechildren; import org.zkoss.zul.Treechildren;
import org.zkoss.zul.Treeitem; import org.zkoss.zul.Treeitem;
import org.zkoss.zul.Treerow;
import org.zkoss.zul.Vlayout; import org.zkoss.zul.Vlayout;
import org.zkoss.zul.impl.LabelElement; import org.zkoss.zul.impl.LabelElement;
import org.zkoss.zul.impl.LabelImageElement; import org.zkoss.zul.impl.LabelImageElement;
/** /**
* Controller for search on AD_Menu records.
* @author hengsin * @author hengsin
*
*/ */
public class MenuSearchController implements EventListener<Event>{ public class MenuSearchController implements EventListener<Event>{
/** Component attribute to hold reference of {@link MTreeNode} **/
public static final String M_TREE_NODE_ATTR = "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"; 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 Z_ICON_STAR = "z-icon-star";
private static final String ON_SEARCH_ECHO = "onSearchEcho"; /** Event echo from {@link #search(String)} to initiate search action **/
private static final String ON_LOAD_MORE = "onLoadMore"; private static final String ON_SEARCH_ECHO_EVENT = "onSearchEcho";
private static final String ONSELECT_TIMESTAMP = "onselect.timestamp"; /** 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"; private static final String STAR_BUTTON_NAME = "Star";
/** name of new button **/
private static final String NEW_BUTTON_NAME = "New"; private static final String NEW_BUTTON_NAME = "New";
/** tree for AD_Menu **/
private Tree tree; private Tree tree;
/** list box for menu items **/
private Listbox listbox; private Listbox listbox;
/** model for all menu items **/
private ListModelList<MenuItem> model; private ListModelList<MenuItem> model;
/** main layout component. parent of {@link #listbox}. **/
private Vlayout layout; private Vlayout layout;
/** model for all menu items **/
private ListModelList<MenuItem> fullModel; private ListModelList<MenuItem> fullModel;
/** true when controller is handling event from Star/Favourite button **/
private boolean inStarEvent; private boolean inStarEvent;
/** Event post from {@link #selectTreeitem(Object, Boolean)} **/
private static final String ON_POST_SELECT_TREEITEM_EVENT = "onPostSelectTreeitem"; private static final String ON_POST_SELECT_TREEITEM_EVENT = "onPostSelectTreeitem";
/** /**
* * @param tree
*/ */
public MenuSearchController(Tree tree) { public MenuSearchController(Tree tree) {
this.tree = tree; this.tree = tree;
} }
/**
* Populate {@link #model} from {@link #tree}
*/
public void refreshModel() { public void refreshModel() {
final List<MenuItem> list = new ArrayList<MenuItem>(); final List<MenuItem> list = new ArrayList<MenuItem>();
if (tree.getModel() == null) { if (tree.getModel() == null) {
@ -116,6 +135,11 @@ public class MenuSearchController implements EventListener<Event>{
}, true); }, true);
} }
/**
* Add treeNode to list
* @param list
* @param treeNode
*/
private void addTreeItem(List<MenuItem> list, DefaultTreeNode<?> treeNode) { private void addTreeItem(List<MenuItem> list, DefaultTreeNode<?> treeNode) {
MTreeNode mNode = (MTreeNode) treeNode.getData(); MTreeNode mNode = (MTreeNode) treeNode.getData();
if (!mNode.isLeaf()) if (!mNode.isLeaf())
@ -129,6 +153,10 @@ public class MenuSearchController implements EventListener<Event>{
list.add(item); list.add(item);
} }
/**
* @param treeItem
* @return true if treeItem is a folder
*/
private boolean isFolder(Treeitem treeItem) { private boolean isFolder(Treeitem treeItem) {
List<Component> list = treeItem.getChildren(); List<Component> list = treeItem.getChildren();
for (Component c : list) { for (Component c : list) {
@ -139,6 +167,11 @@ public class MenuSearchController implements EventListener<Event>{
return false; return false;
} }
/**
* Add treeItem to list
* @param list
* @param treeItem
*/
private void addTreeItem(List<MenuItem> list, Treeitem treeItem) { private void addTreeItem(List<MenuItem> list, Treeitem treeItem) {
if (isFolder(treeItem)) if (isFolder(treeItem))
return; return;
@ -158,6 +191,10 @@ public class MenuSearchController implements EventListener<Event>{
item.setType((String) treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE)); item.setType((String) treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE));
} }
/**
* @param treeItem
* @return label for treeItem
*/
private String getLabel(Treeitem treeItem) { private String getLabel(Treeitem treeItem) {
String label = treeItem.getLabel(); String label = treeItem.getLabel();
if (label == null || label.trim().length() == 0) if (label == null || label.trim().length() == 0)
@ -172,6 +209,10 @@ public class MenuSearchController implements EventListener<Event>{
return label; return label;
} }
/**
* @param treeItem
* @return image url or font icon sclass (start with z-icon)
*/
private String getImage(Treeitem treeItem) { private String getImage(Treeitem treeItem) {
String image = treeItem.getImage(); String image = treeItem.getImage();
if (image == null || image.trim().length() == 0) if (image == null || image.trim().length() == 0)
@ -189,6 +230,10 @@ public class MenuSearchController implements EventListener<Event>{
return image != null ? image.intern() : null; return image != null ? image.intern() : null;
} }
/**
* Call {@link #refreshModel()} and layout UI.
* @param parent
*/
public void create(Component parent) { public void create(Component parent) {
refreshModel(); refreshModel();
@ -220,8 +265,8 @@ public class MenuSearchController implements EventListener<Event>{
ZKUpdateUtil.setWidth(listheader, "28px"); ZKUpdateUtil.setWidth(listheader, "28px");
listhead.appendChild(listheader); listhead.appendChild(listheader);
layout.addEventListener(ON_SEARCH_ECHO, this); layout.addEventListener(ON_SEARCH_ECHO_EVENT, this);
layout.addEventListener(ON_LOAD_MORE, this); layout.addEventListener(ON_LOAD_MORE_EVENT, this);
updateListboxModel(model); updateListboxModel(model);
FavouriteController controller = FavouriteController.getInstance(Executions.getCurrent().getSession()); FavouriteController controller = FavouriteController.getInstance(Executions.getCurrent().getSession());
@ -240,7 +285,7 @@ public class MenuSearchController implements EventListener<Event>{
} else if (Events.ON_CLICK.equals(event.getName())) { } else if (Events.ON_CLICK.equals(event.getName())) {
if (event.getTarget() instanceof ListItem) { if (event.getTarget() instanceof ListItem) {
ListItem item = (ListItem) event.getTarget(); ListItem item = (ListItem) event.getTarget();
Long onSelect = (Long) item.getAttribute(ONSELECT_TIMESTAMP); Long onSelect = (Long) item.getAttribute(ONSELECT_TIMESTAMP_ATTR);
if (onSelect == null) { if (onSelect == null) {
onSelect(item, Boolean.FALSE); onSelect(item, Boolean.FALSE);
} else if (System.currentTimeMillis() - onSelect.longValue() > 1000) { } else if (System.currentTimeMillis() - onSelect.longValue() > 1000) {
@ -276,9 +321,9 @@ public class MenuSearchController implements EventListener<Event>{
inStarEvent = false; inStarEvent = false;
} }
} }
} else if (event.getName().equals(ON_SEARCH_ECHO)) { } else if (event.getName().equals(ON_SEARCH_ECHO_EVENT)) {
onSearchEcho((String) event.getData()); onSearchEcho((String) event.getData());
} else if (event.getName().equals(ON_LOAD_MORE)) { } else if (event.getName().equals(ON_LOAD_MORE_EVENT)) {
loadMore(); loadMore();
} }
} }
@ -297,13 +342,19 @@ public class MenuSearchController implements EventListener<Event>{
listbox.setModel(t); 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) { private void onSelect(ListItem selected, Boolean newRecord) {
MenuItem item = selected.getValue(); MenuItem item = selected.getValue();
if (item == null) return; if (item == null) return;
if ("...".equals(item.getType())) { if ("...".equals(item.getType())) {
selected.setAttribute(ONSELECT_TIMESTAMP, System.currentTimeMillis()); selected.setAttribute(ONSELECT_TIMESTAMP_ATTR, System.currentTimeMillis());
Clients.showBusy(selected, null); Clients.showBusy(selected, null);
Events.echoEvent(ON_LOAD_MORE, layout, null); Events.echoEvent(ON_LOAD_MORE_EVENT, layout, null);
} else { } else {
if (newRecord) { if (newRecord) {
Treeitem ti = (Treeitem)item.getData(); Treeitem ti = (Treeitem)item.getData();
@ -312,10 +363,14 @@ public class MenuSearchController implements EventListener<Event>{
newRecord = false; newRecord = false;
} }
selectTreeitem(item.getData(), newRecord); 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() { private void loadMore() {
ListModel<MenuItem> listModel = listbox.getModel(); ListModel<MenuItem> listModel = listbox.getModel();
ListModelList<MenuItem> lml = (ListModelList<MenuItem>) listModel; ListModelList<MenuItem> lml = (ListModelList<MenuItem>) listModel;
@ -327,6 +382,11 @@ public class MenuSearchController implements EventListener<Event>{
Clients.scrollIntoView(listbox.getSelectedItem()); 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) { private void selectTreeitem(Object node, Boolean newRecord) {
if (Executions.getCurrent().getAttribute(listbox.getUuid()+".selectTreeitem") != null) if (Executions.getCurrent().getAttribute(listbox.getUuid()+".selectTreeitem") != null)
return; return;
@ -350,6 +410,10 @@ public class MenuSearchController implements EventListener<Event>{
} }
} }
/**
* Make sure all parent node is open and ensure tree selected item is selectedItem
* @param selectedItem
*/
private void select(Treeitem selectedItem) { private void select(Treeitem selectedItem) {
Treeitem parent = selectedItem.getParentItem(); Treeitem parent = selectedItem.getParentItem();
while (parent != null) { while (parent != null) {
@ -361,6 +425,11 @@ public class MenuSearchController implements EventListener<Event>{
selectedItem.getTree().setSelectedItem(selectedItem); 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) { private void onPostSelectTreeitem(Boolean newRecord) {
Event event = null; Event event = null;
if (tree.getSelectedItem().getTreerow().getFirstChild().getFirstChild() instanceof A) if (tree.getSelectedItem().getTreerow().getFirstChild().getFirstChild() instanceof A)
@ -374,11 +443,19 @@ public class MenuSearchController implements EventListener<Event>{
Events.postEvent(event); Events.postEvent(event);
} }
/**
* Echo {@link #ON_SEARCH_ECHO_EVENT} to initial search with value.
* @param value
*/
public void search(String value) { public void search(String value) {
listbox.setModel((ListModel<?>)null); 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) { public void onSearchEcho(String value) {
ListModelList<MenuItem> newModel = null; ListModelList<MenuItem> newModel = null;
if (Util.isEmpty(value)) { if (Util.isEmpty(value)) {
@ -391,6 +468,12 @@ public class MenuSearchController implements EventListener<Event>{
updateListboxModel(newModel); 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<MenuItem> newModel) { private void updateListboxModel(ListModelList<MenuItem> newModel) {
fullModel = null; fullModel = null;
if (newModel.size() > 50) { if (newModel.size() > 50) {
@ -406,10 +489,20 @@ public class MenuSearchController implements EventListener<Event>{
listbox.setModel(newModel); listbox.setModel(newModel);
} }
/**
* Comparator to help filter menu items with a filter value.
*/
private class MenuListComparator implements Comparator<MenuItem> { private class MenuListComparator implements Comparator<MenuItem> {
/**
* Text to filter menu items by label.
* Use startsWith if length of compare is < 3, otherwise use contains for filter.
*/
private String compare; private String compare;
/**
* @param compare filter text
*/
private MenuListComparator(String compare) { private MenuListComparator(String compare) {
this.compare = Util.deleteAccents(compare.toLowerCase().trim()); this.compare = Util.deleteAccents(compare.toLowerCase().trim());
} }
@ -431,6 +524,10 @@ public class MenuSearchController implements EventListener<Event>{
} }
/**
* select ListItem that comes before the current selected ListItem.
* @return new selected {@link MenuItem}
*/
public MenuItem selectPrior() { public MenuItem selectPrior() {
int i = listbox.getSelectedIndex(); int i = listbox.getSelectedIndex();
if (i > 0) { if (i > 0) {
@ -444,6 +541,10 @@ public class MenuSearchController implements EventListener<Event>{
return null; return null;
} }
/**
* select ListItem that comes after the current selected ListItem.
* @return new selected {@link MenuItem}
*/
public MenuItem selectNext() { public MenuItem selectNext() {
int i = listbox.getSelectedIndex(); int i = listbox.getSelectedIndex();
if (i < 0 && listbox.getItemCount() > 0) { if (i < 0 && listbox.getItemCount() > 0) {
@ -467,6 +568,11 @@ public class MenuSearchController implements EventListener<Event>{
return null; 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) { public boolean onOk(Textbox textbox) {
String text = textbox.getText(); String text = textbox.getText();
if (Util.isEmpty(text)) if (Util.isEmpty(text))
@ -498,6 +604,9 @@ public class MenuSearchController implements EventListener<Event>{
return false; return false;
} }
/**
* {@link ListitemRenderer} for {@link #listbox}
*/
private class MenuItemRenderer implements ListitemRenderer<MenuItem>, ListitemRendererExt { private class MenuItemRenderer implements ListitemRenderer<MenuItem>, ListitemRendererExt {
private static final String REMOVE_FROM_FAVOURITES_MSG = "RemoveFromFavourites"; private static final String REMOVE_FROM_FAVOURITES_MSG = "RemoveFromFavourites";
private static final String ADD_TO_FAVOURITES_MSG = "AddToFavourites"; private static final String ADD_TO_FAVOURITES_MSG = "AddToFavourites";

View File

@ -78,7 +78,7 @@ import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfWriter; import com.lowagie.text.pdf.PdfWriter;
/** /**
* Dialog to Start process or report. * Embedded Dialog to Start process or report.
* Displays information about the process * Displays information about the process
* and lets the user decide to start it * and lets the user decide to start it
* and displays results (optionally print them). * and displays results (optionally print them).
@ -90,30 +90,42 @@ import com.lowagie.text.pdf.PdfWriter;
public class ProcessDialog extends AbstractProcessDialog implements EventListener<Event>, IHelpContext public class ProcessDialog extends AbstractProcessDialog implements EventListener<Event>, IHelpContext
{ {
/** /**
* * generated serial id
*/ */
private static final long serialVersionUID = -6728929130788829223L; private static final long serialVersionUID = -6728929130788829223L;
public static final String ON_INITIAL_FOCUS_EVENT = "onInitialFocus"; 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 */ /** Logger */
private static final CLogger log = CLogger.getCLogger(ProcessDialog.class); private static final CLogger log = CLogger.getCLogger(ProcessDialog.class);
// //
/** message from {@link ProcessInfoLog} **/
private Table logMessageTable; private Table logMessageTable;
private int[] m_ids = null; /** record ids from {@link ProcessInfo} **/
private int[] m_ids = null;
/** true if dialog is showing process parameters **/
private boolean isParameterPage = true; private boolean isParameterPage = true;
private Mask mask; private Mask mask;
/** layout for process execution result **/
private HtmlBasedComponent resultPanelLayout; private HtmlBasedComponent resultPanelLayout;
/** process message content of {@link #resultPanelLayout} **/
private HtmlBasedComponent messageResultContent; private HtmlBasedComponent messageResultContent;
/** process log content of {@link #resultPanelLayout}, host {@link #logMessageTable} **/
private HtmlBasedComponent infoResultContent; private HtmlBasedComponent infoResultContent;
/** Window No */ /** Window No */
private int m_WindowNo = -1; private int m_WindowNo = -1;
/** timestamp of previous key event **/
private long prevKeyEventTime = 0; private long prevKeyEventTime = 0;
/**
* Previous key event. use together with {@link #prevKeyEventTime} to detect double firing of key event from browser.
*/
private KeyEvent prevKeyEvent; private KeyEvent prevKeyEvent;
/** /**
@ -134,7 +146,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
*/ */
public ProcessDialog (int AD_Process_ID, boolean isSOTrx, String predefinedContextVariables) 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); m_WindowNo = SessionManager.getAppDesktop().registerWindow(this);
this.setAttribute(IDesktop.WINDOWNO_ATTRIBUTE, m_WindowNo); this.setAttribute(IDesktop.WINDOWNO_ATTRIBUTE, m_WindowNo);
Env.setContext(Env.getCtx(), m_WindowNo, "IsSOTrx", isSOTrx ? "Y" : "N"); Env.setContext(Env.getCtx(), m_WindowNo, "IsSOTrx", isSOTrx ? "Y" : "N");
@ -145,7 +157,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
querySaved(); querySaved();
addEventListener(WindowContainer.ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT, this); addEventListener(WindowContainer.ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT, this);
addEventListener(ON_INITIAL_FOCUS_EVENT, this); addEventListener(ON_INITIAL_FOCUS_EVENT, this);
addEventListener(ON_OK_ECHO, this); addEventListener(ON_OK_ECHO_EVENT, this);
} }
catch(Exception ex) catch(Exception ex)
{ {
@ -188,7 +200,8 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
super.dispose(); super.dispose();
SessionManager.getAppDesktop().closeWindow(getWindowNo()); SessionManager.getAppDesktop().closeWindow(getWindowNo());
}// dispose }// dispose
@Override
public void onEvent(Event event) { public void onEvent(Event event) {
Component component = event.getTarget(); Component component = event.getTarget();
@ -198,7 +211,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
super.onEvent(event); super.onEvent(event);
onOk(); onOk();
} else if (event.getName().equals(ON_OK_ECHO)) { } else if (event.getName().equals(ON_OK_ECHO_EVENT)) {
onOk(); onOk();
}else if (bCancel.equals(component)){ }else if (bCancel.equals(component)){
super.onEvent(event); super.onEvent(event);
@ -236,12 +249,15 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
} }
} }
/**
* Handle ON_Click event from {@link #bOK}
*/
private void onOk() { private void onOk() {
if (isParameterPage) if (isParameterPage)
{ {
if (getParameterPanel().isWaitingForDialog()) if (getParameterPanel().isWaitingForDialog())
{ {
Events.echoEvent(ON_OK_ECHO, this, null); Events.echoEvent(ON_OK_ECHO_EVENT, this, null);
return; return;
} }
startProcess(); startProcess();
@ -250,6 +266,10 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
restart(); restart();
} }
/**
* Handle shortcut key event
* @param keyEvent
*/
private void onCtrlKeyEvent(KeyEvent keyEvent) { private void onCtrlKeyEvent(KeyEvent keyEvent) {
if (keyEvent.isAltKey() && keyEvent.getKeyCode() == 0x58) { // Alt-X if (keyEvent.isAltKey() && keyEvent.getKeyCode() == 0x58) { // Alt-X
if (m_WindowNo > 0) { 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) { private void doOnClick(A btn) {
int Record_ID = 0; int Record_ID = 0;
int AD_Table_ID =0; int AD_Table_ID =0;
@ -272,8 +296,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
catch (Exception e) { 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); AEnv.zoom(AD_Table_ID, Record_ID);
} }
} }
@ -286,6 +309,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
LayoutUtils.openOverlappedWindow(this, progressWindow, "middle_center"); LayoutUtils.openOverlappedWindow(this, progressWindow, "middle_center");
} }
/**
* @return in progress mask
*/
private Div getMask() { private Div getMask() {
if (mask == null) { if (mask == null) {
mask = new Mask(); mask = new Mask();
@ -293,9 +319,14 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
return mask; return mask;
} }
/**
* show in progress mask
* @param window
*/
private void showBusyMask(Window window) { private void showBusyMask(Window window) {
if (getParent() != null) { if (getParent() != null) {
getParent().appendChild(getMask()); 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.$('#"); StringBuilder script = new StringBuilder("(function(){let w=zk.Widget.$('#");
script.append(getParent().getUuid()).append("');"); script.append(getParent().getUuid()).append("');");
if (window != null) { if (window != null) {
@ -308,6 +339,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
} }
} }
/**
* close in progress mask
*/
private void hideBusyMask() private void hideBusyMask()
{ {
if (mask != null && mask.getParent() != null) { if (mask != null && mask.getParent() != null) {
@ -333,6 +367,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
swithToFinishScreen(); swithToFinishScreen();
} }
/**
* Switch to process execution result panel.
*/
protected void swithToFinishScreen() { protected void swithToFinishScreen() {
ProcessInfo pi = getProcessInfo(); ProcessInfo pi = getProcessInfo();
ProcessInfoUtil.setLogFromDB(pi); ProcessInfoUtil.setLogFromDB(pi);
@ -375,6 +412,10 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
Clients.response(new AuEcho(this, "onAfterProcess", null)); Clients.response(new AuEcho(this, "onAfterProcess", null));
} }
/**
* layout process execution result panel
* @param topParameterLayout
*/
private void layoutResultPanel (HtmlBasedComponent topParameterLayout){ private void layoutResultPanel (HtmlBasedComponent topParameterLayout){
if (resultPanelLayout == null){ if (resultPanelLayout == null){
resultPanelLayout = new Vlayout(); 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) { protected void replaceComponent(HtmlBasedComponent newComponent, HtmlBasedComponent oldComponent) {
oldComponent.getParent().insertBefore(newComponent, oldComponent); oldComponent.getParent().insertBefore(newComponent, oldComponent);
oldComponent.detach(); oldComponent.detach();
} }
/**
* append m_logs content to {@link #logMessageTable}
* @param m_logs
* @param infoResultContent
*/
private void appendRecordLogInfo(ProcessInfoLog[] m_logs, HtmlBasedComponent infoResultContent) { private void appendRecordLogInfo(ProcessInfoLog[] m_logs, HtmlBasedComponent infoResultContent) {
if (m_logs == null) if (m_logs == null)
return; return;
@ -466,9 +517,11 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
tr.appendChild(td); tr.appendChild(td);
} }
} }
//messageDiv.appendChild(logMessageTable);
} }
/**
* Move back from process execution result panel to process parameter panel
*/
private void restart() { private void restart() {
replaceComponent (topParameterLayout, resultPanelLayout); replaceComponent (topParameterLayout, resultPanelLayout);
@ -500,6 +553,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
invalidate(); invalidate();
} }
/**
* Handle onAfterProcess event echo from {@link #swithToFinishScreen()}
*/
public void onAfterProcess() 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() private boolean afterProcessTask()
{ {
// something to do? // something to do?
if (m_ids != null && m_ids.length > 0) if (m_ids != null && m_ids.length > 0)
{ {
log.config(""); if (log.isLoggable(Level.CONFIG)) log.config("");
// Print invoices // Print invoices
if (getAD_Process_ID() == PROCESS_C_INVOICE_GENERATE) if (getAD_Process_ID() == PROCESS_C_INVOICE_GENERATE)
{ {
@ -538,8 +594,8 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
return false; return false;
} // afterProcessTask } // afterProcessTask
/************************************************************************** /**
* Print Shipments * Print Shipments
*/ */
private void printShipments() 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() public void onPrintShipments()
{ {
// Loop through all items // Loop through all items
@ -629,7 +688,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
} }
/** /**
* Print Invoices * Print Invoices
*/ */
private void printInvoices() 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() public void onPrintInvoices()
{ {
// Loop through all items // Loop through all items

View File

@ -48,15 +48,22 @@ import org.zkoss.zk.ui.event.Events;
public class ProcessModalDialog extends AbstractProcessDialog implements EventListener<Event>, DialogEvents public class ProcessModalDialog extends AbstractProcessDialog implements EventListener<Event>, DialogEvents
{ {
/** /**
* * generated serial id
*/ */
private static final long serialVersionUID = -6227339628038418701L; 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 */ /** Logger */
private static final CLogger log = CLogger.getCLogger(ProcessModalDialog.class); 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; private String orientation;
/** /**
@ -172,10 +179,17 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi
{ {
log.log(Level.SEVERE, "", ex); log.log(Level.SEVERE, "", ex);
} }
addEventListener(ON_OK_ECHO, this); addEventListener(ON_OK_ECHO_EVENT, this);
addEventListener(Events.ON_CANCEL, e -> onCancel()); 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) public ProcessModalDialog (int WindowNo, int AD_Process_ID, int tableId, int recordId, boolean autoStart)
{ {
this(null, WindowNo, AD_Process_ID, tableId, recordId, autoStart); this(null, WindowNo, AD_Process_ID, tableId, recordId, autoStart);
@ -265,12 +279,13 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi
/** /**
* handle events * handle events
*/ */
@Override
public void onEvent(Event event) { public void onEvent(Event event) {
Component component = event.getTarget(); Component component = event.getTarget();
if (component.equals(bOK)) { if (component.equals(bOK)) {
super.onEvent(event); super.onEvent(event);
onOk(); onOk();
} else if (event.getName().equals(ON_OK_ECHO)) { } else if (event.getName().equals(ON_OK_ECHO_EVENT)) {
onOk(); onOk();
} else if (component.equals(bCancel)) { } else if (component.equals(bCancel)) {
super.onEvent(event); super.onEvent(event);
@ -280,14 +295,20 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi
} }
} }
/**
* Handle ON_Click event from {@link #bCancel}
*/
private void onCancel() { private void onCancel() {
cancelProcess(); cancelProcess();
} }
/**
* Handle ON_Click event from {@link #bOK}
*/
private void onOk() { private void onOk() {
if (getParameterPanel().isWaitingForDialog()) if (getParameterPanel().isWaitingForDialog())
{ {
Events.echoEvent(ON_OK_ECHO, this, null); Events.echoEvent(ON_OK_ECHO_EVENT, this, null);
return; return;
} }
if(fPrintFormat != null && fPrintFormat.getValue() != null) { if(fPrintFormat != null && fPrintFormat.getValue() != null) {
@ -302,6 +323,9 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi
startProcess(); startProcess();
} }
/**
* Handle client info event from browser
*/
protected void onClientInfo() { protected void onClientInfo() {
if (getPage() != null) { if (getPage() != null) {
String newOrientation = ClientInfo.get().orientation; String newOrientation = ClientInfo.get().orientation;

View File

@ -84,9 +84,9 @@ import org.zkoss.zul.impl.InputElement;
import org.zkoss.zul.impl.XulElement; import org.zkoss.zul.impl.XulElement;
/** /**
* Process Parameter Panel, based on existing ProcessParameter dialog. - * Process Parameter Panel.
* Embedded in ProcessDialog - checks, if parameters exist and inquires and * Embedded in {@link ProcessDialog} and {@link ProcessModalDialog}.
* saves them * Capture parameters input, validate and save to DB.
* *
* @author Low Heng Sin * @author Low Heng Sin
* @version 2006-12-01 * @version 2006-12-01
@ -94,17 +94,18 @@ import org.zkoss.zul.impl.XulElement;
public class ProcessParameterPanel extends Panel implements public class ProcessParameterPanel extends Panel implements
ValueChangeListener, IProcessParameter, EventListener<Event> { ValueChangeListener, IProcessParameter, EventListener<Event> {
/** /**
* * generated serial id
*/ */
private static final long serialVersionUID = -6099317911368929787L; 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. * Dynamic generated Parameter panel.
* *
* @param WindowNo * @param WindowNo register window number
* window * @param pi process info
* @param pi
* process info
*/ */
public ProcessParameterPanel(int WindowNo, ProcessInfo pi) { public ProcessParameterPanel(int WindowNo, ProcessInfo pi) {
this(WindowNo, 0, pi); this(WindowNo, 0, pi);
@ -113,12 +114,9 @@ public class ProcessParameterPanel extends Panel implements
/** /**
* Dynamic generated Parameter panel. * Dynamic generated Parameter panel.
* *
* @param WindowNo * @param WindowNo register window number
* window * @param tabNo tabNo
* @param tabNo * @param pi process info
* tabNo
* @param pi
* process info
*/ */
public ProcessParameterPanel(int WindowNo,int tabNo, ProcessInfo pi) { public ProcessParameterPanel(int WindowNo,int tabNo, ProcessInfo pi) {
// //
@ -130,9 +128,12 @@ public class ProcessParameterPanel extends Panel implements
// //
initComponent(); initComponent();
addEventListener("onDynamicDisplay", this); addEventListener("onDynamicDisplay", this);
addEventListener("onPostEditorValueChange", this); addEventListener(ON_POST_EDITOR_VALUE_CHANGE_EVENT, this);
} // ProcessParameterPanel } // ProcessParameterPanel
/**
* Layout UI
*/
private void initComponent() { private void initComponent() {
centerPanel = GridFactory.newGridLayout(); centerPanel = GridFactory.newGridLayout();
this.appendChild(centerPanel); this.appendChild(centerPanel);
@ -151,27 +152,36 @@ public class ProcessParameterPanel extends Panel implements
private int m_WindowNo; private int m_WindowNo;
private int m_TabNo; private int m_TabNo;
private ProcessInfo m_processInfo; 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; 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; private int m_InfoWindowID = 0;
/** Logger */ /** Logger */
private static final CLogger log = CLogger private static final CLogger log = CLogger
.getCLogger(ProcessParameterPanel.class); .getCLogger(ProcessParameterPanel.class);
// /** parameter editor list **/
private ArrayList<WEditor> m_wEditors = new ArrayList<WEditor>(); private ArrayList<WEditor> m_wEditors = new ArrayList<WEditor>();
private ArrayList<WEditor> m_wEditors2 = new ArrayList<WEditor>(); // for ranges /** to parameter editor list for range parameter **/
private ArrayList<WEditor> m_wEditors2 = new ArrayList<WEditor>();
/** parameter field list **/
private ArrayList<GridField> m_mFields = new ArrayList<GridField>(); private ArrayList<GridField> m_mFields = new ArrayList<GridField>();
/** to parameter field list for range parameter **/
private ArrayList<GridField> m_mFields2 = new ArrayList<GridField>(); private ArrayList<GridField> m_mFields2 = new ArrayList<GridField>();
private ArrayList<Space> m_separators = new ArrayList<Space>(); private ArrayList<Space> m_separators = new ArrayList<Space>();
/** all rows of {@link #centerPanel} **/
private ArrayList<Row> m_Rows = new ArrayList<Row>(); private ArrayList<Row> m_Rows = new ArrayList<Row>();
// /** layout grid for parameter fields **/
private Grid centerPanel = null; private Grid centerPanel = null;
/** Group Name:Rows for parameter field **/
private Map<String, List<Row>> fieldGroupContents = new HashMap<String, List<Row>>(); private Map<String, List<Row>> fieldGroupContents = new HashMap<String, List<Row>>();
/** Group Name:Rows for group header **/
private Map<String, List<org.zkoss.zul.Row>> fieldGroupHeaders = new HashMap<String, List<org.zkoss.zul.Row>>(); private Map<String, List<org.zkoss.zul.Row>> fieldGroupHeaders = new HashMap<String, List<org.zkoss.zul.Row>>();
/** rows of current rendering group **/
private ArrayList<Row> rowList; private ArrayList<Row> rowList;
/** all groups of field type collapsible or tab **/
private List<Group> allCollapsibleGroups = new ArrayList<Group>(); private List<Group> allCollapsibleGroups = new ArrayList<Group>();
/** current rendering group **/
private Group currentGroup; private Group currentGroup;
/** /**
@ -186,12 +196,12 @@ public class ProcessParameterPanel extends Panel implements
} // dispose } // dispose
/** /**
* Read Fields to display * Render all visible fields
* *
* @return true if loaded OK * @return true if loaded OK
*/ */
public boolean init() { public boolean init() {
log.config(""); if (log.isLoggable(Level.CONFIG)) log.config("");
// ASP // ASP
MClient client = MClient.get(Env.getCtx()); MClient client = MClient.get(Env.getCtx());
@ -385,12 +395,13 @@ public class ProcessParameterPanel extends Panel implements
} // initDialog } // initDialog
/** /**
* Create Field. - creates Fields and adds it to m_mFields list - creates * Create editor and adds it to {@link #m_wEditors}.
* Editor and adds it to m_vEditors list Handeles Ranges by adding * <br/>
* additional mField/vEditor. * 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}.
* <p> * <p>
* mFields are used for default value and mandatory checking; vEditors are * mField is used for default value and mandatory checking and editor is
* used to retrieve the value (no data binding) * used to capture input value from user (no data binding).
* *
* @param voF GridFieldVO * @param voF GridFieldVO
* @param mField * @param mField
@ -403,7 +414,7 @@ public class ProcessParameterPanel extends Panel implements
editor.getComponent().addEventListener(Events.ON_FOCUS, this); editor.getComponent().addEventListener(Events.ON_FOCUS, this);
editor.addValueChangeListener(this); editor.addValueChangeListener(this);
editor.dynamicDisplay(); 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); mField.addPropertyChangeListener(editor);
// Set Default // Set Default
Object defaultObject = mField.getDefaultForPanel(); Object defaultObject = mField.getDefaultForPanel();
@ -446,6 +457,7 @@ public class ProcessParameterPanel extends Panel implements
Div box = new Div(); Div box = new Div();
box.setStyle("display: flex; align-items: center;"); box.setStyle("display: flex; align-items: center;");
ZKUpdateUtil.setWidth(box, "100%"); ZKUpdateUtil.setWidth(box, "100%");
//create to field and editor
if (voF.isRange) { if (voF.isRange) {
box.appendChild(editor.getComponent()); box.appendChild(editor.getComponent());
ZKUpdateUtil.setWidth((HtmlBasedComponent) editor.getComponent(), "49%"); ZKUpdateUtil.setWidth((HtmlBasedComponent) editor.getComponent(), "49%");
@ -492,6 +504,7 @@ public class ProcessParameterPanel extends Panel implements
m_mFields2.add(null); m_mFields2.add(null);
m_wEditors2.add(null); m_wEditors2.add(null);
m_separators.add(null); m_separators.add(null);
//add not in support for multi selection field
if(DisplayType.isChosenMultipleSelection(mField.getDisplayType())) { if(DisplayType.isChosenMultipleSelection(mField.getDisplayType())) {
Button bNegate = ButtonFactory.createButton("", null, null); Button bNegate = ButtonFactory.createButton("", null, null);
bNegate.setTooltiptext(Msg.translate(Env.getCtx(), "IncludeSelectedValues")); bNegate.setTooltiptext(Msg.translate(Env.getCtx(), "IncludeSelectedValues"));
@ -507,6 +520,11 @@ public class ProcessParameterPanel extends Panel implements
row.appendChild(box); row.appendChild(box);
} // createField } // createField
/**
* set place holder message
* @param editor
* @param msg
*/
private void setEditorPlaceHolder(WEditor editor, String msg) { private void setEditorPlaceHolder(WEditor editor, String msg) {
Component c = editor.getComponent(); Component c = editor.getComponent();
if (c instanceof InputElement) { if (c instanceof InputElement) {
@ -528,17 +546,15 @@ public class ProcessParameterPanel extends Panel implements
* @return true if parameters are valid * @return true if parameters are valid
*/ */
public boolean validateParameters() { public boolean validateParameters() {
log.config(""); if (log.isLoggable(Level.CONFIG)) log.config("");
/** //mandatory fields validation
* Mandatory fields see - MTable.getMandatory
*/
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int size = m_mFields.size(); int size = m_mFields.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
GridField field = (GridField) m_mFields.get(i); GridField field = (GridField) m_mFields.get(i);
if (field.isMandatory(true)) // check context if (field.isMandatory(true)) // check context
{ {
WEditor wEditor = (WEditor) m_wEditors.get(i); WEditor wEditor = (WEditor) m_wEditors.get(i);
Object data = wEditor.getValue(); Object data = wEditor.getValue();
if (data == null || data.toString().length() == 0) { if (data == null || data.toString().length() == 0) {
@ -577,6 +593,7 @@ public class ProcessParameterPanel extends Panel implements
return false; return false;
} }
/** call {@link IProcessParameterListener} validate(ProcessParameterPanel) **/
if (m_processInfo.getAD_Process_ID() > 0) { if (m_processInfo.getAD_Process_ID() > 0) {
String className = MProcess.get(Env.getCtx(), m_processInfo.getAD_Process_ID()).getClassname(); String className = MProcess.get(Env.getCtx(), m_processInfo.getAD_Process_ID()).getClassname();
List<IProcessParameterListener> listeners = Extensions.getProcessParameterListeners(className, null); List<IProcessParameterListener> listeners = Extensions.getProcessParameterListeners(className, null);
@ -592,12 +609,13 @@ public class ProcessParameterPanel extends Panel implements
return true; return true;
} // validateParameters } // validateParameters
/* /**
* load parameters from saved instance * load parameters from saved instance
* @param instance
*/ */
public boolean loadParameters(MPInstance instance) public boolean loadParameters(MPInstance instance)
{ {
log.config(""); if (log.isLoggable(Level.CONFIG)) log.config("");
MPInstancePara[] params = instance.getParameters(); MPInstancePara[] params = instance.getParameters();
for (int j = 0; j < m_mFields.size(); j++) for (int j = 0; j < m_mFields.size(); j++)
@ -688,12 +706,13 @@ public class ProcessParameterPanel extends Panel implements
return true; return true;
} // loadParameters } // loadParameters
/* /**
* Load parameters from Process Info * Load parameters from Process Info
* @param pi
*/ */
public boolean loadParametersFromProcessInfo(ProcessInfo pi) public boolean loadParametersFromProcessInfo(ProcessInfo pi)
{ {
log.config(""); if (log.isLoggable(Level.CONFIG)) log.config("");
ProcessInfoParameter[] params = pi.getParameter(); ProcessInfoParameter[] params = pi.getParameter();
for (int j = 0; j < m_mFields.size(); j++) for (int j = 0; j < m_mFields.size(); j++)
@ -742,12 +761,12 @@ public class ProcessParameterPanel extends Panel implements
} // loadParameters } // loadParameters
/** /**
* Save Parameter values * Save parameter values to {@link MPInstancePara}.
* *
* @return true if parameters saved * @return true if parameters saved
*/ */
public boolean saveParameters() { public boolean saveParameters() {
log.config(""); if (log.isLoggable(Level.CONFIG)) log.config("");
if (!validateParameters()) if (!validateParameters())
return false; return false;
@ -839,21 +858,19 @@ public class ProcessParameterPanel extends Panel implements
} // saveParameters } // 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() { public MPInstancePara[] getParameters() {
log.config(""); if (log.isLoggable(Level.CONFIG)) log.config("");
if (!validateParameters()) if (!validateParameters())
return new MPInstancePara[0]; return new MPInstancePara[0];
List<MPInstancePara> paras = new ArrayList<MPInstancePara>(); List<MPInstancePara> paras = new ArrayList<MPInstancePara>();
/********************************************************************** /** create MPInstancePara from editors and add to paras (without saving MPInstancePara to DB) **/
* Save Now
*/
for (int i = 0; i < m_mFields.size(); i++) { for (int i = 0; i < m_mFields.size(); i++) {
// Get Values // Get Values
WEditor editor = (WEditor) m_wEditors.get(i); 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 * @param evt ValueChangeEvent
* ValueChangeEvent
*/ */
public void valueChange(ValueChangeEvent evt) { public void valueChange(ValueChangeEvent evt) {
String propName = evt.getPropertyName(); String propName = evt.getPropertyName();
if (evt.getSource() instanceof WEditor) { if (evt.getSource() instanceof WEditor) {
@ -947,7 +962,7 @@ public class ProcessParameterPanel extends Panel implements
processDependencies (changedField); processDependencies (changedField);
// future processCallout (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); processNewValue(evt.getNewValue(), propName);
} }
@ -955,6 +970,7 @@ public class ProcessParameterPanel extends Panel implements
@Override @Override
public void onEvent(Event event) throws Exception { public void onEvent(Event event) throws Exception {
if (event.getName().equals(Events.ON_FOCUS)) { if (event.getName().equals(Events.ON_FOCUS)) {
//update tooltip text inside desktop help panel.
for (WEditor editor : m_wEditors) for (WEditor editor : m_wEditors)
{ {
if (editor.isComponentOfEditor(event.getTarget())) if (editor.isComponentOfEditor(event.getTarget()))
@ -976,7 +992,7 @@ public class ProcessParameterPanel extends Panel implements
else if (event.getName().equals("onDynamicDisplay")) { else if (event.getName().equals("onDynamicDisplay")) {
dynamicDisplay(); dynamicDisplay();
} }
else if (event.getName().equals("onPostEditorValueChange")) { else if (event.getName().equals(ON_POST_EDITOR_VALUE_CHANGE_EVENT)) {
WEditor editor = (WEditor)event.getData(); WEditor editor = (WEditor)event.getData();
onPostEditorValueChange(editor); onPostEditorValueChange(editor);
if(editor.getComponent() != null) { if(editor.getComponent() != null) {
@ -996,6 +1012,7 @@ public class ProcessParameterPanel extends Panel implements
} }
else if (event.getName().equals(Events.ON_CLICK)) { else if (event.getName().equals(Events.ON_CLICK)) {
if(event.getTarget() instanceof Button) { if(event.getTarget() instanceof Button) {
//from not in button of multi selection field
Button bNegate = (Button)event.getTarget(); Button bNegate = (Button)event.getTarget();
boolean isSelected = !(boolean)bNegate.getAttribute("isSelected"); boolean isSelected = !(boolean)bNegate.getAttribute("isSelected");
if(isSelected) { if(isSelected) {
@ -1013,6 +1030,12 @@ public class ProcessParameterPanel extends Panel implements
} }
} }
/**
* Handle ON_POST_EDITOR_VALUE_CHANGE_EVENT event.
* <br/>
* Call {@link IProcessParameterListener#validate(ProcessParameterPanel)}.
* @param editor
*/
private void onPostEditorValueChange(WEditor editor) { private void onPostEditorValueChange(WEditor editor) {
if (m_processInfo.getAD_Process_ID() > 0) { if (m_processInfo.getAD_Process_ID() > 0) {
String className = MProcess.get(Env.getCtx(), m_processInfo.getAD_Process_ID()).getClassname(); 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 * @param changedField changed field
*/ */
private void processDependencies (GridField changedField) private void processDependencies (GridField changedField)
@ -1048,6 +1071,11 @@ public class ProcessParameterPanel extends Panel implements
} }
} // processDependencies } // 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) { private void verifyChangedField(GridField field, String columnName) {
ArrayList<String> list = field.getDependentOn(); ArrayList<String> list = field.getDependentOn();
if (list.contains(columnName)) { 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) { private void processNewValue(Object value, String name) {
if (value == null) if (value == null)
value = new String(""); value = new String("");
@ -1086,6 +1119,9 @@ public class ProcessParameterPanel extends Panel implements
Events.postEvent("onDynamicDisplay", this, (Object)null); Events.postEvent("onDynamicDisplay", this, (Object)null);
} }
/**
* Dynamic update the UI state and properties of all fields.
*/
private void dynamicDisplay() { private void dynamicDisplay() {
for (int i = 0; i < m_wEditors.size(); i++) { for (int i = 0; i < m_wEditors.size(); i++) {
WEditor editor = m_wEditors.get(i); WEditor editor = m_wEditors.get(i);
@ -1172,6 +1208,10 @@ public class ProcessParameterPanel extends Panel implements
m_processInfo = processInfo; m_processInfo = processInfo;
} }
/**
* focus to first visible field editor.
* @return true if there is at least one visible field editor.
*/
public boolean focusToFirstEditor() { public boolean focusToFirstEditor() {
if (m_wEditors.isEmpty()) if (m_wEditors.isEmpty())
return false; return false;
@ -1184,6 +1224,9 @@ public class ProcessParameterPanel extends Panel implements
return false; return false;
} }
/**
* @param toFocus
*/
private void focusToEditor(WEditor toFocus) { private void focusToEditor(WEditor toFocus) {
Component c = toFocus.getComponent(); Component c = toFocus.getComponent();
if (c instanceof EditorBox) { 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 * @param columnName
* @return editor * @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() { public boolean isWaitingForDialog() {
for (int i = 0; i < m_mFields.size(); i++) { for (int i = 0; i < m_mFields.size(); i++) {
@ -1244,6 +1287,9 @@ public class ProcessParameterPanel extends Panel implements
return false; return false;
} }
/**
* Field label ON_CLICK listener for {@link IZoomableEditor}.
*/
static class ZoomListener implements EventListener<Event> { static class ZoomListener implements EventListener<Event> {
private IZoomableEditor searchEditor; private IZoomableEditor searchEditor;
@ -1261,6 +1307,9 @@ public class ProcessParameterPanel extends Panel implements
} }
/**
* @return register window number.
*/
public int getWindowNo() { public int getWindowNo() {
return m_WindowNo; return m_WindowNo;
} }

View File

@ -70,14 +70,14 @@ import org.zkoss.zul.Center;
import org.zkoss.zul.Div; import org.zkoss.zul.Div;
/** /**
* * Drill assistant dialog
* @author Igor Pojzl, Cloudempiere * @author Igor Pojzl, Cloudempiere
* *
*/ */
public class WDrillReport extends Window implements EventListener<Event> { public class WDrillReport extends Window implements EventListener<Event> {
/** /**
* * generated serial id
*/ */
private static final long serialVersionUID = 5143424676962140799L; private static final long serialVersionUID = 5143424676962140799L;
@ -88,10 +88,14 @@ public class WDrillReport extends Window implements EventListener<Event> {
private static final String DRILL_REPORT_TABLE_NAME = "TableName"; private static final String DRILL_REPORT_TABLE_NAME = "TableName";
private DrillReportCtl drillReportCtl; private DrillReportCtl drillReportCtl;
/** generated unique window name prefix **/
private String winpref; private String winpref;
/** tabpanel for related table drill **/
private Tabpanel tabPanel; private Tabpanel tabPanel;
/** tab for related table drill **/
private Tab tableTab; private Tab tableTab;
/** true if {@link #tabPanel} loaded **/
private boolean tablesLoaded = false; private boolean tablesLoaded = false;
private int windowNo = 0; private int windowNo = 0;
@ -150,6 +154,10 @@ public class WDrillReport extends Window implements EventListener<Event> {
td.appendChild(getContent()); td.appendChild(getContent());
} }
/**
* Header text
* @return {@link Table}
*/
private Table getHeader() private Table getHeader()
{ {
Table table = new Table(); Table table = new Table();
@ -202,6 +210,10 @@ public class WDrillReport extends Window implements EventListener<Event> {
return table; return table;
} }
/**
* Tabbox with Drill Rules and Related Tables tab.
* @return {@link Tabbox}
*/
private Tabbox getContent() private Tabbox getContent()
{ {
@ -236,6 +248,14 @@ public class WDrillReport extends Window implements EventListener<Event> {
return tabbox; 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<Integer, KeyNamePair[]> drillPrintFormatMap, boolean isDrillProcessRule) private Table getTabContent(int tabIndex, KeyNamePair[] drillTables, HashMap<Integer, KeyNamePair[]> drillPrintFormatMap, boolean isDrillProcessRule)
{ {
Table table = new Table(); Table table = new Table();
@ -276,7 +296,6 @@ public class WDrillReport extends Window implements EventListener<Event> {
td.appendChild(getTablesBox(tabIndex, drillTables)); td.appendChild(getTablesBox(tabIndex, drillTables));
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
KeyNamePair drillTable = drillTables[i]; KeyNamePair drillTable = drillTables[i];
// tab // tab
@ -292,6 +311,15 @@ public class WDrillReport extends Window implements EventListener<Event> {
return table; 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<Integer, KeyNamePair[]> drillPrintFormatMap, boolean isDrillProcessRule) private Table getDrillTableBox(KeyNamePair drillTable, int tabIndex, int groupIndex, HashMap<Integer, KeyNamePair[]> drillPrintFormatMap, boolean isDrillProcessRule)
{ {
Table table = new Table(); Table table = new Table();
@ -325,11 +353,14 @@ public class WDrillReport extends Window implements EventListener<Event> {
a.appendChild(new Text("..")); a.appendChild(new Text(".."));
header.appendChild(a); header.appendChild(a);
//[AD_Process_DrillRule_ID,Name]
KeyNamePair[] drillRules = drillPrintFormatMap != null ? drillPrintFormatMap.get(drillTable.getKey()) : new KeyNamePair[]{findTablePrintFormat(drillTable)}; KeyNamePair[] drillRules = drillPrintFormatMap != null ? drillPrintFormatMap.get(drillTable.getKey()) : new KeyNamePair[]{findTablePrintFormat(drillTable)};
for (int j = 0; j < drillRules.length; j++) for (int j = 0; j < drillRules.length; j++)
{ {
//(AD_Process_DrillRule_ID,Name) or (AD_PrintFormat_ID,Name)
KeyNamePair drillRule = drillRules[j]; KeyNamePair drillRule = drillRules[j];
//[AD_PrintFormat_ID,Name]
KeyNamePair[] printFormats = isDrillProcessRule ? drillReportCtl.getDrillProcessRulesPrintFormatMap(drillRule.getKey()) : new KeyNamePair[] {drillRule} ; KeyNamePair[] printFormats = isDrillProcessRule ? drillReportCtl.getDrillProcessRulesPrintFormatMap(drillRule.getKey()) : new KeyNamePair[] {drillRule} ;
// create new Print Format // create new Print Format
@ -376,7 +407,10 @@ public class WDrillReport extends Window implements EventListener<Event> {
return table; return table;
} }
/**
* @param drillTable KeyNamePair(AD_Process_ID,Process Name)
* @return KeyNamePair(AD_PrintFormat_ID,Name)
*/
private KeyNamePair findTablePrintFormat(KeyNamePair drillTable) { private KeyNamePair findTablePrintFormat(KeyNamePair drillTable) {
Integer printFormatID = new Query(Env.getCtx(), MPrintFormat.Table_Name, " AD_Table_ID = ? AND AD_Client_ID IN (0,?) ", null) 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<Event> {
return new KeyNamePair((printFormatID != null && printFormatID > 0) ? printFormatID : 0, drillTable.getName()); 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) private Table getTablesBox(int tabIndex, KeyNamePair[] drillTables)
{ {
Table table = new Table(); Table table = new Table();
@ -436,6 +475,17 @@ public class WDrillReport extends Window implements EventListener<Event> {
return table; 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) 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<Event> {
H4 h4 = new H4(); H4 h4 = new H4();
h4.appendChild(new Text(drillPrintFormat.getName())); h4.appendChild(new Text(drillPrintFormat.getName()));
td.appendChild(h4); td.appendChild(h4);
a = new A(); a = new A();
a.setHref("#"+winpref+"Rep"+reportIndex+"-"+groupIndex); a.setHref("#"+winpref+"Rep"+reportIndex+"-"+groupIndex);
@ -459,8 +508,6 @@ public class WDrillReport extends Window implements EventListener<Event> {
a.appendChild(new Text("..")); a.appendChild(new Text(".."));
td.appendChild(a); td.appendChild(a);
td = new Td(); td = new Td();
td.setStyle("width: 10%"); td.setStyle("width: 10%");
tr.appendChild(td); tr.appendChild(td);
@ -495,7 +542,6 @@ public class WDrillReport extends Window implements EventListener<Event> {
} }
} }
td = new Td(); td = new Td();
td.setStyle("width: 60"); td.setStyle("width: 60");
tr.appendChild(td); tr.appendChild(td);

View File

@ -40,7 +40,8 @@ import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.EventListener;
/** /**
* Ported from org.compiere.apps.ProcessCtl * Zk client controller for execution of process.
*
* @author hengsin * @author hengsin
* @contributor red1 IDEMPIERE-1711 with final review by Hengsin * @contributor red1 IDEMPIERE-1711 with final review by Hengsin
* *
@ -50,25 +51,28 @@ public class WProcessCtl extends AbstractProcessCtl {
/** Logger */ /** Logger */
private static final CLogger log = CLogger.getCLogger(WProcessCtl.class); 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) public static void process (int WindowNo, ProcessInfo pi, Trx trx)
{ {
process(WindowNo, pi, trx, null); process(WindowNo, pi, trx, null);
} }
/** /**
* Process Control * Open ProcessModalDialog to run process.
* <code> * <pre>
* - Get Instance ID * - Create and save {@link MPInstance} if no pi.AD_PInstance_ID.
* - Get Parameters * - Use {@link ProcessModalDialog} to capture process parameters and run process.
* - execute (lock - start process - unlock) * </pre>
* </code> *
* Creates a ProcessCtl instance, which calls * @param WindowNo window no
* lockUI and unlockUI if parent is a ASyncProcess * @param pi ProcessInfo process info
* <br> * @param trx Transaction
* * @param listener listener for {@link ProcessModalDialog}
* @param WindowNo window no
* @param pi ProcessInfo process info
* @param trx Transaction
*/ */
public static void process (int WindowNo, ProcessInfo pi, Trx trx, EventListener<Event> listener) public static void process (int WindowNo, ProcessInfo pi, Trx trx, EventListener<Event> listener)
{ {
@ -104,7 +108,6 @@ public class WProcessCtl extends AbstractProcessCtl {
ProcessModalDialog para = new ProcessModalDialog(listener, WindowNo, pi, false); ProcessModalDialog para = new ProcessModalDialog(listener, WindowNo, pi, false);
if (para.isValid()) if (para.isValid())
{ {
//para.setWidth("500px");
para.setVisible(true); para.setVisible(true);
Object window = SessionManager.getAppDesktop().findWindow(WindowNo); Object window = SessionManager.getAppDesktop().findWindow(WindowNo);
@ -116,7 +119,7 @@ public class WProcessCtl extends AbstractProcessCtl {
parent.hideMask(); 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); final Mask mask = LayoutUtils.showWindowWithMask(para, (Component)window, null);
para.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener<Event>() { para.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener<Event>() {
@Override @Override
@ -124,7 +127,7 @@ public class WProcessCtl extends AbstractProcessCtl {
mask.hideMask(); mask.hideMask();
} }
}); });
}else{ } else {
para.setPosition("center"); para.setPosition("center");
para.setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED); para.setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED);
AEnv.showWindow(para); AEnv.showWindow(para);
@ -134,57 +137,54 @@ public class WProcessCtl extends AbstractProcessCtl {
} // execute } // execute
/** /**
* Async Process - Do it all. * Save parameters and execute process.
* <code> * <pre>
* - Get Instance ID * - Create and save {@link MPInstance} if no pi.AD_PInstance_ID.
* - Get Parameters * - Call parameter.saveParameters ({@link IProcessParameter#saveParameters()}) to save process parameters.
* - execute (lock - start process - unlock) * - Save pi.getRecord_IDs() to T_Selections ({@link DB#createT_Selection(int, java.util.Collection, String)}).
* </code> * - Call {@link WProcessCtl#run()} to execute process.
* Creates a ProcessCtl instance, which calls * </pre>
* lockUI and unlockUI if parent is a ASyncProcess
* <br>
* Called from ProcessDialog.actionPerformed
* *
* @param aProcessUI ASyncProcess and Container * @param aProcessUI {@link IProcessUI}
* @param WindowNo window no * @param WindowNo window no
* @param parameter Process Parameter Panel * @param parameter Process Parameter Panel
* @param pi ProcessInfo process info * @param pi {@link ProcessInfo}
* @param trx Transaction * @param trx Transaction
*/ */
public static void process(IProcessUI aProcessUI, int WindowNo, IProcessParameter parameter, ProcessInfo pi, Trx trx) 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; MPInstance instance = null;
if (pi.getAD_PInstance_ID() < 1) { //red1 bypass if PInstance exists if (pi.getAD_PInstance_ID() < 1) { //red1 bypass if PInstance exists
try try
{ {
instance = new MPInstance(Env.getCtx(), pi.getAD_Process_ID(), pi.getRecord_ID()); 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 // Get Parameters
if (parameter != null) { if (parameter != null) {

View File

@ -40,15 +40,15 @@ import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Menupopup; 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 * @author Low Heng Sin
* *
*/ */
public class WReport implements EventListener<Event> { public class WReport implements EventListener<Event> {
/** /**
* Constructor * Call {@link #WReport(int, MQuery, Component, int)}
*
* @param AD_Table_ID table * @param AD_Table_ID table
* @param query query * @param query query
*/ */
@ -58,11 +58,10 @@ public class WReport implements EventListener<Event> {
} }
/** /**
* Constructor * Call {@link #WReport(int, MQuery, Component, int, String)}
*
* @param AD_Table_ID table * @param AD_Table_ID table
* @param query query * @param query query
* @param parent The invoking parent window * @param parent The invoking parent component
* @param WindowNo The invoking parent window number * @param WindowNo The invoking parent window number
*/ */
public WReport (int AD_Table_ID, MQuery query, Component parent, public WReport (int AD_Table_ID, MQuery query, Component parent,
@ -72,7 +71,8 @@ public class WReport implements EventListener<Event> {
} }
/** /**
* 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 AD_Table_ID table
* @param query query * @param query query
@ -103,25 +103,26 @@ public class WReport implements EventListener<Event> {
getPrintFormats (AD_Table_ID, AD_Window_ID); getPrintFormats (AD_Table_ID, AD_Window_ID);
} // AReport } // AReport
/** The Query */ /** Query parameter **/
private MQuery m_query; private MQuery m_query;
/** menu popup to show the list of print formats discover **/
private Menupopup m_popup; private Menupopup m_popup;
/** The Option List */ /** List of KeyNamePair(AD_PrintFormat_ID,Name) **/
private List<KeyNamePair> m_list = new ArrayList<KeyNamePair>(); private List<KeyNamePair> m_list = new ArrayList<KeyNamePair>();
/** Logger */ /** Logger **/
private static final CLogger log = CLogger.getCLogger(WReport.class); private static final CLogger log = CLogger.getCLogger(WReport.class);
/** The parent window for locking/unlocking during process execution */ /** The invoking parent component **/
Component parent; protected Component parent;
/** The parent window number */ /** The parent window number **/
int WindowNo; protected int WindowNo;
/** The filter to apply to this report */ /** The filter to apply to this report **/
private String whereExtended; private String whereExtended;
/** /**
* Get the Print Formats for the table. * Get Print Formats for table and window.
* Fill the list and the popup menu * If there's only 1 print format found, call {@link #launchReport(KeyNamePair)}, otherwise call {@link #showPopup()}.
* @param AD_Table_ID table * @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) private void getPrintFormats (int AD_Table_ID, int AD_Window_ID)
{ {
@ -134,6 +135,9 @@ public class WReport implements EventListener<Event> {
showPopup(); // below button showPopup(); // below button
} // getPrintFormats } // getPrintFormats
/**
* Show popup menu for the list of print formats found.
*/
private void showPopup() { private void showPopup() {
m_popup = new Menupopup(); m_popup = new Menupopup();
for(int i = 0; i < m_list.size(); i++) for(int i = 0; i < m_list.size(); i++)
@ -150,7 +154,7 @@ public class WReport implements EventListener<Event> {
/** /**
* Launch Report * Launch Report
* @param pp Key=AD_PrintFormat_ID * @param pp KeyNamePair(AD_PrintFormat_ID,Name)
*/ */
private void launchReport (KeyNamePair pp) private void launchReport (KeyNamePair pp)
{ {
@ -202,7 +206,7 @@ public class WReport implements EventListener<Event> {
} }
} // launchReport } // launchReport
/************************************************************************** /**
* Get AD_Table_ID for Table Name * Get AD_Table_ID for Table Name
* @param tableName table name * @param tableName table name
* @return AD_Table_ID or 0 * @return AD_Table_ID or 0
@ -212,9 +216,11 @@ public class WReport implements EventListener<Event> {
return MTable.getTable_ID(tableName); return MTable.getTable_ID(tableName);
} // getAD_Table_ID } // getAD_Table_ID
@Override
public void onEvent(Event event) { public void onEvent(Event event) {
if(event.getTarget() instanceof Menuitem) if(event.getTarget() instanceof Menuitem)
{ {
//ON_CLICK event from showPopup() menu item.
Menuitem mi = (Menuitem) event.getTarget(); Menuitem mi = (Menuitem) event.getTarget();
launchReport(m_list.get(Integer.parseInt(mi.getValue().toString()))); launchReport(m_list.get(Integer.parseInt(mi.getValue().toString())));
} }