IDEMPIERE-5570 Zk: Improve readability of code (#1666)
This commit is contained in:
parent
801d1fb898
commit
19459be87b
|
@ -53,11 +53,13 @@ public class AtmosphereServerPush implements ServerPush {
|
|||
|
||||
private static final String ON_ACTIVATE_DESKTOP = "onActivateDesktop";
|
||||
|
||||
/** default timeout of of 2 minutes **/
|
||||
public static final int DEFAULT_TIMEOUT = 1000 * 60 * 2;
|
||||
|
||||
private final AtomicReference<Desktop> desktop = new AtomicReference<Desktop>();
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
/** asynchronous request reference as AtmosphereResource **/
|
||||
private final AtomicReference<AtmosphereResource> resource = new AtomicReference<AtmosphereResource>();
|
||||
private final int timeout;
|
||||
|
||||
|
@ -66,6 +68,9 @@ public class AtmosphereServerPush implements ServerPush {
|
|||
private final Object _mutex = new Object();
|
||||
private List<Schedule<Event>> schedules = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public AtmosphereServerPush() {
|
||||
String timeoutString = Library.getProperty("fi.jawsy.jawwa.zk.atmosphere.timeout");
|
||||
if (timeoutString == null || timeoutString.trim().length() == 0) {
|
||||
|
@ -120,10 +125,19 @@ public class AtmosphereServerPush implements ServerPush {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* release current AtmosphereResource
|
||||
* @param resource
|
||||
*/
|
||||
public void clearResource(AtmosphereResource resource) {
|
||||
this.resource.compareAndSet(resource, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* commit/resume response for current AtmosphereResource
|
||||
* @return true if resource is available
|
||||
* @throws IOException
|
||||
*/
|
||||
private boolean commitResponse() throws IOException {
|
||||
AtmosphereResource resource = this.resource.getAndSet(null);
|
||||
if (resource != null) {
|
||||
|
@ -224,6 +238,10 @@ public class AtmosphereServerPush implements ServerPush {
|
|||
startClientPush(desktop);
|
||||
}
|
||||
|
||||
/**
|
||||
* start serverpush request at client side
|
||||
* @param desktop
|
||||
*/
|
||||
private void startClientPush(Desktop desktop) {
|
||||
Clients.response("jawwa.atmosphere.serverpush", new AuScript(null, "jawwa.atmosphere.startServerPush('" + desktop.getId() + "', " + timeout
|
||||
+ ");"));
|
||||
|
@ -256,6 +274,10 @@ public class AtmosphereServerPush implements ServerPush {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle asynchronous server push request (long polling request)
|
||||
* @param resource
|
||||
*/
|
||||
public void onRequest(AtmosphereResource resource) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace(resource.transport().name());
|
||||
|
@ -267,6 +289,7 @@ public class AtmosphereServerPush implements ServerPush {
|
|||
return;
|
||||
}
|
||||
|
||||
//suspend request for server push event
|
||||
if (!resource.isSuspended()) {
|
||||
//browser default timeout is 2 minutes
|
||||
resource.suspend(5, TimeUnit.MINUTES);
|
||||
|
|
|
@ -1,18 +1,59 @@
|
|||
/***********************************************************************
|
||||
* 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 fi.jawsy.jawwa.zk.atmosphere;
|
||||
|
||||
/**
|
||||
* class to hold two value, left and right
|
||||
* @author hengsin
|
||||
*
|
||||
* @param <L>
|
||||
* @param <R>
|
||||
*/
|
||||
public class Either<L, R> {
|
||||
private L left;
|
||||
private R right;
|
||||
|
||||
/**
|
||||
* @param l left value
|
||||
* @param r right value
|
||||
*/
|
||||
public Either(L l, R r) {
|
||||
left = l;
|
||||
right = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return left value
|
||||
*/
|
||||
public L getLeftValue() {
|
||||
return left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return right value
|
||||
*/
|
||||
public R getRightValue() {
|
||||
return right;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,12 @@ public class ZkAtmosphereHandler implements AtmosphereHandler {
|
|||
public void destroy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Zk {@link Desktop} instance from session by desktop id
|
||||
* @param session
|
||||
* @param dtid desktop id
|
||||
* @return left as error message and right as {@link Desktop} reference
|
||||
*/
|
||||
private Either<String, Desktop> getDesktop(Session session, String dtid) {
|
||||
if (session.getWebApp() instanceof WebAppCtrl) {
|
||||
WebAppCtrl webAppCtrl = (WebAppCtrl) session.getWebApp();
|
||||
|
@ -64,11 +70,21 @@ public class ZkAtmosphereHandler implements AtmosphereHandler {
|
|||
return new Either<String, Desktop>("Webapp does not implement WebAppCtrl", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Zk {@link Desktop} id from HttpServletRequest parameter (dtid)
|
||||
* @param request
|
||||
* @return left as desktop id and right as error message
|
||||
*/
|
||||
private Either<String, String> getDesktopId(HttpServletRequest request) {
|
||||
String dtid = request.getParameter("dtid");
|
||||
return new Either<String, String>(dtid, DESKTOP_NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link AtmosphereServerPush} instance from {@link AtmosphereResource}
|
||||
* @param resource {@link AtmosphereResource}
|
||||
* @return left as error message and right as AtmosphereServerPush reference
|
||||
*/
|
||||
private Either<String, AtmosphereServerPush> getServerPush(AtmosphereResource resource) {
|
||||
AtmosphereRequest request = resource.getRequest();
|
||||
|
||||
|
@ -96,6 +112,11 @@ public class ZkAtmosphereHandler implements AtmosphereHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link AtmosphereServerPush} instance from {@link Desktop}
|
||||
* @param desktop
|
||||
* @return left as error message and right as {@link AtmosphereServerPush} reference
|
||||
*/
|
||||
private Either<String, AtmosphereServerPush> getServerPush(Desktop desktop) {
|
||||
if (desktop instanceof DesktopCtrl) {
|
||||
DesktopCtrl desktopCtrl = (DesktopCtrl) desktop;
|
||||
|
@ -109,6 +130,12 @@ public class ZkAtmosphereHandler implements AtmosphereHandler {
|
|||
return new Either<String, AtmosphereServerPush>("Desktop does not implement DesktopCtrl", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link Session} from request
|
||||
* @param resource
|
||||
* @param request
|
||||
* @return left as error message and right as Session reference
|
||||
*/
|
||||
private Either<String, Session> getSession(AtmosphereResource resource, HttpServletRequest request) {
|
||||
Session session = WebManager.getSession(resource.getAtmosphereConfig().getServletContext(), request, false);
|
||||
if (session == null) {
|
||||
|
|
|
@ -90,23 +90,31 @@ import org.zkoss.zul.Window;
|
|||
*/
|
||||
public class AdempiereWebUI extends Window implements EventListener<Event>, IWebClient
|
||||
{
|
||||
/** {@link Session} attribute to hold current login user id value **/
|
||||
public static final String CHECK_AD_USER_ID_ATTR = "Check_AD_User_ID";
|
||||
|
||||
/** Boolean attribute to indicate the HTTP session of a Desktop have been invalidated **/
|
||||
public static final String DESKTOP_SESSION_INVALIDATED_ATTR = "DesktopSessionInvalidated";
|
||||
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = -6725805283410008847L;
|
||||
|
||||
/** {@link Desktop} attribute to hold {@link IDesktop} reference **/
|
||||
public static final String APPLICATION_DESKTOP_KEY = "application.desktop";
|
||||
|
||||
public static String APP_NAME = null;
|
||||
|
||||
public static final String UID = "1.0.0";
|
||||
|
||||
/** Attribute for widget instance name, use for Selenium test **/
|
||||
public static final String WIDGET_INSTANCE_NAME = "instanceName";
|
||||
|
||||
/** login and role selection window **/
|
||||
private WLogin loginDesktop;
|
||||
|
||||
/** client info from browser **/
|
||||
private ClientInfo clientInfo = new ClientInfo();
|
||||
|
||||
private String langSession;
|
||||
|
@ -119,16 +127,23 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
|
||||
private static final CLogger logger = CLogger.getCLogger(AdempiereWebUI.class);
|
||||
|
||||
@Deprecated(forRemoval = true, since = "11")
|
||||
public static final String EXECUTION_CARRYOVER_SESSION_KEY = "execution.carryover";
|
||||
|
||||
/** Session attribute to hold {@link ClientInfo} reference **/
|
||||
private static final String CLIENT_INFO = "client.info";
|
||||
|
||||
/** the use of event thread have been deprecated, this should always be false **/
|
||||
private static boolean eventThreadEnabled = false;
|
||||
|
||||
private ConcurrentMap<String, String[]> m_URLParameters;
|
||||
|
||||
/** Login completed event **/
|
||||
private static final String ON_LOGIN_COMPLETED = "onLoginCompleted";
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public AdempiereWebUI()
|
||||
{
|
||||
this.setVisible(false);
|
||||
|
@ -140,8 +155,12 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
this.addEventListener(ON_LOGIN_COMPLETED, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle onCreate event from index.zul, don't call this directly.
|
||||
*/
|
||||
public void onCreate()
|
||||
{
|
||||
//handle ping request
|
||||
String ping = Executions.getCurrent().getHeader("X-PING");
|
||||
if (!Util.isEmpty(ping, true))
|
||||
{
|
||||
|
@ -183,6 +202,9 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
eventThreadEnabled = Executions.getCurrent().getDesktop().getWebApp().getConfiguration().isEventThreadEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* perform clean up for ping request
|
||||
*/
|
||||
private void cleanupForPing() {
|
||||
final Desktop desktop = Executions.getCurrent().getDesktop();
|
||||
final WebApp wapp = desktop.getWebApp();
|
||||
|
@ -208,10 +230,16 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle onOK (enter key) event
|
||||
*/
|
||||
public void onOk()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle onCancel(escape key) event
|
||||
*/
|
||||
public void onCancel()
|
||||
{
|
||||
}
|
||||
|
@ -219,6 +247,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
/* (non-Javadoc)
|
||||
* @see org.adempiere.webui.IWebClient#loginCompleted()
|
||||
*/
|
||||
@Override
|
||||
public void loginCompleted()
|
||||
{
|
||||
if (loginDesktop != null)
|
||||
|
@ -280,7 +309,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
mSession.saveEx();
|
||||
}
|
||||
|
||||
currSess.setAttribute("Check_AD_User_ID", Env.getAD_User_ID(ctx));
|
||||
currSess.setAttribute(CHECK_AD_USER_ID_ATTR, Env.getAD_User_ID(ctx));
|
||||
|
||||
//enable full interface, relook into this when doing preference
|
||||
Env.setContext(ctx, Env.SHOW_TRANSLATION, true);
|
||||
|
@ -298,14 +327,14 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
keyListener.setCtrlKeys("@a@c@d@e@f@h@l@m@n@o@p@q@r@s@t@w@x@z@#left@#right@#up@#down@#home@#end#enter^u@u@#pgdn@#pgup$#f2^#f2");
|
||||
keyListener.setAutoBlur(false);
|
||||
|
||||
//create new desktop
|
||||
//create IDesktop instance
|
||||
IDesktop appDesktop = createDesktop();
|
||||
appDesktop.setClientInfo(clientInfo);
|
||||
appDesktop.createPart(this.getPage());
|
||||
this.getPage().getDesktop().setAttribute(APPLICATION_DESKTOP_KEY, new WeakReference<IDesktop>(appDesktop));
|
||||
appDesktop.getComponent().getRoot().addEventListener(Events.ON_CLIENT_INFO, this);
|
||||
|
||||
//track browser tab per session
|
||||
//track browser tab per session, 1 browser tab = 1 zk Desktop
|
||||
SessionContextListener.addDesktopId(mSession.getAD_Session_ID(), getPage().getDesktop().getId());
|
||||
|
||||
//ensure server push is on
|
||||
|
@ -330,7 +359,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
Env.setContext(ctx, Env.IS_CAN_APPROVE_OWN_DOC, MRole.getDefault().isCanApproveOwnDoc());
|
||||
Clients.response(new AuScript("zAu.cmd0.clearBusy()"));
|
||||
|
||||
//add dynamic style
|
||||
//add dynamic style for AD tab
|
||||
StringBuilder cssContent = new StringBuilder();
|
||||
cssContent.append(".adtab-form-borderlayout .z-south-collapsed:before { ");
|
||||
cssContent.append("content: \"");
|
||||
|
@ -347,6 +376,9 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
processParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* process URL parameters from browser
|
||||
*/
|
||||
private void processParameters() {
|
||||
String action = getPrmString("Action");
|
||||
if ("Zoom".equalsIgnoreCase(action)) {
|
||||
|
@ -368,6 +400,10 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
m_URLParameters = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param prm parameter name
|
||||
* @return string value for parameter
|
||||
*/
|
||||
private String getPrmString(String prm) {
|
||||
String retValue = "";
|
||||
if (m_URLParameters != null) {
|
||||
|
@ -378,6 +414,10 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
return retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param prm parameter name
|
||||
* @return integer value for parameter
|
||||
*/
|
||||
private int getPrmInt(String prm) {
|
||||
int retValue = 0;
|
||||
String str = getPrmString(prm);
|
||||
|
@ -398,6 +438,10 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
return keyListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create IDesktop instance. Default is {@link DefaultDesktop}
|
||||
* @return {@link IDesktop}
|
||||
*/
|
||||
private IDesktop createDesktop()
|
||||
{
|
||||
IDesktop appDesktop = null;
|
||||
|
@ -424,6 +468,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
/* (non-Javadoc)
|
||||
* @see org.adempiere.webui.IWebClient#logout()
|
||||
*/
|
||||
@Override
|
||||
public void logout()
|
||||
{
|
||||
final Desktop desktop = Executions.getCurrent().getDesktop();
|
||||
|
@ -447,6 +492,10 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* after logout action for Session
|
||||
* @param session
|
||||
*/
|
||||
private void afterLogout(final Session session) {
|
||||
try {
|
||||
((SessionCtrl)session).onDestroyed();
|
||||
|
@ -457,7 +506,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
}
|
||||
|
||||
/**
|
||||
* Perform logout after user close a browser tab without first logging out
|
||||
* Auto logout after user close browser tab without first logging out
|
||||
*/
|
||||
public void logoutAfterTabDestroyed(){
|
||||
Desktop desktop = Executions.getCurrent().getDesktop();
|
||||
|
@ -472,7 +521,10 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
afterLogout(session);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Logout current session
|
||||
* @return {@link Session}
|
||||
*/
|
||||
protected Session logout0() {
|
||||
Session session = Executions.getCurrent() != null ? Executions.getCurrent().getDesktop().getSession() : null;
|
||||
|
||||
|
@ -502,6 +554,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
/**
|
||||
* @return IDesktop
|
||||
*/
|
||||
@Override
|
||||
public IDesktop getAppDeskop()
|
||||
{
|
||||
Desktop desktop = Executions.getCurrent() != null ? Executions.getCurrent().getDesktop() : null;
|
||||
|
@ -519,6 +572,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
return appDesktop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
if (event instanceof ClientInfoEvent) {
|
||||
ClientInfoEvent c = (ClientInfoEvent)event;
|
||||
|
@ -564,6 +618,11 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* handle change role event
|
||||
* @param locale
|
||||
* @param context
|
||||
*/
|
||||
private void onChangeRole(Locale locale, Properties context) {
|
||||
SessionManager.setSessionApplication(this);
|
||||
loginDesktop = new WLogin(this);
|
||||
|
@ -576,6 +635,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
* @param userId
|
||||
* @return UserPreference
|
||||
*/
|
||||
@Override
|
||||
public UserPreference loadUserPreference(int userId) {
|
||||
userPreference.loadPreference(userId);
|
||||
return userPreference;
|
||||
|
@ -584,10 +644,15 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
/**
|
||||
* @return UserPrerence
|
||||
*/
|
||||
@Override
|
||||
public UserPreference getUserPreference() {
|
||||
return userPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should always return false
|
||||
* @return true if event thread is enabled
|
||||
*/
|
||||
public static boolean isEventThreadEnabled() {
|
||||
return eventThreadEnabled;
|
||||
}
|
||||
|
@ -635,6 +700,12 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
appDesktop.logout(T -> {if (T) asyncChangeRole(session, locale, properties);});
|
||||
}
|
||||
|
||||
/**
|
||||
* change role, asynchronous callback from {@link IDesktop#logout(org.adempiere.util.Callback)}
|
||||
* @param httpSession
|
||||
* @param locale
|
||||
* @param properties
|
||||
*/
|
||||
private void asyncChangeRole(HttpSession httpSession, Locale locale, Properties properties) {
|
||||
//stop key listener
|
||||
if (keyListener != null) {
|
||||
|
@ -675,8 +746,8 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
}
|
||||
|
||||
/**
|
||||
* @return string for setupload
|
||||
*/
|
||||
* @return setting for setUpload call
|
||||
*/
|
||||
public static String getUploadSetting() {
|
||||
StringBuilder uploadSetting = new StringBuilder("true,native");
|
||||
int size = MSysConfig.getIntValue(MSysConfig.ZK_MAX_UPLOAD_SIZE, 0);
|
||||
|
|
|
@ -29,16 +29,17 @@ import org.zkoss.zk.ui.event.Events;
|
|||
import org.zkoss.zk.ui.sys.ComponentCtrl;
|
||||
|
||||
/**
|
||||
*
|
||||
* Model for client info from browser
|
||||
* @author Low Heng Sin
|
||||
*
|
||||
*/
|
||||
public class ClientInfo implements Serializable {
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = -2686811277627911861L;
|
||||
|
||||
//values from browser
|
||||
public int colorDepth;
|
||||
public int desktopWidth;
|
||||
public int desktopHeight;
|
||||
|
@ -52,6 +53,7 @@ public class ClientInfo implements Serializable {
|
|||
public boolean tablet;
|
||||
public double devicePixelRatio;
|
||||
|
||||
//size constants for responsive layout
|
||||
public static final int LARGE_WIDTH = 1200;
|
||||
public static final int MEDIUM_WIDTH = 1000;
|
||||
public static final int SMALL_WIDTH = 700;
|
||||
|
|
|
@ -67,7 +67,7 @@ public class DefaultWebAppInit implements WebAppInit {
|
|||
}
|
||||
|
||||
/**
|
||||
* Process modle event of table system config
|
||||
* Process model event of table system config
|
||||
* @author hieplq
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,7 @@ import javax.servlet.ServletRequest;
|
|||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
@Deprecated(forRemoval = true, since = "11")
|
||||
public class DelegatingServlet extends HttpServlet {
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,7 +50,7 @@ import org.idempiere.ui.zk.media.IMediaViewProvider;
|
|||
import org.zkoss.zk.ui.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* Entry point to get implementation instance for UI extensions (through OSGI service or Equinox extension).
|
||||
* @author viola
|
||||
* @author hengsin
|
||||
*
|
||||
|
@ -372,8 +372,8 @@ public class Extensions {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param tabType
|
||||
* @return {@link IADTabpanel}
|
||||
* @param tabType build in - FORM or SORT, custom - through IADTabPanelFactory extension
|
||||
* @return {@link IADTabpanel}
|
||||
*/
|
||||
public static IADTabpanel getADTabPanel(String tabType)
|
||||
{
|
||||
|
|
|
@ -18,56 +18,61 @@ import org.compiere.model.MUser;
|
|||
import org.zkforge.keylistener.Keylistener;
|
||||
|
||||
/**
|
||||
*
|
||||
* Interface for web client
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public interface IWebClient {
|
||||
|
||||
/**
|
||||
* login completed
|
||||
* handle login completed
|
||||
*/
|
||||
public void loginCompleted();
|
||||
|
||||
/**
|
||||
* logout
|
||||
* handle logout
|
||||
*/
|
||||
public void logout();
|
||||
|
||||
/**
|
||||
* logout after browser destroyed
|
||||
* auto logout after close of browser tab
|
||||
*/
|
||||
public void logoutAfterTabDestroyed();
|
||||
|
||||
/**
|
||||
*
|
||||
* Get {@link IDesktop} instance
|
||||
* @return IDesktop
|
||||
*/
|
||||
public IDesktop getAppDeskop();
|
||||
|
||||
/**
|
||||
*
|
||||
* load user preference by user id
|
||||
* @param userId
|
||||
* @return UserPreference
|
||||
*/
|
||||
public UserPreference loadUserPreference(int userId);
|
||||
|
||||
/**
|
||||
*
|
||||
* Get current user preference
|
||||
* @return UserPreference
|
||||
*/
|
||||
public UserPreference getUserPreference();
|
||||
|
||||
/**
|
||||
* change Role
|
||||
* handle change Role
|
||||
*/
|
||||
public void changeRole(MUser user);
|
||||
|
||||
/**
|
||||
* @return keylistener
|
||||
* Get global key listener
|
||||
* @return {@link Keylistener}
|
||||
*/
|
||||
public abstract Keylistener getKeylistener();
|
||||
|
||||
/**
|
||||
* Get current ClientInfo
|
||||
* @return {@link ClientInfo}
|
||||
*/
|
||||
default ClientInfo getClientInfo() {
|
||||
return getAppDeskop().getClientInfo();
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import org.zkoss.zul.Window;
|
|||
import org.zkoss.zul.Window.Mode;
|
||||
|
||||
/**
|
||||
*
|
||||
* Some static UI helper methods
|
||||
* @author Low Heng Sin
|
||||
*
|
||||
*/
|
||||
|
@ -55,7 +55,7 @@ public final class LayoutUtils {
|
|||
/**
|
||||
* @param layout
|
||||
*/
|
||||
@Deprecated
|
||||
@Deprecated(forRemoval = true, since = "11")
|
||||
public static void sendDeferLayoutEvent(org.zkoss.zul.Borderlayout layout, int timeout) {
|
||||
/* this is not required anymore */
|
||||
// StringBuilder content = new StringBuilder();
|
||||
|
@ -68,7 +68,7 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* append cls to target's sclass property
|
||||
* @param cls
|
||||
* @param target
|
||||
*/
|
||||
|
@ -82,7 +82,7 @@ public final class LayoutUtils {
|
|||
*
|
||||
* @param cls
|
||||
* @param target
|
||||
* @return boolean
|
||||
* @return true if target's sclass property contain cls
|
||||
*/
|
||||
public static boolean hasSclass(String cls, HtmlBasedComponent target) {
|
||||
String sclass = target.getSclass();
|
||||
|
@ -93,9 +93,9 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* create right align label (wrapped in div)
|
||||
* @param label
|
||||
* @return wrapped label
|
||||
* @return right align label (wrapped in div)
|
||||
*/
|
||||
public static Component makeRightAlign(Label label) {
|
||||
Div div = new Div();
|
||||
|
@ -105,28 +105,41 @@ public final class LayoutUtils {
|
|||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* open popup window overlapping ref component
|
||||
* @param ref
|
||||
* @param window
|
||||
*/
|
||||
public static void openPopupWindow(Component ref, Window window) {
|
||||
openPopupWindow(ref, window, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* open popup window overlapping the ref component
|
||||
* open popup window overlapping ref component
|
||||
* @param ref
|
||||
* @param window
|
||||
* @param delayMs
|
||||
*/
|
||||
public static void openPopupWindow(Component ref, Window window, int delayMs) {
|
||||
openPopupWindow(ref, window, "overlap", delayMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* open popup window relative to ref component
|
||||
* @param ref
|
||||
* @param window
|
||||
* @param position Refer to https://www.zkoss.org/javadoc/latest/jsdoc/_global_/jqzk.html#position-_global_.Dimension-_global_.String-_global_.Map-
|
||||
*/
|
||||
public static void openPopupWindow(Component ref, Window window, String position) {
|
||||
openPopupWindow(ref, window, position, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* open popup window relative to the ref component
|
||||
* open popup window relative to ref component
|
||||
* @param ref
|
||||
* @param window
|
||||
* @param position
|
||||
* @param position Refer to https://www.zkoss.org/javadoc/latest/jsdoc/_global_/jqzk.html#position-_global_.Dimension-_global_.String-_global_.Map-
|
||||
* @param delayMs
|
||||
*/
|
||||
public static void openPopupWindow(Component ref, Window window, String position, int delayMs) {
|
||||
if (window.getPage() == null)
|
||||
|
@ -152,10 +165,10 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* open popup window relative to the ref component
|
||||
* open overlapped window (mode overlapped) relative to ref component
|
||||
* @param ref
|
||||
* @param window
|
||||
* @param position
|
||||
* @param position Refer to https://www.zkoss.org/javadoc/latest/jsdoc/_global_/jqzk.html#position-_global_.Dimension-_global_.String-_global_.Map-
|
||||
*/
|
||||
public static void openOverlappedWindow(Component ref, Window window, String position) {
|
||||
if (window.getPage() == null)
|
||||
|
@ -173,10 +186,10 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* position opened window relative to the ref component
|
||||
* position opened window relative to ref component
|
||||
* @param ref
|
||||
* @param window
|
||||
* @param position
|
||||
* @param position Refer to https://www.zkoss.org/javadoc/latest/jsdoc/_global_/jqzk.html#position-_global_.Dimension-_global_.String-_global_.Map-
|
||||
*/
|
||||
public static void positionWindow(Component ref, Window window, String position) {
|
||||
StringBuilder script = new StringBuilder();
|
||||
|
@ -191,10 +204,10 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* open embedded window relative to the ref component
|
||||
* open embedded window relative to ref component
|
||||
* @param ref
|
||||
* @param window
|
||||
* @param position
|
||||
* @param position Refer to https://www.zkoss.org/javadoc/latest/jsdoc/_global_/jqzk.html#position-_global_.Dimension-_global_.String-_global_.Map-
|
||||
*/
|
||||
public static void openEmbeddedWindow(Component ref, Window window, String position) {
|
||||
StringBuilder script = new StringBuilder();
|
||||
|
@ -211,10 +224,10 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* open highlighted window relative to the ref component
|
||||
* open highlighted window relative to ref component
|
||||
* @param ref
|
||||
* @param window
|
||||
* @param position
|
||||
* @param position Refer to https://www.zkoss.org/javadoc/latest/jsdoc/_global_/jqzk.html#position-_global_.Dimension-_global_.String-_global_.Map-
|
||||
*/
|
||||
public static void openHighlightedWindow(Component ref, Window window, String position) {
|
||||
StringBuilder script = new StringBuilder();
|
||||
|
@ -230,7 +243,7 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Force redraw of component
|
||||
* @param component
|
||||
*/
|
||||
public static void redraw(AbstractComponent component) {
|
||||
|
@ -259,6 +272,11 @@ public final class LayoutUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove cls from target's sclass property
|
||||
* @param cls
|
||||
* @param target
|
||||
*/
|
||||
public static void removeSclass(String cls, HtmlBasedComponent target) {
|
||||
String sclass = target.getSclass();
|
||||
if (Util.isEmpty(sclass))
|
||||
|
@ -281,13 +299,13 @@ public final class LayoutUtils {
|
|||
/**
|
||||
* show window with a mask below. mask over tabPanel, all window or only over a control, dependency ownModel flag.
|
||||
* when ownModel == {@link #OVERLAP_SELF}, window show overlap childOfOwn,
|
||||
* when childOfOwn isn't implement {@link ISupportMask} make new {@link Mask} object to make mask layout
|
||||
* when childOfOwn doesn't implement {@link ISupportMask} make new {@link Mask} object to make mask layout
|
||||
* ownModel == {@link #OVERLAP_ALL_PAGE}, window show overlap all page
|
||||
* ownModel == {@link #OVERLAP_TAB_PANEL}, window show overlap tabPanel
|
||||
* ownModel == {@link #OVERLAP_PARENT}, search near parent of childOfOwn implement {@link ISupportMask} if not exist user as OVERLAP_ALL_PAGE
|
||||
* @param window
|
||||
* @param childOfOwn
|
||||
* @param ownModel
|
||||
* @param ownModel OVERLAP_TAB_PANEL, OVERLAP_ALL_PAGE, OVERLAP_PARENT or OVERLAP_SELF
|
||||
* @return when show success return IMask object, it is own window, use {@link ISupportMask#hideMask()} to hidden mask.
|
||||
* other return null.
|
||||
*/
|
||||
|
@ -316,7 +334,7 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Show window in center of component
|
||||
* Show window in center of mask
|
||||
* @param window
|
||||
* @param mask
|
||||
*/
|
||||
|
@ -334,7 +352,7 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Show window over ownWindow with a mask, use when ownWindow isn't implement {@link ISupportMask}
|
||||
* Show window over ownWindow with a mask, use when ownWindow doesn't implement {@link ISupportMask}
|
||||
* @param window
|
||||
* @param ownWindow
|
||||
* @param mask if mask = null, make new and return it
|
||||
|
@ -353,11 +371,11 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* find parent control of child control, parent must implement {@link ISupportMask}
|
||||
* find parent of child component, parent must implement {@link ISupportMask}
|
||||
* if parentClass != null, parent class must extends parentClass
|
||||
* @param child
|
||||
* @param parentClass
|
||||
* @return
|
||||
* @return {@link ISupportMask}
|
||||
*/
|
||||
public static ISupportMask findMaskParent (Component child, Class<?> parentClass){
|
||||
Component parent = child;
|
||||
|
@ -429,6 +447,11 @@ public final class LayoutUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand number of grid column to min (for e.g, to min of 2 column)
|
||||
* @param grid
|
||||
* @param min
|
||||
*/
|
||||
public static void expandTo(Grid grid, int min) {
|
||||
expandTo(grid, min, false);
|
||||
}
|
||||
|
@ -488,6 +511,7 @@ public final class LayoutUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/** Event listener to add/remove slide from target component's sclass property **/
|
||||
private static final EventListener<OpenEvent> addSlideEventListener = (OpenEvent evt) -> {
|
||||
if (evt.isOpen())
|
||||
LayoutUtils.removeSclass("slide", (HtmlBasedComponent) evt.getTarget());
|
||||
|
@ -504,7 +528,7 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* find popup ancestor of comp
|
||||
* find first popup ancestor of comp
|
||||
* @param comp
|
||||
* @return {@link Popup} if comp or one of its ancestor is Popup
|
||||
*/
|
||||
|
@ -519,7 +543,7 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* call popup.detach when it is close
|
||||
* Auto call popup.detach when popup is close
|
||||
* @param popup
|
||||
*/
|
||||
public static void autoDetachOnClose(Popup popup) {
|
||||
|
@ -531,7 +555,7 @@ public final class LayoutUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* set target same width as ref using client side script
|
||||
* Make target same width as ref using client side script
|
||||
* @param target
|
||||
* @param ref
|
||||
*/
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
/***********************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
**********************************************************************/
|
||||
package org.adempiere.webui;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -23,6 +45,9 @@ import org.compiere.util.DB;
|
|||
import org.compiere.util.Ini;
|
||||
import org.compiere.util.WebUtil;
|
||||
|
||||
/**
|
||||
* Sync state of {@link HttpSession} and AD_Session
|
||||
*/
|
||||
public class LoggedSessionListener implements HttpSessionListener, ServletContextListener, ServerStateChangeListener{
|
||||
private static Hashtable<String, HttpSession> AD_SessionList = new Hashtable<String, HttpSession>();
|
||||
private static final CLogger logger = CLogger.getCLogger(LoggedSessionListener.class);
|
||||
|
@ -83,7 +108,7 @@ public class LoggedSessionListener implements HttpSessionListener, ServletContex
|
|||
*/
|
||||
}
|
||||
|
||||
public void DestroyAllSession() {
|
||||
private void DestroyAllSession() {
|
||||
if (!Adempiere.isStarted())
|
||||
{
|
||||
Adempiere.addServerStateChangeListener(this);
|
||||
|
@ -100,7 +125,7 @@ public class LoggedSessionListener implements HttpSessionListener, ServletContex
|
|||
Adempiere.removeServerStateChangeListener(this);
|
||||
}
|
||||
|
||||
public void removeADSession(String sessionID, String serverName) {
|
||||
private void removeADSession(String sessionID, String serverName) {
|
||||
String sql = "UPDATE AD_Session SET Processed='Y' WHERE WebSession=? AND ServerName=? AND Processed='N'";
|
||||
int no = DB.executeUpdate(sql, new Object[] {sessionID, serverName}, false, null);
|
||||
if (no < 0) {
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.zkoss.zk.ui.Component;
|
|||
import org.zkoss.zk.ui.util.Clients;
|
||||
|
||||
/**
|
||||
* Helper class for any component want implement {@link ISupportMask}
|
||||
* Helper class for {@link ISupportMask} implementation
|
||||
* Just make a instance of this class and let it do everything
|
||||
* @author hieplq
|
||||
*
|
||||
|
@ -39,7 +39,7 @@ public class ShowMaskWrapper implements ISupportMask {
|
|||
private Mask maskObj;
|
||||
|
||||
/**
|
||||
* comp is component want implement this interface
|
||||
* comp is component that implement ISupportMask
|
||||
* @param comp
|
||||
*/
|
||||
public ShowMaskWrapper (Component comp){
|
||||
|
|
|
@ -20,8 +20,8 @@ import org.zkoss.zk.ui.ShadowElement;
|
|||
import org.zkoss.zk.ui.util.UiLifeCycle;
|
||||
|
||||
/**
|
||||
* Utility class for selenium support
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class UiLifeCycleListener implements UiLifeCycle {
|
||||
|
||||
|
|
|
@ -68,12 +68,12 @@ import org.zkoss.zul.Vlayout;
|
|||
public class ValuePreference extends Window implements EventListener<Event>
|
||||
{
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 7594680475358417813L;
|
||||
|
||||
/**
|
||||
* Factory
|
||||
* Show value preference dialog
|
||||
* @param ref
|
||||
* @param mField field
|
||||
* @param aValue value
|
||||
|
@ -89,7 +89,7 @@ public class ValuePreference extends Window implements EventListener<Event>
|
|||
} // start
|
||||
|
||||
/**
|
||||
* Factory
|
||||
* Show value preference dialog
|
||||
* @param ref
|
||||
* @param mField field
|
||||
* @param aValue value
|
||||
|
@ -127,7 +127,7 @@ public class ValuePreference extends Window implements EventListener<Event>
|
|||
int AD_Org_ID = Env.getContextAsInt(Env.getCtx(), WindowNo, "AD_Org_ID");
|
||||
int AD_User_ID = Env.getAD_User_ID(Env.getCtx());
|
||||
|
||||
// Create Editor
|
||||
// Create and show value preference dialog
|
||||
@SuppressWarnings("unused")
|
||||
ValuePreference vp = new ValuePreference (WindowNo,
|
||||
AD_Client_ID, AD_Org_ID, AD_User_ID, AD_Window_ID, mField.getAD_Process_ID_Of_Panel(), mField.getAD_InfoWindow_ID_of_Panel(),
|
||||
|
@ -135,42 +135,8 @@ public class ValuePreference extends Window implements EventListener<Event>
|
|||
displayType, AD_Reference_ID, ref);
|
||||
} // create
|
||||
|
||||
/**
|
||||
* Create the popup menu item to start the ValuePreference editor.
|
||||
* <code>
|
||||
* .. add method
|
||||
* public void setField (MField mField)
|
||||
* {
|
||||
* m_mField = mField;
|
||||
* if (m_mField != null)
|
||||
* ValuePreference.addMenu (this, m_popupMenu);
|
||||
* } // setField
|
||||
*
|
||||
* .. in actionPerformed add ..
|
||||
* if (e.getActionCommand().equals(ValuePreference.NAME))
|
||||
* {
|
||||
* ValuePreference.start (m_mField, getValue(), DisplayValue);
|
||||
* return;
|
||||
* }
|
||||
* </code>
|
||||
* @param l listener
|
||||
* @param popupMenu menu
|
||||
* @return JMenuItem
|
||||
*/
|
||||
/*
|
||||
public static CMenuItem addMenu (ActionListener l, JPopupMenu popupMenu)
|
||||
{
|
||||
CMenuItem mi = new CMenuItem (Msg.getMsg(Env.getCtx(), NAME), s_icon);
|
||||
mi.setActionCommand(NAME);
|
||||
mi.addActionListener(l);
|
||||
popupMenu.add(mi);
|
||||
return mi;
|
||||
}*/ // addMenu
|
||||
|
||||
/** The Name of the Editor */
|
||||
/** The Name of the Dialog */
|
||||
public static final String NAME = "ValuePreference";
|
||||
/** The Menu Icon */
|
||||
//private static String ICON_URL = "images/VPreference16.png";
|
||||
/** Logger */
|
||||
private static final CLogger log = CLogger.getCLogger(ValuePreference.class);
|
||||
private AbstractADWindowContent adwindowContent;
|
||||
|
@ -189,7 +155,7 @@ public class ValuePreference extends Window implements EventListener<Event>
|
|||
* @param DisplayValue value display
|
||||
* @param displayType display type
|
||||
* @param AD_Reference_ID reference
|
||||
* @param ref
|
||||
* @param ref
|
||||
*/
|
||||
public ValuePreference (int WindowNo,
|
||||
int AD_Client_ID, int AD_Org_ID, int AD_User_ID, int AD_Window_ID, int AD_Process_ID_Of_Panel, int AD_Infowindow_ID,
|
||||
|
@ -439,7 +405,6 @@ public class ValuePreference extends Window implements EventListener<Event>
|
|||
// ActionListener
|
||||
cbClient.setEnabled(false);
|
||||
cbClient.setChecked(true);
|
||||
// cbClient.addActionListener(this);
|
||||
|
||||
// Can Change Org
|
||||
if (MRole.PREFERENCETYPE_Client.equals(m_role.getPreferenceType()))
|
||||
|
@ -498,7 +463,7 @@ public class ValuePreference extends Window implements EventListener<Event>
|
|||
}
|
||||
else
|
||||
setExplanation();
|
||||
} // actionPerformed
|
||||
}
|
||||
|
||||
private void onCancel() {
|
||||
this.detach();
|
||||
|
@ -557,8 +522,6 @@ public class ValuePreference extends Window implements EventListener<Event>
|
|||
*/
|
||||
public int delete()
|
||||
{
|
||||
log.info("");
|
||||
|
||||
StringBuilder sql = new StringBuilder ("DELETE FROM AD_Preference WHERE ");
|
||||
sql.append("AD_Client_ID=").append(cbClient.isChecked() ? m_AD_Client_ID : 0);
|
||||
sql.append(" AND AD_Org_ID=").append(cbOrg.isChecked() ? m_AD_Org_ID : 0);
|
||||
|
@ -654,12 +617,10 @@ public class ValuePreference extends Window implements EventListener<Event>
|
|||
} // getContextKey
|
||||
|
||||
/**
|
||||
* Save to Disk
|
||||
* Save to DB
|
||||
*/
|
||||
public void insert()
|
||||
{
|
||||
log.info("");
|
||||
|
||||
// --- Delete first
|
||||
int no = delete();
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ public class WArchive implements EventListener<Event>
|
|||
} // getZoomTargets
|
||||
|
||||
/**
|
||||
* Listner
|
||||
* Listener
|
||||
* @param e event
|
||||
*/
|
||||
@Override
|
||||
|
@ -151,6 +151,7 @@ public class WArchive implements EventListener<Event>
|
|||
{
|
||||
if (e.getTarget() instanceof Menuitem)
|
||||
{
|
||||
//open archive viewer
|
||||
int AD_Form_ID = FORM_ARCHIVEVIEWER; // ArchiveViewer
|
||||
ADForm form = ADForm.openForm(AD_Form_ID);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.zkoss.zul.West;
|
|||
import org.zkoss.zul.Window;
|
||||
|
||||
/**
|
||||
*
|
||||
* Manage login window for login and role selection
|
||||
* @author <a href="mailto:agramdass@gmail.com">Ashley G Ramdass</a>
|
||||
* @author Low Heng Sin
|
||||
* @date Mar 3, 2007
|
||||
|
@ -42,17 +42,28 @@ import org.zkoss.zul.Window;
|
|||
*/
|
||||
public class WLogin extends AbstractUIPart
|
||||
{
|
||||
|
||||
/** IWebClient instance ({@link AdempiereWebUI}) **/
|
||||
private IWebClient app;
|
||||
/** Main layout **/
|
||||
private Borderlayout layout;
|
||||
@Deprecated(forRemoval = true, since = "11")
|
||||
private Window browserWarningWindow;
|
||||
/** embedded window for login and role selection **/
|
||||
private LoginWindow loginWindow;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param app
|
||||
*/
|
||||
public WLogin(IWebClient app)
|
||||
{
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create UI from login.zul file. The main layout component ("layout") must be instance of {@link Borderlayout}.
|
||||
*/
|
||||
@Override
|
||||
protected Component doCreatePart(Component parent)
|
||||
{
|
||||
PageDefinition pageDefintion = Executions.getCurrent().getPageDefinition(ThemeManager.getThemeResource("zul/login/login.zul"));
|
||||
|
@ -107,6 +118,9 @@ public class WLogin extends AbstractUIPart
|
|||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* detach/dispose window content
|
||||
*/
|
||||
public void detach() {
|
||||
layout.detach();
|
||||
layout = null;
|
||||
|
@ -114,12 +128,15 @@ public class WLogin extends AbstractUIPart
|
|||
browserWarningWindow.detach();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link Component}
|
||||
*/
|
||||
public Component getComponent() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show change role window
|
||||
* Show change role panel in {@link #loginWindow}
|
||||
* @param locale
|
||||
* @param properties env context
|
||||
*/
|
||||
|
|
|
@ -36,8 +36,8 @@ import org.zkoss.zul.Menupopup;
|
|||
import org.zkoss.zul.Popup;
|
||||
|
||||
/**
|
||||
* Request Button Action.
|
||||
* Popup Menu
|
||||
* Handle Request Button Action.
|
||||
* Show Popup Menu.
|
||||
*
|
||||
* @author Jorg Janke
|
||||
* @version $Id: ARequest.java,v 1.2 2006/07/30 00:51:27 jjanke Exp $
|
||||
|
@ -133,6 +133,7 @@ public class WRequest implements EventListener<Event>
|
|||
{
|
||||
if (e.getTarget() instanceof Menuitem)
|
||||
{
|
||||
//open request window
|
||||
MQuery query = null;
|
||||
if (e.getTarget() == m_active)
|
||||
{
|
||||
|
@ -171,6 +172,11 @@ public class WRequest implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set initial values for new request record
|
||||
* @param e
|
||||
* @param frame
|
||||
*/
|
||||
private void onNew(Event e, ADWindow frame) {
|
||||
// New - set Table/Record
|
||||
if (e.getTarget() == m_new)
|
||||
|
|
|
@ -37,11 +37,10 @@ import org.zkoss.zul.Menupopup;
|
|||
import org.zkoss.zul.Popup;
|
||||
|
||||
/**
|
||||
* Application Zoom Across Launcher.
|
||||
* Called from APanel; Queries available Zoom Targets for Table.
|
||||
* Handle Zoom Across button action.
|
||||
*
|
||||
* @author Jorg Janke
|
||||
* @version $Id: AZoomAcross.java,v 1.2 2006/07/30 00:51:27 jjanke Exp $
|
||||
* @author Jorg Janke
|
||||
* @version $Id: AZoomAcross.java,v 1.2 2006/07/30 00:51:27 jjanke Exp $
|
||||
*
|
||||
* @author Teo Sarca, SC ARHIPAC SERVICE SRL - FR [ 1762465 ]
|
||||
*
|
||||
|
@ -64,6 +63,12 @@ public class WZoomAcross
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* show zoom across popup menu
|
||||
* @param invoker
|
||||
* @param po
|
||||
* @param windowID
|
||||
*/
|
||||
public WZoomAcross(Component invoker, PO po, final int windowID) {
|
||||
|
||||
if (log.isLoggable(Level.CONFIG)) log.config("PO=" + po+", WindowID="+windowID);
|
||||
|
@ -104,12 +109,18 @@ public class WZoomAcross
|
|||
m_popup.open(invoker, "after_start");
|
||||
}
|
||||
|
||||
private Menupopup m_popup = new Menupopup(); //"ZoomMenu"
|
||||
/** popup menu for zoom across targets **/
|
||||
private Menupopup m_popup = new Menupopup();
|
||||
|
||||
private static final CLogger log = CLogger.getCLogger(WZoomAcross.class);
|
||||
|
||||
private final List<ZoomInfoFactory.ZoomInfo> zoomInfos = new ArrayList<ZoomInfoFactory.ZoomInfo>();
|
||||
|
||||
/**
|
||||
* find zoom across targets
|
||||
* @param po
|
||||
* @param windowID
|
||||
*/
|
||||
private void mkZoomTargets(final PO po, final int windowID) {
|
||||
|
||||
for (final ZoomInfoFactory.ZoomInfo zoomInfo : ZoomInfoFactory.retrieveZoomInfos(po,
|
||||
|
@ -125,18 +136,18 @@ public class WZoomAcross
|
|||
}
|
||||
|
||||
/**
|
||||
* Launch Zoom
|
||||
* @param pp KeyPair
|
||||
* Zoom to destination window
|
||||
* @param zoomInfo
|
||||
*/
|
||||
private void launchZoom (final ZoomInfoFactory.ZoomInfo zoomInfo)
|
||||
{
|
||||
final int AD_Window_ID = zoomInfo.windowId;
|
||||
final MQuery query = zoomInfo.query;
|
||||
|
||||
log.info("AD_Window_ID=" + AD_Window_ID
|
||||
+ " - " + query);
|
||||
if (log.isLoggable(Level.INFO))
|
||||
log.info("AD_Window_ID=" + AD_Window_ID + " - " + query);
|
||||
|
||||
AEnv.zoom(AD_Window_ID, query);
|
||||
} // launchZoom
|
||||
|
||||
} // AZoom
|
||||
}
|
||||
|
|
|
@ -18,8 +18,9 @@ import org.osgi.framework.BundleActivator;
|
|||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
* {@link BundleActivator} for web UI
|
||||
* Start {@link WindowValidatorManager}
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class WebUIActivator implements BundleActivator {
|
||||
|
||||
|
@ -44,6 +45,10 @@ public class WebUIActivator implements BundleActivator {
|
|||
WindowValidatorManager.getInstance().stop(context);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return {@link BundleContext}
|
||||
*/
|
||||
public static BundleContext getBundleContext() {
|
||||
return bundleContext;
|
||||
}
|
||||
|
|
|
@ -104,11 +104,10 @@ import org.zkoss.zul.Space;
|
|||
* @author Elaine Tan
|
||||
* @author Low Heng Sin
|
||||
*/
|
||||
|
||||
public class WAcctViewer extends Window implements EventListener<Event>
|
||||
{
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 3440375640756094077L;
|
||||
|
||||
|
@ -207,7 +206,6 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
|
||||
public WAcctViewer()
|
||||
{
|
||||
this (0, 0, 0);
|
||||
|
@ -220,14 +218,13 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
* @param AD_Table_ID Table
|
||||
* @param Record_ID Record
|
||||
*/
|
||||
|
||||
public WAcctViewer(int AD_Client_ID, int AD_Table_ID, int Record_ID)
|
||||
{
|
||||
super ();
|
||||
|
||||
log.info("AD_Table_ID=" + AD_Table_ID + ", Record_ID=" + Record_ID);
|
||||
if (log.isLoggable(Level.INFO))
|
||||
log.info("AD_Table_ID=" + AD_Table_ID + ", Record_ID=" + Record_ID);
|
||||
|
||||
//setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
m_windowNo = SessionManager.getAppDesktop().registerWindow(this);
|
||||
m_data = new WAcctViewerData (Env.getCtx(), m_windowNo, AD_Client_ID, AD_Table_ID);
|
||||
|
||||
|
@ -242,9 +239,8 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
catch(Exception e)
|
||||
{
|
||||
log.log(Level.SEVERE, "", e);
|
||||
//dispose();
|
||||
}
|
||||
} // AcctViewer
|
||||
}
|
||||
|
||||
/**
|
||||
* Static Init.
|
||||
|
@ -257,7 +253,6 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
* </pre>
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
private void init() throws Exception
|
||||
{
|
||||
// Selection Panel
|
||||
|
@ -450,8 +445,6 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
ZKUpdateUtil.setHflex(sortBy4, "1");
|
||||
row.appendChild(group4);
|
||||
|
||||
//"images/InfoAccount16.png"
|
||||
|
||||
Groupbox groupDisplay = new Groupbox();
|
||||
Caption capDisplay = new Caption(Msg.getMsg(Env.getCtx(), "Display"));
|
||||
groupDisplay.appendChild(capDisplay);
|
||||
|
@ -549,11 +542,8 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
resultPanel.appendChild(resultCenter);
|
||||
ZKUpdateUtil.setHflex(table, "1");
|
||||
ZKUpdateUtil.setVflex(table, true);
|
||||
//ZKUpdateUtil.setHeight(table, "99%");
|
||||
//table.setStyle("position: absolute;");
|
||||
resultCenter.appendChild(table);
|
||||
ZKUpdateUtil.setHflex(table, "1");
|
||||
//ZKUpdateUtil.setVflex(table, "1");
|
||||
table.addEventListener(Events.ON_DOUBLE_CLICK, this);
|
||||
if (ClientInfo.isMobile())
|
||||
table.setSizedByContent(true);
|
||||
|
@ -599,7 +589,7 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
layout.setParent(this);
|
||||
ZKUpdateUtil.setHeight(layout, "100%");
|
||||
ZKUpdateUtil.setWidth(layout, "100%");
|
||||
layout.setStyle("background-color: transparent; margin: 0; position: absolute; padding: 0;");
|
||||
layout.setStyle("background-color: transparent; margin: 0; position: relative; padding: 0;");
|
||||
|
||||
Center center = new Center();
|
||||
center.setParent(layout);
|
||||
|
@ -618,7 +608,7 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
|
||||
this.setTitle(Msg.getMsg(Env.getCtx(), TITLE));
|
||||
this.setClosable(true);
|
||||
this.setStyle("position: absolute; width: 100%; height: 100%;");
|
||||
this.setStyle("position: relative; width: 100%; height: 100%;");
|
||||
this.setSizable(true);
|
||||
this.setMaximizable(true);
|
||||
}
|
||||
|
@ -629,7 +619,6 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
* @param AD_Table_ID table
|
||||
* @param Record_ID record
|
||||
*/
|
||||
|
||||
private void dynInit (int AD_Table_ID, int Record_ID)
|
||||
{
|
||||
m_data.validateAcctSchemas(Record_ID);
|
||||
|
@ -702,6 +691,12 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
stateChanged();
|
||||
} // dynInit
|
||||
|
||||
/**
|
||||
* set selected table and record id
|
||||
* @param AD_Table_ID
|
||||
* @param Record_ID
|
||||
* @return true if AD_Table_ID is found, false otherwise
|
||||
*/
|
||||
private boolean setSelectedTable(int AD_Table_ID, int Record_ID)
|
||||
{
|
||||
int cnt = selTable.getItemCount();
|
||||
|
@ -727,9 +722,8 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Dispose
|
||||
* Dispose window
|
||||
*/
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
m_data.dispose();
|
||||
|
@ -738,11 +732,10 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
} // dispose;
|
||||
|
||||
/**************************************************************************
|
||||
* Tab Changed
|
||||
* After Tab Selection Changed
|
||||
*/
|
||||
public void stateChanged()
|
||||
{
|
||||
// log.info( "AcctViewer.stateChanged");
|
||||
boolean visible = m_data.documentQuery && tabResult.isSelected();
|
||||
|
||||
bRePost.setVisible(visible);
|
||||
|
@ -756,11 +749,8 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
* Event Performed (Event Listener)
|
||||
* @param e Event
|
||||
*/
|
||||
|
||||
public void onEvent(Event e) throws Exception
|
||||
{
|
||||
// log.info(e.getActionCommand());
|
||||
|
||||
Object source = e.getTarget();
|
||||
|
||||
if (source == tabResult)
|
||||
|
@ -802,6 +792,10 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
}
|
||||
} // onEvent
|
||||
|
||||
/**
|
||||
* export to excel
|
||||
* show excel viewer if available
|
||||
*/
|
||||
private void actionExport() {
|
||||
if (m_rmodel != null && m_rmodel.getRowCount() > 0) {
|
||||
RModelExcelExporter exporter = new RModelExcelExporter(m_rmodel);
|
||||
|
@ -835,9 +829,8 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* New Acct Schema
|
||||
* Handle Acct Schema selection
|
||||
*/
|
||||
|
||||
private void actionAcctSchema()
|
||||
{
|
||||
Listitem listitem = selAcctSchema.getSelectedItem();
|
||||
|
@ -853,7 +846,8 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
m_data.C_AcctSchema_ID = kp.getKey();
|
||||
m_data.ASchema = MAcctSchema.get(Env.getCtx(), m_data.C_AcctSchema_ID);
|
||||
|
||||
log.info(m_data.ASchema.toString());
|
||||
if (log.isLoggable(Level.INFO))
|
||||
log.info(m_data.ASchema.toString());
|
||||
|
||||
// Sort Options
|
||||
|
||||
|
@ -916,7 +910,6 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
* Add to Sort
|
||||
* @param vn name pair
|
||||
*/
|
||||
|
||||
private void sortAddItem(ValueNamePair vn)
|
||||
{
|
||||
sortBy1.appendItem(vn.getName(), vn);
|
||||
|
@ -926,9 +919,9 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
} // sortAddItem
|
||||
|
||||
/**
|
||||
* Query
|
||||
* Query.
|
||||
* Delegate to {@link WAcctViewerData#query()}
|
||||
*/
|
||||
|
||||
private void actionQuery()
|
||||
{
|
||||
// Parameter Info
|
||||
|
@ -1171,7 +1164,6 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
/**
|
||||
* Document selection
|
||||
*/
|
||||
|
||||
private void actionDocument()
|
||||
{
|
||||
boolean doc = selDocument.isChecked();
|
||||
|
@ -1193,9 +1185,8 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
} // actionDocument
|
||||
|
||||
/**
|
||||
* Save Table selection (reset Record selection)
|
||||
* Handle Table selection (reset Record selection)
|
||||
*/
|
||||
|
||||
private void actionTable()
|
||||
{
|
||||
Listitem listitem = selTable.getSelectedItem();
|
||||
|
@ -1217,17 +1208,15 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
} // actionTable
|
||||
|
||||
/**
|
||||
* Action Button
|
||||
* Handle Info Button action
|
||||
* Show info window
|
||||
*
|
||||
* @param button pressed button
|
||||
* @return ID
|
||||
* @throws Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
private void actionButton(final Button button) throws Exception
|
||||
{
|
||||
final String keyColumn = button.getName();
|
||||
log.info(keyColumn);
|
||||
String whereClause = "(IsSummary='N' OR IsSummary IS NULL)";
|
||||
String lookupColumn = keyColumn;
|
||||
|
||||
|
@ -1321,14 +1310,12 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
|
||||
}
|
||||
});
|
||||
AEnv.showWindow(info);
|
||||
|
||||
AEnv.showWindow(info);
|
||||
} // actionButton
|
||||
|
||||
/**
|
||||
* RePost Record
|
||||
*/
|
||||
|
||||
private void actionRePost()
|
||||
{
|
||||
if (m_data.documentQuery
|
||||
|
@ -1362,7 +1349,9 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
}
|
||||
} // actionRePost
|
||||
|
||||
// Elaine 2009/07/29
|
||||
/**
|
||||
* zoom to table id + record id
|
||||
*/
|
||||
private void actionZoom()
|
||||
{
|
||||
int selected = table.getSelectedIndex();
|
||||
|
@ -1380,8 +1369,10 @@ public class WAcctViewer extends Window implements EventListener<Event>
|
|||
AEnv.zoom(AD_Table_ID, Record_ID);
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* zoom to fact acct window (double click action)
|
||||
*/
|
||||
private void actionZoomFactAcct() {
|
||||
int selected = table.getSelectedIndex();
|
||||
if(selected == -1) return;
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.compiere.model.MFactAcct;
|
|||
import org.compiere.model.MJournal;
|
||||
import org.compiere.model.MLookupFactory;
|
||||
import org.compiere.model.MRefList;
|
||||
import org.compiere.model.SystemIDs;
|
||||
import org.compiere.report.core.RColumn;
|
||||
import org.compiere.report.core.RModel;
|
||||
import org.compiere.util.CLogger;
|
||||
|
@ -53,8 +54,7 @@ import org.compiere.util.Msg;
|
|||
import org.compiere.util.ValueNamePair;
|
||||
|
||||
/**
|
||||
* Account Viewer State - maintains State information for the Account Viewer
|
||||
* Based on class AcctViewerData
|
||||
* State and data access helper for {@link WAcctViewer}
|
||||
*
|
||||
* @author Niraj Sohun
|
||||
* July 27, 2007
|
||||
|
@ -68,68 +68,70 @@ public class WAcctViewerData
|
|||
/** Client */
|
||||
public int AD_Client_ID;
|
||||
|
||||
/** All Acct Schema */
|
||||
/** All Accounting Schemas for client */
|
||||
public MAcctSchema[] ASchemas = null;
|
||||
|
||||
/** This Acct Schema */
|
||||
/** Selected Accounting Schema */
|
||||
public MAcctSchema ASchema = null;
|
||||
|
||||
// Selection Info
|
||||
|
||||
/** Document Query */
|
||||
/** Document Query - query with {@link #AD_Table_ID} and {@link #Record_ID} */
|
||||
public boolean documentQuery = false;
|
||||
|
||||
/** Acct Schema */
|
||||
/** Selected Accounting Schema ID */
|
||||
public int C_AcctSchema_ID = 0;
|
||||
|
||||
/** Posting Type */
|
||||
/** Selected Posting Type */
|
||||
public String PostingType = "";
|
||||
|
||||
/** Organization */
|
||||
/** Selected Organization ID */
|
||||
public int AD_Org_ID = 0;
|
||||
|
||||
/** Date From */
|
||||
/** Date From, for DateAcct filter */
|
||||
public Timestamp DateFrom = null;
|
||||
|
||||
/** Date To */
|
||||
/** Date To, for DateAcct filter */
|
||||
public Timestamp DateTo = null;
|
||||
|
||||
// Document Table Selection Info
|
||||
|
||||
/** Table ID */
|
||||
/** Selected Table ID for {@link #documentQuery} */
|
||||
public int AD_Table_ID;
|
||||
|
||||
/** Record */
|
||||
/** Selected Record ID for {@link #documentQuery} */
|
||||
public int Record_ID;
|
||||
|
||||
/** Containing Column and Query */
|
||||
/** ColumnName:Filter */
|
||||
public HashMap<String,String> whereInfo = new HashMap<String,String>();
|
||||
|
||||
/** Containing TableName and AD_Table_ID */
|
||||
/** TableName:AD_Table_ID */
|
||||
public HashMap<String,Integer> tableInfo = new HashMap<String,Integer>();
|
||||
|
||||
// Display Info
|
||||
|
||||
/** Display Qty */
|
||||
boolean displayQty = false;
|
||||
/** Display Qty Columns */
|
||||
protected boolean displayQty = false;
|
||||
|
||||
/** Display Source Surrency */
|
||||
boolean displaySourceAmt = false;
|
||||
/** Display Source Amount Columns */
|
||||
protected boolean displaySourceAmt = false;
|
||||
|
||||
/** Display Document info */
|
||||
boolean displayDocumentInfo = false;
|
||||
protected boolean displayDocumentInfo = false;
|
||||
|
||||
String sortBy1 = "";
|
||||
String sortBy2 = "";
|
||||
String sortBy3 = "";
|
||||
String sortBy4 = "";
|
||||
//order by
|
||||
protected String sortBy1 = "";
|
||||
protected String sortBy2 = "";
|
||||
protected String sortBy3 = "";
|
||||
protected String sortBy4 = "";
|
||||
|
||||
boolean group1 = false;
|
||||
boolean group2 = false;
|
||||
boolean group3 = false;
|
||||
boolean group4 = false;
|
||||
//group by
|
||||
protected boolean group1 = false;
|
||||
protected boolean group2 = false;
|
||||
protected boolean group3 = false;
|
||||
protected boolean group4 = false;
|
||||
|
||||
/** Leasing Columns */
|
||||
/** Leading Columns. Number of columns shown before Accounted and Source Amount Columns. */
|
||||
private int m_leadingColumns = 0;
|
||||
|
||||
/** UserElement1 Reference */
|
||||
|
@ -148,7 +150,6 @@ public class WAcctViewerData
|
|||
* @param ad_Client_ID client
|
||||
* @param ad_Table_ID table
|
||||
*/
|
||||
|
||||
public WAcctViewerData (Properties ctx, int windowNo, int ad_Client_ID, int ad_Table_ID)
|
||||
{
|
||||
WindowNo = windowNo;
|
||||
|
@ -168,8 +169,7 @@ public class WAcctViewerData
|
|||
|
||||
/**
|
||||
* Dispose
|
||||
*/
|
||||
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
ASchemas = null;
|
||||
|
@ -182,8 +182,8 @@ public class WAcctViewerData
|
|||
} // dispose
|
||||
|
||||
/**
|
||||
* GL Journal only posts in one Accounting Schema
|
||||
* if the record is a GL Journal, remove the others from the array
|
||||
* GL Journal only posts in one Accounting Schema.
|
||||
* If the record is a GL Journal, remove the other accounting schema from {@link #ASchemas}
|
||||
* @param Record_ID
|
||||
*/
|
||||
protected void validateAcctSchemas(int Record_ID)
|
||||
|
@ -191,7 +191,7 @@ public class WAcctViewerData
|
|||
if (Record_ID > 0 && AD_Table_ID == MJournal.Table_ID) {
|
||||
MJournal journal = new MJournal(Env.getCtx(), Record_ID, null);
|
||||
|
||||
if (journal != null) {
|
||||
if (journal.getGL_Journal_ID() == Record_ID) {
|
||||
ASchemas = new MAcctSchema[1];
|
||||
ASchemas[0] = MAcctSchema.get(Env.getCtx(), journal.getC_AcctSchema_ID());
|
||||
ASchema = ASchemas[0];
|
||||
|
@ -199,11 +199,10 @@ public class WAcctViewerData
|
|||
}
|
||||
} // validateAcctSchemas
|
||||
|
||||
/**************************************************************************
|
||||
/**
|
||||
* Fill Accounting Schema
|
||||
* @param cb Listbox to be filled
|
||||
*/
|
||||
|
||||
*/
|
||||
protected void fillAcctSchema (Listbox cb)
|
||||
{
|
||||
for (int i = 0; i < ASchemas.length; i++)
|
||||
|
@ -214,10 +213,9 @@ public class WAcctViewerData
|
|||
} // fillAcctSchema
|
||||
|
||||
/**
|
||||
* Fill Posting Type
|
||||
* @param cb Listox to be filled
|
||||
*/
|
||||
|
||||
* Fill Posting Type from {@link SystemIDs#REFERENCE_POSTING_TYPE} list.
|
||||
* @param cb Listbox to be filled
|
||||
*/
|
||||
protected void fillPostingType (Listbox cb)
|
||||
{
|
||||
int AD_Reference_ID = REFERENCE_POSTING_TYPE;
|
||||
|
@ -230,18 +228,15 @@ public class WAcctViewerData
|
|||
} // fillPostingType
|
||||
|
||||
/**
|
||||
* Fill Table with
|
||||
* Fill Listbox with
|
||||
* ValueNamePair (TableName, translatedKeyColumnName)
|
||||
* and tableInfo with (TableName, AD_Table_ID)
|
||||
* and {@link #tableInfo} with (TableName, AD_Table_ID)
|
||||
* and select the entry for AD_Table_ID
|
||||
*
|
||||
* @param cb Listbox to be filled
|
||||
*/
|
||||
|
||||
*/
|
||||
protected void fillTable (Listbox cb)
|
||||
{
|
||||
ValueNamePair select = null;
|
||||
|
||||
String sql = "SELECT AD_Table_ID, TableName FROM AD_Table t "
|
||||
+ "WHERE EXISTS (SELECT * FROM AD_Column c"
|
||||
+ " WHERE t.AD_Table_ID=c.AD_Table_ID AND c.ColumnName='Posted')"
|
||||
|
@ -261,10 +256,7 @@ public class WAcctViewerData
|
|||
|
||||
ValueNamePair pp = new ValueNamePair(tableName, name);
|
||||
cb.appendItem(pp.getName(),pp);
|
||||
tableInfo.put (tableName, Integer.valueOf(id));
|
||||
|
||||
if (id == AD_Table_ID)
|
||||
select = pp;
|
||||
tableInfo.put (tableName, Integer.valueOf(id));
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
|
@ -276,18 +268,14 @@ public class WAcctViewerData
|
|||
DB.close(rs, pstmt);
|
||||
rs = null;
|
||||
pstmt = null;
|
||||
}
|
||||
|
||||
if (select != null)
|
||||
;//cb.setSelectedItem(select);
|
||||
}
|
||||
} // fillTable
|
||||
|
||||
/**
|
||||
* Fill Org
|
||||
*
|
||||
* @param cb Listbox to be filled
|
||||
*/
|
||||
|
||||
*/
|
||||
protected void fillOrg (Listbox cb)
|
||||
{
|
||||
KeyNamePair pp = new KeyNamePair(0, "");
|
||||
|
@ -320,7 +308,7 @@ public class WAcctViewerData
|
|||
} // fillOrg
|
||||
|
||||
/**
|
||||
* Get Button Text
|
||||
* Get Info Button Text
|
||||
*
|
||||
* @param tableName table
|
||||
* @param columnName column
|
||||
|
@ -362,10 +350,9 @@ public class WAcctViewerData
|
|||
return retValue;
|
||||
} // getButtonText
|
||||
|
||||
/**************************************************************************
|
||||
/**
|
||||
* Create Query and submit
|
||||
* @return Report Model
|
||||
* Create query and execute
|
||||
* @return {@link RModel} query result
|
||||
*/
|
||||
|
||||
protected RModel query()
|
||||
|
@ -502,10 +489,9 @@ public class WAcctViewerData
|
|||
} // query
|
||||
|
||||
/**
|
||||
* Create Report Model (Columns)
|
||||
* @return Report Model
|
||||
*/
|
||||
|
||||
* Create new Report Model (Setup Columns) instance
|
||||
* @return {@link RModel}
|
||||
*/
|
||||
private RModel getRModel()
|
||||
{
|
||||
Properties ctx = Env.getCtx();
|
||||
|
@ -596,10 +582,9 @@ public class WAcctViewerData
|
|||
} // createRModel
|
||||
|
||||
/**
|
||||
* Create the key columns in sequence
|
||||
* Create the list of key/mandatory columns to display in viewer
|
||||
* @return List of Key Columns
|
||||
*/
|
||||
|
||||
private ArrayList<String> createKeyColumns()
|
||||
{
|
||||
ArrayList<String> columns = new ArrayList<String>();
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.compiere.util.CCache;
|
|||
import org.zkoss.image.AImage;
|
||||
|
||||
/**
|
||||
*
|
||||
* Static methods to get {@link IAction} osgi service instance.
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
|
@ -58,7 +58,10 @@ public class Actions {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Image name: actionId+"24.png".
|
||||
* Get image from current theme or plugin resource.
|
||||
* For plugin resource, it will try the path /action/images/{theme}/{image name}, /action/images/default/{image name} and
|
||||
* /action/images/{image name}
|
||||
* @param actionId
|
||||
* @return {@link AImage}
|
||||
*/
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.zkoss.zul.Toolbarbutton;
|
|||
*/
|
||||
public interface IAction {
|
||||
/**
|
||||
*
|
||||
* execute action
|
||||
* @param target
|
||||
*/
|
||||
public void execute(Object target);
|
||||
|
|
|
@ -78,10 +78,13 @@ import org.zkoss.zul.event.ListDataEvent;
|
|||
public class ADSortTab extends Panel implements IADTabpanel
|
||||
{
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 4302282658814599752L;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public ADSortTab()
|
||||
{
|
||||
}
|
||||
|
@ -133,7 +136,7 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
private Button bUp = ButtonFactory.createButton(null, ThemeManager.getThemeResource("images/MoveUp16.png"), null);
|
||||
private Button bDown = ButtonFactory.createButton(null, ThemeManager.getThemeResource("images/MoveDown16.png"), null);
|
||||
//
|
||||
SimpleListModel noModel = new SimpleListModel() {
|
||||
protected SimpleListModel noModel = new SimpleListModel() {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -153,12 +156,13 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
fireEvent(ListDataEvent.INTERVAL_ADDED, index, index);
|
||||
}
|
||||
};
|
||||
SimpleListModel yesModel = new SimpleListModel();
|
||||
Listbox noList = new Listbox();
|
||||
Listbox yesList = new Listbox();
|
||||
protected SimpleListModel yesModel = new SimpleListModel();
|
||||
protected Listbox noList = new Listbox();
|
||||
protected Listbox yesList = new Listbox();
|
||||
|
||||
private GridTab gridTab;
|
||||
private boolean uiCreated;
|
||||
/** true if tab have been activated **/
|
||||
private boolean active = false;
|
||||
private boolean isChanged;
|
||||
private boolean detailPaneMode;
|
||||
|
@ -277,7 +281,8 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
m_IdentifierSql = identifierSql.toString();
|
||||
//
|
||||
noLabel.setValue(Msg.getMsg(Env.getCtx(), "Available"));
|
||||
log.fine(m_ColumnSortName);
|
||||
if (log.isLoggable(Level.FINE))
|
||||
log.fine(m_ColumnSortName);
|
||||
} // dynInit
|
||||
|
||||
/**
|
||||
|
@ -520,14 +525,19 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if tab has changes
|
||||
*/
|
||||
public boolean isChanged() {
|
||||
return isChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move an item between yes and no list.
|
||||
* Delegate to {@link #migrateLists(Listbox, Listbox, int)}
|
||||
* @param event
|
||||
*/
|
||||
void migrateValueAcrossLists (Event event)
|
||||
protected void migrateValueAcrossLists (Event event)
|
||||
{
|
||||
Object source = event.getTarget();
|
||||
if (source instanceof ListItem) {
|
||||
|
@ -544,7 +554,13 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
migrateLists (listFrom,listTo,endIndex);
|
||||
} // migrateValueAcrossLists
|
||||
|
||||
void migrateLists (Listbox listFrom , Listbox listTo , int endIndex)
|
||||
/**
|
||||
* Move an item from listFrom to listTo.
|
||||
* @param listFrom
|
||||
* @param listTo
|
||||
* @param endIndex destination index
|
||||
*/
|
||||
protected void migrateLists (Listbox listFrom , Listbox listTo , int endIndex)
|
||||
{
|
||||
int index = 0;
|
||||
SimpleListModel lmFrom = (listFrom == yesList) ? yesModel:noModel;
|
||||
|
@ -577,10 +593,10 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
}
|
||||
|
||||
/**
|
||||
* Move within Yes List
|
||||
* Move an item within Yes List
|
||||
* @param event event
|
||||
*/
|
||||
void migrateValueWithinYesList (Event event)
|
||||
protected void migrateValueWithinYesList (Event event)
|
||||
{
|
||||
Object[] selObjects = yesList.getSelectedItems().toArray();
|
||||
if (selObjects == null)
|
||||
|
@ -643,10 +659,10 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
|
||||
|
||||
/**
|
||||
* Move within Yes List with Drag Event and Multiple Choice
|
||||
* Move items within Yes List with Drag Event and Multiple Choice
|
||||
* @param event event
|
||||
*/
|
||||
void migrateValueWithinYesList (int endIndex, List<ListElement> selObjects)
|
||||
protected void migrateValueWithinYesList (int endIndex, List<ListElement> selObjects)
|
||||
{
|
||||
int iniIndex =0;
|
||||
Arrays.sort(selObjects.toArray());
|
||||
|
@ -667,8 +683,9 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
setIsChanged(true);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.compiere.grid.APanelTab#registerAPanel(APanel)
|
||||
/**
|
||||
* Set AD Window content part that own this ADSortTab instance.
|
||||
* @param panel
|
||||
*/
|
||||
public void registerAPanel (AbstractADWindowContent panel)
|
||||
{
|
||||
|
@ -676,14 +693,15 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
} // registerAPanel
|
||||
|
||||
|
||||
/** (non-Javadoc)
|
||||
/**
|
||||
* Save changes to db.
|
||||
*/
|
||||
public void saveData()
|
||||
{
|
||||
if (!adWindowPanel.getToolbar().isSaveEnable())
|
||||
return;
|
||||
log.fine("");
|
||||
boolean ok = true;
|
||||
//TODO: should use model instead to enable change log and event handling
|
||||
StringBuilder info = new StringBuilder();
|
||||
StringBuffer sql = null;
|
||||
// noList - Set SortColumn to null and optional YesNo Column to 'N'
|
||||
|
@ -851,6 +869,7 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
if (event instanceof DropEvent)
|
||||
{
|
||||
|
@ -884,6 +903,7 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate(boolean b) {
|
||||
if (b) {
|
||||
if (getAttribute(ATTR_ON_ACTIVATE_POSTED) != null) {
|
||||
|
@ -899,6 +919,7 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
Events.postEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createUI() {
|
||||
if (uiCreated) return;
|
||||
try
|
||||
|
@ -913,64 +934,80 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
uiCreated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dynamicDisplay(int i) {
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true, since = "11")
|
||||
public void editRecord(boolean b) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayLogic() {
|
||||
return gridTab.getDisplayLogic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridTab getGridTab() {
|
||||
return gridTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTabLevel() {
|
||||
return gridTab.getTabLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableName()
|
||||
{
|
||||
return gridTab.getTableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRecord_ID() {
|
||||
return gridTab.getRecord_ID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return gridTab.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrent() {
|
||||
return gridTab != null ? gridTab.isCurrent() : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void query() {
|
||||
loadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void query(boolean currentRows, int currentDays, int i) {
|
||||
loadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
createUI();
|
||||
loadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void switchRowPresentation() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get_ValueAsString(String variableName) {
|
||||
return Env.getContext(Env.getCtx(), m_WindowNo, variableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSave(boolean onSaveEvent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEnterKey() {
|
||||
return false;
|
||||
}
|
||||
|
@ -991,6 +1028,7 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
ZKUpdateUtil.setVflex(this, "true");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDetailPaneMode() {
|
||||
return this.detailPaneMode;
|
||||
}
|
||||
|
@ -1053,6 +1091,7 @@ public class ADSortTab extends Panel implements IADTabpanel
|
|||
noList.setModel(noModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ADTreePanel getTreePanel() {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ import org.zkoss.zul.West;
|
|||
import org.zkoss.zul.impl.XulElement;
|
||||
|
||||
/**
|
||||
* UI for an AD_Tab content (AD_Tab + AD_Fields).
|
||||
*
|
||||
* This class is based on org.compiere.grid.GridController written by Jorg Janke.
|
||||
* Changes have been brought for UI compatibility.
|
||||
|
@ -142,6 +143,7 @@ import org.zkoss.zul.impl.XulElement;
|
|||
public class ADTabpanel extends Div implements Evaluatee, EventListener<Event>,
|
||||
DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
||||
{
|
||||
//css for slide animation
|
||||
private static final String SLIDE_LEFT_IN_CSS = "slide-left-in";
|
||||
|
||||
private static final String SLIDE_LEFT_OUT_CSS = "slide-left-out";
|
||||
|
@ -151,19 +153,26 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
private static final String SLIDE_RIGHT_OUT_CSS = "slide-right-out";
|
||||
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = -5335610241895151024L;
|
||||
|
||||
/** event to save open/close state of detail pane as user preference for ad window **/
|
||||
private static final String ON_SAVE_OPEN_PREFERENCE_EVENT = "onSaveOpenPreference";
|
||||
|
||||
/** post init event for tab panel **/
|
||||
public static final String ON_POST_INIT_EVENT = "onPostInit";
|
||||
|
||||
/** event after tab panel had switch presentation between form and list view **/
|
||||
public static final String ON_SWITCH_VIEW_EVENT = "onSwitchView";
|
||||
|
||||
/** Event after execution of {@link #dynamicDisplay(int)} **/
|
||||
public static final String ON_DYNAMIC_DISPLAY_EVENT = "onDynamicDisplay";
|
||||
|
||||
/** defer event to set selected tree node **/
|
||||
private static final String ON_DEFER_SET_SELECTED_NODE = "onDeferSetSelectedNode";
|
||||
|
||||
/** ADTabpanel attribute to prevent ON_DEFER_SET_SELECTED_NODE event posted twice within 1 execution **/
|
||||
private static final String ON_DEFER_SET_SELECTED_NODE_ATTR = "onDeferSetSelectedNode.Event.Posted";
|
||||
|
||||
private static final CLogger logger;
|
||||
|
@ -177,68 +186,95 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
private GridWindow gridWindow;
|
||||
|
||||
/** AD Window content part that own this ADTabpanel instance **/
|
||||
private AbstractADWindowContent windowPanel;
|
||||
|
||||
private int windowNo;
|
||||
|
||||
/** form view for center of {@link #formContainer} **/
|
||||
private Grid form;
|
||||
|
||||
/** field editors **/
|
||||
private ArrayList<WEditor> editors = new ArrayList<WEditor>();
|
||||
|
||||
/** components for field editors **/
|
||||
private ArrayList<Component> editorComps = new ArrayList<Component>();
|
||||
|
||||
/** editor toolbar buttons**/
|
||||
private ArrayList<WButtonEditor> toolbarButtonEditors = new ArrayList<WButtonEditor>();
|
||||
|
||||
/** toolbar buttons for AD_ToolBarButton **/
|
||||
private ArrayList<ToolbarProcessButton> toolbarProcessButtons = new ArrayList<ToolbarProcessButton>();
|
||||
|
||||
/** true if UI have been created for form and list **/
|
||||
private boolean uiCreated = false;
|
||||
|
||||
/** list view for center of {@link #formContainer} **/
|
||||
private GridView listPanel;
|
||||
|
||||
/** content rows for group **/
|
||||
private Map<String, List<Row>> fieldGroupContents;
|
||||
|
||||
/** header row for group **/
|
||||
private Map<String, List<org.zkoss.zul.Row>> fieldGroupHeaders;
|
||||
|
||||
/** tabs for group (for tab type field group) **/
|
||||
private Map<String, List<Tab>> fieldGroupTabHeaders;
|
||||
|
||||
/** all rows for current group (regardless of field group type) **/
|
||||
private ArrayList<Row> rowList;
|
||||
|
||||
/** all collapsible groups **/
|
||||
protected List<Group> allCollapsibleGroups;
|
||||
|
||||
/** main layout for header (center), tree (west) and detail pane (south) **/
|
||||
private Borderlayout formContainer = null;
|
||||
|
||||
/** Tree panel for west of {@link #formContainer} **/
|
||||
private ADTreePanel treePanel = null;
|
||||
|
||||
/** Sync field editor changes to GridField **/
|
||||
private GridTabDataBinder dataBinder;
|
||||
|
||||
/** true if tab have been activated **/
|
||||
protected boolean activated = false;
|
||||
|
||||
/**
|
||||
* current group for collapsible type field group
|
||||
*/
|
||||
private Group currentGroup;
|
||||
|
||||
/** Panel for child tabs, south of {@link #formContainer} **/
|
||||
private DetailPane detailPane;
|
||||
|
||||
/** true if this ADTabpanel instance is own by detail pane **/
|
||||
private boolean detailPaneMode;
|
||||
|
||||
/** tab no within an AD Window (sequence start from 0) **/
|
||||
private int tabNo;
|
||||
|
||||
/** DefaultFocusField */
|
||||
/** Default focus field */
|
||||
private WEditor defaultFocusField = null;
|
||||
|
||||
/** number of columns for {@link #form} **/
|
||||
private int numberOfFormColumns;
|
||||
|
||||
/** event to toggle between form and list view **/
|
||||
public static final String ON_TOGGLE_EVENT = "onToggle";
|
||||
|
||||
/** default width for west tree panel **/
|
||||
private static final String DEFAULT_PANEL_WIDTH = "300px";
|
||||
|
||||
private static CCache<Integer, Boolean> quickFormCache = new CCache<Integer, Boolean>(null, "QuickForm", 20, false);
|
||||
|
||||
/** Tab Box for Tab Field Groups */
|
||||
/** Tab Box for Tab Type Field Groups */
|
||||
private Tabbox tabbox = new Tabbox();
|
||||
/** List of Tab Group Grids */
|
||||
private List<Grid> tabForms;
|
||||
/** Current Tab Group Rows */
|
||||
private Rows currentTabRows;
|
||||
/** List of Grid/Form for tab type field group */
|
||||
private List<Grid> tabGroupForms;
|
||||
/** Current Rows for tab type field group */
|
||||
private Rows currentTabGroupRows;
|
||||
|
||||
/** Event for south of {@link #formContainer} **/
|
||||
private static enum SouthEvent {
|
||||
SLIDE(),
|
||||
OPEN(),
|
||||
|
@ -247,11 +283,17 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
private SouthEvent() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public ADTabpanel()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* init components and event listeners
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
initComponents();
|
||||
|
@ -270,6 +312,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
ClientInfo.onClientInfo(this, this::onClientInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link #form} and {@link #listPanel} instance.
|
||||
*/
|
||||
private void initComponents()
|
||||
{
|
||||
LayoutUtils.addSclass("adtab-content", this);
|
||||
|
@ -282,6 +327,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
form.setVflex(false);
|
||||
form.setSclass("grid-layout adwindow-form");
|
||||
form.setWidgetAttribute(AdempiereWebUI.WIDGET_INSTANCE_NAME, "form");
|
||||
//swipe listener for mobile
|
||||
if (ClientInfo.isMobile())
|
||||
{
|
||||
form.addEventListener("onSwipeRight", e -> {
|
||||
|
@ -313,6 +359,10 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
listPanel.getListbox().addEventListener(Events.ON_DOUBLE_CLICK, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup client side form swipe listener for mobile.
|
||||
* Send onSwipeRight and onSwipeLeft event to server.
|
||||
*/
|
||||
private void setupFormSwipeListener() {
|
||||
String uuid = form.getUuid();
|
||||
StringBuilder script = new StringBuilder("(function(){let w=zk.Widget.$('")
|
||||
|
@ -344,7 +394,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
public void setDetailPane(DetailPane component) {
|
||||
detailPane = component;
|
||||
|
||||
Borderlayout borderLayout = (Borderlayout) formContainer;
|
||||
Borderlayout borderLayout = formContainer;
|
||||
South south = borderLayout.getSouth();
|
||||
if (south == null) {
|
||||
south = new South();
|
||||
|
@ -375,7 +425,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
ZKUpdateUtil.setHeight(formContainer.getSouth(), height);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// just ignore exception is harmless here, consequence is just not setting height so it will assume the default of theme
|
||||
// just ignore, exception is harmless here, consequence is just not setting height so it will assume the default of theme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -386,7 +436,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* init tab panel layout ({@link #formContainer} and listeners
|
||||
* @param winPanel
|
||||
* @param gridTab
|
||||
*/
|
||||
|
@ -487,7 +537,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* Create UI components if not already created
|
||||
* Create UI for AD_Fields
|
||||
*/
|
||||
@Override
|
||||
public void createUI()
|
||||
|
@ -496,7 +546,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Create UI for AD_Fields
|
||||
* @param update true if it is update instead of create new
|
||||
*/
|
||||
protected void createUI(boolean update)
|
||||
|
@ -515,7 +565,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
fieldGroupHeaders = new HashMap<String, List<org.zkoss.zul.Row>>();
|
||||
allCollapsibleGroups = new ArrayList<Group>();
|
||||
|
||||
tabForms = new ArrayList<Grid>();
|
||||
tabGroupForms = new ArrayList<Grid>();
|
||||
fieldGroupTabHeaders = new HashMap<String, List<Tab>>();
|
||||
|
||||
int numCols=gridTab.getNumColumns();
|
||||
|
@ -610,8 +660,8 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
if (numCols - actualxpos + 1 > 0)
|
||||
row.appendCellChild(createSpacer(), numCols - actualxpos + 1);
|
||||
if(currentTabRows != null) {
|
||||
currentTabRows.appendChild(row);
|
||||
if (currentTabGroupRows != null) {
|
||||
currentTabGroupRows.appendChild(row);
|
||||
} else {
|
||||
row.setGroup(currentGroup);
|
||||
rows.appendChild(row);
|
||||
|
@ -641,7 +691,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
rows.appendChild(row);
|
||||
headerRows.add(row);
|
||||
currentGroup = null;
|
||||
currentTabRows = null;
|
||||
currentTabGroupRows = null;
|
||||
} else if(X_AD_FieldGroup.FIELDGROUPTYPE_Tab.equals(field.getFieldGroupType())) {
|
||||
// Create New Tab for FieldGroup
|
||||
List<Tab> headerTabs = new ArrayList<Tab>();
|
||||
|
@ -658,7 +708,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
headerTabs.add(tab);
|
||||
|
||||
Grid tabForm = new Grid();
|
||||
tabForms.add(tabForm);
|
||||
tabGroupForms.add(tabForm);
|
||||
ZKUpdateUtil.setHflex(tabForm, "1");
|
||||
ZKUpdateUtil.setHeight(tabForm, null);
|
||||
tabForm.setVflex(false);
|
||||
|
@ -696,7 +746,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
tp.appendChild(tabForm);
|
||||
|
||||
currentGroup = null;
|
||||
currentTabRows = tabRows;
|
||||
currentTabGroupRows = tabRows;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -710,7 +760,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
{
|
||||
rowg.setOpen(false);
|
||||
}
|
||||
currentTabRows = null;
|
||||
currentTabGroupRows = null;
|
||||
currentGroup = rowg;
|
||||
rows.appendChild(rowg);
|
||||
headerRows.add(rowg);
|
||||
|
@ -738,8 +788,8 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
if (numCols - actualxpos + 1 > 0)
|
||||
row.appendCellChild(createSpacer(), numCols - actualxpos + 1);
|
||||
// Tab Group vs Grid Group
|
||||
if(currentTabRows != null) {
|
||||
currentTabRows.appendChild(row);
|
||||
if (currentTabGroupRows != null) {
|
||||
currentTabGroupRows.appendChild(row);
|
||||
} else {
|
||||
row.setGroup(currentGroup);
|
||||
rows.appendChild(row);
|
||||
|
@ -899,8 +949,8 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
if (numCols - actualxpos + 1 > 0)
|
||||
row.appendCellChild(createSpacer(), numCols - actualxpos + 1);
|
||||
// Tab Group vs Grid Group
|
||||
if(currentTabRows != null) {
|
||||
currentTabRows.appendChild(row);
|
||||
if (currentTabGroupRows != null) {
|
||||
currentTabGroupRows.appendChild(row);
|
||||
} else {
|
||||
row.setGroup(currentGroup);
|
||||
rows.appendChild(row);
|
||||
|
@ -936,6 +986,10 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
switchRowPresentation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field
|
||||
* @return {@link WEditor} or null if not found
|
||||
*/
|
||||
private WEditor findEditor(GridField field) {
|
||||
for(WEditor editor : editors) {
|
||||
if (editor.getGridField() == field)
|
||||
|
@ -944,6 +998,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* load toolbar buttons from AD_ToolBarButton
|
||||
*/
|
||||
private void loadToolbarButtons() {
|
||||
//get extra toolbar process buttons
|
||||
MToolBarButton[] mToolbarButtons = MToolBarButton.getProcessButtonOfTab(gridTab.getAD_Tab_ID(), null);
|
||||
|
@ -976,7 +1033,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* Validate display properties of fields of current row.
|
||||
* Update state of fields (visibility, style, writable, etc)
|
||||
* @param col
|
||||
*/
|
||||
@Override
|
||||
|
@ -987,6 +1044,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
return;
|
||||
}
|
||||
|
||||
//css animation for slide
|
||||
if (form.getSclass() != null && form.getSclass().contains(SLIDE_RIGHT_OUT_CSS)) {
|
||||
Executions.schedule(getDesktop(), e -> {
|
||||
LayoutUtils.removeSclass(SLIDE_RIGHT_OUT_CSS, form);
|
||||
|
@ -1104,7 +1162,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
//hide row if all editor within the row is invisible in Tabbox grid
|
||||
for(Grid tabForm: tabForms) {
|
||||
for(Grid tabForm: tabGroupForms) {
|
||||
List<Component> tabrows = tabForm.getRows().getChildren();
|
||||
for (Component comp : tabrows)
|
||||
{
|
||||
|
@ -1217,6 +1275,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
LayoutUtils.removeSclass(SLIDE_RIGHT_IN_CSS, form);
|
||||
}
|
||||
|
||||
/**
|
||||
* echo set selected node event for tree
|
||||
*/
|
||||
private void echoDeferSetSelectedNodeEvent() {
|
||||
if (getAttribute(ON_DEFER_SET_SELECTED_NODE_ATTR) == null) {
|
||||
setAttribute(ON_DEFER_SET_SELECTED_NODE_ATTR, Boolean.TRUE);
|
||||
|
@ -1225,7 +1286,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
* @return display logic
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayLogic()
|
||||
|
@ -1234,7 +1295,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
* @return title of tab
|
||||
*/
|
||||
@Override
|
||||
public String getTitle()
|
||||
|
@ -1244,6 +1305,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
/**
|
||||
* @param variableName
|
||||
* @return value
|
||||
*/
|
||||
@Override
|
||||
public String get_ValueAsString(String variableName)
|
||||
|
@ -1270,7 +1332,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return The record ID of this Tabpanel
|
||||
* @return The record ID of current row
|
||||
*/
|
||||
@Override
|
||||
public int getRecord_ID()
|
||||
|
@ -1280,7 +1342,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
/**
|
||||
* Is panel need refresh
|
||||
* @return boolean
|
||||
* @return true if GridTab need refresh
|
||||
*/
|
||||
@Override
|
||||
public boolean isCurrent()
|
||||
|
@ -1298,7 +1360,8 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve from db
|
||||
* Retrieve from db.
|
||||
* Delegate to {@link GridTab#query(boolean)}
|
||||
*/
|
||||
@Override
|
||||
public void query()
|
||||
|
@ -1311,9 +1374,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
/**
|
||||
* Retrieve from db
|
||||
* @param onlyCurrentRows
|
||||
* @param onlyCurrentDays
|
||||
* @param maxRows
|
||||
* @param onlyCurrentRows True to show only unprocessed or the one updated within x days (default is 1 day before today)
|
||||
* @param onlyCurrentDays if > 0, filter records with created >= current_date - onlyCurrentDays
|
||||
* @param maxRows if > 0, maximum number of rows to load
|
||||
*/
|
||||
@Override
|
||||
public void query (boolean onlyCurrentRows, int onlyCurrentDays, int maxRows)
|
||||
|
@ -1339,7 +1402,8 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* reset detail data grid for new parent record that's not saved yet
|
||||
* Reset detail data grid for new parent record that's not saved yet.
|
||||
* Delegate to {@link GridTab#resetDetailForNewParentRecord()}.
|
||||
*/
|
||||
@Override
|
||||
public void resetDetailForNewParentRecord ()
|
||||
|
@ -1364,7 +1428,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return TreePanel
|
||||
* @return ADTreePanel
|
||||
*/
|
||||
public ADTreePanel getTreePanel()
|
||||
{
|
||||
|
@ -1372,7 +1436,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return TreePanel
|
||||
* @return master, detail or both
|
||||
*/
|
||||
public String getTreeDisplayedOn()
|
||||
{
|
||||
|
@ -1434,7 +1498,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Delegate to {@link #focusToEditor(WEditor, boolean)}
|
||||
* @param checkCurrent
|
||||
*/
|
||||
public void focusToFirstEditor(boolean checkCurrent) {
|
||||
|
@ -1535,6 +1599,10 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle open/close event of south panel (detail pane)
|
||||
* @param event
|
||||
*/
|
||||
private void onSouthEvent(SouthEvent event) {
|
||||
if (event == SouthEvent.OPEN || event == SouthEvent.CLOSE) {
|
||||
boolean open = event == SouthEvent.OPEN ? true : false;
|
||||
|
@ -1563,6 +1631,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if detail pane is open/visible
|
||||
*/
|
||||
private boolean isOpenDetailPane() {
|
||||
if (isMobile())
|
||||
return false;
|
||||
|
@ -1578,6 +1649,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
return open;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return height of detail pane from user preference
|
||||
*/
|
||||
private String heigthDetailPane() {
|
||||
String height = null;
|
||||
int windowId = getGridTab().getAD_Window_ID();
|
||||
|
@ -1588,6 +1662,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return width of tree panel from user preference (or default if no user preference)
|
||||
*/
|
||||
private String widthTreePanel() {
|
||||
String width = null;
|
||||
int windowId = getGridTab().getAD_Window_ID();
|
||||
|
@ -1597,6 +1674,10 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
return Util.isEmpty(width) ? DEFAULT_PANEL_WIDTH : width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a tree node
|
||||
* @param value
|
||||
*/
|
||||
private void navigateTo(DefaultTreeNode<MTreeNode> value) {
|
||||
MTreeNode treeNode = value.getData();
|
||||
// We Have a TreeNode
|
||||
|
@ -1654,7 +1735,8 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
Dialog.error(windowNo, msg);
|
||||
}
|
||||
}
|
||||
//if (col >= 0)
|
||||
|
||||
//update UI state
|
||||
if (!uiCreated)
|
||||
createUI();
|
||||
dynamicDisplay(col);
|
||||
|
@ -1750,6 +1832,8 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
treePanel.initTree(AD_Tree_ID, windowNo);
|
||||
}
|
||||
}
|
||||
|
||||
//update list view
|
||||
if (listPanel.isVisible()) {
|
||||
listPanel.updateListIndex();
|
||||
listPanel.dynamicDisplay(col);
|
||||
|
@ -1760,6 +1844,10 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete tree node by recordId
|
||||
* @param recordId
|
||||
*/
|
||||
private void deleteNode(int recordId) {
|
||||
if (recordId <= 0) return;
|
||||
|
||||
|
@ -1780,6 +1868,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add new tree node for current row
|
||||
*/
|
||||
private void addNewNode() {
|
||||
if (gridTab.getRecord_ID() > 0) {
|
||||
String name = (String)gridTab.getValue("Name");
|
||||
|
@ -1817,6 +1908,10 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set selected tree node by recordId
|
||||
* @param recordId
|
||||
*/
|
||||
private void setSelectedNode(int recordId) {
|
||||
if (recordId <= 0) return;
|
||||
|
||||
|
@ -1921,15 +2016,15 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
static class ZoomListener implements EventListener<Event> {
|
||||
|
||||
private IZoomableEditor searchEditor;
|
||||
private IZoomableEditor zoomableEditor;
|
||||
|
||||
ZoomListener(IZoomableEditor editor) {
|
||||
searchEditor = editor;
|
||||
zoomableEditor = editor;
|
||||
}
|
||||
|
||||
public void onEvent(Event event) throws Exception {
|
||||
if (Events.ON_CLICK.equals(event.getName())) {
|
||||
searchEditor.actionZoom();
|
||||
zoomableEditor.actionZoom();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1980,7 +2075,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
* @return true if list/grid view is visible
|
||||
*/
|
||||
@Override
|
||||
public boolean isGridView() {
|
||||
|
@ -1989,7 +2084,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
/**
|
||||
*
|
||||
* @return GridPanel
|
||||
* @return {@link GridView}
|
||||
*/
|
||||
@Override
|
||||
public GridView getGridView() {
|
||||
|
@ -2015,6 +2110,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show detail pane
|
||||
*/
|
||||
private void attachDetailPane() {
|
||||
if (formContainer.getSouth() != null) {
|
||||
formContainer.getSouth().setVisible(true);
|
||||
|
@ -2029,6 +2127,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide detail pane
|
||||
*/
|
||||
private void detachDetailPane() {
|
||||
if (formContainer.getSouth() != null) {
|
||||
formContainer.getSouth().setVisible(false);
|
||||
|
@ -2039,8 +2140,8 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all visible button editors
|
||||
* @return List<WButtonEditor>
|
||||
* Get all visible toolbar button editors
|
||||
* @return List<Button>
|
||||
*/
|
||||
public List<Button> getToolbarButtons() {
|
||||
List<Button> buttonList = new ArrayList<Button>();
|
||||
|
@ -2085,7 +2186,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* activate current selected detail tab if it is visible
|
||||
* activate selected detail tab if it is visible
|
||||
*/
|
||||
public void activateDetailIfVisible() {
|
||||
if (isDetailVisible()) {
|
||||
|
@ -2110,7 +2211,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
/**
|
||||
*
|
||||
* @return true if the detailpane is visible
|
||||
* @return true if {@link DetailPane} is visible
|
||||
*/
|
||||
@Override
|
||||
public boolean isDetailVisible() {
|
||||
|
@ -2124,7 +2225,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
|
||||
/**
|
||||
*
|
||||
* @return true if have one or more detail tabs
|
||||
* @return true if selected tab has one or more detail/child tab
|
||||
*/
|
||||
public boolean hasDetailTabs() {
|
||||
if (formContainer.getSouth() == null || !formContainer.getSouth().isVisible()) {
|
||||
|
@ -2196,6 +2297,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if tree is order by value
|
||||
*/
|
||||
private boolean isTreeDrivenByValue() {
|
||||
SimpleTreeModel model = (SimpleTreeModel)(TreeModel<?>) treePanel.getTree().getModel();
|
||||
boolean retValue = false;
|
||||
|
@ -2203,6 +2307,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
return retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if value is shown in tree
|
||||
*/
|
||||
private boolean isValueDisplayed() {
|
||||
SimpleTreeModel model = (SimpleTreeModel)(TreeModel<?>) treePanel.getTree().getModel();
|
||||
boolean retValue = false;
|
||||
|
@ -2233,7 +2340,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Save user preference for this AD Window
|
||||
* @param attribute
|
||||
* @param value
|
||||
*/
|
||||
|
@ -2287,6 +2394,9 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return true if client is mobile
|
||||
*/
|
||||
protected boolean isMobile() {
|
||||
return ClientInfo.isMobile();
|
||||
}
|
||||
|
@ -2323,7 +2433,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
}
|
||||
|
||||
/**
|
||||
* Set Visibility for Tabbox based on Children and Form Visibility
|
||||
* Set Visibility for {@link #tabbox} based on {@link #form} Visibility and whether {@link #tabbox} is empty
|
||||
*/
|
||||
private void setGroupTabboxVisibility() {
|
||||
boolean isGroupTabVisible = false;
|
||||
|
|
|
@ -35,29 +35,40 @@ import org.zkoss.zul.Tree;
|
|||
|
||||
/**
|
||||
*
|
||||
* Tree panel for AD_Tab with HasTree=Y
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class ADTreePanel extends Panel implements EventListener<Event>
|
||||
{
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 2718257463734592729L;
|
||||
/** event to expand/collapse all tree nodes **/
|
||||
private static final String ON_EXPAND_MENU_EVENT = "onExpandMenu";
|
||||
/** search/lookup panel for tree **/
|
||||
private TreeSearchPanel pnlSearch;
|
||||
private Tree tree;
|
||||
|
||||
/** ToolBarButton to expand or collapse all tree nodes **/
|
||||
private ToolBarButton expandToggle; // Elaine 2009/02/27 - expand tree
|
||||
private int m_windowno = -1;
|
||||
private int m_tabno = -1;
|
||||
private int AD_Tree_ID = -1;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public ADTreePanel()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param windowno
|
||||
* @param tabno
|
||||
*/
|
||||
public ADTreePanel(int windowno, int tabno)
|
||||
{
|
||||
m_windowno = windowno;
|
||||
|
@ -66,6 +77,7 @@ public class ADTreePanel extends Panel implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Delegate to {@link #initTree(int, int, String, int)}
|
||||
* @param AD_Tree_ID
|
||||
* @param windowNo
|
||||
*/
|
||||
|
@ -74,6 +86,14 @@ public class ADTreePanel extends Panel implements EventListener<Event>
|
|||
return initTree(AD_Tree_ID, windowNo, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init and load tree
|
||||
* @param AD_Tree_ID
|
||||
* @param windowNo
|
||||
* @param linkColName
|
||||
* @param linkID
|
||||
* @return true if a new tree have been created and loaded, false if AD_Tree_ID have already been loaded
|
||||
*/
|
||||
public boolean initTree(int AD_Tree_ID, int windowNo, String linkColName, int linkID)
|
||||
{
|
||||
if (this.AD_Tree_ID != AD_Tree_ID)
|
||||
|
@ -89,6 +109,9 @@ public class ADTreePanel extends Panel implements EventListener<Event>
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout panel
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
setWidgetAttribute(AdempiereWebUI.WIDGET_INSTANCE_NAME, "treepanel");
|
||||
|
@ -191,6 +214,9 @@ public class ADTreePanel extends Panel implements EventListener<Event>
|
|||
}
|
||||
//
|
||||
|
||||
/**
|
||||
* Reset AD_Tree_ID to create a new Tree in next {@link #initTree(int, int, String, int)} call
|
||||
*/
|
||||
public void prepareForRefresh() {
|
||||
this.AD_Tree_ID = -1;
|
||||
}
|
||||
|
|
|
@ -38,30 +38,37 @@ import org.compiere.util.Env;
|
|||
import org.zkoss.zk.ui.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* UI part for AD_Window
|
||||
* @author <a href="mailto:agramdass@gmail.com">Ashley G Ramdass</a>
|
||||
* @date Feb 25, 2007
|
||||
* @version $Revision: 0.10 $
|
||||
*/
|
||||
public class ADWindow extends AbstractUIPart
|
||||
{
|
||||
/** Component attribute to hold reference to ancestor ADWindow instance **/
|
||||
public static final String AD_WINDOW_ATTRIBUTE_KEY = "org.adempiere.webui.adwindow";
|
||||
/** Content part for AD_Window (toolbar, tabbox, statusbar, etc) **/
|
||||
private ADWindowContent windowContent;
|
||||
/** Environment Context **/
|
||||
private Properties ctx;
|
||||
/** AD_Window_ID **/
|
||||
private int adWindowId;
|
||||
private String _title;
|
||||
private String windowTitle;
|
||||
private int windowNo;
|
||||
|
||||
/** initial query when AD Window is first open **/
|
||||
private MQuery query;
|
||||
|
||||
/** main component of ADWindowContent **/
|
||||
private Component windowPanelComponent;
|
||||
/** image for window (desktop tab) title **/
|
||||
private MImage image;
|
||||
|
||||
/** AD_Tab_ID:BtnComponentName. List of toolbar buttons to exclude, loaded from AD_ToolBarButtonRestrict **/
|
||||
private Map<Integer, List<String>> tabToolbarRestricMap = new HashMap<Integer, List<String>>();
|
||||
|
||||
/** List of BtnComponentName to exclude, loaded from AD_ToolBarButtonRestrict **/
|
||||
private List<String> windowToolbarRestrictList = null;
|
||||
|
||||
/** List of advanced (IsAdvancedButton=Y) window toolbar buttons. Accessible by advanced role only. **/
|
||||
private List<String> windowToolbarAdvancedList = null;
|
||||
/** AD_Window_UU value **/
|
||||
private String adWindowUUID;
|
||||
|
||||
/**
|
||||
|
@ -100,11 +107,14 @@ public class ADWindow extends AbstractUIPart
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init ADWindowContent
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
windowContent = new ADWindowContent(ctx, windowNo, adWindowId);
|
||||
windowContent.setADWindow(this);
|
||||
_title = windowContent.getTitle();
|
||||
windowTitle = windowContent.getTitle();
|
||||
image = windowContent.getImage();
|
||||
}
|
||||
|
||||
|
@ -114,18 +124,22 @@ public class ADWindow extends AbstractUIPart
|
|||
*/
|
||||
public String getTitle()
|
||||
{
|
||||
return _title;
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return image for the country
|
||||
* @return image for window title
|
||||
*/
|
||||
public MImage getMImage()
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create component for content part (ADWindowContent).
|
||||
* @see ADWindowContent#createPart(Object)
|
||||
*/
|
||||
@Override
|
||||
protected Component doCreatePart(Component parent)
|
||||
{
|
||||
windowPanelComponent = windowContent.createPart(parent);
|
||||
|
@ -154,6 +168,10 @@ public class ADWindow extends AbstractUIPart
|
|||
return windowContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AD_Tab_ID
|
||||
* @return list of toolbar button to exclude/restrict for current login role
|
||||
*/
|
||||
public List<String> getTabToolbarRestrictList(int AD_Tab_ID) {
|
||||
List<String> tabRestrictList = tabToolbarRestricMap.get(AD_Tab_ID);
|
||||
if (tabRestrictList == null) {
|
||||
|
@ -174,6 +192,9 @@ public class ADWindow extends AbstractUIPart
|
|||
return tabRestrictList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of window toolbar button to exclude/restrict for current login role
|
||||
*/
|
||||
public List<String> getWindowToolbarRestrictList() {
|
||||
if (windowToolbarRestrictList == null) {
|
||||
//load window restriction
|
||||
|
@ -192,6 +213,9 @@ public class ADWindow extends AbstractUIPart
|
|||
return windowToolbarRestrictList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of advance (IsAdvancedButton=Y) toolbar buttons for window
|
||||
*/
|
||||
public List<String> getWindowAdvancedButtonList() {
|
||||
if (windowToolbarAdvancedList == null) {
|
||||
//load window advance buttons
|
||||
|
@ -207,18 +231,23 @@ public class ADWindow extends AbstractUIPart
|
|||
return windowToolbarAdvancedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AD_Window_ID
|
||||
*/
|
||||
public int getAD_Window_ID() {
|
||||
return adWindowId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AD_Window_UU
|
||||
*/
|
||||
public String getAD_Window_UU() {
|
||||
return adWindowUUID;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param windowNo
|
||||
* @return adwindow instance for windowNo ( if any )
|
||||
* @return {@link ADWindow} instance for windowNo ( if any )
|
||||
*/
|
||||
public static ADWindow get(int windowNo) {
|
||||
Object window = SessionManager.getAppDesktop().findWindow(windowNo);
|
||||
|
@ -229,8 +258,9 @@ public class ADWindow extends AbstractUIPart
|
|||
}
|
||||
|
||||
/**
|
||||
* Find ADWindow instance that's the ancestor of comp
|
||||
* @param comp
|
||||
* @return adwindow instance if found, null otherwise
|
||||
* @return {@link ADWindow} instance if found, null otherwise
|
||||
*/
|
||||
public static ADWindow findADWindow(Component comp) {
|
||||
Component parent = comp;
|
||||
|
|
|
@ -46,7 +46,8 @@ import org.zkoss.zul.Tab;
|
|||
import org.zkoss.zul.Vlayout;
|
||||
|
||||
/**
|
||||
*
|
||||
* Content area of {@link ADWindow}.
|
||||
*
|
||||
* This class is based on org.compiere.apps.APanel written by Jorg Janke.
|
||||
* @author Jorg Janke
|
||||
*
|
||||
|
@ -60,15 +61,26 @@ public class ADWindowContent extends AbstractADWindowContent
|
|||
@SuppressWarnings("unused")
|
||||
private static final CLogger logger = CLogger.getCLogger(ADWindowContent.class);
|
||||
|
||||
/** Main layout component **/
|
||||
private Vlayout layout;
|
||||
|
||||
/** Center Div of {@link #layout}, host {@link CompositeADTabbox} **/
|
||||
private Div contentArea;
|
||||
|
||||
/**
|
||||
* @param ctx
|
||||
* @param windowNo
|
||||
* @param adWindowId
|
||||
*/
|
||||
public ADWindowContent(Properties ctx, int windowNo, int adWindowId)
|
||||
{
|
||||
super(ctx, windowNo, adWindowId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout UI.
|
||||
* Vertical layout of toolbar, breadCrumb, statusBar and {@link #contentArea}.
|
||||
*/
|
||||
@Override
|
||||
protected Component doCreatePart(Component parent)
|
||||
{
|
||||
layout = new ADWindowVlayout(this);
|
||||
|
@ -100,6 +112,7 @@ public class ADWindowContent extends AbstractADWindowContent
|
|||
|
||||
LayoutUtils.addSclass("adwindow-status", statusBar);
|
||||
|
||||
//IADTabbox
|
||||
contentArea = new Div();
|
||||
contentArea.setParent(layout);
|
||||
ZKUpdateUtil.setVflex(contentArea, "1");
|
||||
|
@ -119,12 +132,21 @@ public class ADWindowContent extends AbstractADWindowContent
|
|||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link CompositeADTabbox}
|
||||
*/
|
||||
@Override
|
||||
protected IADTabbox createADTab()
|
||||
{
|
||||
CompositeADTabbox composite = new CompositeADTabbox();
|
||||
return composite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get main layout component
|
||||
* @return {@link Vlayout}
|
||||
*/
|
||||
@Override
|
||||
public Vlayout getComponent() {
|
||||
return layout;
|
||||
}
|
||||
|
@ -133,6 +155,7 @@ public class ADWindowContent extends AbstractADWindowContent
|
|||
* @param event
|
||||
* @see EventListener#onEvent(Event)
|
||||
*/
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
if (Events.ON_CTRL_KEY.equals(event.getName())) {
|
||||
KeyEvent keyEvent = (KeyEvent) event;
|
||||
|
@ -154,6 +177,9 @@ public class ADWindowContent extends AbstractADWindowContent
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ITabOnCloseHandler to call {@link ADWindowContent#onExit(Callback)} when user wants to close an AD Window
|
||||
*/
|
||||
class TabOnCloseHanlder implements ITabOnCloseHandler, Callback<Boolean> {
|
||||
private Tabpanel tabPanel;
|
||||
public void onClose(Tabpanel tabPanel) {
|
||||
|
@ -170,8 +196,8 @@ public class ADWindowContent extends AbstractADWindowContent
|
|||
}
|
||||
|
||||
/**
|
||||
* close tab contain this window
|
||||
* @param tabPanel
|
||||
* Close tab related to tabPanel
|
||||
* @param tabPanel Tabpanel that represent AD_Window
|
||||
*/
|
||||
protected void closeTab (Tabpanel tabPanel) {
|
||||
Tab tab = tabPanel.getLinkedTab();
|
||||
|
@ -180,6 +206,9 @@ public class ADWindowContent extends AbstractADWindowContent
|
|||
SessionManager.getAppDesktop().unregisterWindow(getWindowNo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Vlayout subclass to override onPageDetached.
|
||||
*/
|
||||
public static class ADWindowVlayout extends Vlayout implements IHelpContext {
|
||||
/**
|
||||
* generated serial id
|
||||
|
@ -192,6 +221,9 @@ public class ADWindowContent extends AbstractADWindowContent
|
|||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up listeners
|
||||
*/
|
||||
@Override
|
||||
public void onPageDetached(Page page) {
|
||||
super.onPageDetached(page);
|
||||
|
|
|
@ -77,7 +77,7 @@ import org.zkoss.zul.Toolbarbutton;
|
|||
import org.zkoss.zul.impl.LabelImageElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* Toolbar of AD_Window
|
||||
* @author <a href="mailto:agramdass@gmail.com">Ashley G Ramdass</a>
|
||||
* @date Feb 25, 2007
|
||||
* @version $Revision: 0.10 $
|
||||
|
@ -86,21 +86,29 @@ import org.zkoss.zul.impl.LabelImageElement;
|
|||
* <li>FR [ 2076330 ] Add new methods in CWindowToolbar class
|
||||
*/
|
||||
public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
||||
{
|
||||
{
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = -5151981978053022864L;
|
||||
|
||||
/**
|
||||
* Attribute for {@link #overflowPopup} to store the last close timestamp in ms.
|
||||
* Use to prevent too rapid open and close of overflow popup.
|
||||
*/
|
||||
private static final String POPUP_CLOSE_TIMESTAMP_ATTR = "popup.close";
|
||||
|
||||
/** Prefix for Button Name **/
|
||||
public static final String BTNPREFIX = "Btn";
|
||||
|
||||
@Deprecated(forRemoval = true, since = "11")
|
||||
public static final String MNITMPREFIX = "Mnitm";
|
||||
|
||||
private static final CLogger log = CLogger.getCLogger(ADWindowToolbar.class);
|
||||
|
||||
/** Search messages using translation */
|
||||
private String m_sNew;
|
||||
|
||||
/** translated message for new query label (default for en is "** New Query **") */
|
||||
private String m_sNew;
|
||||
/** combobox to select user query **/
|
||||
private Combobox fQueryName;
|
||||
private MUserQuery[] userQueries;
|
||||
private MUserQuery selectedUserQuery;
|
||||
|
@ -136,25 +144,31 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
private ToolBarButton btnProcess;
|
||||
|
||||
private ToolBarButton btnQuickForm;
|
||||
|
||||
/** button to open overflow popup for toolbar buttons with IsShowMore=Y (for non-mobile client) **/
|
||||
private ToolBarButton btnShowMore;
|
||||
|
||||
/** Button Name:ToolBarButton. Map for all buttons **/
|
||||
private HashMap<String, ToolBarButton> buttons = new HashMap<String, ToolBarButton>();
|
||||
/**
|
||||
* For mobile client, the list of toolbar button with IsShowMore=Y is first keep here
|
||||
* and move to {@link #overflows} in {@link #onOverflowButton(Event) event}
|
||||
* */
|
||||
private ArrayList<ToolBarButton> mobileShowMoreButtons = new ArrayList<ToolBarButton>();
|
||||
|
||||
// private ToolBarButton btnExit;
|
||||
|
||||
/** All register toolbar listener **/
|
||||
private ArrayList<ToolbarListener> listeners = new ArrayList<ToolbarListener>();
|
||||
|
||||
/** current ON_Click event that's being handle **/
|
||||
private Event event;
|
||||
|
||||
/** shortcut key map without ctrl and alt **/
|
||||
private Map<Integer, ToolBarButton> keyMap = new HashMap<Integer, ToolBarButton>();
|
||||
/** alt+key shortcut map **/
|
||||
private Map<Integer, ToolBarButton> altKeyMap = new HashMap<Integer, ToolBarButton>();
|
||||
/** ctrl+key shortcut map **/
|
||||
private Map<Integer, ToolBarButton> ctrlKeyMap = new HashMap<Integer, ToolBarButton>();
|
||||
|
||||
/** list of custom toolbar button (IsCustomization=Y) **/
|
||||
private List<ToolbarCustomButton> toolbarCustomButtons = new ArrayList<ToolbarCustomButton>();
|
||||
|
||||
/** Restriction list for window, loaded from AD_ToolBarButtonRestrict **/
|
||||
private List<String> restrictionList;
|
||||
/** List of toolbar button with IsAdvanced=Y **/
|
||||
private List<String> advancedList;
|
||||
|
||||
// Elaine 2008/12/04
|
||||
|
@ -163,34 +177,45 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
private boolean isAllowProductInfo = MRole.getDefault().canAccess_Info_Product();
|
||||
|
||||
private int windowNo = 0;
|
||||
|
||||
/** previous key event time in ms **/
|
||||
private long prevKeyEventTime = 0;
|
||||
|
||||
/**
|
||||
* Previous key event.
|
||||
* Use together with prevKeyEventTime to detect double fire of key event from browser
|
||||
*/
|
||||
private KeyEvent prevKeyEvent;
|
||||
|
||||
// Maintain hierarchical Quick form by its parent-child tab while open leaf
|
||||
// tab once & dispose and doing same action
|
||||
private int quickFormTabHrchyLevel = 0;
|
||||
|
||||
private A overflowButton;
|
||||
|
||||
/**
|
||||
* Maintain hierarchical Quick form by its parent-child tab while open leaf
|
||||
* tab once & dispose and doing same action
|
||||
*/
|
||||
private int quickFormTabHrchyLevel = 0;
|
||||
/** show more button for mobile client **/
|
||||
private A mobileOverflowButton;
|
||||
/**
|
||||
* list of toolbar button overflow to show more popup (or with IsShowMore=Y).
|
||||
* Use for both mobile and desktop client.
|
||||
* */
|
||||
private ArrayList<ToolBarButton> overflows;
|
||||
|
||||
/** Popup for overflow/IsShowMore=Y toolbar buttons. Use for both mobile and desktop client. **/
|
||||
private Popup overflowPopup;
|
||||
|
||||
/** width of toolbar from previous ON_AFTER_SIZE event **/
|
||||
private int prevWidth;
|
||||
|
||||
/** AD Window content part that own this toolbar **/
|
||||
private AbstractADWindowContent windowContent;
|
||||
|
||||
/** Last Modifier of Action Event */
|
||||
// public int lastModifiers;
|
||||
//
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public ADWindowToolbar()
|
||||
{
|
||||
this(null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param windowContent
|
||||
* @param windowNo
|
||||
*/
|
||||
public ADWindowToolbar(AbstractADWindowContent windowContent, int windowNo) {
|
||||
this.windowContent = windowContent;
|
||||
setWindowNo(windowNo);
|
||||
|
@ -200,6 +225,9 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init components
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
LayoutUtils.addSclass("adwindow-toolbar", this);
|
||||
|
@ -292,6 +320,8 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
|
||||
if (!ClientInfo.isMobile())
|
||||
overflows = new ArrayList<ToolBarButton>();
|
||||
|
||||
//Window toolbar buttons from AD_ToolBarButton
|
||||
MToolBarButton[] officialButtons = MToolBarButton.getToolbarButtons("W", null);
|
||||
for (MToolBarButton button : officialButtons) {
|
||||
if (!button.isActive() || !hasAccess(BTNPREFIX+button.getComponentName())) {
|
||||
|
@ -374,7 +404,13 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
ZKUpdateUtil.setWidth(this, "100%");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create new toolbar button
|
||||
* @param name button name (BTNPREFIX+name)
|
||||
* @param image image name (images/image+suffix) or iconSclass name (z-icon-image)
|
||||
* @param tooltip
|
||||
* @return {@link ToolBarButton}
|
||||
*/
|
||||
private ToolBarButton createButton(String name, String image, String tooltip)
|
||||
{
|
||||
ToolBarButton btn = new ToolBarButton("");
|
||||
|
@ -415,11 +451,21 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
return btn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ToolBarButton by name
|
||||
* @param name
|
||||
* @return {@link ToolBarButton} or null
|
||||
*/
|
||||
public ToolBarButton getButton(String name)
|
||||
{
|
||||
return buttons.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ToolBarButton by name
|
||||
* @param name
|
||||
* @return {@link LabelImageElement} or null
|
||||
*/
|
||||
public LabelImageElement getToolbarItem(String name)
|
||||
{
|
||||
return buttons.get(name);
|
||||
|
@ -453,6 +499,9 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
public static final int VK_Y = 0x59;
|
||||
public static final int VK_Z = 0x5A;
|
||||
|
||||
/**
|
||||
* Configure shortcut key for each button
|
||||
*/
|
||||
private void configureKeyMap()
|
||||
{
|
||||
altKeyMap.put(VK_H, btnHelp);
|
||||
|
@ -473,6 +522,9 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
altKeyMap.put(VK_L, btnCustomize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add separator/spacer between button
|
||||
*/
|
||||
protected void addSeparator()
|
||||
{
|
||||
Space s = new Space();
|
||||
|
@ -481,16 +533,25 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
this.appendChild(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ToolbarListener
|
||||
* @param toolbarListener
|
||||
*/
|
||||
public void addListener(ToolbarListener toolbarListener)
|
||||
{
|
||||
listeners.add(toolbarListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove ToolbarListener
|
||||
* @param toolbarListener
|
||||
*/
|
||||
public void removeListener(ToolbarListener toolbarListener)
|
||||
{
|
||||
listeners.remove(toolbarListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event)
|
||||
{
|
||||
String eventName = event.getName();
|
||||
|
@ -547,6 +608,11 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ON_Click event for button.
|
||||
* Call register {@link ToolbarListener}.
|
||||
* @param event
|
||||
*/
|
||||
private void doOnClick(Event event) {
|
||||
this.event = event;
|
||||
String compName;
|
||||
|
@ -590,127 +656,216 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
this.event = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable buttons for navigation between parent and detail tab
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableTabNavigation(boolean enabled)
|
||||
{
|
||||
enableTabNavigation(enabled, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable buttons for navigation between parent and detail tab
|
||||
* @param enableParent
|
||||
* @param enableDetail
|
||||
*/
|
||||
public void enableTabNavigation(boolean enableParent, boolean enableDetail)
|
||||
{
|
||||
this.btnParentRecord.setDisabled(!enableParent);
|
||||
this.btnDetailRecord.setDisabled(!enableDetail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Refresh button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableRefresh(boolean enabled)
|
||||
{
|
||||
this.btnRefresh.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Save button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableSave(boolean enabled)
|
||||
{
|
||||
this.btnSave.setDisabled(!enabled);
|
||||
this.btnSaveAndCreate.setDisabled(!(isNewEnabled() || isSaveEnable()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if Save button is enable
|
||||
*/
|
||||
public boolean isSaveEnable() {
|
||||
return !btnSave.isDisabled();
|
||||
}
|
||||
|
||||
// public void enableExit(boolean enabled)
|
||||
// {
|
||||
// this.btnExit.setDisabled(!enabled);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Enable/disable Delete button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableDelete(boolean enabled)
|
||||
{
|
||||
this.btnDelete.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if Delete button is enable
|
||||
*/
|
||||
public boolean isDeleteEnable()
|
||||
{
|
||||
return !btnDelete.isDisabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if New button is enable
|
||||
*/
|
||||
public boolean isNewEnabled() {
|
||||
return !btnNew.isDisabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Ignore/Undo button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableIgnore(boolean enabled)
|
||||
{
|
||||
this.btnIgnore.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable New button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableNew(boolean enabled)
|
||||
{
|
||||
this.btnNew.setDisabled(!enabled);
|
||||
this.btnSaveAndCreate.setDisabled(!(isNewEnabled() || isSaveEnable()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Copy/Duplicate button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableCopy(boolean enabled)
|
||||
{
|
||||
this.btnCopy.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Attachment button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableAttachment(boolean enabled)
|
||||
{
|
||||
this.btnAttachment.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Chat button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableChat(boolean enabled)
|
||||
{
|
||||
this.btnChat.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Print button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enablePrint(boolean enabled)
|
||||
{
|
||||
this.btnPrint.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Report button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableReport(boolean enabled)
|
||||
{
|
||||
this.btnReport.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Find/Query button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableFind(boolean enabled)
|
||||
{
|
||||
this.btnFind.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Toggle button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableGridToggle(boolean enabled)
|
||||
{
|
||||
btnGridToggle.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Customize Grid button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableCustomize(boolean enabled)
|
||||
{
|
||||
btnCustomize.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Archive button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableArchive(boolean enabled)
|
||||
{
|
||||
btnArchive.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Zoom Across button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableZoomAcross(boolean enabled)
|
||||
{
|
||||
btnZoomAcross.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Active Workflows button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableActiveWorkflows(boolean enabled)
|
||||
{
|
||||
btnActiveWorkflows.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Requests button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableRequests(boolean enabled)
|
||||
{
|
||||
btnRequests.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Quick Form button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableQuickForm(boolean enabled)
|
||||
{
|
||||
btnQuickForm.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on/off Lock button (Pressed=On, Not Pressed=Off)
|
||||
* @param enabled
|
||||
*/
|
||||
public void lock(boolean locked)
|
||||
{
|
||||
setPressed("Lock", locked);
|
||||
|
@ -735,13 +890,17 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Post It Note button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enablePostIt(boolean enabled)
|
||||
{
|
||||
this.btnPostIt.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the label button
|
||||
* Enable/disable Label record button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableLabel(boolean enabled)
|
||||
|
@ -749,11 +908,18 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
this.btnLabel.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ON_Click event that's being handle
|
||||
*/
|
||||
public Event getEvent()
|
||||
{
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle shortcut key event
|
||||
* @param keyEvent
|
||||
*/
|
||||
private void onCtrlKeyEvent(KeyEvent keyEvent) {
|
||||
if (windowContent != null && windowContent.isBlock())
|
||||
return;
|
||||
|
@ -810,6 +976,11 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
fireButtonClickEvent(keyEvent, btn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire ON_Click event for button, trigger by shortcut key event.
|
||||
* @param keyEvent source shortcut key event
|
||||
* @param btn
|
||||
*/
|
||||
private void fireButtonClickEvent(KeyEvent keyEvent, ToolBarButton btn)
|
||||
{
|
||||
if (btn != null) {
|
||||
|
@ -823,7 +994,7 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Make all toolbar buttons visible
|
||||
* @param visible
|
||||
*/
|
||||
public void setVisibleAll(boolean visible)
|
||||
|
@ -835,7 +1006,6 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param buttonName
|
||||
* @param visible
|
||||
*/
|
||||
|
@ -849,7 +1019,6 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param windowNo
|
||||
*/
|
||||
public void setWindowNo(int windowNo) {
|
||||
|
@ -857,7 +1026,7 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Enable/disable export button
|
||||
* Enable/disable Export button
|
||||
* @param b
|
||||
*/
|
||||
public void enableExport(boolean b) {
|
||||
|
@ -866,7 +1035,7 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Enable/disable file import button
|
||||
* Enable/disable File Import button
|
||||
* @param b
|
||||
*/
|
||||
public void enableFileImport(boolean b) {
|
||||
|
@ -875,7 +1044,7 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Enable/disable CSV import button
|
||||
* Enable/disable CSV Import button
|
||||
* @param b
|
||||
*/
|
||||
public void enableCSVImport(boolean b) {
|
||||
|
@ -885,6 +1054,10 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
|
||||
private boolean ToolBarMenuRestictionLoaded = false;
|
||||
|
||||
/**
|
||||
* @param buttonName
|
||||
* @return true if current login user has access to buttonName
|
||||
*/
|
||||
private boolean hasAccess(String buttonName) {
|
||||
ADWindow adwindow = ADWindow.get(windowNo);
|
||||
if (restrictionList == null)
|
||||
|
@ -904,6 +1077,9 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the accessibility state of toolbar buttons
|
||||
*/
|
||||
public void updateToolbarAccess() {
|
||||
if (ToolBarMenuRestictionLoaded)
|
||||
return;
|
||||
|
@ -921,19 +1097,31 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
ToolBarMenuRestictionLoaded = true;
|
||||
}
|
||||
|
||||
/** btnActiveWorkflow should be disabled when table has not workflow defined */
|
||||
boolean hasWorkflow(GridTab gridTab)
|
||||
/**
|
||||
* btnActiveWorkflow should be disabled when table has no workflow defined
|
||||
* @param gridTab
|
||||
* @return true if has workflow define for gridTab
|
||||
*/
|
||||
protected boolean hasWorkflow(GridTab gridTab)
|
||||
{
|
||||
String sql = "SELECT COUNT(*) FROM AD_Workflow WHERE IsActive='Y' AND AD_Table_ID=? AND AD_Client_ID IN (0,?)";
|
||||
return (DB.getSQLValueEx(null, sql, gridTab.getAD_Table_ID(), Env.getAD_Client_ID(Env.getCtx())) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Process button
|
||||
* @param enabled
|
||||
*/
|
||||
public void enableProcessButton(boolean b) {
|
||||
if (btnProcess != null) {
|
||||
btnProcess.setDisabled(!b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic update of each toolbar button state (Check restrictions).
|
||||
* For custom button, call {@link ToolbarCustomButton#dynamicDisplay()}, process pressedLogic and readOnlyLogic.
|
||||
*/
|
||||
public void dynamicDisplay() {
|
||||
List<Toolbarbutton> customButtons = new ArrayList<Toolbarbutton>();
|
||||
for(ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons) {
|
||||
|
@ -995,6 +1183,9 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
readOnlyLogic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link ToolbarCustomButton#pressedLogic()}
|
||||
*/
|
||||
private void pressedLogic()
|
||||
{
|
||||
for (ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons)
|
||||
|
@ -1003,6 +1194,9 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link ToolbarCustomButton#readOnlyLogic()}
|
||||
*/
|
||||
private void readOnlyLogic()
|
||||
{
|
||||
for (ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons)
|
||||
|
@ -1027,6 +1221,9 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init for mobile client only.
|
||||
*/
|
||||
private void mobileInit() {
|
||||
LayoutUtils.addSclass("mobile", this);
|
||||
addEventListener("onOverflowButton", evt -> onOverflowButton(evt));
|
||||
|
@ -1064,6 +1261,9 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
addCallback(AFTER_PAGE_ATTACHED, t -> afterPageAttached());
|
||||
}
|
||||
|
||||
/**
|
||||
* Mobile specific handling for AFTER_PAGE_ATTACHED callback.
|
||||
*/
|
||||
private void afterPageAttached() {
|
||||
Component p = getParent();
|
||||
while (p != null) {
|
||||
|
@ -1075,12 +1275,16 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mobile specific event handling for ON_AFTER_SIZE event.
|
||||
* @param evt
|
||||
*/
|
||||
private void onAfterSize(AfterSizeEvent evt) {
|
||||
int width = evt.getWidth();
|
||||
if (width != prevWidth) {
|
||||
prevWidth = width;
|
||||
if (overflowButton != null)
|
||||
overflowButton.detach();
|
||||
if (mobileOverflowButton != null)
|
||||
mobileOverflowButton.detach();
|
||||
if (overflowPopup != null)
|
||||
overflowPopup.detach();
|
||||
if (overflows != null) {
|
||||
|
@ -1093,6 +1297,10 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle onOverflowButton event from mobile client.
|
||||
* @param evt
|
||||
*/
|
||||
private void onOverflowButton(Event evt) {
|
||||
overflows = new ArrayList<>();
|
||||
String uuid = (String) evt.getData();
|
||||
|
@ -1113,11 +1321,15 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
for (ToolBarButton toolbarButton : mobileShowMoreButtons)
|
||||
overflows.add(toolbarButton);
|
||||
if (overflows.size() > 0) {
|
||||
createOverflowButton();
|
||||
createOverflowButtonForMobile();
|
||||
populateOverflowPopup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate overflow popup.
|
||||
* Use for both desktop and mobile client.
|
||||
*/
|
||||
private void populateOverflowPopup() {
|
||||
boolean vertical = !ClientInfo.isMobile() && MSysConfig.getBooleanValue(MSysConfig.ZK_TOOLBAR_SHOW_MORE_VERTICAL, true, Env.getAD_Client_ID(Env.getCtx()));
|
||||
if (vertical) {
|
||||
|
@ -1164,6 +1376,10 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable show more feature for desktop client.
|
||||
* Overflow for mobile client is initialise differently in {@link #mobileInit()}.
|
||||
*/
|
||||
private void enableShowMore() {
|
||||
this.appendChild(btnShowMore);
|
||||
btnShowMore.setDisabled(false);
|
||||
|
@ -1173,8 +1389,12 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
populateOverflowPopup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show overflow popup after {@link #btnShowMore}.
|
||||
* For desktop client only.
|
||||
*/
|
||||
private void onShowMore() {
|
||||
Long ts = (Long) overflowPopup.removeAttribute("popup.close");
|
||||
Long ts = (Long) overflowPopup.removeAttribute(POPUP_CLOSE_TIMESTAMP_ATTR);
|
||||
if (ts != null) {
|
||||
if (System.currentTimeMillis() - ts.longValue() < 500) {
|
||||
return;
|
||||
|
@ -1183,30 +1403,37 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
overflowPopup.open(btnShowMore, "after_end");
|
||||
}
|
||||
|
||||
private void createOverflowButton() {
|
||||
overflowButton = new A();
|
||||
overflowButton.setTooltiptext(Msg.getMsg(Env.getCtx(), "ShowMore"));
|
||||
overflowButton.setIconSclass("z-icon-ShowMore");
|
||||
overflowButton.setSclass("font-icon-toolbar-button toolbar-button mobile-overflow-link");
|
||||
appendChild(overflowButton);
|
||||
/**
|
||||
* Create show more button for mobile client
|
||||
*/
|
||||
private void createOverflowButtonForMobile() {
|
||||
mobileOverflowButton = new A();
|
||||
mobileOverflowButton.setTooltiptext(Msg.getMsg(Env.getCtx(), "ShowMore"));
|
||||
mobileOverflowButton.setIconSclass("z-icon-ShowMore");
|
||||
mobileOverflowButton.setSclass("font-icon-toolbar-button toolbar-button mobile-overflow-link");
|
||||
appendChild(mobileOverflowButton);
|
||||
newOverflowPopup();
|
||||
appendChild(overflowPopup);
|
||||
overflowButton.addEventListener(Events.ON_CLICK, e -> {
|
||||
Long ts = (Long) overflowPopup.removeAttribute("popup.close");
|
||||
mobileOverflowButton.addEventListener(Events.ON_CLICK, e -> {
|
||||
Long ts = (Long) overflowPopup.removeAttribute(POPUP_CLOSE_TIMESTAMP_ATTR);
|
||||
if (ts != null) {
|
||||
if (System.currentTimeMillis() - ts.longValue() < 500) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
overflowPopup.open(overflowButton, "after_end");
|
||||
overflowPopup.open(mobileOverflowButton, "after_end");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create overflow popup.
|
||||
* For both desktop and mobile client.
|
||||
*/
|
||||
private void newOverflowPopup() {
|
||||
overflowPopup = new Popup();
|
||||
overflowPopup.addEventListener(Events.ON_OPEN, (OpenEvent oe) -> {
|
||||
if (!oe.isOpen()) {
|
||||
overflowPopup.setAttribute("popup.close", System.currentTimeMillis());
|
||||
overflowPopup.setAttribute(POPUP_CLOSE_TIMESTAMP_ATTR, System.currentTimeMillis());
|
||||
Component[] childrens = overflowPopup.getChildren().toArray(new Component[0]);
|
||||
for (Component child : childrens) {
|
||||
if (child instanceof Grid || child instanceof Toolbarbutton)
|
||||
|
@ -1217,6 +1444,10 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Post after size event handler for mobile client.
|
||||
* Calculate which toolbar buttons should overflow to show more popup.
|
||||
*/
|
||||
public void onPostAfterSize() {
|
||||
if (this.getPage() != null) {
|
||||
String script = "(function(){let w = zk.Widget.$('#" + getUuid() + "'); w.toolbarScrollable(w);";
|
||||
|
@ -1225,13 +1456,18 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set button to pressed/not pressed state
|
||||
* @param buttonName
|
||||
* @param pressed
|
||||
*/
|
||||
public void setPressed(String buttonName, boolean pressed) {
|
||||
if (getButton(buttonName) != null)
|
||||
getButton(buttonName).setPressed(pressed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @return parent tab level for quick form
|
||||
*/
|
||||
public int getQuickFormTabHrchyLevel()
|
||||
{
|
||||
|
@ -1246,6 +1482,11 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
this.quickFormTabHrchyLevel = quickFormHrchyTabLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload user queries and set selected item to AD_UserQuery_ID
|
||||
* @param AD_Tab_ID
|
||||
* @param AD_UserQuery_ID
|
||||
*/
|
||||
public void refreshUserQuery(int AD_Tab_ID, int AD_UserQuery_ID) {
|
||||
if (AEnv.getOrSetExecutionAttribute(getClass().getName()+".refreshUserQuery")) {
|
||||
return;
|
||||
|
@ -1269,6 +1510,10 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
fQueryName.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selected user query
|
||||
* @param AD_UserQuery_ID
|
||||
*/
|
||||
public void setSelectedUserQuery(int AD_UserQuery_ID) {
|
||||
for (MUserQuery userQuery : userQueries) {
|
||||
if (AD_UserQuery_ID == userQuery.getAD_UserQuery_ID()) {
|
||||
|
@ -1278,12 +1523,19 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selected user query
|
||||
* @param selectedUserQuery
|
||||
*/
|
||||
public void setSelectedUserQuery(MUserQuery selectedUserQuery) {
|
||||
this.selectedUserQuery = selectedUserQuery;
|
||||
if (selectedUserQuery != null)
|
||||
fQueryName.setValue(selectedUserQuery.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AD_UserQuery_ID of selected user query
|
||||
*/
|
||||
public int getAD_UserQuery_ID() {
|
||||
if (selectedUserQuery == null)
|
||||
return 0;
|
||||
|
@ -1291,8 +1543,8 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Init Default Query in Window Toolbar
|
||||
* @return true if initialized
|
||||
* Set selected user query to first default user query (if any)
|
||||
* @return true if there's a default user query
|
||||
*/
|
||||
public boolean initDefaultQuery() {
|
||||
if(userQueries != null) {
|
||||
|
|
|
@ -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.
|
||||
* @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
|
||||
|
@ -46,16 +46,21 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
/** List of dependent Variables */
|
||||
private ArrayList<String> m_dependents = new ArrayList<String>();
|
||||
|
||||
/** Tabs associated to this tab box */
|
||||
/** AD tab panels associated to this tab box */
|
||||
protected List<IADTabpanel> tabPanelList = new ArrayList<IADTabpanel>();
|
||||
/** Parent part, the content part of AD Window **/
|
||||
protected AbstractADWindowContent adWindowPanel;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public AbstractADTabbox()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Tab
|
||||
* Add new tab(AD_Tab).
|
||||
* Delegate to {@link #doAddTab(GridTab, IADTabpanel)}
|
||||
* @param gTab grid tab model
|
||||
* @param tabPanel
|
||||
*/
|
||||
|
@ -76,7 +81,8 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
}// addTab
|
||||
|
||||
/**
|
||||
* handle add tab to tabbox
|
||||
* Handle add new tab to UI.
|
||||
* Override to implement add new tab to UI.
|
||||
* @param tab
|
||||
* @param tabPanel
|
||||
*/
|
||||
|
@ -84,19 +90,24 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
|
||||
/**
|
||||
* @param index of tab panel
|
||||
* @return true if enable
|
||||
* @return true if enable, false otherwise
|
||||
*/
|
||||
public boolean isEnabledAt(int index)
|
||||
{
|
||||
return true;
|
||||
}// isEnabledAt
|
||||
|
||||
private boolean isDisplay(IADTabpanel newTab)
|
||||
/**
|
||||
* Evaluate display logic
|
||||
* @param tabPanel
|
||||
* @return true if visible, false otherwise
|
||||
*/
|
||||
private boolean isDisplay(IADTabpanel tabPanel)
|
||||
{
|
||||
String logic = newTab.getDisplayLogic();
|
||||
String logic = tabPanel.getDisplayLogic();
|
||||
if (logic != null && logic.length() > 0)
|
||||
{
|
||||
boolean display = Evaluator.evaluateLogic(newTab, logic);
|
||||
boolean display = Evaluator.evaluateLogic(tabPanel, logic);
|
||||
if (!display)
|
||||
{
|
||||
log.info("Not displayed - " + logic);
|
||||
|
@ -107,11 +118,13 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
}
|
||||
|
||||
/**
|
||||
* Updated selected tab index
|
||||
* Change selected tab index from oldIndex to newIndex.
|
||||
* Delegate to {@link #doTabSelectionChanged(int, int)}.
|
||||
* @param oldIndex
|
||||
* @param newIndex
|
||||
* @return true if successfully switch to newIndex
|
||||
*/
|
||||
@Override
|
||||
public boolean updateSelectedIndex(int oldIndex, int newIndex)
|
||||
{
|
||||
IADTabpanel newTab = tabPanelList.get(newIndex);
|
||||
|
@ -136,6 +149,11 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
return canJump;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare environment context for newTab.
|
||||
* @param newIndex
|
||||
* @param newTab
|
||||
*/
|
||||
private void prepareContext(int newIndex, IADTabpanel newTab) {
|
||||
//update context
|
||||
if (newTab != null)
|
||||
|
@ -192,15 +210,17 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
}
|
||||
|
||||
/**
|
||||
* handle tab selection changed event
|
||||
* Handle tab selection change event.
|
||||
* Override to update UI for tab selection change.
|
||||
* @param oldIndex
|
||||
* @param newIndex
|
||||
*/
|
||||
protected abstract void doTabSelectionChanged(int oldIndex, int newIndex);
|
||||
|
||||
/**
|
||||
* @param index tab index
|
||||
* @return true if tab is visible
|
||||
* Evaluate display logic
|
||||
* @param index
|
||||
* @return true if visible, false otherwise
|
||||
*/
|
||||
public boolean isDisplay(int index) {
|
||||
if (index >= tabPanelList.size())
|
||||
|
@ -218,21 +238,23 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
}
|
||||
|
||||
/**
|
||||
* Delegate to {@link #canNavigateTo(int, int, boolean)}
|
||||
* @param fromIndex
|
||||
* @param toIndex
|
||||
* @return true if can navigate to toIndex
|
||||
* @return true if can change selected tab from fromIndex to toIndex
|
||||
*/
|
||||
@Override
|
||||
public boolean canNavigateTo(int fromIndex, int toIndex) {
|
||||
return canNavigateTo(fromIndex, toIndex, false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param fromIndex
|
||||
* @param toIndex
|
||||
* @param checkRecordID true to validate record id of fromIndex tab
|
||||
* @return true if can navigate to toIndex tab
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* @param fromIndex
|
||||
* @param toIndex
|
||||
* @param checkRecordID true to validate fromIndex has a valid record id
|
||||
* @return true if can change selected tab from fromIndex to toIndex
|
||||
*/
|
||||
public boolean canNavigateTo(int fromIndex, int toIndex, boolean checkRecordID) {
|
||||
IADTabpanel newTab = tabPanelList.get(toIndex);
|
||||
if (newTab instanceof ADTabpanel)
|
||||
|
@ -281,7 +303,7 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get break crumb path
|
||||
* @return full path
|
||||
*/
|
||||
public String getPath() {
|
||||
|
@ -310,7 +332,8 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
}
|
||||
|
||||
/**
|
||||
* Evaluate Tab Logic
|
||||
* Handle DataStatusEvent.
|
||||
* Delegate to {@link #updateTabState()}.
|
||||
* @param e event
|
||||
*/
|
||||
public void evaluate (DataStatusEvent e)
|
||||
|
@ -335,7 +358,7 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
} // evaluate
|
||||
|
||||
/**
|
||||
* Update display state of tab (visibility, activation and if need invalidate)
|
||||
* Update UI state of tab (visibility, activation and if need invalidate)
|
||||
*/
|
||||
protected abstract void updateTabState();
|
||||
|
||||
|
@ -366,8 +389,10 @@ public abstract class AbstractADTabbox extends AbstractUIPart implements IADTabb
|
|||
|
||||
/**
|
||||
* Set newIndex as selected tab
|
||||
* Delegate to {@link #updateSelectedIndex(int, int)}
|
||||
* @param newIndex
|
||||
*/
|
||||
@Override
|
||||
public void setSelectedIndex(int newIndex) {
|
||||
int oldIndex = getSelectedIndex();
|
||||
updateSelectedIndex(oldIndex, newIndex);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -52,13 +52,20 @@ import org.zkoss.zul.Menuitem;
|
|||
import org.zkoss.zul.Window;
|
||||
|
||||
/**
|
||||
* Bread crumb component for AD Window
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class BreadCrumb extends Div implements EventListener<Event> {
|
||||
|
||||
/**
|
||||
* Event echo after ON_MOUSE_OVER event.
|
||||
*/
|
||||
private static final String ON_MOUSE_OVER_ECHO_EVENT = "onMouseOverEcho";
|
||||
|
||||
/**
|
||||
* This is echo after some delay after ON_MOUSE_OUT event (to close linkPopup).
|
||||
* Also use as attribute to allow a rapid ON_MOUSE_OVER event to cancel the delay ON_MOUSE_OUT_ECHO_EVENT, thus keeping linkPopup open.
|
||||
**/
|
||||
private static final String ON_MOUSE_OUT_ECHO_EVENT = "onMouseOutEcho";
|
||||
|
||||
/**
|
||||
|
@ -68,29 +75,39 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
|
||||
private static final String BTNPREFIX = "Btn";
|
||||
|
||||
/** west layout for paths to a tab (for e.g "Business Partner > Location") **/
|
||||
private Hlayout layout;
|
||||
|
||||
/** record navigation buttons **/
|
||||
private ToolBarButton btnFirst, btnPrevious, btnNext, btnLast, btnRecordInfo;
|
||||
|
||||
/** Label:TabIndex. Link to other tabs at same level (i.e other child tabs of the same parent tab). **/
|
||||
private LinkedHashMap<String, String> links;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private int windowNo;
|
||||
|
||||
/** BtnName:ToolBarButton. Map of all toolbar buttons. **/
|
||||
private HashMap<String, ToolBarButton> buttons = new HashMap<String, ToolBarButton>();
|
||||
|
||||
/** Last DataStatusEvent from {@link AbstractADWindowContent#dataStatusChanged(DataStatusEvent)} **/
|
||||
private DataStatusEvent m_dse;
|
||||
|
||||
/** Last data status text from {@link AbstractADWindowContent#dataStatusChanged(DataStatusEvent)} **/
|
||||
private String m_text;
|
||||
|
||||
/** register ToolbarListener **/
|
||||
private ToolbarListener toolbarListener;
|
||||
|
||||
/** east layout for record navigation buttons **/
|
||||
private Hlayout toolbarContainer;
|
||||
|
||||
/** popup for link to other tabs at same level **/
|
||||
protected Menupopup linkPopup;
|
||||
|
||||
private GridTab m_gridTab;
|
||||
|
||||
/** AD Window content part that own this bread crumb **/
|
||||
private AbstractADWindowContent windowContent;
|
||||
|
||||
/**
|
||||
|
@ -140,7 +157,6 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
public void setToolbarListener(ToolbarListener listener) {
|
||||
|
@ -148,10 +164,10 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param label
|
||||
* @param id
|
||||
* @param clickable
|
||||
* Add path to tab
|
||||
* @param label path label
|
||||
* @param id path id
|
||||
* @param clickable true to add clickable {@link BreadCrumbLink} false to add text label
|
||||
*/
|
||||
public void addPath(String label, String id, boolean clickable) {
|
||||
if (clickable) {
|
||||
|
@ -181,7 +197,7 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get parent BreadCrumbLinks
|
||||
* @return list of parent links
|
||||
*/
|
||||
public List<BreadCrumbLink> getParentLinks() {
|
||||
|
@ -195,7 +211,7 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
|
||||
/**
|
||||
* add links to other tabs at the same level
|
||||
* @param links
|
||||
* @param links Label:TabIndex map
|
||||
*/
|
||||
public void addLinks(LinkedHashMap<String, String> links) {
|
||||
this.links = links;
|
||||
|
@ -368,7 +384,7 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
}
|
||||
|
||||
/**
|
||||
* remove all links
|
||||
* remove all path and links
|
||||
*/
|
||||
public void reset() {
|
||||
layout.getChildren().clear();
|
||||
|
@ -395,6 +411,13 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
this.btnNext.setDisabled(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create toolbar button.
|
||||
* @param name
|
||||
* @param image
|
||||
* @param tooltip
|
||||
* @return {@link ToolBarButton}
|
||||
*/
|
||||
private ToolBarButton createButton(String name, String image, String tooltip)
|
||||
{
|
||||
ToolBarButton btn = new ToolBarButton("");
|
||||
|
@ -425,6 +448,7 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set record info text
|
||||
* @param text
|
||||
*/
|
||||
public void setStatusDB (String text)
|
||||
|
@ -433,7 +457,8 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param text
|
||||
* Data status from {@link AbstractADWindowContent#dataStatusChanged(DataStatusEvent)}
|
||||
* @param text record info text (for e.g 1/1)
|
||||
* @param dse
|
||||
* @param gridTab
|
||||
*/
|
||||
|
@ -471,7 +496,7 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Set visibility of record navigation toolbar
|
||||
* @param visible
|
||||
*/
|
||||
public void setNavigationToolbarVisibility(boolean visible) {
|
||||
|
@ -498,22 +523,37 @@ public class BreadCrumb extends Div implements EventListener<Event> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if previous button is enable
|
||||
*/
|
||||
public boolean isPreviousEnabled() {
|
||||
return !btnPrevious.isDisabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if next button is enable
|
||||
*/
|
||||
public boolean isNextEnabled() {
|
||||
return !btnNext.isDisabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return next ToolBarButton
|
||||
*/
|
||||
public ToolBarButton getNextButton() {
|
||||
return btnNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return previous ToolBarButton
|
||||
*/
|
||||
public ToolBarButton getPreviousButton() {
|
||||
return btnPrevious;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if path/link is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return layout == null || layout.getChildren().isEmpty();
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ package org.adempiere.webui.adwindow;
|
|||
import org.zkoss.zul.A;
|
||||
|
||||
/**
|
||||
* Link component for {@link BreadCrumb}
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class BreadCrumbLink extends A {
|
||||
|
||||
|
@ -26,12 +26,19 @@ public class BreadCrumbLink extends A {
|
|||
*/
|
||||
private static final long serialVersionUID = 170361731431877695L;
|
||||
|
||||
/** id for path (tab index) **/
|
||||
private String pathId;
|
||||
|
||||
/**
|
||||
* @return path id
|
||||
*/
|
||||
public String getPathId() {
|
||||
return pathId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pathId
|
||||
*/
|
||||
public void setPathId(String pathId) {
|
||||
this.pathId = pathId;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,10 @@ import org.zkoss.zul.RowRenderer;
|
|||
import org.zkoss.zul.Vlayout;
|
||||
|
||||
/**
|
||||
*
|
||||
* Header and detail UI for AD_Tabs.
|
||||
* This class manage a list of tabs with the current selected tab as the attached and visible {@link ADTabpanel} instance.
|
||||
* Child tabs of selected tab is shown in {@link DetailPane} inside {@link ADTabpanel}.
|
||||
*
|
||||
* @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
|
||||
|
@ -63,27 +66,45 @@ import org.zkoss.zul.Vlayout;
|
|||
*/
|
||||
public class CompositeADTabbox extends AbstractADTabbox
|
||||
{
|
||||
/**
|
||||
* DetailPane attribute to hold list of child tabs.
|
||||
* List of Object[] of tabIndex, tabPanel, tabLabel, enable.
|
||||
*/
|
||||
private static final String DETAILPANE_TABLIST_ATTR = "detailpane.tablist";
|
||||
|
||||
/** Execution attribute to hold reference to detail ADTabpanel that's handling onEditDetail event **/
|
||||
public static final String AD_TABBOX_ON_EDIT_DETAIL_ATTRIBUTE = "ADTabbox.onEditDetail";
|
||||
|
||||
/** after tab selection change event **/
|
||||
private static final String ON_POST_TAB_SELECTION_CHANGED_EVENT = "onPostTabSelectionChanged";
|
||||
|
||||
/** event echo from ON_POST_TAB_SELECTION_CHANGED_EVENT handler **/
|
||||
private static final String ON_TAB_SELECTION_CHANGED_ECHO_EVENT = "onTabSelectionChangedEcho";
|
||||
|
||||
/** tab selection change event **/
|
||||
public static final String ON_SELECTION_CHANGED_EVENT = "onSelectionChanged";
|
||||
|
||||
|
||||
/** List of all tab **/
|
||||
private List<ADTabListModel.ADTabLabel> tabLabelList = new ArrayList<ADTabListModel.ADTabLabel>();
|
||||
|
||||
/** List of all tab panel **/
|
||||
private List<IADTabpanel> tabPanelList = new ArrayList<IADTabpanel>();
|
||||
|
||||
/** main layout component **/
|
||||
private Vlayout layout;
|
||||
|
||||
/** tab selection change listener **/
|
||||
private EventListener<Event> selectionListener;
|
||||
|
||||
/** {@link IADTabpanel} instance for selected tab **/
|
||||
private IADTabpanel headerTab;
|
||||
|
||||
/** Index of selected tab **/
|
||||
private int selectedIndex = 0;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public CompositeADTabbox(){
|
||||
}
|
||||
|
||||
|
@ -221,6 +242,9 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete current row of selected detail tab
|
||||
*/
|
||||
private void onDelete() {
|
||||
if (headerTab.getGridTab().isNew()) return;
|
||||
|
||||
|
@ -245,6 +269,10 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete selected rows of selected detail tab
|
||||
* @param tabPanel
|
||||
*/
|
||||
private void onDeleteSelected(final IADTabpanel tabPanel) {
|
||||
if (tabPanel == null || tabPanel.getGridTab() == null) return;
|
||||
|
||||
|
@ -283,6 +311,10 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
return detailPane;
|
||||
}
|
||||
|
||||
/**
|
||||
* defer execution of adTabPanel.focus()
|
||||
* @param adTabPanel
|
||||
*/
|
||||
private void focusToTabpanel(IADTabpanel adTabPanel ) {
|
||||
if (adTabPanel != null && adTabPanel instanceof HtmlBasedComponent) {
|
||||
final HtmlBasedComponent comp = (HtmlBasedComponent) adTabPanel;
|
||||
|
@ -291,7 +323,8 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
}
|
||||
|
||||
/**
|
||||
* Edit selected detail tab
|
||||
* Edit current row of selected detail tab.
|
||||
* Make selected detail tab the new header tab.
|
||||
* @param row
|
||||
* @param formView
|
||||
*/
|
||||
|
@ -328,6 +361,10 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create layout and setup listeners for bread crumb.
|
||||
* Vertical layout with {@link ADTabpanel} as the only child component.
|
||||
*/
|
||||
@Override
|
||||
protected Component doCreatePart(Component parent)
|
||||
{
|
||||
|
@ -359,8 +396,9 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
breadCrumb.addEventListener(Events.ON_CLICK, new EventListener<Event>() {
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
//send tab selection change event
|
||||
int oldIndex = selectedIndex;
|
||||
if (event.getTarget() instanceof BreadCrumbLink) {
|
||||
if (event.getTarget() instanceof BreadCrumbLink) {
|
||||
BreadCrumbLink link = (BreadCrumbLink) event.getTarget();
|
||||
int newIndex = Integer.parseInt(link.getPathId());
|
||||
|
||||
|
@ -381,8 +419,8 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
|
||||
@Override
|
||||
protected void doAddTab(GridTab gTab, IADTabpanel tabPanel) {
|
||||
ADTabListModel.ADTabLabel tabLabel = new ADTabListModel.ADTabLabel(gTab.getName(), gTab.getTabLevel(),gTab.getDescription(),
|
||||
gTab.getWindowNo(),gTab.getAD_Tab_ID());
|
||||
ADTabListModel.ADTabLabel tabLabel = new ADTabListModel.ADTabLabel(gTab.getName(), gTab.getTabLevel(), gTab.getDescription(),
|
||||
gTab.getWindowNo(), gTab.getAD_Tab_ID());
|
||||
tabLabelList.add(tabLabel);
|
||||
tabPanelList.add(tabPanel);
|
||||
|
||||
|
@ -480,6 +518,7 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
});
|
||||
}
|
||||
|
||||
//add to header or detail pane
|
||||
if (layout.getChildren().isEmpty()) {
|
||||
layout.appendChild(tabPanel);
|
||||
headerTab = tabPanel;
|
||||
|
@ -516,6 +555,9 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link ADTabpanel#activateDetailIfVisible()}
|
||||
*/
|
||||
private void activateDetailIfVisible() {
|
||||
if (headerTab instanceof ADTabpanel) {
|
||||
((ADTabpanel)headerTab).activateDetailIfVisible();
|
||||
|
@ -595,7 +637,7 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
|
||||
//set state
|
||||
headerTab.setDetailPaneMode(false);
|
||||
//show empty path, update later with actual path in onTabSelectionChangedEcho
|
||||
//show empty path, update later with actual path in onPostTabSelectionChanged
|
||||
getBreadCrumb().getFirstChild().getChildren().clear();
|
||||
getBreadCrumb().getFirstChild().appendChild(new Label(""));
|
||||
|
||||
|
@ -603,11 +645,13 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
}
|
||||
|
||||
/**
|
||||
* first after tab selection change event, follow by onTabSelectionChangedEcho event
|
||||
* Handle after tab selection change event, echo onTabSelectionChangedEcho event.
|
||||
* @param back
|
||||
*/
|
||||
private void onPostTabSelectionChanged(Boolean back) {
|
||||
if (headerTab instanceof ADTabpanel && !headerTab.getGridTab().isSortTab()) {
|
||||
if (headerTab instanceof ADTabpanel && !headerTab.getGridTab().isSortTab()) {
|
||||
//gather all child tabs (both immediate and not immediate)
|
||||
//Object[]: tabIndex, tabPanel, tabLabel, enable
|
||||
List<Object[]> list = new ArrayList<Object[]>();
|
||||
int tabIndex = -1;
|
||||
int currentLevel = headerTab.getTabLevel();
|
||||
|
@ -633,7 +677,7 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
if (detailPane == null) {
|
||||
detailPane = createDetailPane();
|
||||
}
|
||||
detailPane.setAttribute("detailpane.tablist", list);
|
||||
detailPane.setAttribute(DETAILPANE_TABLIST_ATTR, list);
|
||||
|
||||
ZKUpdateUtil.setVflex(detailPane, "true");
|
||||
if (headerTab.getDetailPane() == null) {
|
||||
|
@ -658,7 +702,8 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
//setup tabs of detail pane
|
||||
if (detailPane != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object[]> list = (List<Object[]>) detailPane.removeAttribute("detailpane.tablist");
|
||||
//tabIndex, tabPanel, tabLabel, enable
|
||||
List<Object[]> list = (List<Object[]>) detailPane.removeAttribute(DETAILPANE_TABLIST_ATTR);
|
||||
if (list != null && !list.isEmpty()) {
|
||||
int currentLevel = headerTab.getTabLevel();
|
||||
for (Object[] value : list) {
|
||||
|
@ -747,6 +792,7 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
private void updateBreadCrumb() {
|
||||
BreadCrumb breadCrumb = getBreadCrumb();
|
||||
breadCrumb.reset();
|
||||
//add parent path
|
||||
if (selectedIndex > 0) {
|
||||
List<ADTabLabel> parents = new ArrayList<ADTabListModel.ADTabLabel>();
|
||||
List<Integer> parentIndex = new ArrayList<Integer>();
|
||||
|
@ -771,6 +817,8 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
if (!breadCrumb.isVisible())
|
||||
breadCrumb.setVisible(true);
|
||||
|
||||
//Links for other child tabs at same level
|
||||
//Tab Index:Tab Label
|
||||
LinkedHashMap<String, String> links = new LinkedHashMap<String, String>();
|
||||
int parentIndex = 0;
|
||||
if (headerTab.getTabLevel() > 1) {
|
||||
|
@ -823,6 +871,9 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link BreadCrumb}
|
||||
*/
|
||||
private BreadCrumb getBreadCrumb() {
|
||||
ADWindowContent window = (ADWindowContent) adWindowPanel;
|
||||
BreadCrumb breadCrumb = window.getBreadCrumb();
|
||||
|
@ -844,6 +895,9 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify selected detail tab after data status change of header tab
|
||||
*/
|
||||
class SyncDataStatusListener implements DataStatusListener {
|
||||
|
||||
private IADTabpanel tabPanel;
|
||||
|
@ -867,7 +921,7 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
|
||||
IADTabpanel detailTab = getSelectedDetailADTabpanel();
|
||||
if (detailTab != null) {
|
||||
//check data action
|
||||
//check is data action from detail tab
|
||||
String uuid = (String) execution.getAttribute(CompositeADTabbox.class.getName()+".dataAction");
|
||||
if (uuid != null && uuid.equals(detailTab.getUuid()) && detailTab.getGridTab().isCurrent()) {
|
||||
//refresh current row
|
||||
|
@ -909,7 +963,6 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if selected detail tab have been activated
|
||||
*/
|
||||
public boolean isDetailActivated() {
|
||||
|
@ -1074,6 +1127,10 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* force invalidate of tabPanel
|
||||
* @param tabPanel
|
||||
*/
|
||||
private void invalidateTabPanel(IADTabpanel tabPanel) {
|
||||
Center center = findCenter(tabPanel.getGridView());
|
||||
if (center != null)
|
||||
|
@ -1082,6 +1139,11 @@ public class CompositeADTabbox extends AbstractADTabbox
|
|||
tabPanel.invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find {@link Center} that own gridView
|
||||
* @param gridView
|
||||
* @return {@link Center}
|
||||
*/
|
||||
private Center findCenter(GridView gridView) {
|
||||
if (gridView == null)
|
||||
return null;
|
||||
|
|
|
@ -81,8 +81,10 @@ import org.zkoss.zul.Tabs;
|
|||
import org.zkoss.zul.Toolbar;
|
||||
|
||||
/**
|
||||
* Detail panel that display the child tabs of a parent {@link ADTabpanel} tab.
|
||||
* Implemented as a panel with {@link Tabbox}.
|
||||
*
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
||||
|
||||
|
@ -107,12 +109,16 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
|
||||
private static final String BTN_TOGGLE_ID = "BtnToggle";
|
||||
|
||||
/** Boolean execution attribute to indicate tabbox is handling ON_SELECT event **/
|
||||
private static final String TABBOX_ONSELECT_ATTRIBUTE = "detailpane.tabbox.onselect";
|
||||
|
||||
/** event after handling of ON_SElECT event of a detail tab */
|
||||
private static final String ON_POST_SELECT_TAB_EVENT = "onPostSelectTab";
|
||||
|
||||
/** Attribute use by {@link #messageContainers} to hold status text **/
|
||||
private static final String STATUS_TEXT_ATTRIBUTE = "status.text";
|
||||
|
||||
/** Attribute use by {@link #messageContainers} to hold error text **/
|
||||
private static final String STATUS_ERROR_ATTRIBUTE = "status.error";
|
||||
|
||||
private static final String CUSTOMIZE_IMAGE = "images/Customize16.png";
|
||||
|
@ -124,34 +130,57 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
private static final String QUICK_FORM_IMAGE = "images/QuickForm16.png";
|
||||
private static final String TOGGLE_IMAGE = "images/Multi16.png";
|
||||
|
||||
|
||||
/** Timestamp for previous key event **/
|
||||
private long prevKeyEventTime = 0;
|
||||
/**
|
||||
* Previous KeyEvent reference.
|
||||
* Use together with {@link #prevKeyEventTime} to detect double firing of key event by browser.
|
||||
*/
|
||||
private KeyEvent prevKeyEvent;
|
||||
|
||||
/** tabbox for AD_Tabs **/
|
||||
private Tabbox tabbox;
|
||||
|
||||
/** Registered event listener for DetailPane events **/
|
||||
private EventListener<Event> eventListener;
|
||||
|
||||
/** AD_Tab_ID:Hbox. Message (status, error) container for each tab. **/
|
||||
private Map<Integer, Hbox> messageContainers = new HashMap<Integer, Hbox>();
|
||||
|
||||
/** content for message popup **/
|
||||
private Div msgPopupCnt;
|
||||
|
||||
/** message popup window **/
|
||||
private Window msgPopup;
|
||||
|
||||
/** last selected tab index **/
|
||||
private int prevSelectedIndex = 0;
|
||||
|
||||
/**
|
||||
* On activate event for detail tab.
|
||||
* Use to activate detail tab or notify detail tab after header tab change.
|
||||
*/
|
||||
public static final String ON_ACTIVATE_DETAIL_EVENT = "onActivateDetail";
|
||||
|
||||
/** on delete event for selected tab **/
|
||||
public static final String ON_DELETE_EVENT = "onDelete";
|
||||
|
||||
/** on new event for selected tab **/
|
||||
public static final String ON_NEW_EVENT = "onNew";
|
||||
|
||||
/** event to edit current row of selected tab **/
|
||||
public static final String ON_EDIT_EVENT = "onEdit";
|
||||
|
||||
/** on save event for selected tab **/
|
||||
public static final String ON_SAVE_EVENT = "onSave";
|
||||
|
||||
/** on quick form event for selected tab **/
|
||||
public static final String ON_QUICK_FORM_EVENT = "onQuickForm";
|
||||
|
||||
/**
|
||||
* Record navigation event for selected tab.
|
||||
* Event data is the navigation action (previous, next, first and last).
|
||||
*/
|
||||
public static final String ON_RECORD_NAVIGATE_EVENT = "onRecordNavigate";
|
||||
|
||||
/**
|
||||
|
@ -224,7 +253,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* replace of add
|
||||
* Replace or add IADTabpanel to tabbox.
|
||||
* @param index
|
||||
* @param tabPanel
|
||||
* @param tabLabel
|
||||
|
@ -238,7 +267,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* replace or add
|
||||
* Replace or add IADTabpanel to tabbox.
|
||||
* @param index
|
||||
* @param tabPanel
|
||||
* @param tabLabel
|
||||
|
@ -253,7 +282,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add IADTabpanel to tabbox
|
||||
* @param tabPanel
|
||||
* @param tabLabel
|
||||
*/
|
||||
|
@ -262,7 +291,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add IADTabpanel to tabbox
|
||||
* @param tabPanel
|
||||
* @param tabLabel
|
||||
* @param enabled
|
||||
|
@ -284,6 +313,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
tab.addEventListener(Events.ON_CLICK, new EventListener<Event>() {
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
//click on tab title trigger edit of current row
|
||||
Tab tab = (Tab) event.getTarget();
|
||||
if (!tab.isSelected())
|
||||
return;
|
||||
|
@ -313,8 +343,9 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
Tabpanel tp = new Tabpanel();
|
||||
tabpanels.appendChild(tp);
|
||||
ToolBar toolbar = tp.getToolbar();
|
||||
|
||||
//setup toolbar
|
||||
ToolBar toolbar = tp.getToolbar();
|
||||
HashMap<String, ToolBarButton> buttons = new HashMap<String, ToolBarButton>();
|
||||
ToolBarButton button = new ToolBarButton();
|
||||
if (ThemeManager.isUseFontIconForImage())
|
||||
|
@ -444,6 +475,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
button.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Toggle")) + " Shift+Alt+T");
|
||||
buttons.put(BTN_TOGGLE_ID.substring(3, BTN_TOGGLE_ID.length()), button);
|
||||
|
||||
//Detail toolbar button configure at AD_ToolBarButton
|
||||
MToolBarButton[] officialButtons = MToolBarButton.getToolbarButtons("D", null);
|
||||
for (MToolBarButton toolbarButton : officialButtons) {
|
||||
if ( !toolbarButton.isActive() ) {
|
||||
|
@ -505,6 +537,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
}
|
||||
|
||||
//container for status and error text
|
||||
Hbox messageContainer = new Hbox();
|
||||
messageContainer.setPack("end");
|
||||
messageContainer.setAlign("center");
|
||||
|
@ -564,7 +597,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* open customize grid dialog
|
||||
* Open customize grid view dialog.
|
||||
* @param e
|
||||
*/
|
||||
protected void onCustomize(Event e) {
|
||||
|
@ -579,7 +612,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* open process dropdown
|
||||
* open process list popup
|
||||
* @param button
|
||||
*/
|
||||
protected void onProcess(Component button) {
|
||||
|
@ -594,7 +627,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Set event listener for DetailPane events
|
||||
* @param listener
|
||||
*/
|
||||
public void setEventListener(EventListener<Event> listener) {
|
||||
|
@ -616,7 +649,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
|
||||
/**
|
||||
* @param index
|
||||
* @return adtabpanel at index
|
||||
* @return IADTabpanel at index
|
||||
*/
|
||||
public IADTabpanel getADTabpanel(int index) {
|
||||
if (index < 0 || index >= tabbox.getTabpanels().getChildren().size())
|
||||
|
@ -631,8 +664,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return selected adtabpanel
|
||||
* @return selected IADTabpanel
|
||||
*/
|
||||
public IADTabpanel getSelectedADTabpanel() {
|
||||
org.zkoss.zul.Tabpanel selectedPanel = tabbox.getSelectedPanel();
|
||||
|
@ -646,15 +678,14 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return {@link Tabpanel}
|
||||
* @return selected {@link Tabpanel}
|
||||
*/
|
||||
public Tabpanel getSelectedPanel() {
|
||||
return (Tabpanel) tabbox.getSelectedPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Set status and error text for selected tab.
|
||||
* @param status
|
||||
* @param error
|
||||
*/
|
||||
|
@ -676,6 +707,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
messageContainer.getChildren().clear();
|
||||
//store in attribute for retrieval in ON_CLICK event
|
||||
messageContainer.setAttribute(STATUS_ERROR_ATTRIBUTE, error);
|
||||
messageContainer.setAttribute(STATUS_TEXT_ATTRIBUTE, status);
|
||||
messageContainer.setSclass(error ? "docstatus-error" : "docstatus-normal");
|
||||
|
@ -712,6 +744,11 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten status text to a more presentable length.
|
||||
* @param statusText
|
||||
* @return shorten status text
|
||||
*/
|
||||
private String buildLabelText(String statusText) {
|
||||
if (statusText == null)
|
||||
return "";
|
||||
|
@ -724,6 +761,11 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
return statusText.substring(0, 80);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten notification text to a more presentable length.
|
||||
* @param statusText
|
||||
* @return shorten notification text
|
||||
*/
|
||||
private String buildNotificationText(String statusText) {
|
||||
if (statusText == null)
|
||||
return "";
|
||||
|
@ -777,20 +819,31 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create popup content for message popup window
|
||||
* @param status
|
||||
*/
|
||||
protected void createPopupContent(String status) {
|
||||
Text t = new Text(status);
|
||||
msgPopupCnt.getChildren().clear();
|
||||
msgPopupCnt.appendChild(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notification popup using Clients.showNotification
|
||||
* @param error
|
||||
* @param msg
|
||||
*/
|
||||
private void showPopup(boolean error, String msg) {
|
||||
Clients.showNotification(buildNotificationText(msg), "error", findTabpanel(this), "at_pointer", 3500, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create message popup window
|
||||
*/
|
||||
private void createPopup() {
|
||||
msgPopupCnt = new Div();
|
||||
ZKUpdateUtil.setVflex(msgPopupCnt, "1");
|
||||
|
||||
|
||||
msgPopup = new Window();
|
||||
msgPopup.setVisible(false);
|
||||
|
@ -903,10 +956,13 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
}
|
||||
|
||||
// update from customized implementation
|
||||
//Not use by ADTabpanel, for custom IADTabpanel implementation.
|
||||
adtab.updateDetailToolbar(toolbar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update state of Process toolbar button.
|
||||
*/
|
||||
private void updateProcessToolbar() {
|
||||
int index = getSelectedIndex();
|
||||
if (index < 0 || index >= getTabcount()) return;
|
||||
|
@ -934,8 +990,9 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* Edit current record
|
||||
* @param formView
|
||||
* Edit current record of selected tab.
|
||||
* This event will make the selected tab becomes the new header tab, i.e become the selected tab of {@link CompositeADTabbox}.
|
||||
* @param formView true to force form view.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void onEdit(boolean formView) throws Exception {
|
||||
|
@ -944,7 +1001,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* fire the on activate detail event
|
||||
* Fire ON_ACTIVATE_DETAIL_EVENT for selected tab.
|
||||
*/
|
||||
public void fireActivateDetailEvent() {
|
||||
int index = tabbox.getSelectedIndex();
|
||||
|
@ -972,7 +1029,6 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param tabIndex
|
||||
* @return true if tab at tabIndex is visible
|
||||
*/
|
||||
|
@ -996,7 +1052,6 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param tabIndex
|
||||
* @param enabled
|
||||
*/
|
||||
|
@ -1009,7 +1064,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* disable toolbar
|
||||
* Disable all toolbar buttons
|
||||
*/
|
||||
public void disableToolbar() {
|
||||
int index = getSelectedIndex();
|
||||
|
@ -1025,6 +1080,11 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find first {@link Tabpanel} that own comp.
|
||||
* @param comp
|
||||
* @return {@link Component}
|
||||
*/
|
||||
private Component findTabpanel(Component comp) {
|
||||
Component parent = comp.getParent();
|
||||
while (parent != null) {
|
||||
|
@ -1037,7 +1097,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* add new record
|
||||
* add new row
|
||||
* @throws Exception
|
||||
*/
|
||||
public void onNew() throws Exception {
|
||||
|
@ -1052,6 +1112,11 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
private static final int VK_D = 0x44;
|
||||
private static final int VK_O = 0x4F;
|
||||
private static final int VK_Q = 0x51;
|
||||
|
||||
/**
|
||||
* Handle shortcut key event
|
||||
* @param keyEvent
|
||||
*/
|
||||
private void onCtrlKeyEvent(KeyEvent keyEvent) {
|
||||
ToolBarButton btn = null;
|
||||
if (keyEvent.isAltKey() && !keyEvent.isCtrlKey() && keyEvent.isShiftKey()) { // Shift+Alt key
|
||||
|
@ -1096,14 +1161,12 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* tabpanel for adtabpanel
|
||||
* @author hengsin
|
||||
*
|
||||
* Custom {@link org.adempiere.webui.component.Tabpanel} implementation for DetailPane.
|
||||
*/
|
||||
public static class Tabpanel extends org.adempiere.webui.component.Tabpanel {
|
||||
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 8248794614430375822L;
|
||||
|
||||
|
@ -1156,7 +1219,6 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if tab have been toggle to form view
|
||||
*/
|
||||
public boolean isToggleToFormView() {
|
||||
|
@ -1209,7 +1271,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
}
|
||||
|
||||
/**
|
||||
* set paging control container
|
||||
* Set paging control
|
||||
* @param pagingControl
|
||||
*/
|
||||
public void setPagingControl(Div pagingControl) {
|
||||
|
@ -1225,7 +1287,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
|
||||
/**
|
||||
*
|
||||
* @return paging control container
|
||||
* @return paging control
|
||||
*/
|
||||
public Div getPagingControl() {
|
||||
return pagingControl;
|
||||
|
@ -1243,7 +1305,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
|
||||
/**
|
||||
*
|
||||
* @return buttons from the detail toolbar
|
||||
* @return toolbar buttons from the detail toolbar
|
||||
*/
|
||||
private List<ToolBarButton> getToolbarButtons() {
|
||||
|
||||
|
@ -1257,6 +1319,9 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create overflow button (show more) for mobile client.
|
||||
*/
|
||||
private void createOverflowButton() {
|
||||
overflowButton = new A();
|
||||
overflowButton.setTooltiptext(Msg.getMsg(Env.getCtx(), "ShowMore"));
|
||||
|
@ -1276,6 +1341,9 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new overflow popup
|
||||
*/
|
||||
private void newOverflowPopup() {
|
||||
overflowPopup = new Popup();
|
||||
overflowPopup.setHflex("min");
|
||||
|
@ -1291,7 +1359,7 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
private static class RecordToolbar extends Hlayout {
|
||||
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 5024630043211194429L;
|
||||
private ToolBarButton btnFirst;
|
||||
|
@ -1301,6 +1369,9 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
private ToolBarButton btnLast;
|
||||
private GridTab gridTab;
|
||||
|
||||
/**
|
||||
* @param gridTab
|
||||
*/
|
||||
private RecordToolbar(GridTab gridTab) {
|
||||
this.gridTab = gridTab;
|
||||
btnFirst = createButton("First", "First", "First");
|
||||
|
@ -1350,6 +1421,13 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
this.setValign("middle");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create toolbar button
|
||||
* @param name
|
||||
* @param image
|
||||
* @param tooltip
|
||||
* @return {@link ToolBarButton}
|
||||
*/
|
||||
private ToolBarButton createButton(String name, String image, String tooltip)
|
||||
{
|
||||
ToolBarButton btn = new ToolBarButton("");
|
||||
|
@ -1372,6 +1450,9 @@ public class DetailPane extends Panel implements EventListener<Event>, IdSpace {
|
|||
return btn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic update state of toolbar buttons
|
||||
*/
|
||||
private void dynamicDisplay() {
|
||||
int rowCount = gridTab.getRowCount();
|
||||
int currentRow = gridTab.getCurrentRow()+1;
|
||||
|
|
|
@ -81,28 +81,53 @@ import org.zkoss.zul.impl.XulElement;
|
|||
*/
|
||||
public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt, RendererCtrl, EventListener<Event> {
|
||||
|
||||
/** Cell div component attribute to hold field column name value **/
|
||||
protected static final String COLUMN_NAME_ATTR = "columnName";
|
||||
|
||||
/** Cell div component attribute to hold reference to editor component use to create display text for field **/
|
||||
private static final String DISPLAY_COMPONENT_ATTR = "display.component";
|
||||
|
||||
/** Boolean execution attribute to indicate execution is handling the "Select" checkbox's ON_CHECK event **/
|
||||
private static final String GRID_VIEW_ON_SELECT_ROW_ATTR = "gridView.onSelectRow";
|
||||
|
||||
/** Editor component attribute to store row index (absolute) **/
|
||||
public static final String GRID_ROW_INDEX_ATTR = "grid.row.index";
|
||||
|
||||
//styles for grid cell
|
||||
private static final String CELL_DIV_STYLE = "height: 100%; cursor: pointer; ";
|
||||
private static final String CELL_DIV_STYLE_ALIGN_CENTER = CELL_DIV_STYLE + "text-align:center; ";
|
||||
private static final String CELL_DIV_STYLE_ALIGN_RIGHT = CELL_DIV_STYLE + "text-align:right; ";
|
||||
|
||||
/** default max length for display text for field **/
|
||||
private static final int MAX_TEXT_LENGTH_DEFAULT = 60;
|
||||
private GridTab gridTab;
|
||||
private int windowNo;
|
||||
/** Sync field editor changes to GridField **/
|
||||
private GridTabDataBinder dataBinder;
|
||||
/** field editors **/
|
||||
private Map<GridField, WEditor> editors = new LinkedHashMap<GridField, WEditor>();
|
||||
/** readonly field editors to get display text for field value **/
|
||||
private Map<GridField, WEditor> readOnlyEditors = new LinkedHashMap<GridField, WEditor>();
|
||||
private Paging paging;
|
||||
|
||||
/** internal listener for row event **/
|
||||
private RowListener rowListener;
|
||||
|
||||
/** Grid that own this renderer **/
|
||||
private Grid grid = null;
|
||||
/** GridView that uses this renderer **/
|
||||
private GridView gridPanel = null;
|
||||
/** current focus row **/
|
||||
private Row currentRow;
|
||||
/** values of current row. updated in {@link #render(Row, Object[], int)}. **/
|
||||
private Object[] currentValues;
|
||||
/** true if currrent row is in edit mode **/
|
||||
private boolean editing = false;
|
||||
/** index of current row **/
|
||||
private int currentRowIndex = -1;
|
||||
/** AD window content part that own this renderer **/
|
||||
private AbstractADWindowContent m_windowPanel;
|
||||
/** internal listener for button ActionEvent **/
|
||||
private ActionListener buttonListener;
|
||||
/**
|
||||
* Flag detect this view has customized column or not
|
||||
|
@ -112,6 +137,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
/** DefaultFocusField */
|
||||
private WEditor defaultFocusField = null;
|
||||
|
||||
/** editor configuration for readonly field editor **/
|
||||
private final static IEditorConfiguration readOnlyEditorConfiguration = new IEditorConfiguration() {
|
||||
@Override
|
||||
public Boolean getReadonly() {
|
||||
|
@ -135,6 +161,11 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
this.dataBinder = new GridTabDataBinder(gridTab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get editor for GridField.
|
||||
* @param gridField
|
||||
* @return {@link WEditor}
|
||||
*/
|
||||
private WEditor getEditorCell(GridField gridField) {
|
||||
WEditor editor = editors.get(gridField);
|
||||
if (editor != null) {
|
||||
|
@ -147,6 +178,11 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
return editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup field editor
|
||||
* @param gridField
|
||||
* @param editor
|
||||
*/
|
||||
private void prepareFieldEditor(GridField gridField, WEditor editor) {
|
||||
if (editor instanceof WButtonEditor)
|
||||
{
|
||||
|
@ -172,9 +208,8 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param field
|
||||
* @return column index, -1 if not found
|
||||
* @return column index for field, -1 if not found
|
||||
*/
|
||||
public int getColumnIndex(GridField field) {
|
||||
GridField[] fields = gridPanel.getFields();
|
||||
|
@ -185,6 +220,10 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return readonly checkbox component
|
||||
*/
|
||||
private Component createReadonlyCheckbox(Object value) {
|
||||
Checkbox checkBox = new Checkbox();
|
||||
if (value != null && "true".equalsIgnoreCase(value.toString()))
|
||||
|
@ -195,6 +234,11 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
return checkBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create invisible component for GridField with IsHeading=Y.
|
||||
* To fill up space allocated for field component.
|
||||
* @return invisible text box component
|
||||
*/
|
||||
private Component createInvisibleComponent() {
|
||||
Textbox textBox = new Textbox();
|
||||
textBox.setDisabled(true);
|
||||
|
@ -236,7 +280,8 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
* @param value
|
||||
* @param gridField
|
||||
* @param rowIndex
|
||||
* @param isForceGetValue
|
||||
* @param isForceGetValue true to return text for field value even if IsDisplay return false. This is to allow Grid customization
|
||||
* to override IsDisplay result.
|
||||
* @return display text
|
||||
*/
|
||||
private String getDisplayText(Object value, GridField gridField, int rowIndex, boolean isForceGetValue)
|
||||
|
@ -271,8 +316,9 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
* @param rowIndex
|
||||
* @param value
|
||||
* @param gridField
|
||||
* @param isForceGetValue
|
||||
* @return
|
||||
* @param isForceGetValue true to return Component with value even if IsDisplay return false. This is to allow Grid customization
|
||||
* preference to override IsDisplay result.
|
||||
* @return {@link Component}
|
||||
*/
|
||||
private Component getDisplayComponent(int rowIndex, Object value, GridField gridField, boolean isForceGetValue) {
|
||||
Component component;
|
||||
|
@ -308,6 +354,12 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply AD_Style to field.
|
||||
* @param gridField
|
||||
* @param rowIndex
|
||||
* @param component
|
||||
*/
|
||||
private void applyFieldStyle(GridField gridField, int rowIndex,
|
||||
HtmlBasedComponent component) {
|
||||
int AD_Style_ID = gridField.getAD_FieldStyle_ID();
|
||||
|
@ -319,6 +371,11 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
setComponentStyle(component, style.buildStyle(ThemeManager.getTheme(), gridRowCtx));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set component's style, sclass or zclass property
|
||||
* @param component
|
||||
* @param style "@sclass=" for sclass for "@zclass=" for zclass. default to style if there's no prefix.
|
||||
*/
|
||||
protected void setComponentStyle(HtmlBasedComponent component, String style) {
|
||||
if (style != null && style.startsWith(MStyle.SCLASS_PREFIX)) {
|
||||
String sclass = style.substring(MStyle.SCLASS_PREFIX.length());
|
||||
|
@ -341,6 +398,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
* set label text, shorten text if length exceed define max length.
|
||||
* @param text
|
||||
* @param label
|
||||
*/
|
||||
|
@ -355,8 +413,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return active editor list
|
||||
* @return field editor list
|
||||
*/
|
||||
public List<WEditor> getEditors() {
|
||||
List<WEditor> editorList = new ArrayList<WEditor>();
|
||||
|
@ -395,7 +452,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
else
|
||||
child = parent;
|
||||
}
|
||||
Component component = div!=null ? (Component) div.getAttribute("display.component") : null;
|
||||
Component component = div!=null ? (Component) div.getAttribute(DISPLAY_COMPONENT_ATTR) : null;
|
||||
if (updateCellLabel) {
|
||||
if (component instanceof Label) {
|
||||
Label label = (Label)component;
|
||||
|
@ -433,9 +490,10 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
* Render data for row.
|
||||
* @param row
|
||||
* @param data
|
||||
* @param index
|
||||
* @param data Object[] values for row
|
||||
* @param index row index within current page (i.e if page size is 25, index is one of 0 to 24).
|
||||
*/
|
||||
@Override
|
||||
public void render(Row row, Object[] data, int index) throws Exception {
|
||||
|
@ -579,7 +637,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
if (column.isVisible()) {
|
||||
Component component = getDisplayComponent(rowIndex, currentValues[i], gridPanelFields[i], isGridViewCustomized);
|
||||
div.appendChild(component);
|
||||
div.setAttribute("display.component", component);
|
||||
div.setAttribute(DISPLAY_COMPONENT_ATTR, component);
|
||||
if (gridPanelFields[i].isHeading()) {
|
||||
component.setVisible(false);
|
||||
}
|
||||
|
@ -599,7 +657,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
div.setStyle(divStyle);
|
||||
ZKUpdateUtil.setWidth(div, "100%");
|
||||
div.setAttribute("columnName", gridPanelFields[i].getColumnName());
|
||||
div.setAttribute(COLUMN_NAME_ATTR, gridPanelFields[i].getColumnName());
|
||||
div.addEventListener(Events.ON_CLICK, rowListener);
|
||||
div.addEventListener(Events.ON_DOUBLE_CLICK, rowListener);
|
||||
row.appendChild(div);
|
||||
|
@ -693,7 +751,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Row
|
||||
* @return current {@link Row}
|
||||
*/
|
||||
public Row getCurrentRow() {
|
||||
return currentRow;
|
||||
|
@ -707,7 +765,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
* Enter edit mode
|
||||
* Enter edit mode for current focus row.
|
||||
*/
|
||||
public void editCurrentRow() {
|
||||
if (ClientInfo.isMobile()) {
|
||||
|
@ -771,6 +829,9 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if it is own by {@link DetailPane}.
|
||||
*/
|
||||
private boolean isDetailPane() {
|
||||
Component parent = grid.getParent();
|
||||
while (parent != null) {
|
||||
|
@ -828,7 +889,8 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
* set focus to first active editor
|
||||
* Set focus to first writable field editor (or default focus field editor if it is writable).
|
||||
* If no field editor is writable, set focus to first visible field editor.
|
||||
*/
|
||||
public void focusToFirstEditor() {
|
||||
if (currentRow != null && currentRow.getParent() != null) {
|
||||
|
@ -861,7 +923,6 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param toFocus
|
||||
*/
|
||||
protected void focusToEditor(WEditor toFocus) {
|
||||
|
@ -877,7 +938,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
* set focus to next readwrite editor from ref
|
||||
* set focus to next writable editor from ref
|
||||
* @param ref
|
||||
*/
|
||||
public void focusToNextEditor(WEditor ref) {
|
||||
|
@ -897,13 +958,16 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Set {@link GridView} that own this renderer.
|
||||
* @param gridPanel
|
||||
*/
|
||||
public void setGridPanel(GridView gridPanel) {
|
||||
this.gridPanel = gridPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal listener for row event (ON_CLICK, ON_DOUBLE_CLICK and ON_OK).
|
||||
*/
|
||||
static class RowListener implements EventListener<Event> {
|
||||
|
||||
private Grid _grid;
|
||||
|
@ -914,7 +978,7 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
|
||||
public void onEvent(Event event) throws Exception {
|
||||
if (Events.ON_CLICK.equals(event.getName())) {
|
||||
if (Executions.getCurrent().getAttribute("gridView.onSelectRow") != null)
|
||||
if (Executions.getCurrent().getAttribute(GRID_VIEW_ON_SELECT_ROW_ATTR) != null)
|
||||
return;
|
||||
Event evt = new Event(Events.ON_CLICK, _grid, event.getTarget());
|
||||
Events.sendEvent(_grid, evt);
|
||||
|
@ -932,13 +996,15 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
}
|
||||
|
||||
/**
|
||||
* @return true if it is in edit mode, false otherwise
|
||||
* @return true if current row is in edit mode, false otherwise
|
||||
*/
|
||||
public boolean isEditing() {
|
||||
return editing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set AD window content part that own this renderer.
|
||||
* {@link #buttonListener} need this to call {@link AbstractADWindowContent#actionPerformed(ActionEvent)}.
|
||||
* @param windowPanel
|
||||
*/
|
||||
public void setADWindowPanel(AbstractADWindowContent windowPanel) {
|
||||
|
@ -974,12 +1040,15 @@ public class GridTabRowRenderer implements RowRenderer<Object[]>, RowRendererExt
|
|||
else
|
||||
Events.sendEvent(event.getTarget().getParent(), event);
|
||||
} else if (event.getTarget() instanceof Checkbox) {
|
||||
Executions.getCurrent().setAttribute("gridView.onSelectRow", Boolean.TRUE);
|
||||
Executions.getCurrent().setAttribute(GRID_VIEW_ON_SELECT_ROW_ATTR, Boolean.TRUE);
|
||||
Checkbox checkBox = (Checkbox) event.getTarget();
|
||||
Events.sendEvent(gridPanel, new Event("onSelectRow", gridPanel, checkBox));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link GridView#isShowCurrentRowIndicatorColumn}
|
||||
*/
|
||||
private boolean isShowCurrentRowIndicatorColumn() {
|
||||
return gridPanel != null && gridPanel.isShowCurrentRowIndicatorColumn();
|
||||
}
|
||||
|
|
|
@ -28,14 +28,14 @@ import org.zkoss.zul.event.ListDataEvent;
|
|||
import org.zkoss.zul.ext.Sortable;
|
||||
|
||||
/**
|
||||
*
|
||||
* List model for {@link GridTable}
|
||||
* @author Low Heng Sin
|
||||
*
|
||||
*/
|
||||
public class GridTableListModel extends AbstractListModel<Object> implements TableModelListener, Sortable<Object> {
|
||||
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 698185856751242764L;
|
||||
private GridTable tableModel;
|
||||
|
@ -47,10 +47,10 @@ public class GridTableListModel extends AbstractListModel<Object> implements Tab
|
|||
private int pageSize = -1;
|
||||
private int pageNo = 0;
|
||||
|
||||
/** Edit mode flag. When editing is true, do not fire ListDataEvent.CONTENTS_CHANGED event. **/
|
||||
private boolean editing = false;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param tableModel
|
||||
* @param windowNo
|
||||
*/
|
||||
|
@ -142,7 +142,7 @@ public class GridTableListModel extends AbstractListModel<Object> implements Tab
|
|||
}
|
||||
|
||||
/**
|
||||
* Request components that attached to this model to re-render a row.
|
||||
* Delegate to {@link #updateComponent(int, int)}.
|
||||
* @param row
|
||||
*/
|
||||
public void updateComponent(int row) {
|
||||
|
@ -151,6 +151,7 @@ public class GridTableListModel extends AbstractListModel<Object> implements Tab
|
|||
|
||||
/**
|
||||
* Request components that attached to this model to re-render a range of row.
|
||||
* Fire ListDataEvent.CONTENTS_CHANGED event for fromRow to toRow.
|
||||
* @param fromRow
|
||||
* @param toRow
|
||||
*/
|
||||
|
@ -162,6 +163,7 @@ public class GridTableListModel extends AbstractListModel<Object> implements Tab
|
|||
}
|
||||
|
||||
/**
|
||||
* Sort and fire ListDataEvent.CONTENTS_CHANGED event to notify UI component.
|
||||
* @param cmpr
|
||||
* @param ascending
|
||||
*/
|
||||
|
@ -178,6 +180,7 @@ public class GridTableListModel extends AbstractListModel<Object> implements Tab
|
|||
}
|
||||
|
||||
/**
|
||||
* Handle TableModelEvent from GridTable.
|
||||
* @param e
|
||||
* @see TableModelListener#tableChanged(TableModelEvent)
|
||||
*/
|
||||
|
@ -216,6 +219,8 @@ public class GridTableListModel extends AbstractListModel<Object> implements Tab
|
|||
}
|
||||
|
||||
/**
|
||||
* Set editing to true/false.
|
||||
* When editing is true, do not fire ListDataEvent.CONTENTS_CHANGED event.
|
||||
* @param b
|
||||
*/
|
||||
public void setEditing(boolean b) {
|
||||
|
|
|
@ -70,95 +70,132 @@ import org.zkoss.zul.event.ZulEvents;
|
|||
import org.zkoss.zul.impl.CustomGridDataLoader;
|
||||
|
||||
/**
|
||||
* Grid view implemented using the Grid component.
|
||||
* Grid/List view implemented using the Grid component.
|
||||
* @author Low Heng Sin
|
||||
*
|
||||
*/
|
||||
public class GridView extends Vlayout implements EventListener<Event>, IdSpace, IFieldEditorContainer, StateChangeListener
|
||||
{
|
||||
/** Event after the current row index has changed. **/
|
||||
private static final String ON_POST_SELECTED_ROW_CHANGED_EVENT = "onPostSelectedRowChanged";
|
||||
|
||||
public static final String ZERO_PX_WIDTH = "0px";
|
||||
|
||||
/** {@link Column} attribute to store grid field index **/
|
||||
private static final String GRID_VIEW_GRID_FIELD_INDEX = "gridView.gridField.index";
|
||||
|
||||
/** {@link Column} attribute to store initial/original column width value **/
|
||||
public static final String COLUMN_WIDTH_ORIGINAL = "column.width.original";
|
||||
|
||||
/** {@link Column} attribute to store initial/original column hflex value **/
|
||||
private static final String COLUMN_HFLEX_ORIGINAL = "column.hflex.original";
|
||||
|
||||
/** minimum column width for mobile client **/
|
||||
private static final int MIN_COLUMN_MOBILE_WIDTH = 100;
|
||||
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 3995829393137424527L;
|
||||
|
||||
/** Style for Grid and Grid Footer **/
|
||||
private static final String HEADER_GRID_STYLE = "border: none; margin:0; padding: 0;";
|
||||
|
||||
/** default paging size when GridView is in DetailPane **/
|
||||
private static final int DEFAULT_DETAIL_PAGE_SIZE = 10;
|
||||
|
||||
/** default paging size for mobile client when GridView is in header panel **/
|
||||
private static final int DEFAULT_MOBILE_PAGE_SIZE = 20;
|
||||
|
||||
/** default paging size when GridView is in header panel **/
|
||||
private static final int DEFAULT_PAGE_SIZE = 20;
|
||||
|
||||
/** minimum column width **/
|
||||
private static final int MIN_COLUMN_WIDTH = 100;
|
||||
|
||||
/** maximum column width **/
|
||||
private static final int MAX_COLUMN_WIDTH = 300;
|
||||
|
||||
/** minimum column width for combobox field **/
|
||||
private static final int MIN_COMBOBOX_WIDTH = 160;
|
||||
|
||||
/** minimum column width for numeric field **/
|
||||
private static final int MIN_NUMERIC_COL_WIDTH = 120;
|
||||
|
||||
/** GridView boolean attribute to indicate ON_POST_SELECTED_ROW_CHANGED_EVENT have been posted in current execution cycle **/
|
||||
private static final String ATTR_ON_POST_SELECTED_ROW_CHANGED = "org.adempiere.webui.adwindow.GridView.onPostSelectedRowChanged";
|
||||
|
||||
/** Static Logger */
|
||||
private static CLogger s_log = CLogger.getCLogger (GridView.class);
|
||||
|
||||
/** data grid instance **/
|
||||
private Grid listbox = null;
|
||||
|
||||
private int pageSize = DEFAULT_PAGE_SIZE;
|
||||
|
||||
/**
|
||||
* list field display in grid mode, in case user customize grid
|
||||
* this list container only customize list.
|
||||
* this list container only display list.
|
||||
*/
|
||||
private GridField[] gridField;
|
||||
private GridField[] gridFields;
|
||||
|
||||
/** GridTable model for GridTab **/
|
||||
private AbstractTableModel tableModel;
|
||||
|
||||
private int numColumns = 5;
|
||||
|
||||
private int windowNo;
|
||||
|
||||
/** GridTab that back this GridView **/
|
||||
private GridTab gridTab;
|
||||
|
||||
/** true if this GridView instance have been init with GridTab **/
|
||||
private boolean init;
|
||||
|
||||
/** Zk List model for {@link #tableModel} **/
|
||||
private GridTableListModel listModel;
|
||||
|
||||
private Paging paging;
|
||||
|
||||
/** Row renderer for this GridView instance **/
|
||||
private GridTabRowRenderer renderer;
|
||||
|
||||
/** Footer for paging **/
|
||||
private Div gridFooter;
|
||||
|
||||
/** true if current row is always in edit mode **/
|
||||
private boolean modeless = true;
|
||||
|
||||
/** column click by user **/
|
||||
private String columnOnClick;
|
||||
|
||||
/** AD window content part that own this GridView instance **/
|
||||
private AbstractADWindowContent windowPanel;
|
||||
|
||||
/** true when grid is refreshing its data **/
|
||||
private boolean refreshing;
|
||||
|
||||
/** AD_Field_ID:Column Width **/
|
||||
private Map<Integer, String> columnWidthMap;
|
||||
|
||||
/** true if it is in DetailPane **/
|
||||
private boolean detailPaneMode;
|
||||
|
||||
/** checkbox to select all row of current page **/
|
||||
protected Checkbox selectAll;
|
||||
|
||||
boolean isHasCustomizeData = false;
|
||||
/** true if there are AD_Tab_Customization for GridTab **/
|
||||
protected boolean isHasCustomizeData = false;
|
||||
|
||||
/** true to add row indicator column after selection column (i.e second column) **/
|
||||
private boolean showCurrentRowIndicatorColumn = true;
|
||||
|
||||
/** true if auto hide empty column feature is enable **/
|
||||
private String m_isAutoHideEmptyColumn;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
public GridView()
|
||||
{
|
||||
this(0);
|
||||
|
@ -214,6 +251,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
addEventListener("onCustomizeGrid", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* create data grid instances
|
||||
*/
|
||||
protected void createListbox() {
|
||||
listbox = new Grid();
|
||||
listbox.setSizedByContent(false);
|
||||
|
@ -223,6 +263,11 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
listbox.setEmptyMessage(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Processing")));
|
||||
}
|
||||
|
||||
/**
|
||||
* turn on/off detail pane mode
|
||||
* @param detailPaneMode
|
||||
* @param gridTab
|
||||
*/
|
||||
public void setDetailPaneMode(boolean detailPaneMode, GridTab gridTab) {
|
||||
if (this.detailPaneMode != detailPaneMode) {
|
||||
this.detailPaneMode = detailPaneMode;
|
||||
|
@ -231,7 +276,10 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/** Returns the number of records to be displayed in detail grid */
|
||||
/**
|
||||
* @param gridTab
|
||||
* @return the number of records to be displayed in detail grid
|
||||
*/
|
||||
private int getDetailPageSize(GridTab gridTab) {
|
||||
int size = DEFAULT_DETAIL_PAGE_SIZE;
|
||||
String pageDetailSizes = MSysConfig.getValue(MSysConfig.ZK_PAGING_DETAIL_SIZE, Env.getAD_Client_ID(Env.getCtx()));
|
||||
|
@ -279,10 +327,16 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if it is in detail pane mode
|
||||
*/
|
||||
public boolean isDetailPaneMode() {
|
||||
return this.detailPaneMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update paging component with new paging size and notify model if paging size has change.
|
||||
*/
|
||||
private void updatePaging() {
|
||||
if (paging != null && paging.getPageSize() != pageSize) {
|
||||
paging.setPageSize(pageSize);
|
||||
|
@ -296,7 +350,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Init data grid
|
||||
* @param gridTab
|
||||
*/
|
||||
public void init(GridTab gridTab)
|
||||
|
@ -324,6 +378,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
showRecordsCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update {@link DetailPane} status with record count
|
||||
*/
|
||||
private void showRecordsCount() {
|
||||
Component parent = this.getParent();
|
||||
while (parent != null) {
|
||||
|
@ -337,6 +394,10 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup {@link #gridFields} from gridTab.
|
||||
* @param gridTab
|
||||
*/
|
||||
private void setupFields(GridTab gridTab) {
|
||||
this.gridTab = gridTab;
|
||||
gridTab.addStateChangeListener(this);
|
||||
|
@ -366,11 +427,11 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
}
|
||||
gridField = fieldList.toArray(new GridField[0]);
|
||||
gridFields = fieldList.toArray(new GridField[0]);
|
||||
if (customComponent.length == 2) {
|
||||
String[] widths = customComponent[1].split("[,]");
|
||||
for(int i = 0; i< gridField.length && i<widths.length; i++) {
|
||||
columnWidthMap.put(gridField[i].getAD_Field_ID(), widths[i]);
|
||||
for(int i = 0; i< gridFields.length && i<widths.length; i++) {
|
||||
columnWidthMap.put(gridFields[i].getAD_Field_ID(), widths[i]);
|
||||
}
|
||||
}
|
||||
m_isAutoHideEmptyColumn = tabCustomization.getIsAutoHideEmptyColumn();
|
||||
|
@ -396,22 +457,22 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
});
|
||||
|
||||
gridField = new GridField[gridFieldList.size()];
|
||||
gridFieldList.toArray(gridField);
|
||||
gridFields = new GridField[gridFieldList.size()];
|
||||
gridFieldList.toArray(gridFields);
|
||||
}
|
||||
numColumns = gridField.length;
|
||||
numColumns = gridFields.length;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
* @return true if data grid have been init with GridTab
|
||||
*/
|
||||
public boolean isInit() {
|
||||
return init;
|
||||
}
|
||||
|
||||
/**
|
||||
* call when tab is activated
|
||||
* Activate GridView (make visible or GridTab have been refreshed)
|
||||
* @param gridTab
|
||||
*/
|
||||
public void activate(GridTab gridTab) {
|
||||
|
@ -425,7 +486,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
|
||||
/**
|
||||
* refresh after switching from form view
|
||||
* Refresh data grid (after switching from form view or column setup has change)
|
||||
* @param gridTab
|
||||
*/
|
||||
public void refresh(GridTab gridTab) {
|
||||
|
@ -445,12 +506,15 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if data grid is refreshing data from GridTab
|
||||
*/
|
||||
public boolean isRefreshing() {
|
||||
return refreshing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update current row from model
|
||||
* Update current row index from model
|
||||
*/
|
||||
public void updateListIndex() {
|
||||
if (gridTab == null || !gridTab.isOpen()) return;
|
||||
|
@ -506,23 +570,29 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hide paging component
|
||||
*/
|
||||
private void hidePagingControl() {
|
||||
if (gridFooter.isVisible())
|
||||
gridFooter.setVisible(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* show paging component
|
||||
*/
|
||||
private void showPagingControl() {
|
||||
if (!gridFooter.isVisible())
|
||||
gridFooter.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* echo ON_POST_SELECTED_ROW_CHANGED_EVENT after current row index has changed
|
||||
*/
|
||||
protected void echoOnPostSelectedRowChanged() {
|
||||
if (getAttribute(ATTR_ON_POST_SELECTED_ROW_CHANGED) == null) {
|
||||
setAttribute(ATTR_ON_POST_SELECTED_ROW_CHANGED, Boolean.TRUE);
|
||||
Events.echoEvent("onPostSelectedRowChanged", this, null);
|
||||
Events.echoEvent(ON_POST_SELECTED_ROW_CHANGED_EVENT, this, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,11 +605,17 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove all components
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
this.getChildren().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup {@link Columns} of data grid
|
||||
*/
|
||||
private void setupColumns()
|
||||
{
|
||||
if (init) return;
|
||||
|
@ -595,36 +671,36 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
for (int i = 0; i < numColumns; i++)
|
||||
{
|
||||
// IDEMPIERE-2148: when has tab customize, ignore check properties isDisplayedGrid
|
||||
if ((isHasCustomizeData || gridField[i].isDisplayedGrid()) && !gridField[i].isToolbarOnlyButton())
|
||||
if ((isHasCustomizeData || gridFields[i].isDisplayedGrid()) && !gridFields[i].isToolbarOnlyButton())
|
||||
{
|
||||
colnames.put(index, gridField[i].getHeader());
|
||||
colnames.put(index, gridFields[i].getHeader());
|
||||
index++;
|
||||
org.zkoss.zul.Column column = new Column();
|
||||
column.setAttribute(GRID_VIEW_GRID_FIELD_INDEX, i);
|
||||
column.setHeight("2em");
|
||||
int colindex =tableModel.findColumn(gridField[i].getColumnName());
|
||||
int colindex =tableModel.findColumn(gridFields[i].getColumnName());
|
||||
column.setSortAscending(new SortComparator(colindex, true, Env.getLanguage(Env.getCtx())));
|
||||
column.setSortDescending(new SortComparator(colindex, false, Env.getLanguage(Env.getCtx())));
|
||||
//IDEMPIERE-2898 - UX: Field only showing title at header on grid
|
||||
if( gridField[i].isFieldOnly() )
|
||||
if( gridFields[i].isFieldOnly() )
|
||||
column.setLabel("");
|
||||
else
|
||||
column.setLabel(gridField[i].getHeader());
|
||||
column.setLabel(gridFields[i].getHeader());
|
||||
|
||||
if (columnWidthMap != null && columnWidthMap.get(gridField[i].getAD_Field_ID()) != null && !columnWidthMap.get(gridField[i].getAD_Field_ID()).equals("")) {
|
||||
ZKUpdateUtil.setWidth(column, columnWidthMap.get(gridField[i].getAD_Field_ID()));
|
||||
if (columnWidthMap != null && columnWidthMap.get(gridFields[i].getAD_Field_ID()) != null && !columnWidthMap.get(gridFields[i].getAD_Field_ID()).equals("")) {
|
||||
ZKUpdateUtil.setWidth(column, columnWidthMap.get(gridFields[i].getAD_Field_ID()));
|
||||
} else {
|
||||
if (gridField[i].getDisplayType()==DisplayType.YesNo) {
|
||||
if (gridFields[i].getDisplayType()==DisplayType.YesNo) {
|
||||
if (i > 0) {
|
||||
ZKUpdateUtil.setHflex(column, "min");
|
||||
} else {
|
||||
int estimatedWidth=60;
|
||||
int headerWidth = (gridField[i].getHeader().length()+2) * 8;
|
||||
int headerWidth = (gridFields[i].getHeader().length()+2) * 8;
|
||||
if (headerWidth > estimatedWidth)
|
||||
estimatedWidth = headerWidth;
|
||||
ZKUpdateUtil.setWidth(column, estimatedWidth+"px");
|
||||
}
|
||||
} else if (DisplayType.isNumeric(gridField[i].getDisplayType()) && "Line".equals(gridField[i].getColumnName())) {
|
||||
} else if (DisplayType.isNumeric(gridFields[i].getDisplayType()) && "Line".equals(gridFields[i].getColumnName())) {
|
||||
//special treatment for line
|
||||
if (i > 0)
|
||||
ZKUpdateUtil.setHflex(column, "min");
|
||||
|
@ -632,33 +708,33 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
ZKUpdateUtil.setWidth(column, "60px");
|
||||
} else {
|
||||
int estimatedWidth = 0;
|
||||
if (DisplayType.isNumeric(gridField[i].getDisplayType()))
|
||||
if (DisplayType.isNumeric(gridFields[i].getDisplayType()))
|
||||
estimatedWidth = MIN_NUMERIC_COL_WIDTH;
|
||||
else if (DisplayType.isLookup(gridField[i].getDisplayType()))
|
||||
else if (DisplayType.isLookup(gridFields[i].getDisplayType()))
|
||||
estimatedWidth = MIN_COMBOBOX_WIDTH;
|
||||
else if (DisplayType.isText(gridField[i].getDisplayType()))
|
||||
estimatedWidth = gridField[i].getDisplayLength() * 8;
|
||||
else if (DisplayType.isText(gridFields[i].getDisplayType()))
|
||||
estimatedWidth = gridFields[i].getDisplayLength() * 8;
|
||||
else
|
||||
estimatedWidth = MIN_COLUMN_WIDTH;
|
||||
|
||||
int headerWidth = (gridField[i].getHeader().length()+2) * 8;
|
||||
int headerWidth = (gridFields[i].getHeader().length()+2) * 8;
|
||||
if (headerWidth > estimatedWidth)
|
||||
estimatedWidth = headerWidth;
|
||||
|
||||
//hflex=min for first column not working well
|
||||
if (i > 0 && !ClientInfo.isMobile())
|
||||
{
|
||||
if (DisplayType.isLookup(gridField[i].getDisplayType()))
|
||||
if (DisplayType.isLookup(gridFields[i].getDisplayType()))
|
||||
{
|
||||
if (headerWidth > MIN_COMBOBOX_WIDTH)
|
||||
ZKUpdateUtil.setHflex(column, "min");
|
||||
}
|
||||
else if (DisplayType.isNumeric(gridField[i].getDisplayType()))
|
||||
else if (DisplayType.isNumeric(gridFields[i].getDisplayType()))
|
||||
{
|
||||
if (headerWidth > MIN_NUMERIC_COL_WIDTH)
|
||||
ZKUpdateUtil.setHflex(column, "min");
|
||||
}
|
||||
else if (!DisplayType.isText(gridField[i].getDisplayType()))
|
||||
else if (!DisplayType.isText(gridFields[i].getDisplayType()))
|
||||
{
|
||||
if (headerWidth > MIN_COLUMN_WIDTH)
|
||||
ZKUpdateUtil.setHflex(column, "min");
|
||||
|
@ -689,6 +765,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render data grid
|
||||
*/
|
||||
private void render()
|
||||
{
|
||||
updateEmptyMessage();
|
||||
|
@ -722,7 +801,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
|
||||
/**
|
||||
* auto hide empty columns
|
||||
* Auto hide empty columns (if auto hide empty column feature have been turned on)
|
||||
*/
|
||||
protected void autoHideEmptyColumns() {
|
||||
if (!isAutoHideEmptyColumns()) {
|
||||
|
@ -748,7 +827,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
continue;
|
||||
int index = (Integer)value;
|
||||
for(int i = 0; i < gridTabFields.length; i++) {
|
||||
if (gridField[index].getAD_Field_ID() == gridTabFields[i].getAD_Field_ID()) {
|
||||
if (gridFields[index].getAD_Field_ID() == gridTabFields[i].getAD_Field_ID()) {
|
||||
indexMap.put(index, i);
|
||||
break;
|
||||
}
|
||||
|
@ -771,14 +850,14 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
if (paging != null && paging.getPageSize() > 0) {
|
||||
rowIndex = (paging.getActivePage() * paging.getPageSize()) + rowIndex;
|
||||
}
|
||||
String display = renderer.getDisplayTextWithEditorCheck(values[valueIndex], gridField[index], rowIndex);
|
||||
String display = renderer.getDisplayTextWithEditorCheck(values[valueIndex], gridFields[index], rowIndex);
|
||||
if (!Util.isEmpty(display, true)) {
|
||||
hideColumn = false;
|
||||
break;
|
||||
} else if (gridTab.getCurrentRow() == rowIndex && gridTab.isNew()) {
|
||||
if (gridField[index].isEditable(false) && (gridField[index].isMandatory(false) || !Util.isEmpty(gridField[index].getVO().MandatoryLogic)
|
||||
|| !Util.isEmpty(gridField[index].getVO().DisplayLogic)
|
||||
|| !Util.isEmpty(gridField[index].getVO().ReadOnlyLogic))) {
|
||||
if (gridFields[index].isEditable(false) && (gridFields[index].isMandatory(false) || !Util.isEmpty(gridFields[index].getVO().MandatoryLogic)
|
||||
|| !Util.isEmpty(gridFields[index].getVO().DisplayLogic)
|
||||
|| !Util.isEmpty(gridFields[index].getVO().ReadOnlyLogic))) {
|
||||
hideColumn = false;
|
||||
break;
|
||||
}
|
||||
|
@ -808,6 +887,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if auto hide empty columns feature have been turned on
|
||||
*/
|
||||
private boolean isAutoHideEmptyColumns() {
|
||||
if (!Util.isEmpty(m_isAutoHideEmptyColumn, true))
|
||||
return "Y".equalsIgnoreCase(m_isAutoHideEmptyColumn);
|
||||
|
@ -815,6 +897,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
return MSysConfig.getBooleanValue(MSysConfig.ZK_GRID_AUTO_HIDE_EMPTY_COLUMNS, false, Env.getAD_Client_ID(Env.getCtx()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show zero records for processing message
|
||||
*/
|
||||
private void updateEmptyMessage() {
|
||||
if (gridTab.getRowCount() == 0)
|
||||
{
|
||||
|
@ -826,6 +911,10 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update {@link #listModel} with {@link #tableModel} changes.
|
||||
* Re-create {@link #renderer}.
|
||||
*/
|
||||
private void updateModel() {
|
||||
if (listModel != null)
|
||||
((GridTable)tableModel).removeTableModelListener(listModel);
|
||||
|
@ -846,13 +935,14 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
|
||||
/**
|
||||
* deactivate panel
|
||||
* Deactivate Grid View. Stop editing if current row is in edit mode.
|
||||
*/
|
||||
public void deactivate() {
|
||||
if (renderer != null && renderer.isEditing())
|
||||
renderer.stopEditing(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception
|
||||
{
|
||||
if (event == null)
|
||||
|
@ -872,15 +962,15 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
if (cmp.getParent() instanceof org.zkoss.zul.Row)
|
||||
{
|
||||
row = (Row) cmp.getParent();
|
||||
columnName = (String) cmp.getAttribute("columnName");
|
||||
columnName = (String) cmp.getAttribute(GridTabRowRenderer.COLUMN_NAME_ATTR);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (row != null)
|
||||
{
|
||||
//click on selected row to enter edit mode
|
||||
{
|
||||
if (row == renderer.getCurrentRow())
|
||||
{
|
||||
//click on selected row to enter edit mode
|
||||
if (!renderer.isEditing())
|
||||
{
|
||||
renderer.editCurrentRow();
|
||||
|
@ -892,6 +982,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
else
|
||||
{
|
||||
//change selection of current row
|
||||
int index = listbox.getRows().getChildren().indexOf(row);
|
||||
if (index >= 0 ) {
|
||||
columnOnClick = columnName;
|
||||
|
@ -941,6 +1032,10 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param gridView
|
||||
* @return {@link Center} that own this GridView instance
|
||||
*/
|
||||
private Center findCenter(GridView gridView) {
|
||||
if (gridView == null)
|
||||
return null;
|
||||
|
@ -953,6 +1048,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if all row of current page is selected
|
||||
*/
|
||||
private boolean isAllSelected() {
|
||||
org.zkoss.zul.Rows rows = listbox.getRows();
|
||||
List<Component> childs = rows.getChildren();
|
||||
|
@ -974,6 +1072,10 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* turn on/off select all rows for current page
|
||||
* @param b
|
||||
*/
|
||||
private void toggleSelectionForAll(boolean b) {
|
||||
org.zkoss.zul.Rows rows = listbox.getRows();
|
||||
List<Component> childs = rows.getChildren();
|
||||
|
@ -995,6 +1097,10 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update list model and data grid with new current row index
|
||||
* @param index
|
||||
*/
|
||||
private void onSelectedRowChange(int index) {
|
||||
if (updateModelIndex(index)) {
|
||||
updateListIndex();
|
||||
|
@ -1002,7 +1108,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
|
||||
/**
|
||||
* Event after the current selected row change
|
||||
* Event after the current row index has changed.
|
||||
*/
|
||||
public void onPostSelectedRowChanged() {
|
||||
removeAttribute(ATTR_ON_POST_SELECTED_ROW_CHANGED);
|
||||
|
@ -1060,6 +1166,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus to first editor field if GridView instance is not own by the selected detail tab panel.
|
||||
*/
|
||||
private void focusToFirstEditorIfNotDetailTab() {
|
||||
ADTabpanel adtabpanel = null;
|
||||
boolean setFocus = true;
|
||||
|
@ -1095,6 +1204,11 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
onPostSelectedRowChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus to row.
|
||||
* If it is in edit mode, assume row is the current editing row.
|
||||
* @param row
|
||||
*/
|
||||
private void focusToRow(org.zkoss.zul.Row row) {
|
||||
if (renderer.isEditing()) {
|
||||
if (columnOnClick != null && columnOnClick.trim().length() > 0) {
|
||||
|
@ -1123,7 +1237,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
for(Object element : list) {
|
||||
if (element instanceof Div) {
|
||||
Div div = (Div) element;
|
||||
if (columnOnClick.equals(div.getAttribute("columnName"))) {
|
||||
if (columnOnClick.equals(div.getAttribute(GridTabRowRenderer.COLUMN_NAME_ATTR))) {
|
||||
cmp = div.getFirstChild();
|
||||
Clients.response(new AuScript(null, "idempiere.scrollToRow('" + cmp.getUuid() + "');"));
|
||||
break;
|
||||
|
@ -1135,6 +1249,11 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row
|
||||
* @param index
|
||||
* @return true if row have been rendered by row renderer
|
||||
*/
|
||||
private boolean isRowRendered(org.zkoss.zul.Row row, int index) {
|
||||
if (row.getChildren().size() == 0) {
|
||||
return false;
|
||||
|
@ -1146,6 +1265,11 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update gridTab current row index.
|
||||
* @param rowIndex row index of current page
|
||||
* @return true if gridTab current row index has change
|
||||
*/
|
||||
private boolean updateModelIndex(int rowIndex) {
|
||||
if (pageSize > 0) {
|
||||
int start = listModel.getPage() * listModel.getPageSize();
|
||||
|
@ -1214,6 +1338,11 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
selectAll.setChecked(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform dynamic display for editors in list
|
||||
* @param noData true if data grid is empty
|
||||
* @param list
|
||||
*/
|
||||
private void dynamicDisplayEditors(boolean noData, List<WEditor> list) {
|
||||
for (WEditor comp : list)
|
||||
{
|
||||
|
@ -1242,6 +1371,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this GridView instance is own by DetailPane
|
||||
*/
|
||||
private boolean isDetailPane() {
|
||||
Component parent = this.getParent();
|
||||
while (parent != null) {
|
||||
|
@ -1261,6 +1393,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
this.windowNo = windowNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* If current row is in edit mode, set focus to first field editor
|
||||
*/
|
||||
@Override
|
||||
public void focus() {
|
||||
if (renderer != null && renderer.isEditing()) {
|
||||
|
@ -1299,6 +1434,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
|
||||
/**
|
||||
* Set AD window content part that own this GridView instance
|
||||
* @param winPanel
|
||||
*/
|
||||
public void setADWindowPanel(AbstractADWindowContent winPanel) {
|
||||
|
@ -1307,6 +1443,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
renderer.setADWindowPanel(windowPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-Init GridView with cache gridTab.
|
||||
*/
|
||||
public void reInit() {
|
||||
listbox.getChildren().clear();
|
||||
listbox.detach();
|
||||
|
@ -1343,15 +1482,23 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
/**
|
||||
* list field display in grid mode, in case user customize grid
|
||||
* this list container only customize list.
|
||||
* @return GridField[]
|
||||
*/
|
||||
public GridField[] getFields() {
|
||||
return gridField;
|
||||
return gridFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* call {@link #onEditCurrentRow(Event)}
|
||||
*/
|
||||
public void onEditCurrentRow() {
|
||||
onEditCurrentRow(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit current row
|
||||
* @param event
|
||||
*/
|
||||
public void onEditCurrentRow(Event event) {
|
||||
if (!renderer.isEditing()) {
|
||||
Row currentRow = renderer.getCurrentRow();
|
||||
|
@ -1366,6 +1513,9 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If current row is in edit mode, set focus to first writable field editor.
|
||||
*/
|
||||
@Override
|
||||
public void focusToFirstEditor() {
|
||||
if (renderer.isEditing()) {
|
||||
|
@ -1397,10 +1547,18 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parent component change notification from ADTabpanel that own this GridView instance (Usually
|
||||
* after movement between Header and DetailPane panel).
|
||||
* Re-position paging component.
|
||||
*/
|
||||
protected void onADTabPanelParentChanged() {
|
||||
positionPagingControl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set position of paging component depends on whether GridView is in header or DetailPane panel.
|
||||
*/
|
||||
private void positionPagingControl() {
|
||||
if (isDetailPane()) {
|
||||
Component parent = this.getParent();
|
||||
|
@ -1411,6 +1569,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
//use simplify paging presentation for DetailPane
|
||||
if (paging != null)
|
||||
paging.setDetailed(false);
|
||||
}
|
||||
|
@ -1426,12 +1585,18 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call editorTaverseCallback for all field editors.
|
||||
*/
|
||||
@Override
|
||||
public void editorTraverse(Callback<WEditor> editorTaverseCallback) {
|
||||
editorTraverse(editorTaverseCallback, renderer.getEditors());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if current row indicator column is visible.
|
||||
*/
|
||||
public boolean isShowCurrentRowIndicatorColumn() {
|
||||
return showCurrentRowIndicatorColumn;
|
||||
}
|
||||
|
|
|
@ -19,54 +19,53 @@ import org.zkoss.zk.ui.event.Event;
|
|||
import org.zkoss.zk.ui.event.EventListener;
|
||||
|
||||
/**
|
||||
*
|
||||
* Interface for header+details AD_Tabs UI for AD_Window.
|
||||
* @author <a href="mailto:hengsin@gmail.com">Low Heng Sin</a>
|
||||
*
|
||||
*/
|
||||
public interface IADTabbox extends UIPart {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return selected tab index
|
||||
* @return selected header tab index
|
||||
*/
|
||||
public int getSelectedIndex();
|
||||
|
||||
/**
|
||||
*
|
||||
* set selected header tab
|
||||
* @param i tab index
|
||||
*/
|
||||
public void setSelectedIndex(int i);
|
||||
|
||||
/**
|
||||
* Change selected header tab index from oldTabIndex to newTabIndex
|
||||
* @param oldTabIndex
|
||||
* @param newTabIndex
|
||||
* @return
|
||||
* @return true if selected tab successfully change to newTabIndex
|
||||
*/
|
||||
public boolean updateSelectedIndex(int oldTabIndex, int newTabIndex);
|
||||
|
||||
/**
|
||||
* @return selected tab panel reference
|
||||
* @return selected header {@link IADTabpanel} instance
|
||||
*/
|
||||
public IADTabpanel getSelectedTabpanel();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param fromIndex
|
||||
* @param toIndex
|
||||
* @return boolean
|
||||
* @return true if user can change selected tab from fromIndex to toIndex, false otherwise
|
||||
*/
|
||||
public boolean canNavigateTo(int fromIndex, int toIndex);
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return boolean
|
||||
* @return true if tab at index visible, false otherwise
|
||||
*/
|
||||
public boolean isDisplay(int index);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param tab
|
||||
* @param tabPanel
|
||||
* add new tab (AD_Tab)
|
||||
* @param tab {@link GridTab} for AD_Tab
|
||||
* @param tabPanel {@link IADTabpanel} instance for AD_Tab
|
||||
*/
|
||||
public void addTab(GridTab tab, IADTabpanel tabPanel);
|
||||
|
||||
|
@ -76,41 +75,43 @@ public interface IADTabbox extends UIPart {
|
|||
public int getTabCount();
|
||||
|
||||
/**
|
||||
* Evaluate state of each tab after DataStatusEvent
|
||||
* @param e
|
||||
*/
|
||||
public void evaluate(DataStatusEvent e);
|
||||
|
||||
/**
|
||||
* @return path to the active tab
|
||||
* @return folder like parent/child path to the selected tab (for e.g Business Partner > Location)
|
||||
*/
|
||||
public String getPath();
|
||||
|
||||
/**
|
||||
*
|
||||
* Set event listener for tab selection change event
|
||||
* @param listener
|
||||
*/
|
||||
public void setSelectionEventListener(EventListener<Event> listener);
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return IADTabpanel
|
||||
* @param index tab index
|
||||
* @return {@link IADTabpanel} instance at index
|
||||
*/
|
||||
public IADTabpanel getADTabpanel(int index);
|
||||
|
||||
/**
|
||||
* @param gTab
|
||||
* @return IADTabpanel or null if not found
|
||||
* @return {@link IADTabpanel} instance for gTab or null if not found
|
||||
*/
|
||||
public IADTabpanel findADTabpanel(GridTab gTab);
|
||||
|
||||
/**
|
||||
*
|
||||
* Set AD Window content part that own this IADTabbox instance.
|
||||
* @param abstractADWindowPanel
|
||||
*/
|
||||
public void setADWindowPanel(AbstractADWindowContent abstractADWindowPanel);
|
||||
|
||||
/**
|
||||
* drill down to the current selected adtabpanel
|
||||
* Edit current row of selected detail tab.
|
||||
* The selected detail tab will become the new header tab.
|
||||
*/
|
||||
public void onDetailRecord();
|
||||
|
||||
|
@ -120,6 +121,7 @@ public interface IADTabbox extends UIPart {
|
|||
public boolean isSortTab();
|
||||
|
||||
/**
|
||||
* Call {@link IADTabpanel#needSave(boolean, boolean)}
|
||||
* @param rowChange
|
||||
* @param onlyRealChange
|
||||
* @return true if there are changes pending to be save
|
||||
|
@ -127,54 +129,55 @@ public interface IADTabbox extends UIPart {
|
|||
public boolean needSave(boolean rowChange, boolean onlyRealChange);
|
||||
|
||||
/**
|
||||
* ignore all pending changes
|
||||
* ignore/undo all pending changes
|
||||
*/
|
||||
public void dataIgnore();
|
||||
|
||||
/**
|
||||
* @return selected header grid tab
|
||||
* @return {@link GridTab} instance of header tab
|
||||
*/
|
||||
public GridTab getSelectedGridTab();
|
||||
|
||||
/**
|
||||
*
|
||||
* Save changes
|
||||
* @param onSaveEvent
|
||||
* @return true if save is successfull
|
||||
* @return true if save is successful
|
||||
*/
|
||||
public boolean dataSave(boolean onSaveEvent);
|
||||
|
||||
/**
|
||||
*
|
||||
* Update status text of {@link DetailPane}
|
||||
* @param status
|
||||
* @param error
|
||||
*/
|
||||
public void setDetailPaneStatusMessage(String status, boolean error);
|
||||
|
||||
/**
|
||||
* @return the currently selected detail adtabpanel
|
||||
* @return the selected detail {@link IADTabpanel} instance
|
||||
*/
|
||||
IADTabpanel getSelectedDetailADTabpanel();
|
||||
|
||||
/**
|
||||
* @return dirty adtabpanel that need save ( if any )
|
||||
* @return dirty {@link IADTabpanel} that need save ( if any )
|
||||
*/
|
||||
IADTabpanel getDirtyADTabpanel();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param changed
|
||||
* @param readOnly
|
||||
* Call {@link DetailPane#updateToolbar(boolean, boolean)}
|
||||
* @param changed true if header tab has changed
|
||||
* @param readOnly true if header tab is readonly
|
||||
*/
|
||||
public void updateDetailPaneToolbar(boolean changed, boolean readOnly);
|
||||
|
||||
/**
|
||||
* Set selected tab of {@link DetailPane} to tabIndex.
|
||||
* @param tabIndex
|
||||
* @param currentRow
|
||||
* @param currentRow set current row of tab at tabIndex to currentRow
|
||||
*/
|
||||
public void setDetailPaneSelectedTab(int tabIndex, int currentRow);
|
||||
|
||||
/**
|
||||
* @return true if all the tabs of detail pane have been linked up with adtabpanel
|
||||
* @return true if all the tabs of detail pane have been linked up with header tab
|
||||
*/
|
||||
public boolean isDetailPaneLoaded();
|
||||
|
||||
|
|
|
@ -21,13 +21,16 @@ import org.zkoss.zul.Button;
|
|||
import org.zkoss.zul.Toolbar;
|
||||
|
||||
/**
|
||||
* Interface for UI component that edit/display record using ad_tab definitions
|
||||
* Interface for AD_Tab UI (with all the AD_Fields definition)
|
||||
* @author Low Heng Sin
|
||||
*
|
||||
*/
|
||||
public interface IADTabpanel extends Component, Evaluatee {
|
||||
|
||||
/** Activate/Deactivate event for IADTabpanel. Fire for init or after tab selection changed. **/
|
||||
public static final String ON_ACTIVATE_EVENT = "onActivate";
|
||||
|
||||
/** Component boolean attribute to indicate ON_ACTIVATE_EVENT have been posted for the current execution cycle **/
|
||||
public static final String ATTR_ON_ACTIVATE_POSTED = "org.adempiere.webui.adwindow.IADTabpanel.onActivatePosted";
|
||||
|
||||
/**
|
||||
|
@ -47,12 +50,12 @@ public interface IADTabpanel extends Component, Evaluatee {
|
|||
public int getTabLevel();
|
||||
|
||||
/**
|
||||
* @return tablename
|
||||
* @return table name from GridTab
|
||||
*/
|
||||
public String getTableName();
|
||||
|
||||
/**
|
||||
* @return record ID
|
||||
* @return record ID of current row
|
||||
*/
|
||||
public int getRecord_ID();
|
||||
|
||||
|
@ -62,40 +65,39 @@ public interface IADTabpanel extends Component, Evaluatee {
|
|||
public boolean isCurrent();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return title
|
||||
* @return title of tab
|
||||
*/
|
||||
public String getTitle();
|
||||
|
||||
/**
|
||||
* Render the panel
|
||||
* Layout fields of the tab panel
|
||||
*/
|
||||
public void createUI();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return GridTab
|
||||
* @return {@link GridTab} instance that back this IADTabpanel instance
|
||||
*/
|
||||
public GridTab getGridTab();
|
||||
|
||||
/**
|
||||
* activate/deactivate the panel
|
||||
* Activate/deactivate this IADTabpanel instance.
|
||||
* Call by init or after tab selection changed.
|
||||
* @param b
|
||||
*/
|
||||
public void activate(boolean b);
|
||||
|
||||
/**
|
||||
* retrieve data from db
|
||||
* Execute query through the backed {@link GridTab} instance.
|
||||
*/
|
||||
public void query();
|
||||
|
||||
/**
|
||||
* Refresh from db
|
||||
* Refresh data through the backed {@link GridTab} instance.
|
||||
*/
|
||||
public void refresh();
|
||||
|
||||
/**
|
||||
* retrieve data from db
|
||||
* Call {@link GridTab#query(boolean, int, int)}
|
||||
* @param currentRows
|
||||
* @param currentDays
|
||||
* @param maxRows
|
||||
|
@ -103,58 +105,56 @@ public interface IADTabpanel extends Component, Evaluatee {
|
|||
public void query(boolean currentRows, int currentDays, int maxRows);
|
||||
|
||||
/**
|
||||
* Toggle between grid and form view
|
||||
* Switch between grid/list and form view
|
||||
*/
|
||||
public void switchRowPresentation();
|
||||
|
||||
/**
|
||||
* Dynamic update of field properties ( visibility, filter and mandatory )
|
||||
* @param i
|
||||
* Dynamic update of every field's UI properties ( visibility, filter and mandatory ).
|
||||
* @param col optional column name
|
||||
*/
|
||||
public void dynamicDisplay(int i);
|
||||
public void dynamicDisplay(int col);
|
||||
|
||||
/**
|
||||
* After save event
|
||||
* Handle after save event
|
||||
* @param onSaveEvent
|
||||
*/
|
||||
public void afterSave(boolean onSaveEvent);
|
||||
|
||||
/**
|
||||
* Enter key event
|
||||
* Handle enter key event
|
||||
* @return true if the event is process
|
||||
*/
|
||||
public boolean onEnterKey();
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
* @return true if current presentation of the tab panel is grid/list view
|
||||
*/
|
||||
public boolean isGridView();
|
||||
|
||||
/**
|
||||
* @return true if the panel have been activated
|
||||
* @return true if the tab panel have been activated
|
||||
*/
|
||||
public boolean isActivated();
|
||||
|
||||
/**
|
||||
*
|
||||
* Turn on/off detail mode, i.e either tab panel is currently a header or detail tab of the UI.
|
||||
* @param detailMode
|
||||
*/
|
||||
public void setDetailPaneMode(boolean detailMode);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if the panel is in detailpane node
|
||||
* @return true if the panel is in detail mode (i.e a detail tab in DetailPane)
|
||||
*/
|
||||
public boolean isDetailPaneMode();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return gridview instance
|
||||
* @return {@link GridView} instance
|
||||
*/
|
||||
public GridView getGridView();
|
||||
|
||||
/**
|
||||
*
|
||||
* Call {@link GridTab#needSave(boolean, boolean)}
|
||||
* @param rowChange
|
||||
* @param onlyRealChange
|
||||
* @return true if there are pending changes
|
||||
|
@ -162,70 +162,71 @@ public interface IADTabpanel extends Component, Evaluatee {
|
|||
public boolean needSave(boolean rowChange, boolean onlyRealChange);
|
||||
|
||||
/**
|
||||
* Save changes.
|
||||
* Call {@link GridTab#dataSave(boolean)}
|
||||
* @param onSaveEvent
|
||||
* @return true if the save operation completed successfully
|
||||
*/
|
||||
public boolean dataSave(boolean onSaveEvent);
|
||||
|
||||
/**
|
||||
*
|
||||
* Set tab number/sequence within an AD_Window
|
||||
* @param tabNo
|
||||
*/
|
||||
public void setTabNo(int tabNo);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return tab no ( ad_tab.tabno )
|
||||
*/
|
||||
public int getTabNo();
|
||||
|
||||
/**
|
||||
*
|
||||
* Set the {@link DetailPane} part that own this IADTabpanel instance
|
||||
* @param detailPane
|
||||
*/
|
||||
public void setDetailPane(DetailPane detailPane);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return detailpane
|
||||
* @return the {@link DetailPane} part that own this IADTabpanel instance
|
||||
*/
|
||||
public DetailPane getDetailPane();
|
||||
|
||||
/**
|
||||
* reset detail data grid when parent tab current record is new and not saved yet
|
||||
* Reset detail data grid when parent tab current record is new and not saved yet.
|
||||
* Call {@link GridTab#resetDetailForNewParentRecord()}
|
||||
*/
|
||||
public void resetDetailForNewParentRecord();
|
||||
|
||||
/**
|
||||
* @return treepanel instance
|
||||
* @return {@link ADTreePanel} instance
|
||||
*/
|
||||
public ADTreePanel getTreePanel();
|
||||
|
||||
/**
|
||||
* @return Quick Form Button Enabled/Disabled
|
||||
* @return true if Quick Form Button is Enabled
|
||||
*/
|
||||
public boolean isEnableQuickFormButton();
|
||||
|
||||
/**
|
||||
* Get is detail pane visible
|
||||
* @return boolean
|
||||
* @return true if the containing {@link DetailPane} instance is visible
|
||||
*/
|
||||
public default boolean isDetailVisible() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of toolbar buttons
|
||||
* @return List of toolbar buttons
|
||||
*/
|
||||
public List<Button> getToolbarButtons();
|
||||
|
||||
/**
|
||||
* @return customization enabled/disabled for tab
|
||||
* @return true if customize grid button is enabled
|
||||
*/
|
||||
public boolean isEnableCustomizeButton();
|
||||
|
||||
/**
|
||||
* @return process Button Enabled/Disabled
|
||||
* @return true if process Button is Enabled
|
||||
*/
|
||||
default public boolean isEnableProcessButton() {
|
||||
boolean isNewRow = getGridTab().getRowCount() == 0 || getGridTab().isNew();
|
||||
|
@ -233,14 +234,14 @@ public interface IADTabpanel extends Component, Evaluatee {
|
|||
}
|
||||
|
||||
/**
|
||||
* Enabled/Disabled tab toolbar button
|
||||
* Enabled/Disabled ADWindowToolbar buttons
|
||||
*
|
||||
* @param toolbar - {@link ADWindowToolbar}
|
||||
*/
|
||||
public void updateToolbar(ADWindowToolbar toolbar);
|
||||
|
||||
/**
|
||||
* Enabled/Disabled detail panel toolbar button
|
||||
* Enabled/Disabled {@link DetailPane} toolbar buttons
|
||||
*
|
||||
* @param toolbar - {@link Toolbar}
|
||||
*/
|
||||
|
|
|
@ -19,31 +19,30 @@ import org.adempiere.util.Callback;
|
|||
import org.adempiere.webui.editor.WEditor;
|
||||
|
||||
/**
|
||||
*
|
||||
* Interface for container that host one or more field editors
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public interface IFieldEditorContainer {
|
||||
/**
|
||||
* focus to first field editor
|
||||
* set focus to first field editor
|
||||
*/
|
||||
public void focusToFirstEditor();
|
||||
|
||||
/**
|
||||
* focus to next field editor from ref
|
||||
* set focus to next field editor from ref
|
||||
* @param ref
|
||||
*/
|
||||
public void focusToNextEditor(WEditor ref);
|
||||
|
||||
/**
|
||||
* helper method to loop thru editor collection of panel <br/>
|
||||
* can use on callout to check relative editor
|
||||
* Call editorTaverseCallback for all editors hosted by this container
|
||||
* @param editorTaverseCallback
|
||||
*/
|
||||
public void editorTraverse (Callback<WEditor> editorTaverseCallback);
|
||||
|
||||
/**
|
||||
* default implement for {@link #editorTraverse(Callback)}
|
||||
* Default implementation for {@link #editorTraverse(Callback)}
|
||||
* @param editorTaverseCallback
|
||||
* @param editors
|
||||
*/
|
||||
|
|
|
@ -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.adwindow;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -25,13 +46,16 @@ import org.zkoss.zul.Menuseparator;
|
|||
|
||||
/**
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class ProcessButtonPopup extends Menupopup implements EventListener<Event> {
|
||||
|
||||
private static final String DOCUMENT_ACTION_MENUITEM_ATTRIBUTE = "document-action-menuitem";
|
||||
/** sclass for document action menu items **/
|
||||
private static final String DOCUMENT_ACTION_MENUITEM_SCLASS = "document-action-menuitem";
|
||||
/** Menupopup attribute to store reference to WDocActionPanel **/
|
||||
private static final String DOC_ACTION_PANEL_ATTRIBUTE = "doc-action-panel";
|
||||
/** Menupopup/Menuitem attribute to store reference to Button **/
|
||||
private static final String BUTTON_ATTRIBUTE = "button";
|
||||
/** Button yes/no attribute (Y/N) to store whether button is pressed **/
|
||||
public static final String BUTTON_ATTRIBUTE_PRESSED = "buttonPressed";
|
||||
|
||||
/**
|
||||
|
@ -39,6 +63,11 @@ public class ProcessButtonPopup extends Menupopup implements EventListener<Event
|
|||
*/
|
||||
private static final long serialVersionUID = 304878472233552113L;
|
||||
|
||||
/**
|
||||
* Render buttons as menu items.
|
||||
* Special treatment for DocAction - render each available document action as a sub menu item.
|
||||
* @param buttons
|
||||
*/
|
||||
public void render(List<Button> buttons) {
|
||||
this.setSclass("z-menu-noimage");
|
||||
|
||||
|
@ -88,7 +117,7 @@ public class ProcessButtonPopup extends Menupopup implements EventListener<Event
|
|||
for(Listitem action : actions) {
|
||||
Menuitem mi = new Menuitem(action.getLabel());
|
||||
mi.setValue((String)action.getValue());
|
||||
mi.setSclass(DOCUMENT_ACTION_MENUITEM_ATTRIBUTE);
|
||||
mi.setSclass(DOCUMENT_ACTION_MENUITEM_SCLASS);
|
||||
mi.addEventListener(Events.ON_CLICK, this);
|
||||
popup.appendChild(mi);
|
||||
}
|
||||
|
@ -99,7 +128,7 @@ public class ProcessButtonPopup extends Menupopup implements EventListener<Event
|
|||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
Menuitem mi = (Menuitem) event.getTarget();
|
||||
if (DOCUMENT_ACTION_MENUITEM_ATTRIBUTE.equals(mi.getSclass())) {
|
||||
if (DOCUMENT_ACTION_MENUITEM_SCLASS.equals(mi.getSclass())) {
|
||||
final Button button = (Button) mi.getParent().getAttribute(BUTTON_ATTRIBUTE);
|
||||
WDocActionPanel panel = (WDocActionPanel) mi.getParent().getAttribute(DOC_ACTION_PANEL_ATTRIBUTE);
|
||||
panel.setSelectedItem(mi.getValue());
|
||||
|
|
|
@ -71,7 +71,7 @@ import org.zkoss.zul.RowRendererExt;
|
|||
import org.zkoss.zul.Timebox;
|
||||
|
||||
/**
|
||||
* Row renderer for Quick GridTab grid.
|
||||
* Row renderer for Quick GridTab grid (Base on {@link GridTabRowRenderer})
|
||||
*
|
||||
* @author Logilite Technologies
|
||||
* @since Nov 03, 2017
|
||||
|
@ -79,7 +79,9 @@ import org.zkoss.zul.Timebox;
|
|||
public class QuickGridTabRowRenderer
|
||||
implements RowRenderer<Object[]>, RowRendererExt, RendererCtrl, EventListener<Event> {
|
||||
|
||||
/** Component boolean attribute to indicate this component is own by QuickGridView **/
|
||||
public static final String IS_QUICK_FORM_COMPONENT = "IS_QUICK_FORM_COMPONENT";
|
||||
/** Editor component attribute to store row index (absolute) **/
|
||||
public static final String GRID_ROW_INDEX_ATTR = "grid.row.index";
|
||||
private static final String CELL_DIV_STYLE = "height: 100%; cursor: pointer; ";
|
||||
private static final String CELL_DIV_STYLE_ALIGN_CENTER = CELL_DIV_STYLE + "text-align:center; ";
|
||||
|
@ -90,18 +92,27 @@ public class QuickGridTabRowRenderer
|
|||
|
||||
private GridTab gridTab;
|
||||
private int windowNo;
|
||||
/** Sync field editor changes to GridField **/
|
||||
private GridTabDataBinder dataBinder;
|
||||
private Paging paging;
|
||||
|
||||
/** internal listener for row event **/
|
||||
private RowListener rowListener;
|
||||
|
||||
/** Grid that own this renderer **/
|
||||
private Grid grid = null;
|
||||
/** QuickGridView that uses this renderer **/
|
||||
private QuickGridView gridPanel = null;
|
||||
/** current focus row **/
|
||||
private Row currentRow;
|
||||
/** values of current row. updated in {@link #render(Row, Object[], int)}. **/
|
||||
private Object[] currentValues;
|
||||
/** true if currrent row is in edit mode **/
|
||||
private boolean editing = false;
|
||||
public int currentRowIndex = -1;
|
||||
/** AD window content part that own this renderer **/
|
||||
private AbstractADWindowContent m_windowPanel;
|
||||
/** internal listener for button ActionEvent **/
|
||||
private ActionListener buttonListener;
|
||||
// Row-wise Editors Map
|
||||
public Map<Row, ArrayList<WEditor>> editorsListMap = new LinkedHashMap<Row, ArrayList<WEditor>>();
|
||||
|
@ -128,6 +139,12 @@ public class QuickGridTabRowRenderer
|
|||
this.dataBinder = new GridTabDataBinder(gridTab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get editor for GridField and set value to object parameter.
|
||||
* @param gridField
|
||||
* @param object
|
||||
* @return {@link WEditor}
|
||||
*/
|
||||
private WEditor getEditorCell(GridField gridField, Object object) {
|
||||
WEditor editor = WebEditorFactory.getEditor(gridField, true);
|
||||
if (editor != null) {
|
||||
|
@ -137,6 +154,11 @@ public class QuickGridTabRowRenderer
|
|||
return editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup field editor
|
||||
* @param gridField
|
||||
* @param editor
|
||||
*/
|
||||
private void prepareFieldEditor(GridField gridField, WEditor editor) {
|
||||
if (editor instanceof WButtonEditor)
|
||||
{
|
||||
|
@ -161,6 +183,10 @@ public class QuickGridTabRowRenderer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field
|
||||
* @return column index for field, -1 if not found
|
||||
*/
|
||||
public int getColumnIndex(GridField field) {
|
||||
GridField[] fields = gridPanel.getFields();
|
||||
for(int i = 0; i < fields.length; i++) {
|
||||
|
@ -178,6 +204,7 @@ public class QuickGridTabRowRenderer
|
|||
}
|
||||
|
||||
/**
|
||||
* Render data for row.
|
||||
* @param row
|
||||
* @param data
|
||||
* @param index
|
||||
|
@ -409,7 +436,7 @@ public class QuickGridTabRowRenderer
|
|||
*
|
||||
* @param component
|
||||
* @param isDisable
|
||||
* @return
|
||||
* @return true if component is read only
|
||||
*/
|
||||
public boolean isDisableReadonlyComponent(Component component, boolean isDisable)
|
||||
{
|
||||
|
@ -548,7 +575,7 @@ public class QuickGridTabRowRenderer
|
|||
*
|
||||
* @param zclass
|
||||
* @param isDisable
|
||||
* @return
|
||||
* @return modify zclass
|
||||
*/
|
||||
private String addOrRemoveCssClass(String zclass, boolean isDisable)
|
||||
{
|
||||
|
@ -568,14 +595,27 @@ public class QuickGridTabRowRenderer
|
|||
|
||||
private Cell currentCell = null;
|
||||
|
||||
/**
|
||||
* @return current {@link Cell}
|
||||
*/
|
||||
public Cell getCurrentCell() {
|
||||
return currentCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current cell
|
||||
* @param currentCell
|
||||
*/
|
||||
public void setCurrentCell(Cell currentCell) {
|
||||
this.currentCell = currentCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current cell
|
||||
* @param row
|
||||
* @param col
|
||||
* @param code cell navigation code (right, left, down, up, next)
|
||||
*/
|
||||
public void setCurrentCell(int row, int col, int code) {
|
||||
if (col < 0 || row < 0)
|
||||
return;
|
||||
|
@ -660,7 +700,7 @@ public class QuickGridTabRowRenderer
|
|||
}
|
||||
|
||||
/**
|
||||
* Set Property change listener of editor field
|
||||
* Add property change listener (WEditor) to GridField
|
||||
*
|
||||
* @param editorsList
|
||||
*/
|
||||
|
@ -676,7 +716,7 @@ public class QuickGridTabRowRenderer
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove Property change listener of editor field
|
||||
* Remove property change listener (WEditor) from GridField
|
||||
*
|
||||
* @param editorsList
|
||||
*/
|
||||
|
@ -691,7 +731,7 @@ public class QuickGridTabRowRenderer
|
|||
}
|
||||
|
||||
/**
|
||||
* If true add Property Change Listener, a false Remove Property Change Listener
|
||||
* If isAddListener is true add Property Change Listener, otherwise Remove Property Change Listener
|
||||
*
|
||||
* @param isAddListener
|
||||
* @param col
|
||||
|
@ -714,8 +754,8 @@ public class QuickGridTabRowRenderer
|
|||
} // addRemovePropertyChangeListener
|
||||
|
||||
/**
|
||||
* @param code
|
||||
* @return
|
||||
* @param code cell navigation code
|
||||
* @return true to add property change listener, false otherwise
|
||||
*/
|
||||
public Boolean isAddRemoveListener(int code)
|
||||
{
|
||||
|
@ -726,7 +766,8 @@ public class QuickGridTabRowRenderer
|
|||
} // isAddRemoveListener
|
||||
|
||||
/**
|
||||
* @param row
|
||||
* Set current row
|
||||
* @param row absolute row index
|
||||
*/
|
||||
public void setRowTo(int row)
|
||||
{
|
||||
|
@ -736,6 +777,11 @@ public class QuickGridTabRowRenderer
|
|||
setCurrentRow(currentRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row
|
||||
* @param col
|
||||
* @return true if cell is editable, false otherwise
|
||||
*/
|
||||
private boolean isEditable(int row, int col)
|
||||
{
|
||||
Cell cell = null;
|
||||
|
@ -790,6 +836,9 @@ public class QuickGridTabRowRenderer
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set focus to {@link #currentCell}
|
||||
*/
|
||||
public void setFocusOnCurrentCell() {
|
||||
if (currentCell == null || currentCell.getChildren().size() <= 0) {
|
||||
return;
|
||||
|
@ -845,6 +894,7 @@ public class QuickGridTabRowRenderer
|
|||
} // setFocusOnCurrentCell
|
||||
|
||||
/**
|
||||
* Set current focus row
|
||||
* @param row
|
||||
*/
|
||||
public void setCurrentRow(Row row)
|
||||
|
@ -876,7 +926,7 @@ public class QuickGridTabRowRenderer
|
|||
}
|
||||
|
||||
/**
|
||||
* Enter edit mode
|
||||
* Enter edit mode for current focus row.
|
||||
*/
|
||||
public void editCurrentRow() {
|
||||
if (currentRow != null && currentRow.getParent() != null && currentRow.isVisible() && grid != null
|
||||
|
@ -929,13 +979,16 @@ public class QuickGridTabRowRenderer
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Set {@link QuickGridView} that own this renderer.
|
||||
* @param gridPanel
|
||||
*/
|
||||
public void setGridPanel(QuickGridView gridPanel) {
|
||||
this.gridPanel = gridPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal listener for row event (ON_CLICK, ON_DOUBLE_CLICK and ON_OK).
|
||||
*/
|
||||
static class RowListener implements EventListener<Event> {
|
||||
|
||||
private Grid _grid;
|
||||
|
@ -964,13 +1017,15 @@ public class QuickGridTabRowRenderer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
* @return true if current row is in edit mode, false otherwise
|
||||
*/
|
||||
public boolean isEditing() {
|
||||
return editing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set AD window content part that own this renderer.
|
||||
* {@link #buttonListener} need this to call {@link AbstractADWindowContent#actionPerformed(ActionEvent)}.
|
||||
* @param windowPanel
|
||||
*/
|
||||
public void setADWindowPanel(AbstractADWindowContent windowPanel) {
|
||||
|
|
|
@ -73,7 +73,7 @@ import org.zkoss.zul.event.ZulEvents;
|
|||
import org.zkoss.zul.impl.CustomGridDataLoader;
|
||||
|
||||
/**
|
||||
* Quick Grid view implemented using the Grid component.
|
||||
* Quick Grid view implemented using the Grid component (Base on {@link GridView}).
|
||||
*
|
||||
* @author Logilite Technologies
|
||||
* @since Nov 03, 2017
|
||||
|
@ -81,30 +81,39 @@ import org.zkoss.zul.impl.CustomGridDataLoader;
|
|||
public class QuickGridView extends Vbox
|
||||
implements EventListener<Event>, IdSpace, IFieldEditorContainer, StateChangeListener {
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 228387400133234920L;
|
||||
|
||||
static CLogger log = CLogger.getCLogger(QuickGridView.class);
|
||||
|
||||
/** Style for Grid and Grid Footer **/
|
||||
private static final String HEADER_GRID_STYLE = "border: none; margin:0; padding: 0;";
|
||||
|
||||
/** default paging size **/
|
||||
private static final int DEFAULT_PAGE_SIZE = 20;
|
||||
|
||||
/** default paging size for mobile client **/
|
||||
private static final int DEFAULT_MOBILE_PAGE_SIZE = 20;
|
||||
|
||||
/** minimum column width **/
|
||||
private static final int MIN_COLUMN_WIDTH = 100;
|
||||
|
||||
/** maximum column width **/
|
||||
private static final int MAX_COLUMN_WIDTH = 300;
|
||||
|
||||
/** minimum column width for combobox field **/
|
||||
private static final int MIN_COMBOBOX_WIDTH = 160;
|
||||
|
||||
/** minimum column width for numeric field **/
|
||||
private static final int MIN_NUMERIC_COL_WIDTH = 120;
|
||||
|
||||
public static final int SALES_ORDER_LINE_TAB_ID = 187;
|
||||
|
||||
/** GridView boolean attribute to indicate ON_POST_SELECTED_ROW_CHANGED_EVENT have been posted in current execution cycle **/
|
||||
private static final String ATTR_ON_POST_SELECTED_ROW_CHANGED = "org.adempiere.webui.adwindow.GridView.onPostSelectedRowChanged";
|
||||
|
||||
/** shortcut key for cell navigation **/
|
||||
public static final String CNTRL_KEYS = "#left#right#up#down#home@k@r";
|
||||
|
||||
// 'Enter' Work as Down key
|
||||
|
@ -123,47 +132,63 @@ public class QuickGridView extends Vbox
|
|||
public static final int NAVIGATE_CODE = 1;
|
||||
public static final int FOCUS_CODE = 0;
|
||||
|
||||
/** data grid instance **/
|
||||
private Grid listbox = null;
|
||||
|
||||
private int pageSize = DEFAULT_PAGE_SIZE;
|
||||
|
||||
/**
|
||||
* list field display in grid mode, in case user customize grid
|
||||
* this list container only customize list.
|
||||
* this list container only display list.
|
||||
*/
|
||||
private GridField[] gridFields;
|
||||
|
||||
/** GridTable model for GridTab **/
|
||||
private AbstractTableModel tableModel;
|
||||
|
||||
private int numColumns = 5;
|
||||
|
||||
private int windowNo;
|
||||
|
||||
/** GridTab that back this QuickGridView **/
|
||||
private GridTab gridTab;
|
||||
|
||||
/** true if this QuickGridView instance have been init with GridTab **/
|
||||
private boolean init;
|
||||
|
||||
/** Zk List model for {@link #tableModel} **/
|
||||
public GridTableListModel listModel;
|
||||
|
||||
public Paging paging;
|
||||
|
||||
/** Row renderer for this QuickGridView instance **/
|
||||
private QuickGridTabRowRenderer renderer;
|
||||
|
||||
/** Footer for paging **/
|
||||
private Div gridFooter;
|
||||
|
||||
/** true if current row is always in edit mode **/
|
||||
private boolean modeless = true;
|
||||
|
||||
/** AD window content part that own this GridView instance **/
|
||||
private AbstractADWindowContent windowPanel;
|
||||
|
||||
/** true when grid is refreshing its data **/
|
||||
private boolean refreshing;
|
||||
|
||||
/** AD_Field_ID:Column Width **/
|
||||
private Map<Integer, String> columnWidthMap;
|
||||
|
||||
/** checkbox to select all row of current page **/
|
||||
protected Checkbox selectAll;
|
||||
|
||||
boolean isHasCustomizeData = false;
|
||||
/** true if there are AD_Tab_Customization for GridTab **/
|
||||
protected boolean isHasCustomizeData = false;
|
||||
|
||||
Keylistener keyListener;
|
||||
/** reference to desktop key listener **/
|
||||
protected Keylistener keyListener;
|
||||
|
||||
/** true if no new row or new row have been saved **/
|
||||
public boolean isNewLineSaved = true;
|
||||
|
||||
// Prevent focus change until render is complete
|
||||
|
@ -171,16 +196,28 @@ public class QuickGridView extends Vbox
|
|||
// To prevent 'onFocus' event fire twice on same component.
|
||||
private Component preEventComponent;
|
||||
|
||||
public IQuickForm quickForm;
|
||||
/** IQuickForm that own this QuickGridView instance **/
|
||||
public IQuickForm quickForm;
|
||||
|
||||
/**
|
||||
* list field display in grid mode, in case user customize grid
|
||||
* this list container only customize list.
|
||||
* @return GridField[]
|
||||
*/
|
||||
public GridField[] getGridField() {
|
||||
return gridFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param gridField
|
||||
*/
|
||||
public void setGridField(GridField[] gridField) {
|
||||
this.gridFields = gridField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link QuickGridTabRowRenderer}
|
||||
*/
|
||||
public QuickGridTabRowRenderer getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
@ -239,6 +276,11 @@ public class QuickGridView extends Vbox
|
|||
addEventListener(EVENT_ONFOCUS_AFTER_SAVE, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param abstractADWindowContent
|
||||
* @param gridTab
|
||||
* @param wQuickForm
|
||||
*/
|
||||
public QuickGridView(AbstractADWindowContent abstractADWindowContent, GridTab gridTab, IQuickForm wQuickForm)
|
||||
{
|
||||
this(abstractADWindowContent.getWindowNo());
|
||||
|
@ -247,6 +289,9 @@ public class QuickGridView extends Vbox
|
|||
init(gridTab);
|
||||
}
|
||||
|
||||
/**
|
||||
* create data grid instances
|
||||
*/
|
||||
protected void createListbox()
|
||||
{
|
||||
listbox = new Grid();
|
||||
|
@ -258,7 +303,7 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Init data grid
|
||||
* @param gridTab
|
||||
*/
|
||||
public void init(GridTab gridTab)
|
||||
|
@ -278,6 +323,10 @@ public class QuickGridView extends Vbox
|
|||
this.init = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup {@link #gridFields} from gridTab.
|
||||
* @param gridTab
|
||||
*/
|
||||
private void setupFields(GridTab gridTab) {
|
||||
this.gridTab = gridTab;
|
||||
gridTab.addStateChangeListener(this);
|
||||
|
@ -370,14 +419,14 @@ public class QuickGridView extends Vbox
|
|||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
* @return true if data grid have been init with GridTab
|
||||
*/
|
||||
public boolean isInit() {
|
||||
return init;
|
||||
}
|
||||
|
||||
/**
|
||||
* refresh after switching from form view
|
||||
* Refresh data grid (int of quick form or column setup has change)
|
||||
* @param gridTab
|
||||
*/
|
||||
public void refresh(GridTab gridTab) {
|
||||
|
@ -397,12 +446,15 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if data grid is refreshing data from GridTab
|
||||
*/
|
||||
public boolean isRefreshing() {
|
||||
return refreshing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update current row from model
|
||||
* Update current row index from model
|
||||
*/
|
||||
public void updateListIndex() {
|
||||
if (gridTab == null || !gridTab.isOpen()) return;
|
||||
|
@ -451,18 +503,24 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hide paging component
|
||||
*/
|
||||
private void hidePagingControl() {
|
||||
if (gridFooter.isVisible())
|
||||
gridFooter.setVisible(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* show paging component
|
||||
*/
|
||||
private void showPagingControl() {
|
||||
if (!gridFooter.isVisible())
|
||||
gridFooter.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* echo ON_POST_SELECTED_ROW_CHANGED_EVENT after current row index has changed
|
||||
*/
|
||||
protected void echoOnPostSelectedRowChanged() {
|
||||
if (getAttribute(ATTR_ON_POST_SELECTED_ROW_CHANGED) == null) {
|
||||
|
@ -480,11 +538,17 @@ public class QuickGridView extends Vbox
|
|||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove all components
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
this.getChildren().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup {@link Columns} of data grid
|
||||
*/
|
||||
private void setupColumns()
|
||||
{
|
||||
if (init) return;
|
||||
|
@ -608,6 +672,9 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render data grid
|
||||
*/
|
||||
private void render()
|
||||
{
|
||||
updateEmptyMessage();
|
||||
|
@ -635,6 +702,9 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show zero records for processing message
|
||||
*/
|
||||
private void updateEmptyMessage() {
|
||||
if (gridTab.getRowCount() == 0)
|
||||
{
|
||||
|
@ -646,6 +716,10 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update {@link #listModel} with {@link #tableModel} changes.
|
||||
* Re-create {@link #renderer}.
|
||||
*/
|
||||
private void updateModel() {
|
||||
if (listModel != null)
|
||||
((GridTable)tableModel).removeTableModelListener(listModel);
|
||||
|
@ -1128,6 +1202,10 @@ public class QuickGridView extends Vbox
|
|||
event.stopPropagation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set focus to cell (source)
|
||||
* @param source
|
||||
*/
|
||||
private void setFocusOnDiv(Component source) {
|
||||
int rowCount = gridTab.getTableModel().getRowCount();
|
||||
int colCount = renderer.getCurrentRow().getChildren().size();
|
||||
|
@ -1141,6 +1219,9 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if all row of current page is selected
|
||||
*/
|
||||
public boolean isAllSelected() {
|
||||
org.zkoss.zul.Rows rows = listbox.getRows();
|
||||
List<Component> childs = rows.getChildren();
|
||||
|
@ -1162,6 +1243,10 @@ public class QuickGridView extends Vbox
|
|||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* turn on/off select all rows for current page
|
||||
* @param b
|
||||
*/
|
||||
public void toggleSelectionForAll(boolean b) {
|
||||
org.zkoss.zul.Rows rows = listbox.getRows();
|
||||
List<Component> childs = rows.getChildren();
|
||||
|
@ -1188,6 +1273,10 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update list model and data grid with new current row index
|
||||
* @param index
|
||||
*/
|
||||
private void onSelectedRowChange(int index) {
|
||||
if (updateModelIndex(index)) {
|
||||
updateListIndex();
|
||||
|
@ -1195,7 +1284,12 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
|
||||
/**
|
||||
* Event after the current selected row change
|
||||
* Save changes.
|
||||
* Call {@link #dataSave(int)}
|
||||
* @param code cell navigation code
|
||||
* @param row
|
||||
* @param col
|
||||
* @return true if save succesfully
|
||||
*/
|
||||
private boolean save(int code, int row, int col)
|
||||
{
|
||||
|
@ -1211,6 +1305,9 @@ public class QuickGridView extends Vbox
|
|||
return isSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event after the current row index has changed.
|
||||
*/
|
||||
public void onPostSelectedRowChanged() {
|
||||
removeAttribute(ATTR_ON_POST_SELECTED_ROW_CHANGED);
|
||||
if (listbox.getRows() == null || listbox.getRows().getChildren().isEmpty())
|
||||
|
@ -1244,6 +1341,11 @@ public class QuickGridView extends Vbox
|
|||
onPostSelectedRowChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row
|
||||
* @param index
|
||||
* @return true if row have been rendered by row renderer
|
||||
*/
|
||||
private boolean isRowRendered(org.zkoss.zul.Row row, int index) {
|
||||
if (row.getChildren().size() == 0) {
|
||||
return false;
|
||||
|
@ -1255,6 +1357,11 @@ public class QuickGridView extends Vbox
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update gridTab current row index.
|
||||
* @param rowIndex row index of current page
|
||||
* @return true if gridTab current row index has change
|
||||
*/
|
||||
public boolean updateModelIndex(int rowIndex) {
|
||||
if (pageSize > 0) {
|
||||
int start = listModel.getPage() * listModel.getPageSize();
|
||||
|
@ -1309,9 +1416,8 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
|
||||
/**
|
||||
* Change display properties of current row
|
||||
*
|
||||
* @param noData
|
||||
* Perform dynamic display for editors in list
|
||||
* @param noData true if data grid is empty
|
||||
* @param list
|
||||
*/
|
||||
private void dynamicDisplayEditors(boolean noData, List<WEditor> list) {
|
||||
|
@ -1367,6 +1473,7 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
|
||||
/**
|
||||
* Set AD window content part that own this QuickGridView instance
|
||||
* @param winPanel
|
||||
*/
|
||||
public void setADWindowPanel(AbstractADWindowContent winPanel) {
|
||||
|
@ -1375,6 +1482,9 @@ public class QuickGridView extends Vbox
|
|||
renderer.setADWindowPanel(windowPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-Init QuickGridView with cache gridTab.
|
||||
*/
|
||||
public void reInit() {
|
||||
listbox.getChildren().clear();
|
||||
listbox.detach();
|
||||
|
@ -1400,6 +1510,7 @@ public class QuickGridView extends Vbox
|
|||
/**
|
||||
* list field display in grid mode, in case user customize grid
|
||||
* this list container only customize list.
|
||||
* @return GridField[]
|
||||
*/
|
||||
public GridField[] getFields() {
|
||||
return gridFields;
|
||||
|
@ -1430,10 +1541,16 @@ public class QuickGridView extends Vbox
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* not used. candidate for removal.
|
||||
*/
|
||||
protected void onADTabPanelParentChanged() {
|
||||
positionPagingControl();
|
||||
}
|
||||
|
||||
/**
|
||||
* not used. candidate for removal.
|
||||
*/
|
||||
private void positionPagingControl()
|
||||
{
|
||||
if (gridFooter.getParent() != this)
|
||||
|
@ -1446,18 +1563,27 @@ public class QuickGridView extends Vbox
|
|||
paging.setDetailed(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* set status text
|
||||
* @param text
|
||||
* @param error
|
||||
*/
|
||||
public void setStatusLine(String text, boolean error)
|
||||
{
|
||||
windowPanel.getStatusBarQF().setStatusLine(text, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* add new row to data grid
|
||||
*/
|
||||
public void createNewLine() {
|
||||
isNewLineSaved = false;
|
||||
gridTab.dataNew(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param code
|
||||
* Save changes
|
||||
* @param code cell navigation code
|
||||
*/
|
||||
public boolean dataSave(int code) {
|
||||
boolean isSave = false;
|
||||
|
@ -1501,6 +1627,10 @@ public class QuickGridView extends Vbox
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source
|
||||
* @return row that own source cell
|
||||
*/
|
||||
private int getFocusedRowIndex(Component source)
|
||||
{
|
||||
int rowCount = gridTab.getTableModel().getRowCount();
|
||||
|
@ -1516,6 +1646,9 @@ public class QuickGridView extends Vbox
|
|||
return 0;
|
||||
} // getFocusedRowIndex
|
||||
|
||||
/**
|
||||
* @return sort column (if any)
|
||||
*/
|
||||
public Column findCurrentSortColumn()
|
||||
{
|
||||
if (listbox.getColumns() != null)
|
||||
|
|
|
@ -45,6 +45,8 @@ import org.zkoss.zul.Separator;
|
|||
import org.zkoss.zul.Space;
|
||||
|
||||
/**
|
||||
* Status bar component of AD Window.
|
||||
*
|
||||
* This class is based on org.compiere.apps.StatusBar written by Jorg Janke.
|
||||
* @author Jorg Janke
|
||||
*
|
||||
|
@ -55,32 +57,45 @@ import org.zkoss.zul.Space;
|
|||
public class StatusBar extends Panel implements EventListener<Event>
|
||||
{
|
||||
/**
|
||||
*
|
||||
* generated serial id
|
||||
*/
|
||||
private static final long serialVersionUID = 7091641684809092888L;
|
||||
|
||||
/** panel for record info text **/
|
||||
private Panel infoPanel;
|
||||
|
||||
/** html content of {@link #infoPanel} **/
|
||||
private Html infoLine;
|
||||
|
||||
/** west div for status text (info or error message) **/
|
||||
private Div west;
|
||||
|
||||
/** east div for record info text **/
|
||||
private Div east;
|
||||
|
||||
private ProcessInfoLog[] pInfoLogs;
|
||||
|
||||
/** current status text **/
|
||||
private String m_statusText;
|
||||
|
||||
/** indicate current status text is info or error message */
|
||||
private boolean m_statusError;
|
||||
|
||||
/** message popup **/
|
||||
private Window msgPopup;
|
||||
|
||||
/** content div for {@link #msgPopup} **/
|
||||
private Div msgPopupCnt;
|
||||
|
||||
/** layout for {@link #west} **/
|
||||
private Hlayout messageContainer;
|
||||
|
||||
/** Caption for {@link #msgPopup} **/
|
||||
private Caption msgPopupCaption;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public StatusBar()
|
||||
{
|
||||
super();
|
||||
|
@ -89,6 +104,10 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
createPopup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout status bar.
|
||||
* West is for message and East is for HTML record info (usually generated from AD_StatusLine).
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
infoPanel = new Panel();
|
||||
|
@ -114,7 +133,7 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Set Info Line
|
||||
* Set record Info Line
|
||||
* @param text text
|
||||
*/
|
||||
public void setInfo (String text)
|
||||
|
@ -128,6 +147,7 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
} // setInfo
|
||||
|
||||
/**
|
||||
* Call {@link #setStatusLine(String, boolean, ProcessInfoLog[])}.
|
||||
* @param text
|
||||
*/
|
||||
public void setStatusLine (String text)
|
||||
|
@ -136,6 +156,7 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Call {@link #setStatusLine(String, boolean, ProcessInfoLog[])}.
|
||||
* @param text
|
||||
* @param error
|
||||
*/
|
||||
|
@ -145,6 +166,7 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
* Set status message (west part) text.
|
||||
* @param text
|
||||
* @param error
|
||||
* @param m_logs
|
||||
|
@ -154,6 +176,7 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
pInfoLogs = m_logs;
|
||||
Div div = null;
|
||||
|
||||
//detect duplicate call within the current execution cycle
|
||||
Execution execution = Executions.getCurrent();
|
||||
if (execution != null) {
|
||||
String key = this.getClass().getName()+"."+getUuid();
|
||||
|
@ -174,6 +197,7 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
if (text == null || text.trim().length() == 0 )
|
||||
return;
|
||||
|
||||
//show auto dismiss popup notification at top left of ancestor tab panel
|
||||
String labelText = buildLabelText(m_statusText);
|
||||
int duration = MSysConfig.getIntValue(MSysConfig.ZK_ERROR_MSG_LIFETIME_MILLISECONDS, 3500, Env.getAD_Client_ID(Env.getCtx()));
|
||||
if (error) {
|
||||
|
@ -206,6 +230,7 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
label.addEventListener(Events.ON_CLICK, this);
|
||||
}
|
||||
|
||||
//add document/record link from ProcessInfoLog
|
||||
if (m_logs != null) {
|
||||
div = new Div();
|
||||
for (int i = 0; i < m_logs.length; i++) {
|
||||
|
@ -228,6 +253,11 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shorten statusText if exceed predefine max length of 80
|
||||
* @param statusText
|
||||
* @return shorten statusText
|
||||
*/
|
||||
private String buildLabelText(String statusText) {
|
||||
if (statusText == null)
|
||||
return "";
|
||||
|
@ -240,12 +270,20 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
return statusText.substring(0, 80);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create html content for {@link #msgPopupCnt}
|
||||
*/
|
||||
protected void createPopupContent() {
|
||||
Html t = new Html(WTextEditorDialog.sanitize(m_statusText));
|
||||
msgPopupCnt.getChildren().clear();
|
||||
msgPopupCnt.appendChild(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten statusText if length exceed the predefine max length of 140
|
||||
* @param statusText
|
||||
* @return shorten statusText
|
||||
*/
|
||||
private String buildNotificationText(String statusText) {
|
||||
if (statusText == null)
|
||||
return "";
|
||||
|
@ -258,6 +296,11 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
return statusText.substring(0, 136) + " ...";
|
||||
}
|
||||
|
||||
/**
|
||||
* Find {@link Tabpanel} or {@link WQuickForm} that own comp
|
||||
* @param comp
|
||||
* @return
|
||||
*/
|
||||
private Component findTabpanel(Component comp) {
|
||||
Component parent = comp.getParent();
|
||||
while (parent != null) {
|
||||
|
@ -278,13 +321,15 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show message popup ({@link #msgPopup})
|
||||
*/
|
||||
private void showPopup() {
|
||||
appendChild(msgPopup);
|
||||
LayoutUtils.openOverlappedWindow(messageContainer, msgPopup, "overlap_end");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return process logs
|
||||
*/
|
||||
public ProcessInfoLog[] getPLogs() {
|
||||
|
@ -292,17 +337,22 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return current status line text
|
||||
*/
|
||||
* @return current status line text
|
||||
*/
|
||||
public String getStatusLine() {
|
||||
return m_statusText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if current status text is error text
|
||||
*/
|
||||
public boolean getStatusError() {
|
||||
return m_statusError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new message popup instance
|
||||
*/
|
||||
private void createPopup() {
|
||||
msgPopupCnt = new Div();
|
||||
ZKUpdateUtil.setVflex(msgPopupCnt, "1");
|
||||
|
@ -321,6 +371,9 @@ public class StatusBar extends Panel implements EventListener<Event>
|
|||
msgPopup.appendChild(msgPopupCaption);
|
||||
}
|
||||
|
||||
/**
|
||||
* handle onClientInfo event from browser
|
||||
*/
|
||||
protected void onClientInfo() {
|
||||
ZKUpdateUtil.setWindowWidthX(msgPopup, 500);
|
||||
}
|
||||
|
|
|
@ -27,18 +27,38 @@ import org.zkoss.zk.ui.event.EventListener;
|
|||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zul.Toolbarbutton;
|
||||
|
||||
/**
|
||||
* Model for AD_ToolBarButton with IsCustomization=Y
|
||||
* @author hengsin
|
||||
*/
|
||||
public class ToolbarCustomButton implements EventListener<Event>, Evaluatee {
|
||||
|
||||
/** Toolbarbutton instance **/
|
||||
private Toolbarbutton toolbarButton;
|
||||
/** AD_ToolBarButton.ActionClassName **/
|
||||
private String actionId;
|
||||
private int windowNo;
|
||||
private int tabNo = -1;
|
||||
/** model instance for AD_ToolBarButton **/
|
||||
private MToolBarButton mToolbarButton;
|
||||
|
||||
/**
|
||||
* @param mToolbarButton
|
||||
* @param btn
|
||||
* @param actionId
|
||||
* @param windowNo
|
||||
*/
|
||||
public ToolbarCustomButton(MToolBarButton mToolbarButton, Toolbarbutton btn, String actionId, int windowNo) {
|
||||
this(mToolbarButton, btn, actionId, windowNo, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mToolbarButton
|
||||
* @param btn
|
||||
* @param actionId
|
||||
* @param windowNo
|
||||
* @param tabNo
|
||||
*/
|
||||
public ToolbarCustomButton(MToolBarButton mToolbarButton, Toolbarbutton btn, String actionId, int windowNo, int tabNo) {
|
||||
toolbarButton = btn;
|
||||
this.actionId = actionId;
|
||||
|
@ -49,6 +69,9 @@ public class ToolbarCustomButton implements EventListener<Event>, Evaluatee {
|
|||
toolbarButton.addEventListener(Events.ON_CLICK, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link IAction#execute(Object)}.
|
||||
*/
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
IServiceHolder<IAction> serviceHolder = Actions.getAction(actionId);
|
||||
|
@ -77,10 +100,17 @@ public class ToolbarCustomButton implements EventListener<Event>, Evaluatee {
|
|||
return Env.getContext (Env.getCtx(), windowNo, tabNo, variableName, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate to {@link #dynamicDisplay(boolean)}
|
||||
*/
|
||||
public void dynamicDisplay() {
|
||||
dynamicDisplay(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic update of button state.
|
||||
* @param forceValidation if true, execute dynamic update event if button is in detached state
|
||||
*/
|
||||
public void dynamicDisplay(boolean forceValidation) {
|
||||
if (toolbarButton.getParent() == null && !forceValidation)
|
||||
return;
|
||||
|
@ -107,6 +137,9 @@ public class ToolbarCustomButton implements EventListener<Event>, Evaluatee {
|
|||
toolbarButton.setVisible(visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate pressedLogic (if defined)
|
||||
*/
|
||||
public void pressedLogic() {
|
||||
if (toolbarButton.getParent() == null)
|
||||
return;
|
||||
|
@ -130,6 +163,9 @@ public class ToolbarCustomButton implements EventListener<Event>, Evaluatee {
|
|||
((ToolBarButton) toolbarButton).setPressed(isPressed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate readOnlyLogic (if defined)
|
||||
*/
|
||||
public void readOnlyLogic() {
|
||||
if (toolbarButton.getParent() == null)
|
||||
return;
|
||||
|
@ -154,6 +190,13 @@ public class ToolbarCustomButton implements EventListener<Event>, Evaluatee {
|
|||
toolbarButton.setDisabled(isReadOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate SQL or boolean logic expression.
|
||||
* For SQL expression, return true if the SQL expression has result (it doesn't check the return value of the SQL statement).
|
||||
* @param logic
|
||||
* @param tabNo
|
||||
* @return result of evaluation of logic
|
||||
*/
|
||||
private boolean validateLogic(String logic, int tabNo) {
|
||||
boolean isValid = false;
|
||||
|
||||
|
@ -169,6 +212,9 @@ public class ToolbarCustomButton implements EventListener<Event>, Evaluatee {
|
|||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link Toolbarbutton}
|
||||
*/
|
||||
public Toolbarbutton getToolbarbutton() {
|
||||
return toolbarButton;
|
||||
}
|
||||
|
|
|
@ -28,22 +28,30 @@ import org.zkoss.zk.ui.event.Events;
|
|||
import org.zkoss.zul.Button;
|
||||
|
||||
/**
|
||||
* Model for AD_ToolBarButton with AD_Process_ID > 0
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class ToolbarProcessButton implements IProcessButton, Evaluatee {
|
||||
|
||||
/** model instance for AD_ToolBarButton **/
|
||||
private MToolBarButton mToolbarButton;
|
||||
private IADTabpanel adTabpanel;
|
||||
/** {@link IADTabpanel} that own this ToolbarProcessButton instance **/
|
||||
private IADTabpanel adTabpanel;
|
||||
/** translated process name **/
|
||||
private String name;
|
||||
/** translated process description **/
|
||||
private String description;
|
||||
/** ActionListener for button **/
|
||||
private ActionListener actionListener;
|
||||
/** Button instance **/
|
||||
private Button button;
|
||||
private int windowNo;
|
||||
|
||||
/**
|
||||
* @param windowNo
|
||||
*
|
||||
* @param mToolbarButton
|
||||
* @param adTabpanel
|
||||
* @param listener
|
||||
* @param windowNo
|
||||
*/
|
||||
public ToolbarProcessButton(MToolBarButton mToolbarButton, IADTabpanel adTabpanel, ActionListener listener, int windowNo) {
|
||||
this.mToolbarButton = mToolbarButton;
|
||||
|
@ -118,10 +126,16 @@ public class ToolbarProcessButton implements IProcessButton, Evaluatee {
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link Button}
|
||||
*/
|
||||
public Button getButton() {
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic update of button state.
|
||||
*/
|
||||
public void dynamicDisplay() {
|
||||
String displayLogic = mToolbarButton.getDisplayLogic();
|
||||
if (displayLogic == null || displayLogic.trim().length() == 0)
|
||||
|
@ -140,6 +154,9 @@ public class ToolbarProcessButton implements IProcessButton, Evaluatee {
|
|||
return Env.getContext (Env.getCtx(), windowNo, tabNo, variableName, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate readOnlyLogic (if defined)
|
||||
*/
|
||||
public void readOnlyLogic() {
|
||||
|
||||
String readOnlyLogic = mToolbarButton.getReadOnlyLogic();
|
||||
|
@ -150,6 +167,9 @@ public class ToolbarProcessButton implements IProcessButton, Evaluatee {
|
|||
button.setDisabled(disabled);
|
||||
} // readOnlyLogic
|
||||
|
||||
/**
|
||||
* Evaluate pressedLogic (if defined)
|
||||
*/
|
||||
public void pressedLogic() {
|
||||
|
||||
String pressedLogic = mToolbarButton.getPressedLogic();
|
||||
|
@ -160,8 +180,14 @@ public class ToolbarProcessButton implements IProcessButton, Evaluatee {
|
|||
button.setAttribute(ProcessButtonPopup.BUTTON_ATTRIBUTE_PRESSED, isPressed ? "Y" : "N");
|
||||
} // pressedLogic
|
||||
|
||||
/**
|
||||
* Evaluate SQL or boolean logic expression.
|
||||
* For SQL expression, return true if the SQL expression has result (it doesn't check the return value of the SQL statement).
|
||||
* @param logic SQL (@SQL=) or boolean expression
|
||||
* @param tabNo
|
||||
* @return result of evaluation of logic
|
||||
*/
|
||||
private boolean validateLogic(String logic, int tabNo) {
|
||||
|
||||
boolean isValid = false;
|
||||
if (logic.startsWith("@SQL=")) {
|
||||
isValid = Evaluator.parseSQLLogic(logic, Env.getCtx(), windowNo, tabNo, getColumnName());
|
||||
|
|
|
@ -1,7 +1,41 @@
|
|||
/***********************************************************************
|
||||
* 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.adwindow.validator;
|
||||
|
||||
import org.adempiere.util.Callback;
|
||||
|
||||
/**
|
||||
* Interface for AD Window event
|
||||
* @author hengsin
|
||||
*/
|
||||
public interface WindowValidator {
|
||||
/**
|
||||
* Handle {@link WindowValidatorEvent}.
|
||||
* Call callback with the result of the event (success or error).
|
||||
* @param event
|
||||
* @param callback optional callback
|
||||
*/
|
||||
public void onWindowEvent(WindowValidatorEvent event, Callback<Boolean> callback);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,60 @@
|
|||
/***********************************************************************
|
||||
* 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.adwindow.validator;
|
||||
|
||||
import org.adempiere.webui.adwindow.ADWindow;
|
||||
|
||||
/**
|
||||
* Validation event for AD Window
|
||||
* @author hengsin
|
||||
*/
|
||||
public class WindowValidatorEvent {
|
||||
/** {@link ADWindow} instance **/
|
||||
private ADWindow window;
|
||||
/** Event name **/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* @param window
|
||||
* @param name
|
||||
*/
|
||||
public WindowValidatorEvent(ADWindow window, String name) {
|
||||
this.window = window;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link ADWindow}
|
||||
*/
|
||||
public ADWindow getWindow() {
|
||||
return this.window;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Event name
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,34 @@
|
|||
/***********************************************************************
|
||||
* 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.adwindow.validator;
|
||||
|
||||
/**
|
||||
* Predefine AD Window validation event type
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public enum WindowValidatorEventType {
|
||||
BEFORE_IGNORE("beforeIgnore"),
|
||||
AFTER_IGNORE("afterIgnore"),
|
||||
|
@ -14,12 +43,19 @@ public enum WindowValidatorEventType {
|
|||
BEFORE_COPY("beforeCopy"),
|
||||
AFTER_COPY("afterCopy");
|
||||
|
||||
/** Event name **/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
*/
|
||||
private WindowValidatorEventType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Event name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -1,3 +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.adwindow.validator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -13,14 +37,25 @@ import org.osgi.framework.ServiceReference;
|
|||
import org.osgi.util.tracker.ServiceTracker;
|
||||
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
||||
|
||||
/**
|
||||
*
|
||||
* Manage {@link WindowValidator} osgi services
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class WindowValidatorManager implements BundleActivator, ServiceTrackerCustomizer<WindowValidator, WindowValidator> {
|
||||
|
||||
/** Singleton WindowValidatorManager instance **/
|
||||
private static WindowValidatorManager instance = null;
|
||||
|
||||
/** {@link BundleContext} instance **/
|
||||
private BundleContext context;
|
||||
/** AD_Window_UU:List<WindowValidator> **/
|
||||
private Map<String, List<WindowValidator>> validatorMap = new HashMap<String, List<WindowValidator>>();
|
||||
/** WindowValidator for all AD Window **/
|
||||
private List<WindowValidator> globalValidators = new ArrayList<WindowValidator>();
|
||||
|
||||
/** WindowValidator osgi service tracker **/
|
||||
private ServiceTracker<WindowValidator, WindowValidator> serviceTracker;
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +81,12 @@ public class WindowValidatorManager implements BundleActivator, ServiceTrackerCu
|
|||
return service;
|
||||
}
|
||||
|
||||
void addService(WindowValidator service, String uuid) {
|
||||
/**
|
||||
* Add {@link WindowValidator} service for an AD Window
|
||||
* @param service
|
||||
* @param uuid AD_Window_UU
|
||||
*/
|
||||
protected void addService(WindowValidator service, String uuid) {
|
||||
List<WindowValidator> list = validatorMap.get(uuid);
|
||||
if (list == null) {
|
||||
list = new ArrayList<WindowValidator>();
|
||||
|
@ -81,13 +121,21 @@ public class WindowValidatorManager implements BundleActivator, ServiceTrackerCu
|
|||
}
|
||||
}
|
||||
|
||||
void removeService(WindowValidator service, String uuid) {
|
||||
/**
|
||||
*
|
||||
* @param service
|
||||
* @param uuid
|
||||
*/
|
||||
protected void removeService(WindowValidator service, String uuid) {
|
||||
List<WindowValidator> list = validatorMap.get(uuid);
|
||||
if (list != null) {
|
||||
list.remove(service);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link #serviceTracker} and {@link #instance}
|
||||
*/
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
this.context = context;
|
||||
|
@ -97,6 +145,9 @@ public class WindowValidatorManager implements BundleActivator, ServiceTrackerCu
|
|||
instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close {@link #serviceTracker} and dispose {@link #instance}
|
||||
*/
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
serviceTracker.close();
|
||||
|
@ -104,10 +155,19 @@ public class WindowValidatorManager implements BundleActivator, ServiceTrackerCu
|
|||
instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return {@link WindowValidatorManager}
|
||||
*/
|
||||
public static WindowValidatorManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* fire window validator event for all register {@link WindowValidator} service
|
||||
* @param event
|
||||
* @param callback optional callback
|
||||
*/
|
||||
public void fireWindowValidatorEvent(WindowValidatorEvent event, Callback<Boolean> callback) {
|
||||
ADWindow window = event.getWindow();
|
||||
String uuid = window.getAD_Window_UU();
|
||||
|
@ -129,19 +189,32 @@ public class WindowValidatorManager implements BundleActivator, ServiceTrackerCu
|
|||
chain.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* class to call a list of {@link WindowValidator} through {@link Callback} chain.
|
||||
*/
|
||||
private static class ChainCallback implements Callback<Boolean> {
|
||||
|
||||
/** optional callback to invoke after execution of all {@link #validators} or when there's error **/
|
||||
private Callback<Boolean> callback;
|
||||
private WindowValidator[] validators;
|
||||
/** event for {@link #validators} **/
|
||||
private WindowValidatorEvent event;
|
||||
/** current index of {@link #validators} **/
|
||||
private int index = -1;
|
||||
|
||||
/**
|
||||
* @param event
|
||||
* @param validators
|
||||
* @param callback optional callback to invoke after execution of all {@link #validators} or when there's error
|
||||
*/
|
||||
public ChainCallback(WindowValidatorEvent event, WindowValidator[] validators, Callback<Boolean> callback) {
|
||||
this.event = event;
|
||||
this.validators = validators;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the @link {@link WindowValidator} callback chain.
|
||||
*/
|
||||
public void start() {
|
||||
index = 0;
|
||||
if (index < validators.length)
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.Properties;
|
|||
import java.util.logging.Level;
|
||||
|
||||
import org.adempiere.util.LogAuthFailure;
|
||||
import org.adempiere.webui.AdempiereWebUI;
|
||||
import org.adempiere.webui.LayoutUtils;
|
||||
import org.adempiere.webui.apps.AEnv;
|
||||
import org.adempiere.webui.component.Button;
|
||||
|
@ -660,7 +661,7 @@ public class LoginPanel extends Window implements EventListener<Event>
|
|||
// [ adempiere-ZK Web Client-2832968 ] User context lost?
|
||||
// https://sourceforge.net/p/adempiere/zk-web-client/303/
|
||||
// it's harmless, if there is no bug then this must never fail
|
||||
currSess.setAttribute("Check_AD_User_ID", Env.getAD_User_ID(ctx));
|
||||
currSess.setAttribute(AdempiereWebUI.CHECK_AD_USER_ID_ATTR, Env.getAD_User_ID(ctx));
|
||||
// End of temporary code for [ adempiere-ZK Web Client-2832968 ] User context lost?
|
||||
|
||||
/* Check DB version */
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.util.Properties;
|
|||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.adempiere.util.Callback;
|
||||
import org.adempiere.webui.AdempiereWebUI;
|
||||
import org.adempiere.webui.IWebClient;
|
||||
import org.adempiere.webui.component.FWindow;
|
||||
import org.adempiere.webui.component.Window;
|
||||
|
@ -297,7 +298,7 @@ public class LoginWindow extends FWindow implements EventListener<Event>
|
|||
else
|
||||
loginName = user.getLDAPUser() != null ? user.getLDAPUser() : user.getName();
|
||||
loginOk(loginName, true, login.getClients());
|
||||
getDesktop().getSession().setAttribute("Check_AD_User_ID", Env.getAD_User_ID(ctx));
|
||||
getDesktop().getSession().setAttribute(AdempiereWebUI.CHECK_AD_USER_ID_ATTR, Env.getAD_User_ID(ctx));
|
||||
pnlRole.setChangeRole(true);
|
||||
pnlRole.changeRole(ctx);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue