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;
/**
* 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:hengsin@gmail.com">Low Heng Sin</a>
* @date Feb 25, 2007
@ -41,12 +41,12 @@ import org.compiere.util.Util;
*/
public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabbox
{
/** Logger */
/** Logger **/
private static final CLogger log = CLogger.getCLogger (AbstractADTabbox.class);
/** List of dependent Variables */
/** List of variables/columnName that's reference by one or more gridTab logic expression **/
private ArrayList<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>();
/** Parent part, the content part of AD Window **/
protected AbstractADWindowContent adWindowPanel;

View File

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

View File

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

View File

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

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

View File

@ -21,7 +21,7 @@ import org.compiere.model.MLookup;
import org.zkoss.zk.ui.Desktop;
/**
* Callout Dialog used for Ask For Input
* Callout Dialog used to ask for input from user.
*
* @author Murilo H. Torquato (devCoffee, http://devcoffee.com.br)
*
@ -31,6 +31,10 @@ public class CalloutDialog implements ICalloutUI {
private Desktop desktop;
private int m_windowNo;
/**
* @param desktop
* @param windowNo
*/
public CalloutDialog(Desktop desktop, int windowNo) {
this.desktop = desktop;
this.m_windowNo = windowNo;

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

View File

@ -53,20 +53,29 @@ import org.zkoss.zul.Vlayout;
*/
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 ON_SEARCH_DOCUMENTS = "onSearchDocuments";
/** onSearchDocuments event **/
private static final String ON_SEARCH_DOCUMENTS_EVENT = "onSearchDocuments";
private int MAX_RESULTS_PER_SEARCH_IN_DOCUMENT_CONTROLLER = 3;
/** layout to show links ({@link A}) for each {@link #SEARCH_RESULT} in {@link #list} **/
private Vlayout layout;
/** results from execution of search **/
private ArrayList<SearchResult> list;
/** Current selected index of {@link #list} **/
private int selected = -1;
/**
*
* default constructor
*/
public DocumentSearchController() {
MAX_RESULTS_PER_SEARCH_IN_DOCUMENT_CONTROLLER = MSysConfig.getIntValue(MSysConfig.MAX_RESULTS_PER_SEARCH_IN_DOCUMENT_CONTROLLER, 3, Env.getAD_Client_ID(Env.getCtx()));
}
/**
* Create {@link #layout} for search result
* @param parent
*/
public void create(Component parent) {
layout = new Vlayout();
layout.setStyle("padding: 3px; overflow:auto;");
@ -75,14 +84,23 @@ public class DocumentSearchController implements EventListener<Event>{
parent.appendChild(layout);
layout.addEventListener(ON_SEARCH_DOCUMENTS, this);
layout.addEventListener(ON_SEARCH_DOCUMENTS_EVENT, this);
}
/**
* Echo {@link #ON_SEARCH_DOCUMENTS_EVENT} with value as event data.
* @param value
*/
public void search(String value) {
layout.getChildren().clear();
Events.echoEvent(ON_SEARCH_DOCUMENTS, layout, value);
Events.echoEvent(ON_SEARCH_DOCUMENTS_EVENT, layout, value);
}
/**
* Handle {@link #ON_SEARCH_DOCUMENTS_EVENT} event.
* Delegate execution of search to {@link #doSearch(String)}.
* @param searchString
*/
private void onSearchDocuments(String searchString) {
list = new ArrayList<SearchResult>();
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) {
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;
}
/**
* 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,
String extraWhereClase, List<SearchResult> list) {
PreparedStatement pstmt = null;
@ -250,17 +284,24 @@ public class DocumentSearchController implements EventListener<Event>{
SearchResult result = (SearchResult) event.getTarget().getAttribute(SEARCH_RESULT);
doZoom(result);
}
} else if (event.getName().equals(ON_SEARCH_DOCUMENTS)) {
} else if (event.getName().equals(ON_SEARCH_DOCUMENTS_EVENT)) {
onSearchDocuments((String)event.getData());
}
}
/**
* Zoom to AD Window
* @param result
*/
private void doZoom(SearchResult result) {
MQuery query = new MQuery();
query.addRestriction(result.getTableName()+"_ID", "=", result.getRecordId());
AEnv.zoom(result.getWindowId(), query);
}
/**
* Value class to hold search result
*/
public static class SearchResult {
private String windowName;
private int windowId;
@ -344,6 +385,13 @@ public class DocumentSearchController implements EventListener<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) {
String text = textbox.getText();
if (Util.isEmpty(text))
@ -374,11 +422,16 @@ public class DocumentSearchController implements EventListener<Event>{
result = (SearchResult) firstStart.getAttribute(SEARCH_RESULT);
if (result != null) {
doZoom(result);
return true;
}
return false;
}
/**
* Select and return {@link SearchResult} that comes before the current selected {@link SearchResult} link in {@link #layout}.
* @return {@link SearchResult}
*/
public SearchResult selectPrior() {
if (selected > 0) {
selected--;
@ -399,6 +452,10 @@ public class DocumentSearchController implements EventListener<Event>{
return null;
}
/**
* Select and return {@link SearchResult} that comes after the current selected {@link SearchResult} link in {@link #layout}.
* @return {@link SearchResult}
*/
public SearchResult selectNext() {
if (selected < (list.size()-1)) {
selected++;

View File

@ -64,7 +64,7 @@ import org.zkoss.zul.Div;
import org.zkoss.zul.South;
/**
*
* Window to capture feedback request from user.
* @author hengsin
*
*/
@ -77,13 +77,19 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
private static final CLogger log = CLogger.getCLogger(FeedbackRequestWindow.class);
/** Fields for {@link MRequest} **/
protected WTableDirEditor requestTypeField, priorityField, salesRepField;
protected Textbox txtSummary;
protected ConfirmPanel confirmPanel;
/** attachments uploaded by user **/
protected List<DataSource> attachments = new ArrayList<DataSource>();
/** Div to host list of {@link AttachmentItem} **/
protected Div attachmentBox;
/**
* Default constructor
*/
public FeedbackRequestWindow() {
super();
@ -114,6 +120,7 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
throw new RuntimeException(Msg.getMsg(Env.getCtx(), "AccessTableNoUpdate"));
}
//layout window
Label lblRequestType = new Label(Msg.getElement(Env.getCtx(), "R_RequestType_ID"));
Label lblPriority = new Label(Msg.getElement(Env.getCtx(), "Priority"));
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);
}
@Override
public void onEvent(Event e) throws Exception {
if (e.getTarget() == confirmPanel.getButton(ConfirmPanel.A_OK)) {
Clients.clearBusy();
@ -271,6 +279,10 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
}
}
/**
* Save request
* @throws IOException
*/
protected void saveRequest() throws IOException {
Trx trx = Trx.get(Trx.createTrxName("SaveNewRequest"), true);
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) {
MRequest request = new MRequest(Env.getCtx(), 0, trx.getTrxName());
request.setAD_Org_ID(Env.getAD_Org_ID(Env.getCtx()));
@ -325,6 +342,11 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
return request;
}
/**
* Add attachment from user.
* @param dataSource
* @param removable
*/
public void addAttachment(DataSource dataSource, boolean removable) {
attachments.add(dataSource);
AttachmentItem item = new AttachmentItem(dataSource, attachments, removable);
@ -332,6 +354,11 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
getFirstChild().invalidate();
}
/**
* Get byte[] from media.
* @param media
* @return byte[]
*/
private byte[] getMediaData(Media media) {
byte[] bytes = null;
@ -358,6 +385,11 @@ public class FeedbackRequestWindow extends Window implements EventListener<Event
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) {
if (contentType != null) {
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.util.DocumentSearch;
import org.adempiere.webui.util.ZKUpdateUtil;
import org.compiere.model.MSearchDefinition;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
@ -37,19 +38,27 @@ import org.zkoss.zul.Bandpopup;
import org.zkoss.zul.Div;
/**
* Global search component at desktop header.
* @author hengsin
*
*/
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 = "/";
/**
@ -57,15 +66,20 @@ public class GlobalSearch extends Div implements EventListener<Event> {
*/
private static final long serialVersionUID = -8793878697269469837L;
/** Bandbox to capture search text from user and display result in popup **/
private Bandbox bandbox;
/** controller to search AD_Menu **/
private MenuSearchController menuController;
/** controller to search tables **/
private DocumentSearchController docController;
/** tabbox to host menu and document search tab **/
private Tabbox tabbox;
/**
*
* @param menuController
*/
public GlobalSearch(MenuSearchController menuController) {
this.menuController = menuController;
@ -73,11 +87,13 @@ public class GlobalSearch extends Div implements EventListener<Event> {
init();
}
/**
* Layout UI and setup listeners
*/
private void init() {
bandbox = new Bandbox();
bandbox.setSclass("global-search-box");
appendChild(bandbox);
// ZKUpdateUtil.setWidth(bandbox, "100%");
bandbox.setAutodrop(true);
bandbox.setId("globalSearchBox");
bandbox.addEventListener(Events.ON_CHANGING, this);
@ -114,22 +130,24 @@ public class GlobalSearch extends Div implements EventListener<Event> {
tabPanels.appendChild(tabPanel);
docController.create(tabPanel);
addEventListener(ON_SEARCH, this);
addEventListener(ON_CREATE_ECHO, this);
bandbox.addEventListener(ON_ENTER_KEY, this);
addEventListener(ON_POST_ENTER_KEY, this);
addEventListener(ON_SEARCH_EVENT, this);
addEventListener(ON_CREATE_ECHO_EVENT, this);
bandbox.addEventListener(ON_ENTER_KEY_EVENT, this);
addEventListener(ON_POST_ENTER_KEY_EVENT, this);
}
@Override
public void onEvent(Event event) throws Exception {
if (Events.ON_CHANGING.equals(event.getName())) {
if (Events.ON_CHANGING.equals(event.getName())) {
//post ON_SEARCH_EVENT for ON_CHANGING from bandbox
InputEvent inputEvent = (InputEvent) event;
String value = inputEvent.getValue();
bandbox.setAttribute("last.onchanging", value);
Events.postEvent(ON_SEARCH, this, value);
bandbox.setAttribute(LAST_ONCHANGING_ATTR, value);
Events.postEvent(ON_SEARCH_EVENT, this, value);
} else if (Events.ON_CHANGE.equals(event.getName())) {
bandbox.removeAttribute("last.onchanging");
bandbox.removeAttribute(LAST_ONCHANGING_ATTR);
} else if (Events.ON_CTRL_KEY.equals(event.getName())) {
//handle keyboard navigation for bandbox items
KeyEvent ke = (KeyEvent) event;
if (ke.getKeyCode() == KeyEvent.UP) {
if (bandbox.getFirstChild().isVisible()) {
@ -160,28 +178,30 @@ public class GlobalSearch extends Div implements EventListener<Event> {
}
}
}
} else if (event.getName().equals(ON_SEARCH)) {
} else if (event.getName().equals(ON_SEARCH_EVENT)) {
String value = (String) event.getData();
if (tabbox.getSelectedIndex()==0)
menuController.search(value);
else
docController.search(value);
bandbox.focus();
} else if (event.getName().equals(ON_CREATE_ECHO)) {
} else if (event.getName().equals(ON_CREATE_ECHO_EVENT)) {
//setup client side listener for enter key
StringBuilder script = new StringBuilder("jq('#")
.append(bandbox.getUuid())
.append("').bind('keydown', function(e) {let code=e.keyCode||e.which;if(code==13){")
.append("let widget=zk.Widget.$(this);")
.append("let event=new zk.Event(widget,'")
.append(ON_ENTER_KEY)
.append(ON_ENTER_KEY_EVENT)
.append("',{},{toServer:true});")
.append("zAu.send(event);")
.append("}});");
Clients.evalJavaScript(script.toString());
} else if (event.getName().equals(ON_ENTER_KEY)) {
} else if (event.getName().equals(ON_ENTER_KEY_EVENT)) {
Clients.showBusy(bandbox, null);
Events.echoEvent(ON_POST_ENTER_KEY, this, null);
} else if (event.getName().equals(ON_POST_ENTER_KEY)) {
Events.echoEvent(ON_POST_ENTER_KEY_EVENT, this, null);
} else if (event.getName().equals(ON_POST_ENTER_KEY_EVENT)) {
//execute search trigger by press of enter key
Clients.clearBusy(bandbox);
if (bandbox.getValue() != null && bandbox.getValue().startsWith(PREFIX_DOCUMENT_SEARCH)) {
DocumentSearch search = new DocumentSearch();
@ -195,11 +215,11 @@ public class GlobalSearch extends Div implements EventListener<Event> {
}
}
} else if (event.getName().equals(Events.ON_SELECT)) {
String value = (String) bandbox.getAttribute("last.onchanging");
String value = (String) bandbox.getAttribute(LAST_ONCHANGING_ATTR);
if (value == null) {
value = bandbox.getValue();
}
Events.postEvent(ON_SEARCH, this, value);
Events.postEvent(ON_SEARCH_EVENT, this, value);
}
}
@ -209,15 +229,21 @@ public class GlobalSearch extends Div implements EventListener<Event> {
@Override
public void onPageAttached(Page newpage, Page oldpage) {
super.onPageAttached(newpage, oldpage);
Events.echoEvent(ON_CREATE_ECHO, this, null);
Events.echoEvent(ON_CREATE_ECHO_EVENT, this, null);
}
/**
* Close {@link #bandbox} popup.
*/
public void closePopup() {
if (bandbox != null) {
bandbox.close();
}
}
/**
* Handle client info event from browser.
*/
public void onClientInfo() {
ZKUpdateUtil.setWindowHeightX(bandbox.getDropdown(), ClientInfo.get().desktopHeight-50);
}

View File

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

View File

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

View File

@ -42,16 +42,29 @@ import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.Bandpopup;
import org.zkoss.zul.Div;
public class LabelsSearch extends Div implements EventListener<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 String ON_ENTER_KEY = "onEnterKey";
private static final String ON_CREATE_ECHO = "onCreateEcho";
private static final String ON_SEARCH = "onSearch";
private Bandbox bandbox;
/** Event send from client side upon keyDown of enter key **/
private static final String ON_ENTER_KEY_EVENT = "onEnterKey";
/** Event echo from {@link #onPageAttached(Page, Page)} **/
private static final String ON_CREATE_ECHO_EVENT = "onCreateEcho";
/** Event to execute search. **/
private static final String ON_SEARCH_EVENT = "onSearch";
/** {@link #bandbox} attribute to store value from last {@link Events#ON_CHANGING} event **/
private static final String LAST_ONCHANGING_ATTR = "last.onchanging";
/** Bandbox to capture search text from user and display result in popup **/
private Bandbox bandbox;
/** Controller to perform search on AD_Label* records **/
private LabelsSearchController controller;
/**
* Standard constructot
* Standard constructor
* @param controller
*/
public LabelsSearch(LabelsSearchController controller) {
@ -59,6 +72,9 @@ public class LabelsSearch extends Div implements EventListener<Event> {
init();
}
/**
* Layout UI and setup listeners
*/
private void init() {
bandbox = new Bandbox();
appendChild(bandbox);
@ -77,22 +93,24 @@ public class LabelsSearch extends Div implements EventListener<Event> {
bandbox.appendChild(popup);
controller.create(popup);
addEventListener(ON_SEARCH, this);
addEventListener(ON_CREATE_ECHO, this);
addEventListener(ON_SEARCH_EVENT, this);
addEventListener(ON_CREATE_ECHO_EVENT, this);
addEventListener(LabelsSearchController.ON_POST_SELECT_LABELITEM_EVENT, this);
bandbox.addEventListener(ON_ENTER_KEY, this);
bandbox.addEventListener(ON_ENTER_KEY_EVENT, this);
}
@Override
public void onEvent(Event event) throws Exception {
if (Events.ON_CHANGING.equals(event.getName())) {
if (Events.ON_CHANGING.equals(event.getName())) {
//post ON_SEARCH_EVENT for ON_CHANGING event from bandbox
InputEvent inputEvent = (InputEvent) event;
String value = inputEvent.getValue();
bandbox.setAttribute("last.onchanging", value);
Events.postEvent(ON_SEARCH, this, value);
bandbox.setAttribute(LAST_ONCHANGING_ATTR, value);
Events.postEvent(ON_SEARCH_EVENT, this, value);
} else if (Events.ON_CHANGE.equals(event.getName())) {
bandbox.removeAttribute("last.onchanging");
bandbox.removeAttribute(LAST_ONCHANGING_ATTR);
} else if (Events.ON_CTRL_KEY.equals(event.getName())) {
//handle keyboard navigation for bandbox items
KeyEvent ke = (KeyEvent) event;
if (ke.getKeyCode() == KeyEvent.UP) {
if (bandbox.getFirstChild().isVisible()) {
@ -111,32 +129,33 @@ public class LabelsSearch extends Div implements EventListener<Event> {
}
}
}
} else if (event.getName().equals(ON_SEARCH)) {
} else if (event.getName().equals(ON_SEARCH_EVENT)) {
String value = (String) event.getData();
controller.search(value);
bandbox.focus();
} else if (event.getName().equals(ON_CREATE_ECHO)) {
} else if (event.getName().equals(ON_CREATE_ECHO_EVENT)) {
//setup client side keyDown listener for enter key
StringBuilder script = new StringBuilder("jq('#")
.append(bandbox.getUuid())
.append("').bind('keydown', function(e) {var code=e.keyCode||e.which;if(code==13){")
.append("var widget=zk.Widget.$(this);")
.append("var event=new zk.Event(widget,'")
.append(ON_ENTER_KEY)
.append(ON_ENTER_KEY_EVENT)
.append("',{},{toServer:true});")
.append("zAu.send(event);")
.append("}});");
Clients.evalJavaScript(script.toString());
} else if (event.getName().equals(ON_ENTER_KEY)) {
} else if (event.getName().equals(ON_ENTER_KEY_EVENT)) {
if (event.getTarget() instanceof Bandbox) {
controller.onSelect(controller.getSelectedItem());
}
} else if (event.getName().equals(Events.ON_SELECT)) {
String value = (String) bandbox.getAttribute("last.onchanging");
String value = (String) bandbox.getAttribute(LAST_ONCHANGING_ATTR);
if (value == null) {
value = bandbox.getValue();
}
Events.postEvent(ON_SEARCH, this, value);
Events.postEvent(ON_SEARCH_EVENT, this, value);
}
if (event.getName().equals(LabelsSearchController.ON_POST_SELECT_LABELITEM_EVENT)) {
@ -150,11 +169,11 @@ public class LabelsSearch extends Div implements EventListener<Event> {
@Override
public void onPageAttached(Page newpage, Page oldpage) {
super.onPageAttached(newpage, oldpage);
Events.echoEvent(ON_CREATE_ECHO, this, null);
Events.echoEvent(ON_CREATE_ECHO_EVENT, this, null);
}
/**
* Close the search dropdown
* Close {@link #bandbox} popup
*/
public void closePopup() {
if (bandbox != null) {
@ -163,7 +182,7 @@ public class LabelsSearch extends Div implements EventListener<Event> {
}
/**
* Set height of the search dropdown
* Set height {@link #bandbox} dropdown
*/
public void onClientInfo() {
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.Vlayout;
/**
* Controller for search on AD_Label* records.
*/
public class LabelsSearchController implements EventListener<Event>{
/** Event echo from {@link #onSelect(LabelItem)} **/
public static final String ON_POST_SELECT_LABELITEM_EVENT = "onPostSelectLabelitem";
private static final String ON_SEARCH_ECHO = "onSearchEcho";
private static final String ON_LOAD_MORE = "onLoadMore";
/** Event echo to initiate search for a given input text **/
private static final String ON_SEARCH_ECHO_EVENT = "onSearchEcho";
/** TODO: not used, candidate for removal **/
private static final String ON_LOAD_MORE_EVENT = "onLoadMore";
/** parent of {@link #layout} **/
private Component parent;
/** Listbox to display search result **/
private Listbox listbox;
/** model for {@link #listbox} **/
private ListModelList<LabelItem> model;
/** main layout **/
private Vlayout layout;
/** label window panel, provider for AD_Table_ID and Record_ID **/
private LabelsPanel labelsPanel;
/**
@ -103,13 +114,13 @@ public class LabelsSearchController implements EventListener<Event>{
ZKUpdateUtil.setWidth(listheader, "30px");
listhead.appendChild(listheader);
layout.addEventListener(ON_SEARCH_ECHO, this);
layout.addEventListener(ON_LOAD_MORE, this);
layout.addEventListener(ON_SEARCH_ECHO_EVENT, this);
layout.addEventListener(ON_LOAD_MORE_EVENT, this);
}
@Override
public void onEvent(Event event) throws Exception {
if (event.getName().equals(ON_SEARCH_ECHO)) {
if (event.getName().equals(ON_SEARCH_ECHO_EVENT)) {
onSearchEcho((String) event.getData());
} else if (Events.ON_CLICK.equals(event.getName())) {
if (event.getTarget() instanceof ListItem) {
@ -121,16 +132,16 @@ public class LabelsSearchController implements EventListener<Event>{
}
/**
* Search for a given text
* Echo {@link #ON_SEARCH_ECHO_EVENT} to initiate search for value
* @param value
*/
public void search(String value) {
listbox.setModel((ListModel<?>)null);
Events.echoEvent(ON_SEARCH_ECHO, layout, value);
Events.echoEvent(ON_SEARCH_ECHO_EVENT, layout, value);
}
/**
* Search for a given text
* Handle {@link #ON_SEARCH_ECHO_EVENT} to execute search for a given text
* @param value
*/
public void onSearchEcho(String value) {

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;
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
*
*/
public class MenuItem {
private String label;
private String description;
private String image;
/** report, process, workflow, form, info or window **/
private String type;
/** Corresponding {@link Treeitem} or {@link DefaultTreeNode} **/
private Object data;
/**
*
* default constructor
*/
public MenuItem() {
}

View File

@ -55,41 +55,60 @@ import org.zkoss.zul.Textbox;
import org.zkoss.zul.Tree;
import org.zkoss.zul.Treechildren;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.Treerow;
import org.zkoss.zul.Vlayout;
import org.zkoss.zul.impl.LabelElement;
import org.zkoss.zul.impl.LabelImageElement;
/**
* Controller for search on AD_Menu records.
* @author hengsin
*
*/
public class MenuSearchController implements EventListener<Event>{
/** Component attribute to hold reference of {@link MTreeNode} **/
public static final String M_TREE_NODE_ATTR = "MTreeNode";
/** font icon sclass for already added to favourite menu item **/
private static final String Z_ICON_STAR_O = "z-icon-star-o";
/** font icon sclass for not yet added to favourite menu item **/
private static final String Z_ICON_STAR = "z-icon-star";
private static final String ON_SEARCH_ECHO = "onSearchEcho";
private static final String ON_LOAD_MORE = "onLoadMore";
private static final String ONSELECT_TIMESTAMP = "onselect.timestamp";
/** Event echo from {@link #search(String)} to initiate search action **/
private static final String ON_SEARCH_ECHO_EVENT = "onSearchEcho";
/** Event to load all menu items into {@link #listbox}. Default is to load the first 50 only. **/
private static final String ON_LOAD_MORE_EVENT = "onLoadMore";
/** {@link Listitem} attribute to store the last timestamp of ON_CLICK or ON_SELECT event **/
private static final String ONSELECT_TIMESTAMP_ATTR = "onselect.timestamp";
/** name of star button **/
private static final String STAR_BUTTON_NAME = "Star";
/** name of new button **/
private static final String NEW_BUTTON_NAME = "New";
/** tree for AD_Menu **/
private Tree tree;
/** list box for menu items **/
private Listbox listbox;
/** model for all menu items **/
private ListModelList<MenuItem> model;
/** main layout component. parent of {@link #listbox}. **/
private Vlayout layout;
/** model for all menu items **/
private ListModelList<MenuItem> fullModel;
/** true when controller is handling event from Star/Favourite button **/
private boolean inStarEvent;
/** Event post from {@link #selectTreeitem(Object, Boolean)} **/
private static final String ON_POST_SELECT_TREEITEM_EVENT = "onPostSelectTreeitem";
/**
*
* @param tree
*/
public MenuSearchController(Tree tree) {
this.tree = tree;
}
/**
* Populate {@link #model} from {@link #tree}
*/
public void refreshModel() {
final List<MenuItem> list = new ArrayList<MenuItem>();
if (tree.getModel() == null) {
@ -116,6 +135,11 @@ public class MenuSearchController implements EventListener<Event>{
}, true);
}
/**
* Add treeNode to list
* @param list
* @param treeNode
*/
private void addTreeItem(List<MenuItem> list, DefaultTreeNode<?> treeNode) {
MTreeNode mNode = (MTreeNode) treeNode.getData();
if (!mNode.isLeaf())
@ -129,6 +153,10 @@ public class MenuSearchController implements EventListener<Event>{
list.add(item);
}
/**
* @param treeItem
* @return true if treeItem is a folder
*/
private boolean isFolder(Treeitem treeItem) {
List<Component> list = treeItem.getChildren();
for (Component c : list) {
@ -139,6 +167,11 @@ public class MenuSearchController implements EventListener<Event>{
return false;
}
/**
* Add treeItem to list
* @param list
* @param treeItem
*/
private void addTreeItem(List<MenuItem> list, Treeitem treeItem) {
if (isFolder(treeItem))
return;
@ -158,6 +191,10 @@ public class MenuSearchController implements EventListener<Event>{
item.setType((String) treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE));
}
/**
* @param treeItem
* @return label for treeItem
*/
private String getLabel(Treeitem treeItem) {
String label = treeItem.getLabel();
if (label == null || label.trim().length() == 0)
@ -172,6 +209,10 @@ public class MenuSearchController implements EventListener<Event>{
return label;
}
/**
* @param treeItem
* @return image url or font icon sclass (start with z-icon)
*/
private String getImage(Treeitem treeItem) {
String image = treeItem.getImage();
if (image == null || image.trim().length() == 0)
@ -189,6 +230,10 @@ public class MenuSearchController implements EventListener<Event>{
return image != null ? image.intern() : null;
}
/**
* Call {@link #refreshModel()} and layout UI.
* @param parent
*/
public void create(Component parent) {
refreshModel();
@ -220,8 +265,8 @@ public class MenuSearchController implements EventListener<Event>{
ZKUpdateUtil.setWidth(listheader, "28px");
listhead.appendChild(listheader);
layout.addEventListener(ON_SEARCH_ECHO, this);
layout.addEventListener(ON_LOAD_MORE, this);
layout.addEventListener(ON_SEARCH_ECHO_EVENT, this);
layout.addEventListener(ON_LOAD_MORE_EVENT, this);
updateListboxModel(model);
FavouriteController controller = FavouriteController.getInstance(Executions.getCurrent().getSession());
@ -240,7 +285,7 @@ public class MenuSearchController implements EventListener<Event>{
} else if (Events.ON_CLICK.equals(event.getName())) {
if (event.getTarget() instanceof ListItem) {
ListItem item = (ListItem) event.getTarget();
Long onSelect = (Long) item.getAttribute(ONSELECT_TIMESTAMP);
Long onSelect = (Long) item.getAttribute(ONSELECT_TIMESTAMP_ATTR);
if (onSelect == null) {
onSelect(item, Boolean.FALSE);
} else if (System.currentTimeMillis() - onSelect.longValue() > 1000) {
@ -276,9 +321,9 @@ public class MenuSearchController implements EventListener<Event>{
inStarEvent = false;
}
}
} else if (event.getName().equals(ON_SEARCH_ECHO)) {
} else if (event.getName().equals(ON_SEARCH_ECHO_EVENT)) {
onSearchEcho((String) event.getData());
} else if (event.getName().equals(ON_LOAD_MORE)) {
} else if (event.getName().equals(ON_LOAD_MORE_EVENT)) {
loadMore();
}
}
@ -297,13 +342,19 @@ public class MenuSearchController implements EventListener<Event>{
listbox.setModel(t);
}
/**
* Echo {@link #ON_LOAD_MORE_EVENT} if selected is of type "...".
* Otherwise delegate to {@link #selectTreeitem(Object, Boolean)}.
* @param selected
* @param newRecord true if event is originated from new record button
*/
private void onSelect(ListItem selected, Boolean newRecord) {
MenuItem item = selected.getValue();
if (item == null) return;
if ("...".equals(item.getType())) {
selected.setAttribute(ONSELECT_TIMESTAMP, System.currentTimeMillis());
selected.setAttribute(ONSELECT_TIMESTAMP_ATTR, System.currentTimeMillis());
Clients.showBusy(selected, null);
Events.echoEvent(ON_LOAD_MORE, layout, null);
Events.echoEvent(ON_LOAD_MORE_EVENT, layout, null);
} else {
if (newRecord) {
Treeitem ti = (Treeitem)item.getData();
@ -312,10 +363,14 @@ public class MenuSearchController implements EventListener<Event>{
newRecord = false;
}
selectTreeitem(item.getData(), newRecord);
selected.setAttribute(ONSELECT_TIMESTAMP, System.currentTimeMillis());
selected.setAttribute(ONSELECT_TIMESTAMP_ATTR, System.currentTimeMillis());
}
}
/**
* Load {@link #fullModel} to {@link #listbox}.
* Only first 50 loaded to {@link #listbox} initially.
*/
private void loadMore() {
ListModel<MenuItem> listModel = listbox.getModel();
ListModelList<MenuItem> lml = (ListModelList<MenuItem>) listModel;
@ -327,6 +382,11 @@ public class MenuSearchController implements EventListener<Event>{
Clients.scrollIntoView(listbox.getSelectedItem());
}
/**
* Call {@link #select(Treeitem)} and post {@link #ON_POST_SELECT_TREEITEM_EVENT} event.
* @param node {@link Treeitem} or {@link DefaultTreeNode}
* @param newRecord
*/
private void selectTreeitem(Object node, Boolean newRecord) {
if (Executions.getCurrent().getAttribute(listbox.getUuid()+".selectTreeitem") != null)
return;
@ -350,6 +410,10 @@ public class MenuSearchController implements EventListener<Event>{
}
}
/**
* Make sure all parent node is open and ensure tree selected item is selectedItem
* @param selectedItem
*/
private void select(Treeitem selectedItem) {
Treeitem parent = selectedItem.getParentItem();
while (parent != null) {
@ -361,6 +425,11 @@ public class MenuSearchController implements EventListener<Event>{
selectedItem.getTree().setSelectedItem(selectedItem);
}
/**
* Handle {@link #ON_POST_SELECT_TREEITEM_EVENT} event.
* Post ON_CLICK event to link ({@link A} or {@link Treerow}).
* @param newRecord
*/
private void onPostSelectTreeitem(Boolean newRecord) {
Event event = null;
if (tree.getSelectedItem().getTreerow().getFirstChild().getFirstChild() instanceof A)
@ -374,11 +443,19 @@ public class MenuSearchController implements EventListener<Event>{
Events.postEvent(event);
}
/**
* Echo {@link #ON_SEARCH_ECHO_EVENT} to initial search with value.
* @param value
*/
public void search(String value) {
listbox.setModel((ListModel<?>)null);
Events.echoEvent(ON_SEARCH_ECHO, layout, value);
Events.echoEvent(ON_SEARCH_ECHO_EVENT, layout, value);
}
/**
* Handle {@link #ON_SEARCH_ECHO_EVENT} event.
* @param value
*/
public void onSearchEcho(String value) {
ListModelList<MenuItem> newModel = null;
if (Util.isEmpty(value)) {
@ -391,6 +468,12 @@ public class MenuSearchController implements EventListener<Event>{
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) {
fullModel = null;
if (newModel.size() > 50) {
@ -406,10 +489,20 @@ public class MenuSearchController implements EventListener<Event>{
listbox.setModel(newModel);
}
/**
* Comparator to help filter menu items with a filter value.
*/
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;
/**
* @param compare filter text
*/
private MenuListComparator(String compare) {
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() {
int i = listbox.getSelectedIndex();
if (i > 0) {
@ -444,6 +541,10 @@ public class MenuSearchController implements EventListener<Event>{
return null;
}
/**
* select ListItem that comes after the current selected ListItem.
* @return new selected {@link MenuItem}
*/
public MenuItem selectNext() {
int i = listbox.getSelectedIndex();
if (i < 0 && listbox.getItemCount() > 0) {
@ -467,6 +568,11 @@ public class MenuSearchController implements EventListener<Event>{
return null;
}
/**
* Handle ON_OK event
* @param textbox
* @return true if there's partial or exact match for textbox value
*/
public boolean onOk(Textbox textbox) {
String text = textbox.getText();
if (Util.isEmpty(text))
@ -498,6 +604,9 @@ public class MenuSearchController implements EventListener<Event>{
return false;
}
/**
* {@link ListitemRenderer} for {@link #listbox}
*/
private class MenuItemRenderer implements ListitemRenderer<MenuItem>, ListitemRendererExt {
private static final String REMOVE_FROM_FAVOURITES_MSG = "RemoveFromFavourites";
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;
/**
* Dialog to Start process or report.
* Embedded Dialog to Start process or report.
* Displays information about the process
* and lets the user decide to start it
* and displays results (optionally print them).
@ -90,30 +90,42 @@ import com.lowagie.text.pdf.PdfWriter;
public class ProcessDialog extends AbstractProcessDialog implements EventListener<Event>, IHelpContext
{
/**
*
* generated serial id
*/
private static final long serialVersionUID = -6728929130788829223L;
public static final String ON_INITIAL_FOCUS_EVENT = "onInitialFocus";
private static final String ON_OK_ECHO = "onOkEcho";
/**
* Event echo form {@link #onOk()} to defer execution of {@link #onOk()}.
* Execution is defer to happens after the dismiss of modal dialog (usually info window) blocking parameter panel.
*/
private static final String ON_OK_ECHO_EVENT = "onOkEcho";
/** Logger */
private static final CLogger log = CLogger.getCLogger(ProcessDialog.class);
//
private Table logMessageTable;
private int[] m_ids = null;
/** message from {@link ProcessInfoLog} **/
private Table logMessageTable;
/** record ids from {@link ProcessInfo} **/
private int[] m_ids = null;
/** true if dialog is showing process parameters **/
private boolean isParameterPage = true;
private Mask mask;
/** layout for process execution result **/
private HtmlBasedComponent resultPanelLayout;
/** process message content of {@link #resultPanelLayout} **/
private HtmlBasedComponent messageResultContent;
/** process log content of {@link #resultPanelLayout}, host {@link #logMessageTable} **/
private HtmlBasedComponent infoResultContent;
/** Window No */
private int m_WindowNo = -1;
private int m_WindowNo = -1;
/** timestamp of previous key event **/
private long prevKeyEventTime = 0;
/**
* Previous key event. use together with {@link #prevKeyEventTime} to detect double firing of key event from browser.
*/
private KeyEvent prevKeyEvent;
/**
@ -134,7 +146,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
*/
public ProcessDialog (int AD_Process_ID, boolean isSOTrx, String predefinedContextVariables)
{
log.info("Process=" + AD_Process_ID );
if (log.isLoggable(Level.INFO)) log.info("Process=" + AD_Process_ID );
m_WindowNo = SessionManager.getAppDesktop().registerWindow(this);
this.setAttribute(IDesktop.WINDOWNO_ATTRIBUTE, m_WindowNo);
Env.setContext(Env.getCtx(), m_WindowNo, "IsSOTrx", isSOTrx ? "Y" : "N");
@ -145,7 +157,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
querySaved();
addEventListener(WindowContainer.ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT, this);
addEventListener(ON_INITIAL_FOCUS_EVENT, this);
addEventListener(ON_OK_ECHO, this);
addEventListener(ON_OK_ECHO_EVENT, this);
}
catch(Exception ex)
{
@ -188,7 +200,8 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
super.dispose();
SessionManager.getAppDesktop().closeWindow(getWindowNo());
}// dispose
@Override
public void onEvent(Event event) {
Component component = event.getTarget();
@ -198,7 +211,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
super.onEvent(event);
onOk();
} else if (event.getName().equals(ON_OK_ECHO)) {
} else if (event.getName().equals(ON_OK_ECHO_EVENT)) {
onOk();
}else if (bCancel.equals(component)){
super.onEvent(event);
@ -236,12 +249,15 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
}
}
/**
* Handle ON_Click event from {@link #bOK}
*/
private void onOk() {
if (isParameterPage)
{
if (getParameterPanel().isWaitingForDialog())
{
Events.echoEvent(ON_OK_ECHO, this, null);
Events.echoEvent(ON_OK_ECHO_EVENT, this, null);
return;
}
startProcess();
@ -250,6 +266,10 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
restart();
}
/**
* Handle shortcut key event
* @param keyEvent
*/
private void onCtrlKeyEvent(KeyEvent keyEvent) {
if (keyEvent.isAltKey() && keyEvent.getKeyCode() == 0x58) { // Alt-X
if (m_WindowNo > 0) {
@ -261,6 +281,10 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
}
}
/**
* Handle on click event for record link.
* @param btn
*/
private void doOnClick(A btn) {
int Record_ID = 0;
int AD_Table_ID =0;
@ -272,8 +296,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
catch (Exception e) {
}
if (Record_ID > 0 && AD_Table_ID > 0) {
if (Record_ID > 0 && AD_Table_ID > 0) {
AEnv.zoom(AD_Table_ID, Record_ID);
}
}
@ -286,6 +309,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
LayoutUtils.openOverlappedWindow(this, progressWindow, "middle_center");
}
/**
* @return in progress mask
*/
private Div getMask() {
if (mask == null) {
mask = new Mask();
@ -293,9 +319,14 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
return mask;
}
/**
* show in progress mask
* @param window
*/
private void showBusyMask(Window window) {
if (getParent() != null) {
getParent().appendChild(getMask());
//to prevent focus to components beneath the in progress mask (see canActivate in web/js/org/idempiere/commons/window.js)
StringBuilder script = new StringBuilder("(function(){let w=zk.Widget.$('#");
script.append(getParent().getUuid()).append("');");
if (window != null) {
@ -308,6 +339,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
}
}
/**
* close in progress mask
*/
private void hideBusyMask()
{
if (mask != null && mask.getParent() != null) {
@ -333,6 +367,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
swithToFinishScreen();
}
/**
* Switch to process execution result panel.
*/
protected void swithToFinishScreen() {
ProcessInfo pi = getProcessInfo();
ProcessInfoUtil.setLogFromDB(pi);
@ -375,6 +412,10 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
Clients.response(new AuEcho(this, "onAfterProcess", null));
}
/**
* layout process execution result panel
* @param topParameterLayout
*/
private void layoutResultPanel (HtmlBasedComponent topParameterLayout){
if (resultPanelLayout == null){
resultPanelLayout = new Vlayout();
@ -388,11 +429,21 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
}
}
/**
* replace oldComponent with newComponent
* @param newComponent
* @param oldComponent
*/
protected void replaceComponent(HtmlBasedComponent newComponent, HtmlBasedComponent oldComponent) {
oldComponent.getParent().insertBefore(newComponent, oldComponent);
oldComponent.detach();
}
/**
* append m_logs content to {@link #logMessageTable}
* @param m_logs
* @param infoResultContent
*/
private void appendRecordLogInfo(ProcessInfoLog[] m_logs, HtmlBasedComponent infoResultContent) {
if (m_logs == null)
return;
@ -466,9 +517,11 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
tr.appendChild(td);
}
}
//messageDiv.appendChild(logMessageTable);
}
/**
* Move back from process execution result panel to process parameter panel
*/
private void restart() {
replaceComponent (topParameterLayout, resultPanelLayout);
@ -500,6 +553,9 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
invalidate();
}
/**
* Handle onAfterProcess event echo from {@link #swithToFinishScreen()}
*/
public void onAfterProcess()
{
//
@ -510,15 +566,15 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
}
}
/**************************************************************************
* Optional Processing Task
/**
* Optional after/post process execution task
*/
private boolean afterProcessTask()
{
// something to do?
if (m_ids != null && m_ids.length > 0)
{
log.config("");
if (log.isLoggable(Level.CONFIG)) log.config("");
// Print invoices
if (getAD_Process_ID() == PROCESS_C_INVOICE_GENERATE)
{
@ -538,8 +594,8 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
return false;
} // afterProcessTask
/**************************************************************************
* Print Shipments
/**
* Print Shipments
*/
private void printShipments()
{
@ -557,8 +613,11 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
}
}
});
} // printInvoices
}
/**
* Handle onPrintShipments event echo by {@link #printShipments()}
*/
public void onPrintShipments()
{
// Loop through all items
@ -629,7 +688,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
}
/**
* Print Invoices
* Print Invoices
*/
private void printInvoices()
{
@ -649,8 +708,11 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
}
}
});
} // printInvoices
}
/**
* Handle onPrintInvoices event echo by {@link #printInvoices()}
*/
public void onPrintInvoices()
{
// Loop through all items

View File

@ -48,15 +48,22 @@ import org.zkoss.zk.ui.event.Events;
public class ProcessModalDialog extends AbstractProcessDialog implements EventListener<Event>, DialogEvents
{
/**
*
* generated serial id
*/
private static final long serialVersionUID = -6227339628038418701L;
private static final String ON_OK_ECHO = "onOkEcho";
/**
* Event echo form {@link #onOk()} to defer execution of {@link #onOk()}.
* Execution is defer to happens after the dismiss of modal dialog (usually info window) blocking parameter panel.
*/
private static final String ON_OK_ECHO_EVENT = "onOkEcho";
/** Logger */
private static final CLogger log = CLogger.getCLogger(ProcessModalDialog.class);
//
/**
* Store screen orientation from last onClientInfo event.
* Use to detect change of screen orientation and adapt layout accordingly.
*/
private String orientation;
/**
@ -172,10 +179,17 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi
{
log.log(Level.SEVERE, "", ex);
}
addEventListener(ON_OK_ECHO, this);
addEventListener(ON_OK_ECHO_EVENT, this);
addEventListener(Events.ON_CANCEL, e -> onCancel());
}
/**
* @param WindowNo
* @param AD_Process_ID
* @param tableId
* @param recordId
* @param autoStart
*/
public ProcessModalDialog (int WindowNo, int AD_Process_ID, int tableId, int recordId, boolean autoStart)
{
this(null, WindowNo, AD_Process_ID, tableId, recordId, autoStart);
@ -265,12 +279,13 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi
/**
* handle events
*/
@Override
public void onEvent(Event event) {
Component component = event.getTarget();
if (component.equals(bOK)) {
super.onEvent(event);
onOk();
} else if (event.getName().equals(ON_OK_ECHO)) {
} else if (event.getName().equals(ON_OK_ECHO_EVENT)) {
onOk();
} else if (component.equals(bCancel)) {
super.onEvent(event);
@ -280,14 +295,20 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi
}
}
/**
* Handle ON_Click event from {@link #bCancel}
*/
private void onCancel() {
cancelProcess();
}
/**
* Handle ON_Click event from {@link #bOK}
*/
private void onOk() {
if (getParameterPanel().isWaitingForDialog())
{
Events.echoEvent(ON_OK_ECHO, this, null);
Events.echoEvent(ON_OK_ECHO_EVENT, this, null);
return;
}
if(fPrintFormat != null && fPrintFormat.getValue() != null) {
@ -302,6 +323,9 @@ public class ProcessModalDialog extends AbstractProcessDialog implements EventLi
startProcess();
}
/**
* Handle client info event from browser
*/
protected void onClientInfo() {
if (getPage() != null) {
String newOrientation = ClientInfo.get().orientation;

View File

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

View File

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

View File

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

View File

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