From: Mathieu Baudier Date: Sat, 23 Jan 2021 09:43:18 +0000 (+0100) Subject: Upload media in separate directory. X-Git-Tag: argeo-suite-2.1.18~27 X-Git-Url: https://git.argeo.org/?p=gpl%2Fargeo-suite.git;a=commitdiff_plain;h=1f5f12ce52315e19fb0016527c31127b70dceb5d Upload media in separate directory. --- diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java b/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java index 0750431..ede7447 100644 --- a/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java +++ b/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java @@ -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(); diff --git a/publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/CmsTextImageManager.java b/publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/CmsTextImageManager.java index 9f94a6a..865c2ce 100644 --- a/publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/CmsTextImageManager.java +++ b/publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/CmsTextImageManager.java @@ -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); diff --git a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/DbkUtils.java b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/DbkUtils.java index 6a8da8e..e153e86 100644 --- a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/DbkUtils.java +++ b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/DbkUtils.java @@ -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); diff --git a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java index 4573718..c324756 100644 --- a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java +++ b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java @@ -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); diff --git a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImageManager.java b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImageManager.java index 2e72a3e..2b57b4b 100644 --- a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImageManager.java +++ b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImageManager.java @@ -1,37 +1,137 @@ 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 index 0000000..cb4ce2e --- /dev/null +++ b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DbkImg.java @@ -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; + } + +} diff --git a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DocBookNames.java b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DocBookNames.java index c7848d1..10fa7a4 100644 --- a/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DocBookNames.java +++ b/publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/DocBookNames.java @@ -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"; + }