/****************************************************************************** * Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. This program is distributed in the hope * * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * For the text or an alternative of this public license, you may reach us * * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * * or via info@compiere.org or http://www.compiere.org/license.html * *****************************************************************************/ package org.adempiere.webui.window; import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.Date; import java.util.logging.Level; import org.adempiere.util.Callback; import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.component.ConfirmPanel; import org.adempiere.webui.component.Label; import org.adempiere.webui.component.ListItem; import org.adempiere.webui.component.Listbox; import org.adempiere.webui.component.Mask; import org.adempiere.webui.component.Window; import org.adempiere.webui.component.ZkCssHelper; import org.adempiere.webui.desktop.IDesktop; import org.adempiere.webui.event.DialogEvents; import org.adempiere.webui.panel.WSchedule; import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.util.ZKUpdateUtil; import org.compiere.model.MAssignmentSlot; import org.compiere.model.MResourceAssignment; import org.compiere.model.MRole; import org.compiere.model.MSysConfig; import org.compiere.model.ScheduleUtil; import org.compiere.model.X_AD_CtxHelp; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.KeyNamePair; import org.compiere.util.Msg; import org.compiere.util.TimeUtil; import org.zkoss.calendar.event.CalendarsEvent; import org.zkoss.calendar.impl.SimpleCalendarEvent; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.event.KeyEvent; import org.zkoss.zul.Div; import org.zkoss.zul.Hlayout; import org.zkoss.zul.Space; import org.zkoss.zul.Vbox; /** * Schedule - Resource availability and assignment. * * @author Jorg Janke * @version $Id: InfoSchedule.java,v 1.2 2006/07/30 00:51:27 jjanke Exp $ * * Zk Port * @author Low Heng Sin * @author Elaine * @version InfoSchedule.java Adempiere Swing UI 3.4.1 */ public class InfoSchedule extends Window implements EventListener { /** * generated serial id */ private static final long serialVersionUID = 3349721592479638482L; private Callback m_callback; private Component m_parent; /** Window No */ private int m_windowNo; /** * SysConfig USE_ESC_FOR_TAB_CLOSING */ private boolean isUseEscForTabClosing = MSysConfig.getBooleanValue(MSysConfig.USE_ESC_FOR_TAB_CLOSING, false, Env.getAD_Client_ID(Env.getCtx())); /** * Constructor * @param mAssignment optional assignment * @param createNew if true, allows to create new assignments */ public InfoSchedule (MResourceAssignment mAssignment, boolean createNew) { this(mAssignment, createNew, (Callback)null); } /** * @param mAssignment * @param createNew * @param callback */ public InfoSchedule (MResourceAssignment mAssignment, boolean createNew, Callback callback) { this(mAssignment, createNew, (Component)null, callback); } /** * Constructor * @param mAssignment optional assignment * @param createNew if true, allows to create new assignments * @param parent * @param callback */ public InfoSchedule (MResourceAssignment mAssignment, boolean createNew, Component parent, Callback callback) { super(); setTitle(Msg.getMsg(Env.getCtx(), "InfoSchedule")); if (createNew) { setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED); ZKUpdateUtil.setWindowWidthX(this, 700); ZKUpdateUtil.setWindowHeightX(this, 600); this.setSizable(true); } else { ZKUpdateUtil.setWidth(this, "100%"); ZKUpdateUtil.setHeight(this, "100%"); } this.setClosable(true); this.setBorder("normal"); this.setStyle("position: absolute"); if (mAssignment == null) m_mAssignment = new MResourceAssignment(Env.getCtx(), 0, null); else m_mAssignment = mAssignment; if (mAssignment != null) log.info(mAssignment.toString()); m_dateFrom = m_mAssignment.getAssignDateFrom(); if (m_dateFrom == null) m_dateFrom = new Timestamp(System.currentTimeMillis()); m_createNew = createNew; m_callback = callback; m_parent = parent; if (callback != null) { this.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener() { @Override public void onEvent(Event event) throws Exception { if (!m_cancel) { m_callback.onCallback(getMResourceAssignment()); } else { m_callback.onCallback(null); } } }); } try { init(); dynInit(createNew); } catch(Exception ex) { log.log(Level.SEVERE, "InfoSchedule", ex); } displayCalendar(); m_windowNo = SessionManager.getAppDesktop().registerWindow(this); setAttribute(IDesktop.WINDOWNO_ATTRIBUTE, m_windowNo); // for closing the window with shortcut SessionManager.getSessionApplication().getKeylistener().addEventListener(Events.ON_CTRL_KEY, this); addEventListener(IDesktop.ON_CLOSE_WINDOW_SHORTCUT_EVENT, this); } // InfoSchedule /** * Default Constructor */ public InfoSchedule() { this (null, false); } // InfoSchedule /** Resource */ private MResourceAssignment m_mAssignment; /** Date */ private Timestamp m_dateFrom = null; /** Loading */ private boolean m_loading = false; /** Ability to create new assignments */ private boolean m_createNew; /** Logger */ private static final CLogger log = CLogger.getCLogger(InfoSchedule.class); private Vbox mainLayout = new Vbox(); private Hlayout parameterPanel = new Hlayout(); private Label labelResourceType = new Label(); private Listbox fieldResourceType = new Listbox(); private Label labelResource = new Label(); private Listbox fieldResource = new Listbox(); // private WSchedule schedulePane = new WSchedule(this); private ConfirmPanel confirmPanel = null; private WAssignmentDialog vad; private boolean m_cancel = false; private Mask mask; /** * Layout dialog * @throws Exception */ private void init() throws Exception { this.appendChild(mainLayout); ZKUpdateUtil.setHeight(mainLayout, "100%"); ZKUpdateUtil.setWidth(mainLayout, "100%"); labelResourceType.setValue(Msg.translate(Env.getCtx(), "S_ResourceType_ID")); labelResource.setValue(Msg.translate(Env.getCtx(), "S_Resource_ID")); parameterPanel.setValign("middle"); parameterPanel.appendChild(labelResourceType); parameterPanel.appendChild(fieldResourceType); parameterPanel.appendChild(new Space()); parameterPanel.appendChild(labelResource); parameterPanel.appendChild(fieldResource); mainLayout.appendChild(schedulePane); schedulePane.addNorthPane(parameterPanel); if (m_createNew) { Div div = new Div(); confirmPanel = new ConfirmPanel(true); div.appendChild(confirmPanel); schedulePane.addSouthPane(div, "80px"); schedulePane.addEventListener(CalendarsEvent.ON_EVENT_CREATE, this); schedulePane.addEventListener(CalendarsEvent.ON_EVENT_EDIT, this); schedulePane.addEventListener(CalendarsEvent.ON_EVENT_UPDATE, this); schedulePane.removeRefreshButton(); } else { schedulePane.addEventListener(CalendarsEvent.ON_EVENT_EDIT, this); schedulePane.addEventListener(CalendarsEvent.ON_EVENT_UPDATE, this); } fieldResourceType.setMold("select"); fieldResource.setMold("select"); addEventListener(Events.ON_CANCEL, e -> onCancel()); } // jbInit /** * Load resource and resource type * @param createNew if true, allows to create new assignments */ private void dynInit (boolean createNew) { // Resource fillResourceType(); fillResource(); fieldResourceType.addEventListener(Events.ON_SELECT, this); fieldResource.addEventListener(Events.ON_SELECT, this); // if (createNew) { confirmPanel.addActionListener(Events.ON_CLICK, this); } } // dynInit /** * Fill Resource Type (one time) */ private void fillResourceType() { // Get ResourceType of selected Resource int S_ResourceType_ID = 0; if (m_mAssignment.getS_Resource_ID() != 0) { String sql = "SELECT S_ResourceType_ID FROM S_Resource WHERE S_Resource_ID=?"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, m_mAssignment.getS_Resource_ID()); rs = pstmt.executeQuery(); if (rs.next()) S_ResourceType_ID = rs.getInt(1); } catch (SQLException e) { log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } } // Get Resource Types String sql = MRole.getDefault().addAccessSQL( "SELECT S_ResourceType_ID, Name FROM S_ResourceType WHERE IsActive='Y' ORDER BY 2", "S_ResourceType", MRole.SQL_NOTQUALIFIED, MRole.SQL_RO); KeyNamePair defaultValue = null; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); rs = pstmt.executeQuery(); while (rs.next()) { KeyNamePair pp = new KeyNamePair(rs.getInt(1), rs.getString(2)); if (S_ResourceType_ID == pp.getKey()) defaultValue = pp; fieldResourceType.appendItem(pp.getName(), pp.getKey()); } } catch (SQLException e) { log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } if (defaultValue != null) { int cnt = fieldResourceType.getItemCount(); for(int i = 0; i < cnt; i++) { ListItem li = fieldResourceType.getItemAtIndex(i); Integer key = (Integer) li.getValue(); if (key.intValue() == defaultValue.getKey()) { fieldResourceType.setSelectedItem(li); break; } } } else if (fieldResourceType.getItemCount() > 0) { fieldResourceType.setSelectedIndex(0); } } // fillResourceType /** * Fill Resource Pick from Resource Type */ private void fillResource() { ListItem listItem = fieldResourceType.getSelectedItem(); if (listItem == null) return; // Get Resource Type KeyNamePair pp = new KeyNamePair((Integer)listItem.getValue(), listItem.getLabel()); int S_ResourceType_ID = pp.getKey(); KeyNamePair defaultValue = null; // Load Resources m_loading = true; fieldResource.getChildren().clear(); String sql = "SELECT S_Resource_ID, Name FROM S_Resource WHERE S_ResourceType_ID=? ORDER BY 2"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, S_ResourceType_ID); rs = pstmt.executeQuery(); while (rs.next()) { pp = new KeyNamePair(rs.getInt(1), rs.getString(2)); if (m_mAssignment.getS_Resource_ID() == pp.getKey()) defaultValue = pp; fieldResource.appendItem(pp.getName(), pp.getKey()); } } catch (SQLException e) { log.log(Level.SEVERE, sql, e); } finally { DB.close(rs,pstmt); rs = null; pstmt = null; } if (defaultValue != null) { int cnt = fieldResource.getItemCount(); for(int i = 0; i < cnt; i++) { ListItem li = fieldResource.getItemAtIndex(i); Integer key = (Integer) li.getValue(); if (key.intValue() == defaultValue.getKey()) { fieldResource.setSelectedItem(li); break; } } } else if ( fieldResource.getItemCount() > 0) { fieldResource.setSelectedIndex(0); } m_loading = false; } // fillResource /** * Display Calendar for selected Resource, Time(day/week/month) and Date */ private void displayCalendar () { // Get Values ListItem listItem = fieldResource.getSelectedItem(); if (listItem == null) return; KeyNamePair pp = new KeyNamePair((Integer)listItem.getValue(), listItem.getLabel()); int S_Resource_ID = pp.getKey(); m_mAssignment.setS_Resource_ID(S_Resource_ID); Date date = m_dateFrom; if (date == null) date = new Timestamp(System.currentTimeMillis()); // // Set Info m_loading = true; schedulePane.recreate(S_Resource_ID, date); m_loading = false; invalidate(); } // displayCalendar /** * Close dialog */ public void dispose() { this.detach(); } // dispose /** * Callback. * Called from WSchedule after WAssignmentDialog finished * @param assignment New/Changed Assignment * @param createNew * @param cancelled */ public void mAssignmentCallback (MResourceAssignment assignment, boolean createNew, boolean cancelled) { hideBusyMask(); if (!cancelled) { m_mAssignment = assignment; if (createNew) dispose(); else displayCalendar(); } else displayCalendar(); } // mAssignmentCallback /** * Get Assignment * @return Assignment */ public MResourceAssignment getMResourceAssignment() { return m_mAssignment; } // getMResourceAssignment @Override public void onEvent(Event event) throws Exception { if (m_loading) return; if (event.getTarget().getId().equals("Ok")) { m_cancel = false; dispose(); } else if (event.getTarget().getId().equals("Cancel")) { onCancel(); // } else if (event.getTarget() == fieldResourceType) { fillResource(); displayCalendar(); } // else if (event instanceof CalendarsEvent) doEdit((CalendarsEvent)event); else if (event.getTarget() == fieldResource) displayCalendar(); else if (event.getName().equals(Events.ON_CTRL_KEY)) { KeyEvent keyEvent = (KeyEvent) event; if (LayoutUtils.isReallyVisible(this)) this.onCtrlKeyEvent(keyEvent); } else if(IDesktop.ON_CLOSE_WINDOW_SHORTCUT_EVENT.equals(event.getName())) { IDesktop desktop = SessionManager.getAppDesktop(); if (m_windowNo > 0 && desktop.isCloseTabWithShortcut()) desktop.closeWindow(m_windowNo); else desktop.setCloseTabWithShortcut(true); } // } /** * onCancel event */ private void onCancel() { // do not allow to close tab for Events.ON_CTRL_KEY event if(isUseEscForTabClosing) SessionManager.getAppDesktop().setCloseTabWithShortcut(false); m_cancel = true; dispose(); } /** * Edit or create calendar event (for S_ResourceAssignment) * @param event */ private void doEdit(CalendarsEvent event) { ListItem listItem = fieldResource.getSelectedItem(); if (listItem == null) return; // Get Resource Type KeyNamePair pp = new KeyNamePair((Integer)listItem.getValue(), listItem.getLabel()); int S_Resource_ID = pp.getKey(); ScheduleUtil schedule = new ScheduleUtil (Env.getCtx()); Timestamp start = new Timestamp(event.getBeginDate() != null ? event.getBeginDate().getTime() : event.getCalendarEvent().getBeginDate().getTime()); Timestamp end =new Timestamp(event.getEndDate() != null ? event.getEndDate().getTime() : event.getCalendarEvent().getEndDate().getTime()); double hours = (end.getTime() - start.getTime())/ 1000d / 60d / 60d; MAssignmentSlot[] mas = schedule.getAssignmentSlots(S_Resource_ID, TimeUtil.getPreviousDay(start), TimeUtil.getNextDay(end), null, true, null); MAssignmentSlot slot = null; for(int i = 0; i < mas.length; i++) { if (mas[i].getStartTime().getTime() == start.getTime()) { slot = mas[i]; break; } if (mas[i].getEndTime() != null) { if (start.getTime() > mas[i].getStartTime().getTime() && start.getTime() < mas[i].getEndTime().getTime()) { slot = mas[i]; break; } else if (end.getTime() > mas[i].getStartTime().getTime() && end.getTime() < mas[i].getEndTime().getTime()) { slot = mas[i]; break; } else if (start.getTime() < mas[i].getStartTime().getTime() && end.getTime() >= mas[i].getEndTime().getTime()) { slot = mas[i]; break; } } } if (slot == null) { MResourceAssignment ma; if (m_mAssignment == null) ma = new MResourceAssignment(Env.getCtx(), 0, null); else ma = m_mAssignment; ma.setS_Resource_ID(S_Resource_ID); ma.setAssignDateFrom(start); ma.setQty(BigDecimal.valueOf(hours)); if (m_parent == null || m_callback == null) { final boolean createNew = true; if (vad != null && vad.getPage() != null) vad.detach(); vad = new WAssignmentDialog (ma, false, createNew); if (event.getBeginDate() != null && event.getEndDate() != null) { SimpleCalendarEvent newEvent = new SimpleCalendarEvent(); newEvent.setBeginDate(event.getBeginDate()); newEvent.setEndDate(event.getEndDate()); if (event.getCalendarEvent() != null) { newEvent.setContent(event.getCalendarEvent().getContent()); newEvent.setContentColor(event.getCalendarEvent().getContentColor()); newEvent.setHeaderColor(event.getCalendarEvent().getHeaderColor()); newEvent.setTitle(event.getCalendarEvent().getTitle()); schedulePane.getModel().remove(event.getCalendarEvent()); } schedulePane.getModel().add(newEvent); } vad.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener() { @Override public void onEvent(Event event) throws Exception { mAssignmentCallback(vad.getMResourceAssignment(), createNew, vad.isCancelled()); } }); vad.setTitle(null); ZkCssHelper.appendStyle(vad, "position: absolute"); showBusyMask(); this.appendChild(vad); LayoutUtils.openOverlappedWindow(this, vad, "middle_center"); vad.focus(); } else { m_cancel = false; m_mAssignment = ma; dispose(); } } else { if (!slot.isAssignment()) { Dialog.error(0, "No available time slot for the selected day."); return; } MResourceAssignment ma = slot.getMAssignment(); ma.setAssignDateFrom(start); ma.setQty(BigDecimal.valueOf(hours)); if (m_parent == null || m_callback == null) { if (event.getBeginDate() != null && event.getEndDate() != null) { SimpleCalendarEvent newEvent = new SimpleCalendarEvent(); newEvent.setBeginDate(event.getBeginDate()); newEvent.setEndDate(event.getEndDate()); if (event.getCalendarEvent() != null) { newEvent.setContent(event.getCalendarEvent().getContent()); newEvent.setContentColor(event.getCalendarEvent().getContentColor()); newEvent.setHeaderColor(event.getCalendarEvent().getHeaderColor()); newEvent.setTitle(event.getCalendarEvent().getTitle()); schedulePane.getModel().remove(event.getCalendarEvent()); } schedulePane.getModel().add(newEvent); } final boolean createNew = false; if (vad != null && vad.getPage() != null) vad.detach(); vad = new WAssignmentDialog (ma, false, createNew); vad.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener() { @Override public void onEvent(Event event) throws Exception { mAssignmentCallback(vad.getMResourceAssignment(), createNew, vad.isCancelled()); } }); vad.setTitle(null); ZkCssHelper.appendStyle(vad, "position: absolute"); showBusyMask(); this.appendChild(vad); LayoutUtils.openOverlappedWindow(this, vad, "middle_center"); vad.focus(); } else { m_cancel = false; m_mAssignment = ma; dispose(); } } } /** * @return true if create new assignment is enable */ public boolean isCreateNew() { return m_createNew; } /** * Callback from WSchedule * @param date */ public void dateCallback(Date date) { m_dateFrom = new Timestamp(date.getTime()); } /* (non-Javadoc) * @see org.zkoss.zk.ui.AbstractComponent#onPageAttached(org.zkoss.zk.ui.Page, org.zkoss.zk.ui.Page) */ @Override public void onPageAttached(Page newpage, Page oldpage) { super.onPageAttached(newpage, oldpage); if (newpage != null) { displayCalendar(); SessionManager.getAppDesktop().updateHelpContext(X_AD_CtxHelp.CTXTYPE_Home, 0); } } /** * @return busy mask */ private Div getMask() { if (mask == null) { mask = new Mask(); } return mask; } /** * Show busy mask */ protected void showBusyMask() { appendChild(getMask()); } /** * Hide busy mask */ protected void hideBusyMask() { if (mask != null && mask.getParent() != null) { mask.detach(); } } /** * Handle shortcut key event * @param keyEvent */ private void onCtrlKeyEvent(KeyEvent keyEvent) { if ((keyEvent.isAltKey() && keyEvent.getKeyCode() == 0x58) // Alt-X || (keyEvent.getKeyCode() == 0x1B && isUseEscForTabClosing)) { // ESC keyEvent.stopPropagation(); Events.echoEvent(new Event(IDesktop.ON_CLOSE_WINDOW_SHORTCUT_EVENT, this)); } } } // InfoSchedule