diff --git a/org.adempiere.base/src/org/compiere/model/MAttachment.java b/org.adempiere.base/src/org/compiere/model/MAttachment.java index 50fca012ab..700e5f481a 100644 --- a/org.adempiere.base/src/org/compiere/model/MAttachment.java +++ b/org.adempiere.base/src/org/compiere/model/MAttachment.java @@ -51,17 +51,30 @@ public class MAttachment extends X_AD_Attachment */ private static final long serialVersionUID = -8261865873158774665L; + /** + * + * @param ctx + * @param AD_Table_ID + * @param Record_ID + * @return attachment or null + */ + public static MAttachment get (Properties ctx, int AD_Table_ID, int Record_ID) + { + return get(ctx, AD_Table_ID, Record_ID, (String)null); + } + /** * Get Attachment (if there are more than one attachment it gets the first in no specific order) * @param ctx context * @param AD_Table_ID table * @param Record_ID record + * @param trxName * @return attachment or null */ - public static MAttachment get (Properties ctx, int AD_Table_ID, int Record_ID) + public static MAttachment get (Properties ctx, int AD_Table_ID, int Record_ID, String trxName) { final String whereClause = I_AD_Attachment.COLUMNNAME_AD_Table_ID+"=? AND "+I_AD_Attachment.COLUMNNAME_Record_ID+"=?"; - MAttachment retValue = new Query(ctx,I_AD_Attachment.Table_Name,whereClause, null) + MAttachment retValue = new Query(ctx,I_AD_Attachment.Table_Name,whereClause, trxName) .setParameters(AD_Table_ID, Record_ID) .first(); return retValue; diff --git a/org.adempiere.ui.zk/META-INF/MANIFEST.MF b/org.adempiere.ui.zk/META-INF/MANIFEST.MF index 5dae697633..8c5f926bb2 100644 --- a/org.adempiere.ui.zk/META-INF/MANIFEST.MF +++ b/org.adempiere.ui.zk/META-INF/MANIFEST.MF @@ -4,7 +4,8 @@ Bundle-Name: Zk Web Client Bundle-SymbolicName: org.adempiere.ui.zk;singleton:=true Bundle-Version: 1.0.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.6 -Import-Package: javax.servlet, +Import-Package: javax.activation;version="1.1.1", + javax.servlet, javax.servlet.http, metainfo.zk, org.apache.commons.codec.binary, @@ -58,4 +59,4 @@ Bundle-Activator: org.adempiere.webui.WebUIActivator Eclipse-ExtensibleAPI: true Eclipse-RegisterBuddy: org.zkoss.zk.library Web-ContextPath: webui -Service-Component: OSGI-INF/reportviewerprovider.xml, OSGI-INF/defaultinfofactory.xml, OSGI-INF/defaulteditorfactory.xml, OSGI-INF/jrviewerprovider.xml, OSGI-INF/resourcefinder.xml, OSGI-INF/defaultpaymentformfactory.xml, OSGI-INF/processfactory.xml, OSGI-INF/defaultprintshippinglabel.xml, OSGI-INF/defaultcreatefromfactory.xml, OSGI-INF/defaultformfactory.xml +Service-Component: OSGI-INF/reportviewerprovider.xml, OSGI-INF/defaultinfofactory.xml, OSGI-INF/defaulteditorfactory.xml, OSGI-INF/jrviewerprovider.xml, OSGI-INF/resourcefinder.xml, OSGI-INF/defaultpaymentformfactory.xml, OSGI-INF/processfactory.xml, OSGI-INF/defaultprintshippinglabel.xml, OSGI-INF/defaultcreatefromfactory.xml, OSGI-INF/defaultformfactory.xml, OSGI-INF/feedbackservice.xml diff --git a/org.adempiere.ui.zk/OSGI-INF/feedbackservice.xml b/org.adempiere.ui.zk/OSGI-INF/feedbackservice.xml new file mode 100644 index 0000000000..64c69dd91f --- /dev/null +++ b/org.adempiere.ui.zk/OSGI-INF/feedbackservice.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java index 99c9728d1c..aa2f1b1e76 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java @@ -436,10 +436,14 @@ public class AdempiereWebUI extends Window implements EventListener, IWeb ClientInfoEvent c = (ClientInfoEvent)event; clientInfo = new ClientInfo(); clientInfo.colorDepth = c.getColorDepth(); + clientInfo.screenHeight = c.getScreenHeight(); + clientInfo.screenWidth = c.getScreenWidth(); + clientInfo.devicePixelRatio = c.getDevicePixelRatio(); clientInfo.desktopHeight = c.getDesktopHeight(); clientInfo.desktopWidth = c.getDesktopWidth(); clientInfo.desktopXOffset = c.getDesktopXOffset(); clientInfo.desktopYOffset = c.getDesktopYOffset(); + clientInfo.orientation = c.getOrientation(); clientInfo.timeZone = c.getTimeZone(); if (appDesktop != null) appDesktop.setClientInfo(clientInfo); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/ClientInfo.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/ClientInfo.java index ee68868fe0..1f7a61858d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/ClientInfo.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/ClientInfo.java @@ -37,7 +37,42 @@ public class ClientInfo implements Serializable { public int desktopYOffset; public int screenHeight; public int screenWidth; + public String orientation; public TimeZone timeZone; public String userAgent; public boolean tablet; + public double devicePixelRatio; + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("User Agent: ") + .append(userAgent) + .append("\r\n") + .append("Time Zone: ") + .append(timeZone.getID()) + .append("\r\n") + .append("Screen Size: ") + .append(screenWidth) + .append(" x ") + .append(screenHeight) + .append("\r\n") + .append("Browser Desktop Size: ") + .append(desktopWidth) + .append(" x ") + .append(desktopHeight) + .append("\r\n") + .append("Orientation: ") + .append(orientation) + .append("\r\n") + .append("Color Depth: ") + .append(colorDepth) + .append("\r\n") + .append("Pixel Ratio: ") + .append(devicePixelRatio); + + return builder.toString(); + } + + } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/FeedbackRequestWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/FeedbackRequestWindow.java new file mode 100644 index 0000000000..1e6d9fd021 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/FeedbackRequestWindow.java @@ -0,0 +1,334 @@ +/****************************************************************************** + * Copyright (C) 2013 Heng Sin Low * + * Copyright (C) 2013 Trek Global * + * 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. * + *****************************************************************************/ +package org.adempiere.webui.apps; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +import javax.activation.DataSource; + +import org.adempiere.webui.component.AttachmentItem; +import org.adempiere.webui.component.Button; +import org.adempiere.webui.component.ConfirmPanel; +import org.adempiere.webui.component.Grid; +import org.adempiere.webui.component.GridFactory; +import org.adempiere.webui.component.Label; +import org.adempiere.webui.component.Row; +import org.adempiere.webui.component.Rows; +import org.adempiere.webui.component.Textbox; +import org.adempiere.webui.component.Window; +import org.adempiere.webui.editor.WTableDirEditor; +import org.adempiere.webui.util.FeedbackManager; +import org.adempiere.webui.window.FDialog; +import org.apache.commons.io.IOUtils; +import org.compiere.model.MAttachment; +import org.compiere.model.MColumn; +import org.compiere.model.MLookup; +import org.compiere.model.MLookupFactory; +import org.compiere.model.MRequest; +import org.compiere.model.MRole; +import org.compiere.util.ByteArrayDataSource; +import org.compiere.util.CLogger; +import org.compiere.util.DisplayType; +import org.compiere.util.Env; +import org.compiere.util.Msg; +import org.compiere.util.Trx; +import org.zkoss.util.media.Media; +import org.zkoss.zk.ui.WrongValueException; +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.UploadEvent; +import org.zkoss.zk.ui.util.Clients; +import org.zkoss.zul.Div; +import org.zkoss.zul.Separator; +import org.zkoss.zul.Vlayout; + +/** + * + * @author hengsin + * + */ +public class FeedbackRequestWindow extends Window implements EventListener { + + /** + * generated serial id + */ + private static final long serialVersionUID = 8586980192148533197L; + + private static CLogger log = CLogger.getCLogger(FeedbackRequestWindow.class); + + private WTableDirEditor requestTypeField, priorityField, salesRepField; + private Textbox txtSummary; + private ConfirmPanel confirmPanel; + + private List attachments = new ArrayList(); + private Div attachmentBox; + + public FeedbackRequestWindow() { + + super(); + + setTitle(Msg.getMsg(Env.getCtx(), "RequestNew")); + setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED); + setWidth("400px"); + this.setBorder("normal"); + this.setClosable(true); + + boolean readOnly = !MRole.getDefault().canUpdate( + Env.getAD_Client_ID(Env.getCtx()), Env.getAD_Org_ID(Env.getCtx()), + MRequest.Table_ID, 0, false); + + if (readOnly) + { + throw new RuntimeException(Msg.getMsg(Env.getCtx(), "AccessTableNoUpdate")); + } + + Label lblRequestType = new Label("Request Type"); + Label lblPriority = new Label("Priority"); + Label lblSummary = new Label("Summary"); + Label lblSalesRep = new Label("Sales Representative"); + + int columnID = MColumn.getColumn_ID(MRequest.Table_Name, MRequest.COLUMNNAME_R_RequestType_ID); + MLookup lookup = MLookupFactory.get(Env.getCtx(), 0, 0, columnID, DisplayType.TableDir); + requestTypeField = new WTableDirEditor("R_RequestType_ID", true, false, true, lookup); + requestTypeField.setValue(Env.getContext(Env.getCtx(), "P232|R_RequestType_ID")); + if(requestTypeField.getValue() == null || requestTypeField.getValue().equals("")) + if(requestTypeField.getComponent().getItemCount() > 1) + requestTypeField.setValue(requestTypeField.getComponent().getItemAtIndex(1).getValue()); + + columnID = MColumn.getColumn_ID(MRequest.Table_Name, MRequest.COLUMNNAME_Priority); + lookup = MLookupFactory.get(Env.getCtx(), 0, 0, columnID, DisplayType.List); + priorityField = new WTableDirEditor("Priority", true, false, true, lookup); + priorityField.setValue(Env.getContext(Env.getCtx(), "P232|Priority")); + if(priorityField.getValue() == null || priorityField.getValue().equals("")) + if(priorityField.getComponent().getItemCount() > 1) + priorityField.setValue(priorityField.getComponent().getItemAtIndex(1).getValue()); + + columnID = MColumn.getColumn_ID(MRequest.Table_Name, MRequest.COLUMNNAME_SalesRep_ID); + lookup = MLookupFactory.get(Env.getCtx(), 0, 0, columnID, DisplayType.TableDir); + salesRepField = new WTableDirEditor("SalesRep_ID", true, false, true, lookup); + salesRepField.setValue(Env.getContextAsInt(Env.getCtx(), "SalesRep_ID")); + if(salesRepField.getValue() == null || salesRepField.getValue().equals("0")) + if(salesRepField.getComponent().getItemCount() > 1) + salesRepField.setValue(salesRepField.getComponent().getItemAtIndex(1).getValue()); + + txtSummary = new Textbox(); + txtSummary.setRows(10); + txtSummary.setWidth("95%"); + + confirmPanel = new ConfirmPanel(true); + confirmPanel.addActionListener(this); + + + Grid grid = GridFactory.newGridLayout(); + grid.setVflex("min"); + + Rows rows = new Rows(); + grid.appendChild(rows); + + Row row = rows.newRow(); + row.setStyle("padding: 4px 4px 0px 6px"); + row.appendChild(lblRequestType); + + row = rows.newRow(); + row.setStyle("padding: 0px 4px 4px 6px"); + row.appendChild(requestTypeField.getComponent()); + + + row = rows.newRow(); + row.setStyle("padding: 4px 4px 0px 6px"); + row.appendChild(lblPriority); + + row = rows.newRow(); + row.setStyle("padding: 0px 4px 4px 6px"); + row.appendChild(priorityField.getComponent()); + + row = rows.newRow(); + row.setStyle("padding: 4px 4px 0px 6px"); + row.appendChild(lblSummary); + + row = rows.newRow(); + row.setStyle("padding: 0px 4px 4px 6px"); + row.appendChild(txtSummary); + + row = rows.newRow(); + row.setStyle("padding: 4px 4px 0px 6px"); + row.appendChild(lblSalesRep); + + row = rows.newRow(); + row.setStyle("padding: 0px 4px 4px 6px"); + row.appendChild(salesRepField.getComponent()); + + row = rows.newRow(); + row.setStyle("padding: 4px 4px 0px 6px"); + row.appendChild(new Label(Msg.getMsg(Env.getCtx(), "Attachment"))); + + attachmentBox = new Div(); + attachmentBox.setHflex("1"); + attachmentBox.setVflex("1"); + row = rows.newRow(); + row.setStyle("padding: 0px 4px 4px 6px"); + row.appendChild(attachmentBox); + + Vlayout vlayout = new Vlayout(); + appendChild(vlayout); + + vlayout.appendChild(grid); + grid.setVflex("min"); + grid.setHflex("1"); + + Separator separator = new Separator(); + separator.setOrient("horizontal"); + vlayout.appendChild(separator); + vlayout.appendChild(confirmPanel); + + Button btn = new Button(); + btn.setImage("/images/Attachment24.png"); + btn.setUpload("true"); + btn.addEventListener(Events.ON_UPLOAD, this); + btn.setTooltiptext(Msg.getMsg(Env.getCtx(), "Attachment")); + confirmPanel.addComponentsLeft(btn); + confirmPanel.getButton(ConfirmPanel.A_OK).setWidgetListener("onClick", "zAu.cmd0.showBusy(null)"); + + addAttachment(FeedbackManager.getLogAttachment(false), false); + } + + public void onEvent(Event e) throws Exception { + if (e.getTarget() == confirmPanel.getButton(ConfirmPanel.A_OK)) { + Clients.clearBusy(); + // Check Mandatory fields + if (requestTypeField.getValue() == null || requestTypeField.getValue().equals("0")) + throw new WrongValueException(requestTypeField.getComponent(), Msg.translate(Env.getCtx(), "FillMandatory")); + if (priorityField.getValue() == null || priorityField.getValue().equals("")) + throw new WrongValueException(priorityField.getComponent(), Msg.translate(Env.getCtx(), "FillMandatory")); + if (txtSummary.getText() == null || txtSummary.getText().equals("")) + throw new WrongValueException(txtSummary, Msg.translate(Env.getCtx(), "FillMandatory")); + if (salesRepField.getValue() == null || salesRepField.getValue().equals("0")) + throw new WrongValueException(salesRepField.getComponent(), Msg.translate(Env.getCtx(), "FillMandatory")); + + Trx trx = Trx.get(Trx.createTrxName("SaveNewRequest"), true); + try { + trx.start(); + MRequest request = new MRequest(Env.getCtx(), 0, trx.getTrxName()); + request.setAD_Org_ID(Env.getAD_Org_ID(Env.getCtx())); + request.setR_RequestType_ID((Integer) requestTypeField.getValue()); + request.setPriority((String) priorityField.getValue()); + request.setSummary(txtSummary.getText()); + request.setSalesRep_ID((Integer) salesRepField.getValue()); + + boolean success = request.save(); + if (success) + { + MAttachment attachment = null; + for(DataSource ds : attachments) + { + if (attachment == null) + { + attachment = new MAttachment(Env.getCtx(), 0, request.get_TrxName()); + attachment.setAD_Table_ID(request.get_Table_ID()); + attachment.setRecord_ID(request.get_ID()); + } + + attachment.addEntry(ds.getName(), IOUtils.toByteArray(ds.getInputStream())); + } + if (attachment != null) + success = attachment.save(); + + if (success) + success = trx.commit(); + + } + + if (success) + { + FDialog.info(0, null, Msg.getMsg(Env.getCtx(), "Saved")); + } + else + { + trx.rollback(); + FDialog.error(0, this, Msg.getMsg(Env.getCtx(), "SaveError")); + } + } finally { + trx.close(); + } + + this.detach(); + } + else if (e.getTarget() == confirmPanel.getButton(ConfirmPanel.A_CANCEL)) + { + this.detach(); + } + else if (e instanceof UploadEvent) + { + UploadEvent ue = (UploadEvent) e; + Media media = ue.getMedia(); + if (media != null) + { + byte[] data = getMediaData(media); + ByteArrayDataSource dataSource = new ByteArrayDataSource(data, media.getContentType()); + dataSource.setName(media.getName()); + addAttachment(dataSource, true); + getFirstChild().invalidate(); + } + } + } + + private void addAttachment(DataSource dataSource, boolean removable) { + attachments.add(dataSource); + AttachmentItem item = new AttachmentItem(dataSource, attachments, removable); + attachmentBox.appendChild(item); + } + + private byte[] getMediaData(Media media) { + byte[] bytes = null; + + try { + if (media.inMemory()) { + bytes = media.isBinary() ? media.getByteData() : media.getStringData().getBytes(getCharset(media.getContentType())); + } else { + + InputStream is = media.getStreamData(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[ 1000 ]; + int byteread = 0; + + while (( byteread=is.read(buf) )!=-1) + baos.write(buf,0,byteread); + + bytes = baos.toByteArray(); + } + } catch (IOException e) { + log.log(Level.SEVERE, e.getLocalizedMessage(), e); + throw new IllegalStateException(e.getLocalizedMessage()); + } + + return bytes; + } + + private String getCharset(String contentType) { + if (contentType != null) { + int j = contentType.indexOf("charset="); + if (j >= 0) { + String cs = contentType.substring(j + 8).trim(); + if (cs.length() > 0) return cs; + } + } + return "UTF-8"; + } +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/component/AttachmentItem.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/component/AttachmentItem.java new file mode 100644 index 0000000000..b314878010 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/component/AttachmentItem.java @@ -0,0 +1,60 @@ +/****************************************************************************** + * Copyright (C) 2013 Heng Sin Low * + * Copyright (C) 2013 Trek Global * + * 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. * + *****************************************************************************/ +package org.adempiere.webui.component; + +import java.util.List; + +import javax.activation.DataSource; + +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zul.A; +import org.zkoss.zul.Hlayout; + +/** + * + * @author hengsin + * + */ +public class AttachmentItem extends Hlayout implements EventListener{ + /** + * generate serial id + */ + private static final long serialVersionUID = 9105759170502414466L; + private DataSource ds; + private List list; + + public AttachmentItem(DataSource ds, List list, boolean removable) { + setStyle("border: 1px solid #dcdcdc; background-color: #f5f5f5; " + + "width: auto !important;display: inline-block; height: 21px; " + + "margin-right: 5px; margin-bottom: 5px;padding-left: 5px; padding-right: 5px;"); + appendChild(new Label(ds.getName())); + if (removable) { + A x = new A("", "/images/X8.png"); + x.setStyle("float: right; background-color: #f5f5f5"); + appendChild(x); + this.ds = ds; + this.list = list; + x.addEventListener(Events.ON_CLICK, this); + } + setHflex("0"); + } + + @Override + public void onEvent(Event event) throws Exception { + list.remove(ds); + this.detach(); + } +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/factory/DefaultFeedbackService.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/factory/DefaultFeedbackService.java new file mode 100644 index 0000000000..706a564b79 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/factory/DefaultFeedbackService.java @@ -0,0 +1,77 @@ +/****************************************************************************** + * Copyright (C) 2013 Heng Sin Low * + * Copyright (C) 2013 Trek Global * + * 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. * + *****************************************************************************/ +package org.adempiere.webui.factory; + +import javax.activation.DataSource; + +import org.adempiere.webui.apps.AEnv; +import org.adempiere.webui.apps.FeedbackRequestWindow; +import org.adempiere.webui.component.Window; +import org.adempiere.webui.util.FeedbackManager; +import org.adempiere.webui.window.WEMailDialog; +import org.compiere.model.MSystem; +import org.compiere.model.MUser; +import org.compiere.util.Env; +import org.compiere.util.Msg; +import org.compiere.util.Util; +import org.zkoss.zul.Window.Mode; + +/** + * @author hengsin + * + */ +public class DefaultFeedbackService implements IFeedbackService { + + /** + * default constructor + */ + public DefaultFeedbackService() { + } + + /* (non-Javadoc) + * @see org.adempiere.webui.factory.IFeedbackService#emailSupport(boolean) + */ + @Override + public void emailSupport(boolean errorOnly) { + DataSource ds = FeedbackManager.getLogAttachment(errorOnly); + + WEMailDialog dialog = new WEMailDialog( + Msg.getMsg(Env.getCtx(), "EMailSupport"), + MUser.get(Env.getCtx()), + "", // to + "iDempiere " + Msg.getMsg(Env.getCtx(), "TraceInfo"), + "", ds); + dialog.setAttribute(Window.MODE_KEY, Mode.OVERLAPPED); + + MSystem system = MSystem.get(Env.getCtx()); + if (!Util.isEmpty(system.getSupportEMail())) + { + dialog.addTo(system.getSupportEMail(), true); + } + AEnv.showWindow(dialog); + dialog.focus(); + + } + + /* (non-Javadoc) + * @see org.adempiere.webui.factory.IFeedbackService#createNewRequest() + */ + @Override + public void createNewRequest() { + FeedbackRequestWindow window = new FeedbackRequestWindow(); + AEnv.showWindow(window); + window.focus(); + } + +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/factory/IFeedbackService.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/factory/IFeedbackService.java new file mode 100644 index 0000000000..dab66b0de0 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/factory/IFeedbackService.java @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (C) 2013 Heng Sin Low * + * Copyright (C) 2013 Trek Global * + * 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. * + *****************************************************************************/ +package org.adempiere.webui.factory; + +/** + * + * @author hengsin + * + */ +public interface IFeedbackService { + + /** + * Email to support + * @param errorOnly + */ + public void emailSupport(boolean errorOnly); + + /** + * Create new support request + */ + public void createNewRequest(); +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java index 2186053dcc..a567b47eb1 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java @@ -483,6 +483,7 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL else contentPanel.setStyle("width: 99%; margin: 0px auto;"); contentPanel.setVflex(true); + contentPanel.setSizedByContent(true); North north = new North(); layout.appendChild(north); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoGeneralPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoGeneralPanel.java index 119ec82857..fc2d42c04b 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoGeneralPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoGeneralPanel.java @@ -169,6 +169,7 @@ public class InfoGeneralPanel extends InfoPanel implements EventListener else contentPanel.setStyle("width: 99%; margin: 0px auto;"); contentPanel.setVflex(true); + contentPanel.setSizedByContent(true); div.setStyle("width :100%; height: 100%"); center.appendChild(div); div.setVflex("1"); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/UserPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/UserPanel.java index a98fea3a1d..900ec5aa83 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/UserPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/UserPanel.java @@ -21,9 +21,11 @@ import java.util.Properties; import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.component.Label; +import org.adempiere.webui.component.Menupopup; import org.adempiere.webui.component.Messagebox; import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.session.SessionManager; +import org.adempiere.webui.util.FeedbackManager; import org.adempiere.webui.window.WPreference; import org.compiere.model.MClient; import org.compiere.model.MOrg; @@ -35,6 +37,7 @@ import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zul.Hbox; +import org.zkoss.zul.Menuitem; import org.zkoss.zul.Separator; import org.zkoss.zul.Vbox; @@ -56,9 +59,12 @@ public class UserPanel extends Vbox implements EventListener private ToolBarButton logout = new ToolBarButton(); private ToolBarButton changeRole = new ToolBarButton(); private ToolBarButton preference = new ToolBarButton(); + private ToolBarButton feedback = new ToolBarButton(); private Label lblUserNameValue = new Label(); private WPreference preferencePopup; + + private Menupopup feedbackMenu; public UserPanel() { @@ -87,6 +93,18 @@ public class UserPanel extends Vbox implements EventListener vbox.appendChild(hbox); hbox.setAlign("center"); + feedback.setLabel(Msg.getMsg(Env.getCtx(), "Feedback")); + feedback.setId("feedback"); + feedback.addEventListener(Events.ON_CLICK, this); + LayoutUtils.addSclass("desktop-header-font", feedback); + LayoutUtils.addSclass("link", feedback); + feedback.setParent(hbox); + + Separator sep = new Separator("vertical"); + sep.setBar(true); + sep.setHeight("13px"); + sep.setParent(hbox); + preference.setLabel(Msg.getMsg(Env.getCtx(), "Preference")); preference.setId("preference"); preference.addEventListener(Events.ON_CLICK, this); @@ -94,7 +112,7 @@ public class UserPanel extends Vbox implements EventListener LayoutUtils.addSclass("link", preference); preference.setParent(hbox); - Separator sep = new Separator("vertical"); + sep = new Separator("vertical"); sep.setBar(true); sep.setHeight("13px"); sep.setParent(hbox); @@ -117,6 +135,16 @@ public class UserPanel extends Vbox implements EventListener LayoutUtils.addSclass("desktop-header-font", logout); LayoutUtils.addSclass("link", logout); logout.setParent(hbox); + + feedbackMenu = new Menupopup(); + Menuitem mi = new Menuitem(Msg.getMsg(Env.getCtx(), "RequestNew")); + mi.setId("CreateRequest"); + feedbackMenu.appendChild(mi); + mi.addEventListener(Events.ON_CLICK, this); + mi = new Menuitem(Msg.getMsg(Env.getCtx(), "EMailSupport")); + mi.setId("EmailSupport"); + mi.addEventListener(Events.ON_CLICK, this); + feedbackMenu.appendChild(mi); } private String getUserName() @@ -180,6 +208,26 @@ public class UserPanel extends Vbox implements EventListener preferencePopup.setPage(this.getPage()); preferencePopup.open(preference, "after_start"); } + else if (feedback == event.getTarget()) + { + if (feedbackMenu.getPage() == null) + { + this.appendChild(feedbackMenu); + } + feedbackMenu.open(feedback, "after_start"); + } + else if (event.getTarget() instanceof Menuitem) + { + Menuitem mi = (Menuitem) event.getTarget(); + if ("CreateRequest".equals(mi.getId())) + { + FeedbackManager.createNewRequest(); + } + else if ("EmailSupport".equals(mi.getId())) + { + FeedbackManager.emailSupport(false); + } + } } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/WAttachment.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/WAttachment.java index 4cf9421799..955173a607 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/WAttachment.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/WAttachment.java @@ -115,7 +115,7 @@ public class WAttachment extends Window implements EventListener autoPreviewList.add("image/jpeg"); autoPreviewList.add("image/png"); autoPreviewList.add("image/gif"); - autoPreviewList.add("text/plan"); + autoPreviewList.add("text/plain"); autoPreviewList.add("application/pdf"); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/util/FeedbackManager.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/util/FeedbackManager.java new file mode 100644 index 0000000000..c53f108d12 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/util/FeedbackManager.java @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (C) 2013 Heng Sin Low * + * Copyright (C) 2013 Trek Global * + * 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. * + *****************************************************************************/ +package org.adempiere.webui.util; + +import javax.activation.DataSource; + +import org.adempiere.base.Service; +import org.adempiere.webui.ClientInfo; +import org.adempiere.webui.factory.IFeedbackService; +import org.adempiere.webui.session.SessionManager; +import org.compiere.util.ByteArrayDataSource; +import org.compiere.util.CLogErrorBuffer; +import org.compiere.util.Env; + +/** + * @author hengsin + * + */ +public class FeedbackManager { + + /** + * + * @param errorOnly + * @return attachment datasource + */ + public static DataSource getLogAttachment(boolean errorOnly) + { + String context = CLogErrorBuffer.get(true).getErrorInfo(Env.getCtx(), errorOnly); + ClientInfo browserInfo = SessionManager.getAppDesktop().getClientInfo(); + StringBuilder info = new StringBuilder(browserInfo.toString()); + info.append("\r\n").append(context); + + ByteArrayDataSource ds = new ByteArrayDataSource(info.toString(), "UTF-8", "text/plain"); + ds.setName("idempiere-log.txt"); + + return ds; + } + + /** + * EMail Support + */ + public static void emailSupport(boolean errorOnly) + { + IFeedbackService service = Service.locator().locate(IFeedbackService.class).getService(); + if (service != null) + service.emailSupport(errorOnly); + } + + /** + * Create new support request + */ + public static void createNewRequest() + { + IFeedbackService service = Service.locator().locate(IFeedbackService.class).getService(); + if (service != null) + service.createNewRequest(); + } +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/AboutWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/AboutWindow.java index ac9c79d1d8..1b3752ab56 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/AboutWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/AboutWindow.java @@ -36,6 +36,7 @@ import org.adempiere.webui.component.Tabs; import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.component.Window; import org.adempiere.webui.theme.ThemeManager; +import org.adempiere.webui.util.FeedbackManager; import org.compiere.Adempiere; import org.compiere.model.MUser; import org.compiere.util.CLogErrorBuffer; @@ -550,13 +551,7 @@ public class AboutWindow extends Window implements EventListener { */ private void cmd_errorEMail() { - new WEMailDialog(this, - "EMail Trace", - MUser.get(Env.getCtx()), - "", // to - "Adempiere Trace Info", - CLogErrorBuffer.get(true).getErrorInfo(Env.getCtx(), bErrorsOnly.isSelected()), - null); - + this.detach(); + FeedbackManager.emailSupport(bErrorsOnly.isSelected()); } // cmd_errorEMail } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WEMailDialog.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WEMailDialog.java index 102b671692..30f9c8fdf3 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WEMailDialog.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WEMailDialog.java @@ -18,11 +18,18 @@ package org.adempiere.webui.window; import java.beans.PropertyVetoException; -import java.io.File; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import java.util.StringTokenizer; import java.util.logging.Level; -import org.adempiere.webui.apps.AEnv; +import javax.activation.DataSource; + +import org.adempiere.webui.component.AttachmentItem; +import org.adempiere.webui.component.Button; import org.adempiere.webui.component.Column; import org.adempiere.webui.component.Columns; import org.adempiere.webui.component.ConfirmPanel; @@ -35,24 +42,28 @@ import org.adempiere.webui.component.Window; import org.adempiere.webui.editor.WSearchEditor; import org.adempiere.webui.event.ValueChangeEvent; import org.adempiere.webui.event.ValueChangeListener; -import org.adempiere.webui.panel.StatusBarPanel; import org.compiere.model.Lookup; import org.compiere.model.MClient; import org.compiere.model.MLookupFactory; import org.compiere.model.MUser; import org.compiere.model.MUserMail; +import org.compiere.util.ByteArrayDataSource; import org.compiere.util.CLogger; import org.compiere.util.DisplayType; import org.compiere.util.EMail; import org.compiere.util.Env; import org.compiere.util.Msg; +import org.compiere.util.Util; +import org.zkoss.util.media.Media; +import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; -import org.zkoss.zul.Borderlayout; -import org.zkoss.zul.Center; -import org.zkoss.zul.South; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zk.ui.event.UploadEvent; +import org.zkoss.zk.ui.util.Clients; +import org.zkoss.zul.Cell; import org.zkoss.zul.Div; -import org.zkoss.zul.Separator; +import org.zkoss.zul.Vlayout; /** * EMail Dialog @@ -77,7 +88,6 @@ public class WEMailDialog extends Window implements EventListener, ValueC /** * EMail Dialog - * @param owner calling window * @param title title * @param from from * @param to to @@ -85,16 +95,17 @@ public class WEMailDialog extends Window implements EventListener, ValueC * @param message message * @param attachment optional attachment */ - public WEMailDialog (Window owner, String title, MUser from, String to, - String subject, String message, File attachment) + public WEMailDialog (String title, MUser from, String to, + String subject, String message, DataSource attachment) { super(); this.setTitle(title); - this.setWidth("500px"); + this.setWidth("550px"); this.setHeight("600px"); this.setClosable(true); + this.setMaximizable(true); this.setBorder("normal"); - this.setStyle("position:absolute"); + this.setStyle("position:absolute; margin: 0; padding: 0;"); commonInit(from, to, subject, message, attachment); } // EmailDialog @@ -108,7 +119,7 @@ public class WEMailDialog extends Window implements EventListener, ValueC * @param attachment optional attachment */ private void commonInit (MUser from, String to, - String subject, String message, File attachment) + String subject, String message, DataSource attachment) { m_client = MClient.get(Env.getCtx()); try @@ -124,7 +135,6 @@ public class WEMailDialog extends Window implements EventListener, ValueC fUser.addValueChangeListener(this); fCcUser = new WSearchEditor(lookup, "AD_User_ID", "", false, false, true); fCcUser.addValueChangeListener(this); - jbInit(); } catch(Exception ex) { @@ -133,7 +143,6 @@ public class WEMailDialog extends Window implements EventListener, ValueC set(from, to, subject, message); setAttachment(attachment); setAttribute(Window.MODE_KEY, Window.MODE_HIGHLIGHTED); - AEnv.showWindow(this); } // commonInit @@ -151,7 +160,10 @@ public class WEMailDialog extends Window implements EventListener, ValueC private String m_subject; private String m_message; /** File to be optionally attached */ - private File m_attachFile; + private DataSource m_attachment; + + private List attachments = new ArrayList(); + /** Logger */ private static CLogger log = CLogger.getCLogger(WEMailDialog.class); @@ -166,15 +178,24 @@ public class WEMailDialog extends Window implements EventListener, ValueC private Label lCc = new Label(); private Label lSubject = new Label(); private Label lAttachment = new Label(); - private Textbox fAttachment = new Textbox();//40); private Textbox fMessage = new Textbox(); private ConfirmPanel confirmPanel = new ConfirmPanel(true); - private StatusBarPanel statusBar = new StatusBarPanel(); + + private Div attachmentBox; + + @Override + public void onPageAttached(Page newpage, Page oldpage) { + super.onPageAttached(newpage, oldpage); + try { + render(); + } catch (Exception e) { + } + } /** * Static Init */ - void jbInit() throws Exception + protected void render() throws Exception { lFrom.setValue(Msg.getMsg(Env.getCtx(), "From") + ":"); lTo.setValue(Msg.getMsg(Env.getCtx(), "To") + ":"); @@ -182,13 +203,11 @@ public class WEMailDialog extends Window implements EventListener, ValueC lSubject.setValue(Msg.getMsg(Env.getCtx(), "Subject") + ":"); lAttachment.setValue(Msg.getMsg(Env.getCtx(), "Attachment") + ":"); fFrom.setReadonly(true); - statusBar.setStatusDB(null); // Grid grid = new Grid(); grid.setWidth("100%"); - grid.setHeight("100%"); - grid.setStyle("margin:0; padding:0; position: absolute; align: center; valign: center; border:0"); + grid.setStyle("margin:0; padding:0; align: center; valign: center; border:0"); grid.makeNoStrip(); Columns columns = new Columns(); @@ -241,11 +260,7 @@ public class WEMailDialog extends Window implements EventListener, ValueC row.appendChild(new Label("")); row.appendChild(fCc); fCc.setHflex("1"); - - row = new Row(); - rows.appendChild(row); - row.appendCellChild(new Separator(), 2); - + row = new Row(); rows.appendChild(row); div = new Div(); @@ -255,18 +270,29 @@ public class WEMailDialog extends Window implements EventListener, ValueC row.appendChild(fSubject); fSubject.setHflex("1"); - row = new Row(); - rows.appendChild(row); - row.appendCellChild(new Separator(), 2); - row = new Row(); rows.appendChild(row); div = new Div(); div.setStyle("text-align: right;"); div.appendChild(lAttachment); - row.appendChild(div); - row.appendChild(fAttachment); - fAttachment.setHflex("1"); + Cell cell = new Cell(); + cell.appendChild(lAttachment); + cell.setValign("top"); + cell.setAlign("right"); + row.appendChild(cell); + + attachmentBox = new Div(); + attachmentBox.setHflex("1"); + attachmentBox.setVflex("1"); + row.appendChild(attachmentBox); + for (DataSource ds : attachments) { + boolean removable = true; + if (ds == m_attachment) { + removable = false; + } + AttachmentItem item = new AttachmentItem(ds, attachments, removable); + attachmentBox.appendChild(item); + } row = new Row(); rows.appendChild(row); @@ -276,29 +302,28 @@ public class WEMailDialog extends Window implements EventListener, ValueC confirmPanel.addActionListener(this); - Borderlayout layout = new Borderlayout(); - layout.setWidth("95%"); - layout.setHeight("92%"); - layout.setStyle("background-color: white; position: absolute; margin:0; border:0; padding:0"); + Vlayout vlayout = new Vlayout(); + vlayout.setStyle("width: 99%; margin: auto; height: 100%;"); - Center center = new Center(); - grid.setHflex("true"); - grid.setVflex("true"); - center.appendChild(grid); - layout.appendChild(center); - center.setStyle("background-color: white; border: 0"); + grid.setVflex("1"); + vlayout.appendChild(grid); - South south = new South(); Div southDiv = new Div(); - south.appendChild(southDiv); - layout.appendChild(south); - south.setStyle("background-color: white; border: 0"); + + Button btn = new Button(); + btn.setImage("/images/Attachment24.png"); + btn.setUpload("true"); + btn.addEventListener(Events.ON_UPLOAD, this); + btn.setTooltiptext(Msg.getMsg(Env.getCtx(), "Attachment")); + confirmPanel.addComponentsLeft(btn); + confirmPanel.getButton(ConfirmPanel.A_OK).setWidgetListener("onClick", "zAu.cmd0.showBusy(null)"); southDiv.appendChild(confirmPanel); - southDiv.appendChild(statusBar); + southDiv.setVflex("min"); + vlayout.appendChild(southDiv); - this.appendChild(layout); - } // jbInit + this.appendChild(vlayout); + } // render /** * Set all properties @@ -310,8 +335,6 @@ public class WEMailDialog extends Window implements EventListener, ValueC setTo(to); setSubject(subject); setMessage(message); - // - statusBar.setStatusLine(m_client.getSMTPHost()); } // set /** @@ -360,8 +383,7 @@ public class WEMailDialog extends Window implements EventListener, ValueC || !newFrom.isEMailValid() || !newFrom.isCanSendEMail()) { -// confirmPanel.getOKButton().setEnabled(false); - fFrom.setText("**Invalid**"); + fFrom.setText(""); } else fFrom.setText(m_from.getEMail()); @@ -415,29 +437,19 @@ public class WEMailDialog extends Window implements EventListener, ValueC /** * Set Attachment */ - public void setAttachment (File attachment) + public void setAttachment (DataSource attachment) { - m_attachFile = attachment; - if (attachment == null) - { - lAttachment.setVisible(false); - fAttachment.setVisible(false); - } - else - { - lAttachment.setVisible(true); - fAttachment.setVisible(true); - fAttachment.setText(attachment.getName()); - fAttachment.setReadonly(true); - } + m_attachment = attachment; + if (attachment != null) + attachments.add(attachment); } // setAttachment /** * Get Attachment */ - public File getAttachment() + public DataSource getAttachment() { - return m_attachFile; + return m_attachment; } // getAttachment /************************************************************************** @@ -446,14 +458,15 @@ public class WEMailDialog extends Window implements EventListener, ValueC public void onEvent(Event event) throws Exception { if (event.getTarget().getId().equals(ConfirmPanel.A_CANCEL)) onClose(); - - if (getTo() == null || getTo().length() == 0) - { - return; - } + // Send - if (event.getTarget().getId().equals(ConfirmPanel.A_OK)) + else if (event.getTarget().getId().equals(ConfirmPanel.A_OK)) { + Clients.clearBusy(); + if (getTo() == null || getTo().length() == 0) + { + return; + } StringTokenizer st = new StringTokenizer(getTo(), " ,;", false); String to = st.nextToken(); @@ -472,8 +485,11 @@ public class WEMailDialog extends Window implements EventListener, ValueC email.addCc(cc); } // Attachment - if (m_attachFile != null && m_attachFile.exists()) - email.addAttachment(m_attachFile); + for(DataSource ds : attachments) + { + email.addAttachment(ds); + } + status = email.send(); // if (m_user != null) @@ -488,14 +504,61 @@ public class WEMailDialog extends Window implements EventListener, ValueC } else FDialog.error(0, this, "MessageNotSent", status); - // -// confirmPanel.getOKButton().setEnabled(false); -// setCursor(Cursor.getDefaultCursor()); } - else if (event.getTarget().getId().equals(ConfirmPanel.A_CANCEL)) - onClose(); + else if (event instanceof UploadEvent) + { + UploadEvent ue = (UploadEvent) event; + Media media = ue.getMedia(); + if (media != null) + { + byte[] data = getMediaData(media); + ByteArrayDataSource dataSource = new ByteArrayDataSource(data, media.getContentType()); + dataSource.setName(media.getName()); + attachments.add(dataSource); + AttachmentItem item = new AttachmentItem(dataSource, attachments, true); + attachmentBox.appendChild(item); + getFirstChild().invalidate(); + } + } } + private byte[] getMediaData(Media media) { + byte[] bytes = null; + + try { + if (media.inMemory()) { + bytes = media.isBinary() ? media.getByteData() : media.getStringData().getBytes(getCharset(media.getContentType())); + } else { + + InputStream is = media.getStreamData(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[ 1000 ]; + int byteread = 0; + + while (( byteread=is.read(buf) )!=-1) + baos.write(buf,0,byteread); + + bytes = baos.toByteArray(); + } + } catch (IOException e) { + log.log(Level.SEVERE, e.getLocalizedMessage(), e); + throw new IllegalStateException(e.getLocalizedMessage()); + } + + return bytes; + } + + private String getCharset(String contentType) { + if (contentType != null) { + int j = contentType.indexOf("charset="); + if (j >= 0) { + String cs = contentType.substring(j + 8).trim(); + if (cs.length() > 0) return cs; + } + } + return "UTF-8"; + } + /** * Vetoable Change - User selected * @param evt @@ -518,7 +581,14 @@ public class WEMailDialog extends Window implements EventListener, ValueC { int AD_User_ID = ((Integer)value).intValue(); m_user = MUser.get(Env.getCtx(), AD_User_ID); - fTo.setValue(m_user.getEMail()); + if (Util.isEmpty(m_user.getEMail())) + { + FDialog.error(0, Msg.getMsg(Env.getCtx(), "UserNoEmailAddress")); + } + else + { + addTo(m_user.getEMail(), true); + } } } else { // fCcUser @@ -526,11 +596,41 @@ public class WEMailDialog extends Window implements EventListener, ValueC { int AD_User_ID = ((Integer)value).intValue(); m_ccuser = MUser.get(Env.getCtx(), AD_User_ID); - fCc.setValue(m_ccuser.getEMail()); + if (Util.isEmpty(m_ccuser.getEMail())) + { + FDialog.error(0, Msg.getMsg(Env.getCtx(), "UserNoEmailAddress")); + } + else + { + addCC(m_ccuser.getEMail(), true); + } } } return; } - + + public void addTo(String email, boolean first) { + if (Util.isEmpty(email)) + return; + + String to = fTo.getValue(); + if (!Util.isEmpty(to)) { + fTo.setValue(first ? email+","+to : to+","+email); + } else { + fTo.setValue(email); + } + } + + public void addCC(String email, boolean first) { + if (Util.isEmpty(email)) + return; + + String to = fCc.getValue(); + if (!Util.isEmpty(to)) { + fCc.setValue(first ? email+","+to : to+","+email); + } else { + fCc.setValue(email); + } + } } // VEMailDialog \ No newline at end of file diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/ZkReportViewer.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/ZkReportViewer.java index abd9c36240..4350835c59 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/ZkReportViewer.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/ZkReportViewer.java @@ -27,6 +27,7 @@ import java.sql.SQLException; import java.util.Properties; import java.util.logging.Level; +import javax.activation.FileDataSource; import javax.servlet.http.HttpServletRequest; import org.adempiere.exceptions.AdempiereException; @@ -775,9 +776,9 @@ public class ZkReportViewer extends Window implements EventListener, ITab log.log(Level.SEVERE, "", e); } - new WEMailDialog (this, - Msg.getMsg(Env.getCtx(), "SendMail"), - from, to, subject, message, attachment); + WEMailDialog dialog = new WEMailDialog (Msg.getMsg(Env.getCtx(), "SendMail"), + from, to, subject, message, new FileDataSource(attachment)); + AEnv.showWindow(dialog); } // cmd_sendMail /** diff --git a/org.adempiere.ui.zk/build.properties b/org.adempiere.ui.zk/build.properties index c483da351d..79fca455a6 100644 --- a/org.adempiere.ui.zk/build.properties +++ b/org.adempiere.ui.zk/build.properties @@ -29,7 +29,8 @@ bin.includes = META-INF/,\ WEB-INF/lib/atmosphere-compat-tomcat7-1.0.4.jar,\ WEB-INF/lib/atmosphere-runtime-1.0.4.jar,\ OSGI-INF/defaultcreatefromfactory.xml,\ - OSGI-INF/defaultformfactory.xml + OSGI-INF/defaultformfactory.xml,\ + OSGI-INF/feedbackservice.xml src.includes = WEB-INF/classes/,\ WEB-INF/tld/,\ WEB-INF/web.xml,\ diff --git a/org.adempiere.ui.zk/images/X8.png b/org.adempiere.ui.zk/images/X8.png new file mode 100644 index 0000000000..6b68fb15c6 Binary files /dev/null and b/org.adempiere.ui.zk/images/X8.png differ