Upload media in separate directory.
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 23 Jan 2021 09:43:18 +0000 (10:43 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 23 Jan 2021 09:43:18 +0000 (10:43 +0100)
org.argeo.entity.api/src/org/argeo/entity/EntityNames.java
publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/CmsTextImageManager.java
publishing/org.argeo.publishing.ui/src/org/argeo/docbook/DbkUtils.java
publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java
publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImageManager.java
publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImg.java [new file with mode: 0644]
publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DocBookNames.java

index 07504318aec9f17be245e2a206d3630f8476c6e4..ede744722814360b2a740abbcb0b5e735368c42b 100644 (file)
@@ -29,6 +29,10 @@ public interface EntityNames {
        @Deprecated
        final String ENTITY_RELATED_TO = "entity:relatedTo";
 
+       // DEFAULT FOLDER NAMES
+       final String MEDIA = "media";
+       final String FILES = "files";
+
        // LDAP-LIKE ENTITIES
        @Deprecated
        final String DISPLAY_NAME = LdapAttrs.displayName.property();
index 9f94a6a899a2f2a6f3bf39f0e99261dad665b09b..865c2ce50da0508e9ef51ab192c689c7a4fb8056 100644 (file)
@@ -33,7 +33,9 @@ public class CmsTextImageManager extends DefaultImageManager {
        }
 
        @Override
-       protected void processNewImageFile(Node fileNode, ImageData id) throws RepositoryException, IOException {
+       protected void processNewImageFile(Node context,
+                       Node fileNode, ImageData id)
+                       throws RepositoryException, IOException {
                fileNode.addMixin(CmsTypes.CMS_IMAGE);
                fileNode.setProperty(CmsNames.CMS_IMAGE_WIDTH, id.width);
                fileNode.setProperty(CmsNames.CMS_IMAGE_HEIGHT, id.height);
index 6a8da8e5d54c88bc4392fd3b8e58894e19047166..e153e86c39f226456c0d9f246bff00ddaf1742c5 100644 (file)
@@ -69,6 +69,12 @@ public class DbkUtils {
 
        public static Node insertImageAfter(Node sibling) {
                try {
+
+                       // FIXME make it more robust
+                       if (DocBookTypes.IMAGEDATA.equals(sibling.getName())) {
+                               sibling = sibling.getParent().getParent();
+                       }
+
                        Node parent = sibling.getParent();
                        Node mediaNode = parent.addNode(DocBookTypes.MEDIAOBJECT, DocBookTypes.MEDIAOBJECT);
                        // TODO optimise?
@@ -78,12 +84,18 @@ public class DbkUtils {
                                        mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
 
                        Node imageNode = mediaNode.addNode(DocBookTypes.IMAGEOBJECT, DocBookTypes.IMAGEOBJECT);
-                       Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
-                       Node imageDataNode = JcrUtils.copyBytesAsFile(infoNode, EntityType.box.get(), new byte[0]);
-                       imageDataNode.addMixin(EntityType.box.get());
-                       imageDataNode.setProperty(EntityNames.SVG_WIDTH, 0);
-                       imageDataNode.setProperty(EntityNames.SVG_LENGTH, 0);
-                       imageDataNode.addMixin(NodeType.MIX_MIMETYPE);
+                       Node imageDataNode = imageNode.addNode(DocBookTypes.IMAGEDATA, DocBookTypes.IMAGEDATA);
+//                     Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
+//                     Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]);
+//                     fileNode.addMixin(EntityType.box.get());
+//                     fileNode.setProperty(EntityNames.SVG_WIDTH, 0);
+//                     fileNode.setProperty(EntityNames.SVG_LENGTH, 0);
+//                     fileNode.addMixin(NodeType.MIX_MIMETYPE);
+//
+//                     // we assume this is a folder next to the main DocBook document
+//                     // TODO make it more robust and generic
+//                     String fileRef = mediaNode.getName();
+//                     imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef);
                        return imageDataNode;
                } catch (RepositoryException e) {
                        throw new JcrException("Cannot insert empty image after " + sibling, e);
index 45737180acd3fc15dab39152efcba9c3844ffaca..c324756c28f7944353eb2a5eca05410bb6ce83b2 100644 (file)
@@ -21,8 +21,6 @@ import org.argeo.cms.text.Paragraph;
 import org.argeo.cms.text.TextInterpreter;
 import org.argeo.cms.text.TextSection;
 import org.argeo.cms.ui.CmsEditable;
-import org.argeo.cms.ui.CmsImageManager;
-import org.argeo.cms.ui.CmsView;
 import org.argeo.cms.ui.util.CmsUiUtils;
 import org.argeo.cms.ui.viewers.AbstractPageViewer;
 import org.argeo.cms.ui.viewers.EditablePart;
@@ -30,11 +28,9 @@ import org.argeo.cms.ui.viewers.NodePart;
 import org.argeo.cms.ui.viewers.PropertyPart;
 import org.argeo.cms.ui.viewers.Section;
 import org.argeo.cms.ui.viewers.SectionPart;
-import org.argeo.cms.ui.widgets.EditableImage;
 import org.argeo.cms.ui.widgets.EditableText;
-import org.argeo.cms.ui.widgets.Img;
 import org.argeo.cms.ui.widgets.StyledControl;
-import org.argeo.entity.EntityType;
+import org.argeo.jcr.Jcr;
 import org.argeo.jcr.JcrException;
 import org.argeo.jcr.JcrUtils;
 import org.eclipse.rap.fileupload.FileDetails;
@@ -61,7 +57,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
        private final Section mainSection;
 
        private TextInterpreter textInterpreter = new DbkTextInterpreter();
-       private CmsImageManager imageManager;
+       private DbkImageManager imageManager;
 
        private FileUploadListener fileUploadListener;
        private DbkContextMenu styledTools;
@@ -70,9 +66,8 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
 
        protected AbstractDbkViewer(Section parent, int style, CmsEditable cmsEditable) {
                super(parent, style, cmsEditable);
-               CmsView cmsView = CmsView.getCmsView(parent);
+//             CmsView cmsView = CmsView.getCmsView(parent);
 //             imageManager = cmsView.getImageManager();
-               imageManager = new DbkImageManager();
                flat = SWT.FLAT == (style & SWT.FLAT);
 
                if (getCmsEditable().canEdit()) {
@@ -80,6 +75,8 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        styledTools = new DbkContextMenu(this, parent.getShell());
                }
                this.mainSection = parent;
+               Node baseFolder = Jcr.getParent(mainSection.getNode());
+               imageManager = new DbkImageManager(baseFolder);
                initModelIfNeeded(mainSection.getNode());
                // layout(this.mainSection);
        }
@@ -111,9 +108,8 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                SectionPart sectionPart = null;
                                if (child.isNodeType(DocBookTypes.MEDIAOBJECT)) {
                                        if (child.hasNode(DocBookTypes.IMAGEOBJECT)) {
-                                               Node imageNode = child.getNode(DocBookTypes.IMAGEOBJECT).getNode(DocBookTypes.INFO)
-                                                               .getNode(EntityType.box.get());
-                                               sectionPart = newImg(textSection, imageNode);
+                                               Node imageDataNode = child.getNode(DocBookTypes.IMAGEOBJECT).getNode(DocBookTypes.IMAGEDATA);
+                                               sectionPart = newImg(textSection, imageDataNode);
                                        }
                                } else if (child.isNodeType(DocBookTypes.PARA)) {
                                        sectionPart = newParagraph(textSection, child);
@@ -157,21 +153,9 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                return paragraph;
        }
 
-       protected Img newImg(TextSection parent, Node node) {
+       protected DbkImg newImg(TextSection parent, Node node) {
                try {
-                       Img img = new Img(parent, parent.getStyle(), node, imageManager) {
-                               private static final long serialVersionUID = 1297900641952417540L;
-
-                               @Override
-                               protected void setContainerLayoutData(Composite composite) {
-                                       composite.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
-                               }
-
-                               @Override
-                               protected void setControlLayoutData(Control control) {
-                                       control.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
-                               }
-                       };
+                       DbkImg img = new DbkImg(parent, parent.getStyle(), node, imageManager);
                        img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
                        updateContent(img);
                        img.setMouseListener(getMouseListener());
@@ -241,8 +225,8 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                        paragraph.setText(textInterpreter.raw(partNode));
                                else
                                        paragraph.setText(textInterpreter.readSimpleHtml(partNode));
-                       } else if (part instanceof EditableImage) {
-                               EditableImage editableImage = (EditableImage) part;
+                       } else if (part instanceof DbkImg) {
+                               DbkImg editableImage = (DbkImg) part;
                                imageManager.load(partNode, part.getControl(), editableImage.getPreferredImageSize());
                        }
                } else if (part instanceof DocBookSectionTitle) {
@@ -333,8 +317,8 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                        "ALT+ARROW_RIGHT", "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", "ENTER", "DELETE" });
                        text.setData(RWT.CANCEL_KEYS, new String[] { "RETURN", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
                        text.addKeyListener(this);
-               } else if (part instanceof Img) {
-                       ((Img) part).setFileUploadListener(fileUploadListener);
+               } else if (part instanceof DbkImg) {
+                       ((DbkImg) part).setFileUploadListener(fileUploadListener);
                }
        }
 
@@ -369,9 +353,11 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                try {
                        Node node = sectionPart.getNode();
                        Session session = node.getSession();
-                       if (sectionPart instanceof Img) {
+                       if (sectionPart instanceof DbkImg) {
                                // FIXME make it more robust
-                               node = node.getParent().getParent().getParent();
+                               node = node.getParent().getParent();
+                               if (!DocBookNames.DBK_MEDIAOBJECT.equals(node.getName()))
+                                       throw new IllegalArgumentException("Node " + node + " is not a media object.");
                        }
                        node.remove();
                        session.save();
@@ -538,10 +524,10 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                        // sectionNode.orderBefore(p(partNode.getIndex()),
                                        // p(newNode.getIndex()));
                                        persistChanges(sectionNode);
-                                       Img img = newImg((TextSection) section, newNode);
+                                       DbkImg img = newImg((TextSection) section, newNode);
                                        edit(img, null);
                                        layout(img.getControl());
-                               } else if (part instanceof Img) {
+                               } else if (part instanceof DbkImg) {
                                        if (getEdited() == part)
                                                return;
                                        edit(part, null);
@@ -841,9 +827,9 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                Control source = (Control) e.getSource();
                                EditablePart composite = findDataParent(source);
                                Point point = new Point(e.x, e.y);
-                               if (composite instanceof Img) {
+                               if (composite instanceof DbkImg) {
                                        if (getCmsEditable().canEdit()) {
-                                               if (getCmsEditable().isEditing() && !(getEdited() instanceof Img)) {
+                                               if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg)) {
                                                        if (source == mainSection)
                                                                return;
                                                        EditablePart part = findDataParent(source);
index 2e72a3e767249711de4dd30c4a57fea505342f7b..2b57b4b9cf768883b8f53be7ac6f7843a9505dfc 100644 (file)
 package org.argeo.docbook.ui;
 
+import static javax.jcr.Node.JCR_CONTENT;
+import static javax.jcr.Property.JCR_DATA;
+import static javax.jcr.nodetype.NodeType.NT_FILE;
+
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 
 import javax.jcr.Binary;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
 
 import org.argeo.cms.ui.CmsImageManager;
+import org.argeo.cms.ui.util.CmsUiUtils;
 import org.argeo.cms.ui.util.DefaultImageManager;
 import org.argeo.entity.EntityNames;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
 import org.eclipse.swt.graphics.ImageData;
 import org.eclipse.swt.graphics.Point;
 
 /** Add DocBook images support to {@link CmsImageManager}. */
 public class DbkImageManager extends DefaultImageManager {
+       private Node baseFolder = null;
+
+       public DbkImageManager(Node baseFolder) {
+               this.baseFolder = baseFolder;
+       }
+
        @Override
        public Binary getImageBinary(Node node) throws RepositoryException {
-               Binary binary = super.getImageBinary(node);
-               return binary;
+               Node fileNode = null;
+               if (node.getName().equals(DocBookTypes.IMAGEDATA)) {
+                       fileNode = getFileNode(node);
+               }
+               if (node.isNodeType(NT_FILE)) {
+                       fileNode = node;
+               }
+               if (fileNode != null) {
+                       return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();
+               } else {
+                       return null;
+               }
        }
 
-       public Point getImageSize(Node node) throws RepositoryException {
-               int width = node.hasProperty(EntityNames.SVG_WIDTH) ? (int) node.getProperty(EntityNames.SVG_WIDTH).getLong()
-                               : 0;
-               int height = node.hasProperty(EntityNames.SVG_HEIGHT) ? (int) node.getProperty(EntityNames.SVG_HEIGHT).getLong()
-                               : 0;
-               return new Point(width, height);
+       public Point getImageSize(Node imageDataNode) throws RepositoryException {
+               Node fileNode = getFileNode(imageDataNode);
+               if (fileNode == null)
+                       return new Point(0, 0);
+               Point intrinsicSize;
+               if (fileNode.hasProperty(EntityNames.SVG_WIDTH) && fileNode.hasProperty(EntityNames.SVG_HEIGHT)) {
+                       int width = (int) fileNode.getProperty(EntityNames.SVG_WIDTH).getLong();
+                       int height = (int) fileNode.getProperty(EntityNames.SVG_HEIGHT).getLong();
+                       intrinsicSize = new Point(width, height);
+               } else {
+                       try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
+                               ImageData id = new ImageData(in);
+                               intrinsicSize = updateSize(fileNode, id);
+                       } catch (IOException e) {
+                               throw new RuntimeException("Cannot load file " + fileNode, e);
+                       }
+               }
+               // TODO interpret image data infos
+               return intrinsicSize;
        }
 
-       @Override
-       protected void processNewImageFile(Node fileNode, ImageData id) throws RepositoryException, IOException {
+       protected Point updateSize(Node fileNode, ImageData id) throws RepositoryException {
+               fileNode.addMixin(EntityType.box.get());
                fileNode.setProperty(EntityNames.SVG_WIDTH, id.width);
                fileNode.setProperty(EntityNames.SVG_HEIGHT, id.height);
+               return new Point(id.width, id.height);
+       }
+
+       @Override
+       protected void processNewImageFile(Node context, Node fileNode, ImageData id)
+                       throws RepositoryException, IOException {
+               updateSize(fileNode, id);
+               String filePath = fileNode.getPath();
+               String relPath = filePath.substring(baseFolder.getPath().length() + 1);
+               context.setProperty(DocBookNames.DBK_FILEREF, relPath);
+       }
+
+       @Override
+       public String getImageUrl(Node imageDataNode) throws RepositoryException {
+               // TODO factorise
+               String fileref = null;
+               if (imageDataNode.hasProperty(DocBookNames.DBK_FILEREF))
+                       fileref = imageDataNode.getProperty(DocBookNames.DBK_FILEREF).getString();
+               if (fileref == null)
+                       return null;
+               URI fileUri;
+               try {
+                       fileUri = new URI(URLEncoder.encode(fileref, StandardCharsets.UTF_8.toString()));
+               } catch (URISyntaxException | UnsupportedEncodingException e) {
+                       throw new IllegalArgumentException("File ref in " + imageDataNode + " is badly formatted", e);
+               }
+               if (fileUri.getScheme() != null)
+                       return fileUri.toString();
+               // local
+               Node fileNode = getFileNode(imageDataNode);
+               String url = CmsUiUtils.getDataPath(fileNode);
+               return url;
        }
 
+       protected Node getFileNode(Node imageDataNode) throws RepositoryException {
+               // FIXME make URL use case more robust
+               String fileref = null;
+               if (imageDataNode.hasProperty(DocBookNames.DBK_FILEREF))
+                       fileref = imageDataNode.getProperty(DocBookNames.DBK_FILEREF).getString();
+               if (fileref == null)
+                       return null;
+               Node fileNode;
+               if (fileref.startsWith("/"))
+                       fileNode = baseFolder.getSession().getNode(fileref);
+               else
+                       fileNode = baseFolder.getNode(fileref);
+               return fileNode;
+       }
+
+       protected Node getMediaFolder() {
+               try {
+                       // TODO check edition status
+                       Node mediaFolder = JcrUtils.getOrAdd(baseFolder, EntityNames.MEDIA, NodeType.NT_FOLDER);
+                       return mediaFolder;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get media folder", e);
+               }
+       }
 }
diff --git a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImg.java b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImg.java
new file mode 100644 (file)
index 0000000..cb4ce2e
--- /dev/null
@@ -0,0 +1,70 @@
+package org.argeo.docbook.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.widgets.Img;
+import org.eclipse.rap.fileupload.FileUploadEvent;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadListener;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** DocBook specific image area. */
+public class DbkImg extends Img {
+       private static final long serialVersionUID = -6150996708899219074L;
+
+       public DbkImg(Composite parent, int swtStyle, Node imgNode, DbkImageManager imageManager)
+                       throws RepositoryException {
+               super(parent, swtStyle, imgNode, imageManager);
+       }
+
+       @Override
+       protected Node getUploadFolder() {
+               Node mediaFolder = ((DbkImageManager) getImageManager()).getMediaFolder();
+               return mediaFolder;
+       }
+
+       @Override
+       protected String getUploadName() {
+               return null;
+       }
+
+       @Override
+       protected void setContainerLayoutData(Composite composite) {
+               composite.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+       }
+
+       @Override
+       protected void setControlLayoutData(Control control) {
+               control.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+       }
+
+       @Override
+       protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) {
+               FileUploadHandler fileUploadHandler = super.prepareUpload(receiver);
+               fileUploadHandler.addUploadListener(new FileUploadListener() {
+
+                       @Override
+                       public void uploadProgress(FileUploadEvent event) {
+                               // TODO Auto-generated method stub
+
+                       }
+
+                       @Override
+                       public void uploadFinished(FileUploadEvent event) {
+                       }
+
+                       @Override
+                       public void uploadFailed(FileUploadEvent event) {
+                               // TODO Auto-generated method stub
+
+                       }
+               });
+               return fileUploadHandler;
+       }
+
+}
index c7848d102a8345cd9ce29116cd63c7e9c1390f4c..10fa7a455083392c6665c19c4c0f195aed891c08 100644 (file)
@@ -11,6 +11,10 @@ public interface DocBookNames {
        // ATTRIBUTES
 //     public final static String JCR_XMLTEXT = "jcr:xmltext";
 //     public final static String JCR_XMLCHARACTERS = "jcr:xmlcharacters";
-       
+
        public final static String DBK_ROLE = "dbk:role";
+       public final static String DBK_FILEREF = "dbk:fileref";
+       public final static String DBK_CONTENTWIDTH = "dbk:contentwidth";
+       public final static String DBK_CONTENTDEPTH = "dbk:contentdepth";
+
 }