r675 - in trunk: . faxtomail-persistence/src/main/java/com/franciaflex/faxtomail/persistence/entities faxtomail-persistence/src/main/xmi faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service faxtomail-ui-swing faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/demande faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action faxtomail-ui-web/src/ma
Author: kmorin Date: 2014-10-10 11:40:02 +0200 (Fri, 10 Oct 2014) New Revision: 675 Url: http://forge.codelutin.com/projects/faxtomail/repository/revisions/675 Log: - refs #5940 Page web de d?\195?\169tail d'un ?\195?\169l?\195?\169ment archiv?\195?\169 - correction affichage des pdf (pdfbox fonctionne mal avec les polices embarqu?\195?\169es, reprise du code avec pdf-renderer) Added: trunk/faxtomail-ui-web/src/main/webapp/css/demand-detail.css trunk/faxtomail-ui-web/src/main/webapp/js/demand-detail.js Modified: trunk/faxtomail-persistence/src/main/java/com/franciaflex/faxtomail/persistence/entities/EmailImpl.java trunk/faxtomail-persistence/src/main/xmi/faxtomail.zargo trunk/faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service/EmailService.java trunk/faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service/EmailServiceImpl.java trunk/faxtomail-ui-swing/pom.xml trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/demande/DemandeUIModel.java trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUI.css trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUIHandler.java trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUIModel.java trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/ArchiveSearchAction.java trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/DemandDetailAction.java trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/admin/ImportArchiveAction.java trunk/faxtomail-ui-web/src/main/resources/i18n/faxtomail-ui-web_fr_FR.properties trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/admin/lock-input.jsp trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/archive-search-input.jsp trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/demand-detail.jsp trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/decorators/layout.jsp trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/wro.xml trunk/faxtomail-ui-web/src/main/webapp/js/faxtomail.js trunk/pom.xml Modified: trunk/faxtomail-persistence/src/main/java/com/franciaflex/faxtomail/persistence/entities/EmailImpl.java =================================================================== --- trunk/faxtomail-persistence/src/main/java/com/franciaflex/faxtomail/persistence/entities/EmailImpl.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-persistence/src/main/java/com/franciaflex/faxtomail/persistence/entities/EmailImpl.java 2014-10-10 09:40:02 UTC (rev 675) @@ -26,6 +26,7 @@ import com.google.common.base.Function; import com.google.common.base.Predicate; +import com.google.common.base.Strings; import com.google.common.collect.Collections2; import org.apache.commons.lang3.StringUtils; @@ -198,4 +199,14 @@ } return StringUtils.join(reference, ", "); } + + @Override + public String getTitle() { + String result = getObject(); + String ref = getReference(); + if (!ref.isEmpty()) { + result = ref + " - " + result; + } + return Strings.nullToEmpty(result); + } } Modified: trunk/faxtomail-persistence/src/main/xmi/faxtomail.zargo =================================================================== (Binary files differ) Modified: trunk/faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service/EmailService.java =================================================================== --- trunk/faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service/EmailService.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service/EmailService.java 2014-10-10 09:40:02 UTC (rev 675) @@ -136,6 +136,7 @@ * * @param is input stream of csv file * @param attachmentBase base folder containing attachment listed in csv file + * @return the number of imported archives */ - void importArchive(InputStream is, File attachmentBase); + int importArchive(InputStream is, File attachmentBase); } Modified: trunk/faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service/EmailServiceImpl.java =================================================================== --- trunk/faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service/EmailServiceImpl.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-service/src/main/java/com/franciaflex/faxtomail/services/service/EmailServiceImpl.java 2014-10-10 09:40:02 UTC (rev 675) @@ -1388,13 +1388,7 @@ Map<String, Object> scopes = new HashMap<String, Object>(); - String result = email.getObject(); - String ref = email.getReference(); - if (!ref.isEmpty()) { - result = ref + " - " + result; - } - - scopes.put("title", result); + scopes.put("title", email.getTitle()); scopes.put("receivedDate", DateFormatUtils.format(email.getReceptionDate(), "dd/MM/yyyy HH:mm")); scopes.put("sender", email.getSender()); scopes.put("object", email.getObject()); @@ -1456,7 +1450,7 @@ } @Override - public void importArchive(InputStream inputStream, File attachmentBase) { + public int importArchive(InputStream inputStream, File attachmentBase) { // all doas involved EmailTopiaDao emailDao = getPersistenceContext().getEmailDao(); @@ -1499,15 +1493,25 @@ ArchiveImportModel archiveImportModel = new ArchiveImportModel(';', allWaitingStates, allDemandTypes, allPriority, mailFolderMap); Binder<ArchiveImportBean, Email> emailBinder = BinderFactory.newBinder(ArchiveImportBean.class, Email.class); Import<ArchiveImportBean> importer = null; + + int result = 0; try { importer = Import.newImport(archiveImportModel, new InputStreamReader(inputStream, getApplicationConfig().getImportFileEncoding())); for (ArchiveImportBean archiveBean : importer) { + if (archiveBean.getProjectReference() == null) { + log.error("null project ref for " + archiveBean.getReceptionDate()); + } + if (archiveBean.getMailFolder() == null) { + log.error("null mail folder for " + archiveBean.getReceptionDate()); + } // create new email to persist + //TODO add modified properties Email email = emailDao.newInstance(); emailBinder.copy(archiveBean, email); email.setDemandStatus(DemandStatus.ARCHIVED); + // persist it email = emailDao.create(email); @@ -1537,6 +1541,7 @@ } emailDao.update(email); + result++; } } @@ -1554,6 +1559,8 @@ IOUtils.closeQuietly(importer); IOUtils.closeQuietly(inputStream); } + + return result; } @Override Modified: trunk/faxtomail-ui-swing/pom.xml =================================================================== --- trunk/faxtomail-ui-swing/pom.xml 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-swing/pom.xml 2014-10-10 09:40:02 UTC (rev 675) @@ -231,6 +231,11 @@ </dependency> <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>pdf-renderer</artifactId> + </dependency> + + <dependency> <groupId>javax.media.jai</groupId> <artifactId>com.springsource.javax.media.jai.core</artifactId> <version>1.1.3</version> Modified: trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/demande/DemandeUIModel.java =================================================================== --- trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/demande/DemandeUIModel.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/demande/DemandeUIModel.java 2014-10-10 09:40:02 UTC (rev 675) @@ -945,12 +945,7 @@ @Override public String getTitle() { - String result = getObject(); - String ref = getReference(); - if (!ref.isEmpty()) { - result = ref + " - " + result; - } - return Strings.nullToEmpty(result); + return editObject.getTitle(); } @Override Modified: trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUI.css =================================================================== --- trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUI.css 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUI.css 2014-10-10 09:40:02 UTC (rev 675) @@ -59,14 +59,14 @@ #prevPageButton { actionIcon: left; - enabled: { getModel().getCurrentPageIndex() > 0 }; + enabled: { getModel().getCurrentPageIndex() > 1 }; toolTipText: "faxtomail.pdfEditor.button.previousPage"; } #pageNumber { bean: { model }; property: "currentPageIndex"; - modelText: { String.valueOf(model.getCurrentPageIndex() + 1) }; + modelText: { String.valueOf(model.getCurrentPageIndex()) }; useFloat: false; useSign: false; autoPopup: false; @@ -81,7 +81,7 @@ #nextPageButton { actionIcon: right; - enabled: { getModel().getCurrentPageIndex() < getModel().getPages().length - 1 }; + enabled: { getModel().getCurrentPageIndex() < getModel().getPages().length }; toolTipText: "faxtomail.pdfEditor.button.nextPage"; } Modified: trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUIHandler.java =================================================================== --- trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUIHandler.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUIHandler.java 2014-10-10 09:40:02 UTC (rev 675) @@ -26,12 +26,16 @@ import static org.nuiton.i18n.I18n.t; -import java.awt.*; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Rectangle; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; import java.awt.event.MouseEvent; import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -53,6 +57,8 @@ import javax.swing.JComponent; import javax.swing.JPanel; +import com.sun.pdfview.PDFFile; +import com.sun.pdfview.PDFPage; import jaxx.runtime.swing.ComponentMover; import jaxx.runtime.swing.ComponentResizer; import jaxx.runtime.swing.JAXXButtonGroup; @@ -61,10 +67,6 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.pdfbox.io.RandomAccess; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDPage; -import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.nuiton.jaxx.application.swing.util.Cancelable; import org.nuiton.jaxx.application.swing.util.CloseableUI; @@ -91,7 +93,7 @@ protected ComponentMover cm = new ComponentMover(); protected ComponentResizer cr = new ComponentResizer(); - protected PDDocument pdf; + protected PDFFile pdf; @Override public void afterInit(PDFEditorUI pdfEditorUI) { @@ -192,21 +194,27 @@ } } if (FaxToMailUIUtil.isFileAPDF(attachmentFile)) { + RandomAccessFile raf = null; try { - pdf = PDDocument.load(file); + raf = new RandomAccessFile(file, "r"); + FileChannel channel = raf.getChannel(); + ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + pdf = new PDFFile(buf); - model.setPageNumber(pdf.getNumberOfPages()); - model.setCurrentPageIndex(0); - + model.setPageNumber(pdf.getNumPages()); + model.setCurrentPageIndex(1); + raf.close(); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("", e); } getContext().getErrorHelper().showErrorDialog(t("faxtomail.pdfEditor.readPdf.error")); + } finally { + IOUtils.closeQuietly(raf); } } getUI().setCursor(Cursor.getDefaultCursor()); - model.firePropertyChanged(PDFEditorUIModel.PROPERTY_CURRENT_PAGE_INDEX, null, 0); + model.firePropertyChanged(PDFEditorUIModel.PROPERTY_CURRENT_PAGE_INDEX, null, 1); } } } @@ -343,6 +351,12 @@ for (JPanel panel : p.getCrosses()) { panel.setVisible(false); } + for (JPanel panel : p.getLines()) { + panel.setVisible(false); + } + for (JPanel panel : p.getHighlighters()) { + panel.setVisible(false); + } } displayPage(pageNb, getModel().getZoom(), getModel().getRotation()); @@ -351,10 +365,9 @@ } protected void displayPage(int pageNb, float previousZoom, int previousRotation) { - List<PDPage> pages = pdf.getDocumentCatalog().getAllPages(); - PDPage page = pages.get(pageNb); + PDFPage page = pdf.getPage(pageNb); // create the image - PDRectangle bBox = page.findCropBox(); + Rectangle2D bBox = page.getBBox(); Rectangle rect = new Rectangle(0, 0, (int) bBox.getWidth(), (int) bBox.getHeight()); @@ -363,165 +376,157 @@ int width = (int) (zoom * rect.width); int height = (int) (zoom * rect.height); - try { - Image image = page.convertToImage(BufferedImage.TYPE_INT_RGB, 72); - // page.getImage(width, height, // width & height - // rect, // clip rect - // null, // null for the ImageObserver - // true, // fill background with white - // true // block until drawing is done - // ); + Image image = page.getImage(width, height, // width & height + rect, // clip rect + null, // null for the ImageObserver + true, // fill background with white + true // block until drawing is done + ); - JPanel container = getUI().getContainer(); - Dimension containerSize = new Dimension(rotation % 180 == 0 ? width : height, - rotation % 180 == 0 ? height : width); - container.setPreferredSize(containerSize); - container.setMinimumSize(containerSize); - container.setMaximumSize(containerSize); - container.setSize(containerSize); + JPanel container = getUI().getContainer(); + Dimension containerSize = new Dimension(rotation % 180 == 0 ? width : height, + rotation % 180 == 0 ? height : width); + container.setPreferredSize(containerSize); + container.setMinimumSize(containerSize); + container.setMaximumSize(containerSize); + container.setSize(containerSize); - JImagePanel documentPanel = ui.getDocumentPanel(); - documentPanel.setRotation(rotation); - documentPanel.setImage(image); + JImagePanel documentPanel = ui.getDocumentPanel(); + documentPanel.setRotation(rotation); + documentPanel.setImage(image); - Insets insets = container.getInsets(); - rect = container.getBounds(); + Insets insets = container.getInsets(); + rect = container.getBounds(); - float zoomRatio = zoom / previousZoom; - int rotationDiff = rotation - previousRotation; + float zoomRatio = zoom / previousZoom; + int rotationDiff = rotation - previousRotation; - PDFEditorUIModel.Page p = getModel().getPage(pageNb); + PDFEditorUIModel.Page p = getModel().getPage(pageNb); - for (PDFEditorNoteUI panel : p.getNotes()) { - panel.setVisible(true); + for (PDFEditorNoteUI panel : p.getNotes()) { + panel.setVisible(true); - panel.setZoom(zoom); - Rectangle bounds = panel.getBounds(); - int x, y; + panel.setZoom(zoom); + Rectangle bounds = panel.getBounds(); + int x, y; - if (rotationDiff == 0) { - x = bounds.x; - y = bounds.y; + if (rotationDiff == 0) { + x = bounds.x; + y = bounds.y; - } else if (rotationDiff == 90 || rotationDiff == -270) { - x = rect.width - bounds.height / 2 - bounds.width / 2 - bounds.y; - y = bounds.x + bounds.width / 2 - bounds.height / 2; + } else if (rotationDiff == 90 || rotationDiff == -270) { + x = rect.width - bounds.height / 2 - bounds.width / 2 - bounds.y; + y = bounds.x + bounds.width / 2 - bounds.height / 2; - } else { - x = bounds.y + bounds.height / 2 - bounds.width / 2; - y = rect.height - bounds.height / 2 - bounds.width / 2 - bounds.x; - } - - panel.setBounds((int) (zoomRatio * x) + insets.left, - (int) (zoomRatio * y) + insets.top, - (int) (zoomRatio * bounds.width), (int) (zoomRatio * bounds.height)); - + } else { + x = bounds.y + bounds.height / 2 - bounds.width / 2; + y = rect.height - bounds.height / 2 - bounds.width / 2 - bounds.x; } - boolean orientation180 = Math.abs(rotationDiff) % 180 == 0; + panel.setBounds((int)(zoomRatio * x) + insets.left, + (int)(zoomRatio * y) + insets.top, + (int)(zoomRatio * bounds.width), (int)(zoomRatio * bounds.height)); - for (PDFEditorCrossUI panel : p.getCrosses()) { - panel.setVisible(true); + } - Rectangle bounds = panel.getBounds(); + boolean orientation180 = Math.abs(rotationDiff) % 180 == 0; - int newWidth = orientation180 ? bounds.width : bounds.height; - int newHeight = orientation180 ? bounds.height : bounds.width; + for (PDFEditorCrossUI panel : p.getCrosses()) { + panel.setVisible(true); - int x, y; + Rectangle bounds = panel.getBounds(); - if (rotationDiff == 0) { - x = bounds.x; - y = bounds.y; + int newWidth = orientation180 ? bounds.width : bounds.height; + int newHeight = orientation180 ? bounds.height : bounds.width; - } else if (rotationDiff == 90 || rotationDiff == -270) { - x = rect.width - newWidth - bounds.y; - y = bounds.x; + int x, y; - } else { - x = bounds.y; - y = rect.height - newHeight - bounds.x; - } + if (rotationDiff == 0) { + x = bounds.x; + y = bounds.y; - panel.setBounds((int) (zoomRatio * x) + insets.left, - (int) (zoomRatio * y) + insets.top, - (int) (zoomRatio * newWidth), (int) (zoomRatio * newHeight)); + } else if (rotationDiff == 90 || rotationDiff == -270) { + x = rect.width - newWidth - bounds.y; + y = bounds.x; + } else { + x = bounds.y; + y = rect.height - newHeight - bounds.x; } - List<PDFEditorLineUI> lines = p.getLines(); - cr.deregisterComponent(lines.toArray(new PDFEditorLineUI[lines.size()])); + panel.setBounds((int) (zoomRatio * x) + insets.left, + (int) (zoomRatio * y) + insets.top, + (int) (zoomRatio * newWidth), (int) (zoomRatio * newHeight)); - for (PDFEditorLineUI panel : lines) { - panel.setVisible(true); + } - Rectangle bounds = panel.getBounds(); + List<PDFEditorLineUI> lines = p.getLines(); + cr.deregisterComponent(lines.toArray(new PDFEditorLineUI[lines.size()])); - boolean horizontal = panel.isHorizontal(); - panel.setHorizontal(orientation180 ? horizontal : !horizontal); + for (PDFEditorLineUI panel : lines) { + panel.setVisible(true); - int newWidth = orientation180 ? bounds.width : bounds.height; - int newHeight = orientation180 ? bounds.height : bounds.width; + Rectangle bounds = panel.getBounds(); - int x, y; + boolean horizontal = panel.isHorizontal(); + panel.setHorizontal(orientation180 ? horizontal : ! horizontal); - if (rotationDiff == 0) { - x = bounds.x; - y = bounds.y; + int newWidth = orientation180 ? bounds.width : bounds.height; + int newHeight = orientation180 ? bounds.height : bounds.width; - } else if (rotationDiff == 90 || rotationDiff == -270) { - x = rect.width - newWidth - bounds.y; - y = bounds.x; + int x, y; - } else { - x = bounds.y; - y = rect.height - newHeight - bounds.x; - } + if (rotationDiff == 0) { + x = bounds.x; + y = bounds.y; - panel.setBounds((int) (zoomRatio * x) + insets.left, - (int) (zoomRatio * y) + insets.top, - (int) (zoomRatio * newWidth), (int) (zoomRatio * newHeight)); + } else if (rotationDiff == 90 || rotationDiff == -270) { + x = rect.width - newWidth - bounds.y; + y = bounds.x; - cr.registerComponent(panel.isHorizontal() ? ComponentResizer.DIRECTION_HORIZONTAL : ComponentResizer.DIRECTION_VERTICAL, - panel); + } else { + x = bounds.y; + y = rect.height - newHeight - bounds.x; } - for (PDFEditorHighlighterUI panel : p.getHighlighters()) { - panel.setVisible(true); + panel.setBounds((int) (zoomRatio * x) + insets.left, + (int) (zoomRatio * y) + insets.top, + (int) (zoomRatio * newWidth), (int) (zoomRatio * newHeight)); - Rectangle bounds = panel.getBounds(); + cr.registerComponent(panel.isHorizontal() ? ComponentResizer.DIRECTION_HORIZONTAL : ComponentResizer.DIRECTION_VERTICAL, + panel); + } - int newWidth = orientation180 ? bounds.width : bounds.height; - int newHeight = orientation180 ? bounds.height : bounds.width; + for (PDFEditorHighlighterUI panel : p.getHighlighters()) { + panel.setVisible(true); - int x, y; + Rectangle bounds = panel.getBounds(); - if (rotationDiff == 0) { - x = bounds.x; - y = bounds.y; + int newWidth = orientation180 ? bounds.width : bounds.height; + int newHeight = orientation180 ? bounds.height : bounds.width; - } else if (rotationDiff == 90 || rotationDiff == -270) { - x = rect.width - newWidth - bounds.y; - y = bounds.x; + int x, y; - } else { - x = bounds.y; - y = rect.height - newHeight - bounds.x; - } + if (rotationDiff == 0) { + x = bounds.x; + y = bounds.y; - panel.setBounds((int) (zoomRatio * x) + insets.left, - (int) (zoomRatio * y) + insets.top, - (int) (zoomRatio * newWidth), (int) (zoomRatio * newHeight)); + } else if (rotationDiff == 90 || rotationDiff == -270) { + x = rect.width - newWidth - bounds.y; + y = bounds.x; + } else { + x = bounds.y; + y = rect.height - newHeight - bounds.x; } - container.updateUI(); + panel.setBounds((int) (zoomRatio * x) + insets.left, + (int) (zoomRatio * y) + insets.top, + (int) (zoomRatio * newWidth), (int) (zoomRatio * newHeight)); - } catch (IOException e) { - if (log.isErrorEnabled()) { - log.error("Cannot convert page into image", e); - } } + + container.updateUI(); } public File convertFileToPdf(AttachmentFile attachmentFile) throws IOException, DocumentException { Modified: trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUIModel.java =================================================================== --- trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUIModel.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-swing/src/main/java/com/franciaflex/faxtomail/ui/swing/content/pdfeditor/PDFEditorUIModel.java 2014-10-10 09:40:02 UTC (rev 675) @@ -124,6 +124,7 @@ protected Page[] pages; + // first page is 1 not 0 protected int currentPageIndex = -1; protected float zoom = 1.0f; @@ -193,17 +194,17 @@ } public Page getCurrentPage() { - if (pages == null || currentPageIndex < 0 || currentPageIndex >= pages.length) { + if (pages == null || currentPageIndex < 1 || currentPageIndex > pages.length) { return null; } - return pages[currentPageIndex]; + return pages[currentPageIndex - 1]; } public Page getPage(int i) { - if (pages == null || i < 0 || i >= pages.length) { + if (pages == null || i < 1 || i > pages.length) { return null; } - return pages[i]; + return pages[i - 1]; } public int getCurrentPageIndex() { @@ -212,9 +213,9 @@ public void setCurrentPageIndex(int currentPageIndex) { Object oldValue = getCurrentPageIndex(); - currentPageIndex = Math.max(0, currentPageIndex); + currentPageIndex = Math.max(1, currentPageIndex); if (pages != null) { - currentPageIndex = Math.min(pages.length - 1, currentPageIndex); + currentPageIndex = Math.min(pages.length, currentPageIndex); } this.currentPageIndex = currentPageIndex; firePropertyChange(PROPERTY_CURRENT_PAGE_INDEX, oldValue, currentPageIndex); Modified: trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/ArchiveSearchAction.java =================================================================== --- trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/ArchiveSearchAction.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/ArchiveSearchAction.java 2014-10-10 09:40:02 UTC (rev 675) @@ -77,12 +77,14 @@ @Override @Action("archive-search") public String execute() throws Exception { - results = new ArrayList<>(emailService.searchArchives(commandQuotationNb, company)); - List<MailField> mailFields = configurationService.getSearchDisplayColumns(); - if (CollectionUtils.isEmpty(mailFields)) { - mailFields = Lists.newArrayList(MailField.getTableFields()); + if (commandQuotationNb != null && company != null) { + results = new ArrayList<>(emailService.searchArchives(commandQuotationNb, company)); + List<MailField> mailFields = configurationService.getSearchDisplayColumns(); + if (CollectionUtils.isEmpty(mailFields)) { + mailFields = Lists.newArrayList(MailField.getTableFields()); + } + tableMailFields = getEnumAsMap(mailFields.toArray(new MailField[mailFields.size()])); } - tableMailFields = getEnumAsMap(mailFields.toArray(new MailField[mailFields.size()])); return INPUT; } @@ -201,19 +203,19 @@ attrValue = email.getLastAttachmentOpener(); break; case REPLIES: - attrValue = "<i class='fa fa-envelope-o'></i> " + email.sizeReplies(); + attrValue = "<span class='fa fa-envelope-o'></span> " + email.sizeReplies(); break; case ATTACHMENT: - attrValue = "<i class='fa fa-paperclip'></i> " + email.sizeAttachment(); + attrValue = "<span class='fa fa-paperclip'></span> " + email.sizeAttachment(); break; case GROUP: EmailGroup emailGroup = email.getEmailGroup(); - attrValue = "<i class='fa fa-link'></i> " + (emailGroup == null ? 1 : emailGroup.sizeEmail()); + attrValue = "<span class='fa fa-link'></span> " + (emailGroup == null ? 1 : emailGroup.sizeEmail()); break; } String result; - if (attrValue == null) { + if (attrValue == null || StringUtils.isBlank(attrValue.toString())) { result = " "; } else { Modified: trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/DemandDetailAction.java =================================================================== --- trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/DemandDetailAction.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/DemandDetailAction.java 2014-10-10 09:40:02 UTC (rev 675) @@ -1,13 +1,19 @@ package com.franciaflex.faxtomail.web.action; import com.franciaflex.faxtomail.persistence.entities.Attachment; +import com.franciaflex.faxtomail.persistence.entities.AttachmentFile; +import com.franciaflex.faxtomail.persistence.entities.AttachmentFileImpl; +import com.franciaflex.faxtomail.persistence.entities.AttachmentImpl; import com.franciaflex.faxtomail.persistence.entities.Client; import com.franciaflex.faxtomail.persistence.entities.Email; import com.franciaflex.faxtomail.persistence.entities.EmailGroup; +import com.franciaflex.faxtomail.persistence.entities.FaxToMailUser; import com.franciaflex.faxtomail.persistence.entities.MailField; import com.franciaflex.faxtomail.persistence.entities.RangeRow; import com.franciaflex.faxtomail.persistence.entities.Reply; +import com.franciaflex.faxtomail.persistence.entities.ReplyContent; import com.franciaflex.faxtomail.services.DecoratorService; +import com.franciaflex.faxtomail.services.FaxToMailServiceUtils; import com.franciaflex.faxtomail.services.service.ConfigurationService; import com.franciaflex.faxtomail.services.service.EmailService; import com.franciaflex.faxtomail.web.FaxToMailActionSupport; @@ -15,19 +21,43 @@ import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.InterceptorRef; import org.apache.struts2.convention.annotation.InterceptorRefs; +import org.apache.struts2.convention.annotation.Result; import org.nuiton.decorator.Decorator; +import org.nuiton.topia.persistence.TopiaNoResultException; +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.mail.Address; +import javax.mail.BodyPart; +import javax.mail.Message; +import javax.mail.Part; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import java.awt.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import static org.nuiton.i18n.I18n.t; + /** * @author Kevin Morin (Code Lutin) * @since 1.1 @@ -45,8 +75,20 @@ protected DecoratorService decoratorService; protected String id; + protected boolean original; + protected Email demand; + protected int quotationTotal; + protected int productTotal; + protected int savTotal; + + protected EmailUIModel emailUIModel; + + protected InputStream attachmentFileInputStream; + protected String fileName; + protected String contentType; + public void setEmailService(EmailService emailService) { this.emailService = emailService; } @@ -58,7 +100,35 @@ @Override @Action("demand-detail") public String execute() throws Exception { - demand = emailService.getEmailById(id); + String result = SUCCESS; + try { + demand = emailService.getEmailById(id); + computeTotals(); + decomposeEmail(); + + } catch (TopiaNoResultException e) { + result = ERROR; + addActionError(t("faxtomail.demandDetail.noDemandForId", id)); + } + return result; + } + + @Action(value = "attachment-download", + results = {@Result(name = "success", + type = "stream", + params = { + "contentType", "${contentType}", + "inputName", "attachmentFileInputStream", + "contentDisposition", "attachment;filename=\"${fileName}\"", + "bufferSize", "1024" + }) + }) + public String dlAttachment() throws Exception { + AttachmentFile attachmentFile = emailService.getAttachmentFile(id, original); + File file = attachmentFile.getFile(); + fileName = attachmentFile.getFilename(); + contentType = Files.probeContentType(file.toPath()); + attachmentFileInputStream = new FileInputStream(file); return SUCCESS; } @@ -70,7 +140,287 @@ this.id = id; } + public void setOriginal(boolean original) { + this.original = original; + } + public Email getDemand() { return demand; } -} + + public int getQuotationTotal() { + return quotationTotal; + } + + public int getProductTotal() { + return productTotal; + } + + public int getSavTotal() { + return savTotal; + } + + public EmailUIModel getEmailUIModel() { + return emailUIModel; + } + + public InputStream getAttachmentFileInputStream() { + return attachmentFileInputStream; + } + + public String getFileName() { + return fileName; + } + + public String getContentType() { + return contentType; + } + + public List<EmailUIModel> getReplies() throws Exception { + List<EmailUIModel> result = new ArrayList<>(); + + for (Reply reply : demand.getReplies()) { + ReplyContent replyContent = reply.getReplyContent(); + Message message = new MimeMessage(null, new ByteArrayInputStream(replyContent.getSource())); + + EmailUIModel replyModel = new EmailUIModel(); + replyModel.setSubject(message.getSubject()); + + String toRecipient = message.getRecipients(MimeMessage.RecipientType.TO)[0].toString(); + replyModel.setToRecipients(Lists.newArrayList(toRecipient)); + + replyModel.setSender(message.getFrom()[0].toString()); + + if (ArrayUtils.isNotEmpty(message.getRecipients(MimeMessage.RecipientType.CC))) { + String ccRecipient = message.getRecipients(MimeMessage.RecipientType.CC)[0].toString(); + replyModel.setCcRecipients(Lists.newArrayList(ccRecipient)); + } + if (ArrayUtils.isNotEmpty(message.getRecipients(MimeMessage.RecipientType.BCC))) { + String bccRecipient = message.getRecipients(MimeMessage.RecipientType.BCC)[0].toString(); + replyModel.setBccRecipients(Lists.newArrayList(bccRecipient)); + } + + if (message.isMimeType("multipart/*")) { + decomposeMultipartEmail(message, replyModel); + + } else { + String content = IOUtils.toString(message.getInputStream()); + replyModel.setPlainContent(content); + } + result.add(replyModel); + } + + return result; + } + + public String decorate(Object o) { + return decorate(o, " "); + } + + public String decorateUser(FaxToMailUser user) { + return decorate(user, t("faxtomail.systemUser")); + } + + protected String decorate(Object o, String defaultValue) { + String result = null; + if (o != null) { + Decorator decorator = decoratorService.getDecoratorByType(o.getClass()); + if (decorator != null) { + result = decorator.toString(o); + } else { + result = o.toString(); + } + } + if (StringUtils.isBlank(result)) { + result = defaultValue; + } else { + result = result.replaceAll("(\r\n|\n)", "<br />"); + } + return result; + } + + protected void computeTotals() { + quotationTotal = 0; + productTotal = 0; + savTotal = 0; + + if (demand != null && demand.getRangeRow() != null) { + for (RangeRow row : demand.getRangeRow()) { + if (row.getQuotationQuantity() != null) { + quotationTotal += row.getQuotationQuantity(); + } + if (row.getProductQuantity() != null) { + productTotal += row.getProductQuantity(); + } + if (row.getSavQuantity() != null) { + savTotal += row.getSavQuantity(); + } + } + } + } + + protected void decomposeEmail() { + emailUIModel = new EmailUIModel(); + try { + // ce code peut provoquer une NPE avec les données de test + Message message = new MimeMessage(null, new ByteArrayInputStream(demand.getOriginalEmail().getBytes(StandardCharsets.UTF_8))); + emailUIModel.setSubject(message.getSubject()); + + List<String> toRecipients = new ArrayList<>(); + List<String> ccRecipients = new ArrayList<>(); + Address[] recipients = message.getRecipients(Message.RecipientType.TO); + if (recipients != null) { + for (Address address : recipients) { + toRecipients.add(address.toString()); + } + } + emailUIModel.setToRecipients(toRecipients); + + recipients = message.getRecipients(Message.RecipientType.CC); + if (recipients != null) { + for (Address address : recipients) { + ccRecipients.add(address.toString()); + } + } + emailUIModel.setCcRecipients(ccRecipients); + + if (message.isMimeType("multipart/*")) { + decomposeMultipartEmail(message, emailUIModel); + + } else { + String content = IOUtils.toString(message.getInputStream()); + emailUIModel.setPlainContent(content); + } + + } catch (Exception e) { + //TODO kmorin 20140516 do something when we use the real data + if (log.isErrorEnabled()) { + log.error("", e); + } + } + } + + /** + * Decompose a multipart part. + * - sets the email content if the part contains a text bodypart + * - adds attachments to the email + * + * @param part the part to decompose + * @throws Exception + */ + protected void decomposeMultipartEmail(Part part, EmailUIModel emailUIModel) throws Exception { + DataSource dataSource = part.getDataHandler().getDataSource(); + MimeMultipart mimeMultipart = new MimeMultipart(dataSource); + int multiPartCount = mimeMultipart.getCount(); + + for (int j = 0; j < multiPartCount; j++) { + BodyPart bp = mimeMultipart.getBodyPart(j); + + // if it is a text part, the,n this is the email content + String disposition = bp.getDisposition(); + if (bp.isMimeType("text/*") && !Part.ATTACHMENT.equals(disposition)) { + Charset charset = FaxToMailServiceUtils.getCharset(bp); + String content = IOUtils.toString(bp.getInputStream(), charset); + if (bp.isMimeType("text/plain")) { + emailUIModel.setPlainContent(content); + } else { + emailUIModel.setHtmlContent(content); + } + + // if it is multipart part, decompose it + } else if (bp.isMimeType("multipart/*")) { + decomposeMultipartEmail(bp, emailUIModel); + + // else, this is an attachment + } else { + String fileName = bp.getFileName(); + if (fileName == null) { + fileName = bp.getHeader("Content-ID")[0]; + // remove the guillemets between the id + fileName = fileName.replaceFirst("^<(.*)>$", "$1"); + } + + ByteArrayOutputStream fos = new ByteArrayOutputStream(); + + DataHandler dh = bp.getDataHandler(); + dh.writeTo(fos); + + // copy content into an empty attachment + AttachmentFile attachmentFile = new AttachmentFileImpl(); + attachmentFile.setContent(fos.toByteArray()); + attachmentFile.setFilename(fileName); + + emailUIModel.addAttachmentFile(attachmentFile); + } + } + } + + public static class EmailUIModel { + + protected String subject; + protected String sender; + protected String toRecipients; + protected String ccRecipients; + protected String bccRecipients; + protected String content; + protected List<AttachmentFile> attachments = new ArrayList<>(); + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getSender() { + return sender; + } + + public void setSender(String sender) { + this.sender = sender; + } + + public String getToRecipients() { + return toRecipients; + } + + public void setToRecipients(List<String> toRecipients) { + this.toRecipients = StringUtils.join(toRecipients, ", "); + } + + public String getCcRecipients() { + return ccRecipients; + } + + public void setCcRecipients(List<String> ccRecipients) { + this.ccRecipients = StringUtils.join(ccRecipients, ", "); + } + + public String getBccRecipients() { + return bccRecipients; + } + + public void setBccRecipients(List<String> bccRecipients) { + this.bccRecipients = StringUtils.join(bccRecipients, ", "); + } + + public void setPlainContent(String plainContent) { + if (content == null) { + this.content = plainContent == null ? null : plainContent.replaceAll("(\r\n|\n)", "<br />"); + } + } + + public void setHtmlContent(String htmlContent) { + this.content = htmlContent; + } + + public String getContent() { + return content; + } + + public void addAttachmentFile(AttachmentFile attachmentFile) { + attachments.add(attachmentFile); + } + } +} \ No newline at end of file Modified: trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/admin/ImportArchiveAction.java =================================================================== --- trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/admin/ImportArchiveAction.java 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/java/com/franciaflex/faxtomail/web/action/admin/ImportArchiveAction.java 2014-10-10 09:40:02 UTC (rev 675) @@ -115,8 +115,8 @@ checkDisabled(); } + @Override @Action(results = {@Result(type = "redirectAction", params = {"actionName", "import-archive-input"})}) - @Override public String execute() throws Exception { String result = INPUT; Modified: trunk/faxtomail-ui-web/src/main/resources/i18n/faxtomail-ui-web_fr_FR.properties =================================================================== --- trunk/faxtomail-ui-web/src/main/resources/i18n/faxtomail-ui-web_fr_FR.properties 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/resources/i18n/faxtomail-ui-web_fr_FR.properties 2014-10-10 09:40:02 UTC (rev 675) @@ -35,8 +35,13 @@ com.franciaflex.faxtomail.persistence.entities.MailField.SENDER=Émetteur com.franciaflex.faxtomail.persistence.entities.MailField.TAKEN_BY=Pris par com.franciaflex.faxtomail.persistence.entities.MailField.WAITING_STATE=État d'attente +faxtomail.demandDetail.noAttachmentForId=Aucune pièce jointe ne correspond à l'identifiant %s. +faxtomail.demandDetail.noDemandForId=Aucun élément ne correspond à l'identifiant %s. faxtomail.email.content.attachment.htmlfileName=contenu html du mail faxtomail.email.content.attachment.plainfileName=contenu texte du mail faxtomail.email.object.noClient=Client non trouvé faxtomail.email.projectReference.default=Votre demande du %s faxtomail.email.subject.re=Re \: %s +faxtomail.reply.forwardsubject= +faxtomail.reply.message= +faxtomail.systemUser=Système Modified: trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/admin/lock-input.jsp =================================================================== --- trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/admin/lock-input.jsp 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/admin/lock-input.jsp 2014-10-10 09:40:02 UTC (rev 675) @@ -54,7 +54,7 @@ <tr> <td><input type="checkbox" name="mailLockIds" value="<s:property value="topiaId" />" /> <td><s:property value="lockOn.object" /></td> - <td><s:property value="lockOn.companyReference" /></td> + <td><s:property value="lockOn.reference" /></td> <td><s:property value="lockOn.sender" /></td> <td> <s:property value="lockBy.firstName" /> <s:property value="lockBy.lastName" /> Modified: trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/archive-search-input.jsp =================================================================== --- trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/archive-search-input.jsp 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/archive-search-input.jsp 2014-10-10 09:40:02 UTC (rev 675) @@ -28,7 +28,7 @@ <s:if test="results != null"> - <div style="overflow-x: scroll; margin-top: 20px"> + <div style="overflow-x: auto; margin-top: 20px"> <s:if test="results.isEmpty()"> <em>Aucun résultat pour cette recherche.</em> @@ -50,7 +50,7 @@ <s:url id="detailUrlId" value="demand-detail.action"> <s:param name="id" value="%{topiaId}" /> </s:url> - <s:a href="%{detailUrlId}"><i class="fa fa-eye"></i></s:a> + <s:a href="%{detailUrlId}"><span class="fa fa-eye"></span></s:a> </td> <s:iterator value="tableMailFields"> <td class="cut-eol" title="<s:text name="%{getTooltip(key, #result)}"/>"><s:text name="%{getAttr(key, #result)}"/></td> Modified: trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/demand-detail.jsp =================================================================== --- trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/demand-detail.jsp 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/content/demand-detail.jsp 2014-10-10 09:40:02 UTC (rev 675) @@ -4,16 +4,273 @@ <html> <head> - <title>Détail de l'élément</title> + <title>Détail de l'élément <s:property value="demand.title"/></title> + <link rel="stylesheet" type="text/css" href="<s:url value='/nuiton-js/faxtomail-detail-demand.css' />" /> + <script type="text/javascript" src="<s:url value='/nuiton-js/faxtomail-detail-demand.js' />"></script> + <script type="text/javascript"> + DemandDetailModule.value('DemandDetailData', { + 'replies': <s:property value="toJson(replies)" escapeHtml="false"/> + }); + </script> </head> <body> - <div id="main-container" class="container"> + <div id="main-container" class="container" ng-app="DemandDetailModule" ng-controller="DemandDetailController"> + <s:if test="demand != null"> + <!-- groupe | réponses | historique | pj --> + <nav class="navbar navbar-default" role="navigation"> + <div class="container-fluid"> + <div class="navbar-header"> + <span class="navbar-brand"><s:property value="demand.title"/></span> + </div> + <ul class="nav navbar-nav navbar-right"> - <h1 class="page-header">Détail de l'élément <s:property value="demand.object"/></h1> + <!-- replies --> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" title="Réponses envoyées depuis l'application"> + <span class="fa fa-envelope-o"></span> (<s:property value="demand.sizeReplies()"/>) + <s:if test="demand.sizeReplies() > 0"> + <span class="caret"></span> + </s:if> + </a> + <s:if test="demand.sizeReplies() > 0"> + <ul class="dropdown-menu" role="menu"> + <s:iterator value="demand.replies" var="reply" status="status"> + <li><span> + <a ng-click='showReplyModal(<s:property value="#status.index"/>)' + class="fa fa-eye float-right" title="Voir la réponse"></a> + <span class="margin-right-1-icon"><s:text name="%{decorate(#reply)}" /></span> + </span></li> + </s:iterator> + </ul> + </s:if> + </li> + <!-- history --> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" title="Historique de l'élément"> + <span class="fa fa-calendar-o"></span> (<s:property value="demand.sizeHistory()"/>) + <s:if test="demand.sizeHistory() > 0"> + <span class="caret"></span> + </s:if> + </a> + <s:if test="demand.sizeHistory() > 0"> + <ul class="dropdown-menu" role="menu"> + <s:iterator value="demand.history" var="history"> + <li><span> + <div> + le <s:text name="%{decorate(#history.modificationDate)}"/> + <s:text name="%{decorate(#history.type)}"/> + par <s:text name="%{decorateUser(#history.faxToMailUser)}"/> + </div> + </span></li> + </s:iterator> + </ul> + </s:if> + </li> + <!-- attachments --> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" title="Pièces jointes de l'élément"> + <span class="fa fa-paperclip"></span> (<s:property value="demand.sizeAttachment()"/>) + <s:if test="demand.sizeAttachment() > 0"> + <span class="caret"></span> + </s:if> + </a> + <s:if test="demand.sizeAttachment() > 0"> + <ul class="dropdown-menu" role="menu"> + <s:iterator value="demand.attachment" var="attachment"> + <li><span> + <s:if test="#attachment.editedFileName != null"> + <!-- edited attachment --> + <s:url id="editedAttachmentUrlId" value="attachment-download.action"> + <s:param name="id" value="%{#attachment.topiaId}" /> + <s:param name="original" value="false" /> + </s:url> + <s:a href="%{editedAttachmentUrlId}" cssClass="fa fa-pencil float-right" title="Ouvrir la version éditée"></s:a> + </s:if> + <s:else> + <span class="fa fa-pencil float-right" title="Pas de version éditée"></span> + </s:else> + <!-- original attachment --> + <s:url id="originalAttachmentUrlId" value="attachment-download.action"> + <s:param name="id" value="%{#attachment.topiaId}" /> + <s:param name="original" value="true" /> + </s:url> + <s:a href="%{originalAttachmentUrlId}" cssClass="fa fa-folder-open-o float-right margin-right-10" title="Ouvrir la version originale"></s:a> + + <span class="margin-right-2-icons"><s:text name="%{decorate(#attachment)}" /></span> + </span></li> + </s:iterator> + </ul> + </s:if> + </li> + + <!-- group --> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" title="Éléments groupés"> + <span class="fa fa-link"></span> (<s:property value="demand.emailGroup != null ? demand.emailGroup.sizeEmail() : 1"/>) <span class="caret"></span> + </a> + <ul class="dropdown-menu" role="menu"> + <s:if test="demand.emailGroup != null"> + <s:iterator value="demand.emailGroup.email" var="email"> + <li><span> + <s:if test="demand.equals(#email)"> + <span class="fa fa-eye float-right" title="Élément courant"></span> + <span class="margin-right-1-icon"><s:property value="#email.title"/></span> + </s:if> + <s:else> + <s:url id="detailUrlId" value="demand-detail.action"> + <s:param name="id" value="%{#email.topiaId}" /> + </s:url> + <s:a href="%{detailUrlId}" cssClass="fa fa-eye float-right" title="Ouvrir l'élément groupé"></s:a> + <span class="margin-right-1-icon"><s:property value="#email.title"/></span> + </s:else> + </span></li> + </s:iterator> + </s:if> + <s:else> + <li><span> + <span class="fa fa-eye float-right" title="Élément courant"></span> + <span class="margin-right-1-icon"><s:property value="#email.title"/></span> + </span></li> + </s:else> + </ul> + </li> + </ul> + </div><!-- /.container-fluid --> + </nav> + + <dl class="dl-horizontal large-dl"> + <dt>Reçu le</dt> + <dd><s:property value="demand.receptionDate" /></dd> + <dt>Émetteur</dt> + <dd><s:property value="demand.sender" /></dd> + <dt>Objet</dt> + <dd><s:property value="demand.object" /></dd> + <dt>Client (marque)</dt> + <dd><s:if test="demand.client != null"><s:property value="demand.client.code" /> (<s:property value="demand.client.brand" />)</s:if></dd> + <dt>Type</dt> + <dd><s:text name="%{decorate(demand.demandType)}" /></dd> + <dt>Priorité</dt> + <dd><s:text name="%{decorate(demand.priority)}" /></dd> + <dt>Référence chantier</dt> + <dd><s:property value="demand.projectReference" /></dd> + <dt>Notre référence</dt> + <dd><s:property value="demand.companyReference" /></dd> + <dt>État d'attente</dt> + <dd><s:text name="%{decorate(demand.waitingState)}" /></dd> + </dl> + + <dl class="dl-horizontal large-dl"> + <s:if test="demand.firstOpeningDate != null"> + <dt>Première ouverture</dt> + <dd>par <s:text name="%{decorateUser(demand.firstOpeningUser)}" /> le <s:text name="%{decorate(demand.firstOpeningDate)}" /></dd> + </s:if> + <s:if test="demand.lastModificationDate != null"> + <dt>Dernière modification</dt> + <dd>par <s:text name="%{decorateUser(demand.lastModificationUser)}" /> le <s:text name="%{decorate(demand.lastModificationDate)}" /></dd> + </s:if> + <s:if test="demand.lastAttachmentOpeningInFolderDate != null"> + <dt>Dernière ouverture de pièce jointe</dt> + <dd>par <s:text name="%{decorateUser(demand.lastAttachmentOpeningInFolderUser)}" /> le <s:text name="%{decorate(demand.lastAttachmentOpeningInFolderDate)}" /></dd> + </s:if> + </dl> + + <s:if test="demand.sizeRangeRow() > 0"> + <table class="table table-bordered"> + <thead> + <tr> + <th title="Gamme">Gamme</th> + <th title="N° commande / devis">N° commande / devis</th> + <th title="Quantité de devis">Qté devis</th> + <th title="Quantité de produits">Qté produits</th> + <th title="Quantité de SAV">Qté SAV</th> + </tr> + </thead> + <tbody> + <s:iterator value="demand.rangeRow" var="row"> + <tr> + <td title="<s:text name="%{decorate(#row.range)}" />"><s:text name="%{decorate(#row.range)}" /></td> + <td title="<s:property value="#row.commandNumber"/>"><s:property value="#row.commandNumber"/></td> + <td title="<s:property value="#row.quotationQuantity"/>"><s:property value="#row.quotationQuantity"/></td> + <td title="<s:property value="#row.productQuantity"/>"><s:property value="#row.productQuantity"/></td> + <td title="<s:property value="#row.savQuantity"/>"><s:property value="#row.savQuantity"/></td> + </tr> + </s:iterator> + </tbody> + <tfoot> + <tr> + <th>Total</th> + <th></th> + <th><s:property value="quotationTotal"/></th> + <th><s:property value="productTotal"/></th> + <th><s:property value="savTotal"/></th> + </tr> + </tfoot> + </table> + </s:if> + + <dl class="dl-horizontal large-dl"> + <dt>À</dt> + <dd><s:property value="emailUIModel.toRecipients" /></dd> + <dt>Copie à</dt> + <dd><s:property value="emailUIModel.ccRecipients" /></dd> + <dt>Sujet</dt> + <dd><s:property value="emailUIModel.subject" /></dd> + <dt>Contenu de l'email reçu</dt> + <dd><s:property value="emailUIModel.content" escapeHtml="false"/></dd> + <dt>Message</dt> + <dd><s:text name="%{decorate(demand.comment)}" /> + </dl> + + </s:if> + + + <div class="modal fade" id="replyModal" + tabindex="-1" role="dialog" + aria-labelledby="replyModalLabel" aria-hidden="true"> + + <div class="modal-dialog modal-lg"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal"> + <span aria-hidden="true">×</span><span class="sr-only">Close</span> + </button> + <h4 class="modal-title" id="replyModalLabel">{{currentReply.subject}}</h4> + </div> + <div class="modal-body"> + <dl class="dl-horizontal"> + <dt>De</dt> + <dd>{{currentReply.sender}}</dd> + <dt>À</dt> + <dd>{{currentReply.toRecipients}}</dd> + <dt>Copie à</dt> + <dd>{{currentReply.ccRecipients}}</dd> + <dt>Copie cachée à</dt> + <dd>{{currentReply.bccRecipients}}</dd> + <dt>Sujet</dt> + <dd>{{currentReply.subject}}</dd> + </dl> + <hr/> + <p ng-bind-html="currentReply.content"></p> + <hr/> + Pièces jointes + <ul> + <li ng-repeat="attachment in currentReply.attachments"> + {{attachment.filename}} + </li> + </ul> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button> + </div> + </div> + </div> + </div> + + </div> </body> </html> \ No newline at end of file Modified: trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/decorators/layout.jsp =================================================================== --- trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/decorators/layout.jsp 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/decorators/layout.jsp 2014-10-10 09:40:02 UTC (rev 675) @@ -52,33 +52,50 @@ <div class="navbar-header"> <a href="<s:url value='/' />" class="navbar-brand">FaxToMail</a> </div> - <s:if test="authenticated"> - <nav class="collapse navbar-collapse" role="navigation"> - <ul class="nav navbar-nav"> - + <nav class="collapse navbar-collapse" role="navigation"> + <ul class="nav navbar-nav"> + <s:if test="authenticated"> <s:if test="admin"> - <li><a href="<s:url action='ldap-input' namespace="/admin" />"> - <span class="fa fa-database"></span> Active Directory</a></li> - <li><a href="<s:url action='configuration-input' namespace="/admin" />"> - <span class="fa fa-cog"></span> Configuration</a></li> - <li><a href="<s:url action='import-input' namespace="/admin" />"> - <span class="fa fa-file-excel-o"></span> Import</a></li> - <li><a href="<s:url action='lock-input' namespace="/admin" />"> - <span class="fa fa-unlock-alt"></span> Verrouillages</a></li> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="fa fa-wrench"></span> Administration <span class="caret"></span></a> + <ul class="dropdown-menu" role="menu"> + <li><a href="<s:url action='ldap-input' namespace="/admin" />"> + <span class="fa fa-database"></span> Active Directory</a></li> + <li><a href="<s:url action='configuration-input' namespace="/admin" />"> + <span class="fa fa-cogs"></span> Configuration</a></li> + <li><a href="<s:url action='import-input' namespace="/admin" />"> + <span class="fa fa-file-excel-o"></span> Import</a></li> + <li><a href="<s:url action='lock-input' namespace="/admin" />"> + <span class="fa fa-unlock-alt"></span> Verrouillages</a></li> + <li><a href="<s:url action='import-archive-input' namespace="/admin" />"> + <span class="fa fa-archive"></span> Reprise des archives</a></li> + </ul> + </li> </s:if> <li><a href="<s:url action='user-folder-input' namespace="/admin" />"> <span class="fa fa-folder-open"></span> Dossiers utilisateur</a></li> - </ul> - <ul class="nav navbar-nav navbar-right"> + </s:if> + + <li><a href="<s:url action='archive-search-input' />"> + <span class="fa fa-search"></span> Recherche archive</a></li> + + </ul> + + <ul class="nav navbar-nav navbar-right"> + <s:if test="authenticated"> <li><a><span class="fa fa-user"></span> <s:property value="authenticatedUser.firstName" /> <s:property value="authenticatedUser.lastName" /></a></li> <li><a href="<s:url action='logout' namespace="/" />"> <span class="fa fa-power-off"></span> Déconnexion</a></li> - </ul> - </nav> - </s:if> + </s:if> + <s:else> + <li><a href="<s:url action='login-input' namespace="/" />"> + <span class="fa fa-power-off"></span> Connexion</a></li> + </s:else> + </ul> + </nav> </div> </header> Modified: trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/wro.xml =================================================================== --- trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/wro.xml 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/webapp/WEB-INF/wro.xml 2014-10-10 09:40:02 UTC (rev 675) @@ -54,8 +54,6 @@ <js>classpath:META-INF/resources/webjars/respond/1.4.2/src/respond.js</js> </group> - - <group name='faxtomail'> <group-ref>jquery</group-ref> <group-ref>jquery-ui</group-ref> @@ -95,4 +93,12 @@ <group name='faxtomail-archive-search'> <css>/css/faxtomail.css</css> </group> + + <group name='faxtomail-detail-demand'> + <group-ref>angular-sanitize</group-ref> + <js>/js/demand-detail.js</js> + <css>/css/faxtomail.css</css> + <css>/css/demand-detail.css</css> + </group> + </groups> Added: trunk/faxtomail-ui-web/src/main/webapp/css/demand-detail.css =================================================================== --- trunk/faxtomail-ui-web/src/main/webapp/css/demand-detail.css (rev 0) +++ trunk/faxtomail-ui-web/src/main/webapp/css/demand-detail.css 2014-10-10 09:40:02 UTC (rev 675) @@ -0,0 +1,45 @@ +.float-right { + float: right; +} + +.margin-right-1-icon { + margin-right: 25px; +} + +.margin-right-2-icons { + margin-right: 45px; +} + +.margin-right-10 { + margin-right: 10px; +} + +.large-dl dt { + width: 235px; +} + +.large-dl dd { + margin-left: 255px; +} + +.dropdown-menu > li > span { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + color: #333; + white-space: nowrap; +} + +.dropdown-menu > li > span:hover, .dropdown-menu > li > span:focus { + color: #262626; + background-color: #F5F5F5; +} + +.dropdown-menu > li span,.dropdown-menu > li a { + line-height: 1.42857; +} + +.dropdown-menu > li a { + text-decoration: none; +} \ No newline at end of file Added: trunk/faxtomail-ui-web/src/main/webapp/js/demand-detail.js =================================================================== --- trunk/faxtomail-ui-web/src/main/webapp/js/demand-detail.js (rev 0) +++ trunk/faxtomail-ui-web/src/main/webapp/js/demand-detail.js 2014-10-10 09:40:02 UTC (rev 675) @@ -0,0 +1,15 @@ +var DemandDetailModule = angular.module('DemandDetailModule', ['FaxToMail', 'ngSanitize']); + +DemandDetailModule.controller('DemandDetailController', ['$scope', 'DemandDetailData', + function($scope, DemandDetailData) { + + // {Array} replies + $scope.replies = DemandDetailData.replies; + $scope.currentReply = null; + + $scope.showReplyModal = function(index) { + $scope.currentReply = $scope.replies[index]; + $('#replyModal').modal('show'); + } + +}]); Modified: trunk/faxtomail-ui-web/src/main/webapp/js/faxtomail.js =================================================================== --- trunk/faxtomail-ui-web/src/main/webapp/js/faxtomail.js 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/faxtomail-ui-web/src/main/webapp/js/faxtomail.js 2014-10-10 09:40:02 UTC (rev 675) @@ -92,3 +92,11 @@ } }; }); + +var ngBindHtmlDirective = ['$sce', function($sce) { + return function(scope, element, attr) { + scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) { + element.html(value || ''); + }); + }; + }]; Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2014-10-07 16:13:01 UTC (rev 674) +++ trunk/pom.xml 2014-10-10 09:40:02 UTC (rev 675) @@ -306,6 +306,12 @@ </dependency> <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>pdf-renderer</artifactId> + <version>1.0.5</version> + </dependency> + + <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>1.8.7</version>
participants (1)
-
kmorin@users.forge.codelutin.com