Read-only DocBook viewer almost complete
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 14 Sep 2022 11:38:53 +0000 (13:38 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 14 Sep 2022 11:38:53 +0000 (13:38 +0200)
14 files changed:
org.argeo.app.api/src/org/argeo/app/api/EntityType.java
org.argeo.app.api/src/org/argeo/app/api/JcrName.java [deleted file]
org.argeo.app.core/src/org/argeo/app/docbook/DbkAcrUtils.java
org.argeo.app.core/src/org/argeo/app/docbook/DbkAttr.java
org.argeo.app.core/src/org/argeo/app/docbook/DbkType.java
org.argeo.app.core/src/org/argeo/app/odk/OrxListName.java
org.argeo.app.core/src/org/argeo/app/odk/OrxManifestName.java
org.argeo.app.core/src/org/argeo/app/odk/OrxType.java
org.argeo.app.servlet.odk/bnd.bnd
org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkImageManager.java [new file with mode: 0644]
org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkImg.java [new file with mode: 0644]
org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkVideo.java [new file with mode: 0644]
org.argeo.app.swt/src/org/argeo/app/swt/docbook/DocBookViewer.java
org.argeo.app.ui/src/org/argeo/app/ui/publish/PublishUiProvider.java

index bb7b3de7bf1dfc75892b2c1d650abc3158c6aed0..8b9164a77d86aca468b0417d5712e0a6f4babd48 100644 (file)
@@ -1,9 +1,9 @@
 package org.argeo.app.api;
 
-import org.argeo.util.naming.QNamed;
+import org.argeo.api.acr.QNamed;
 
 /** Types related to entities. */
-public enum EntityType implements JcrName,QNamed {
+public enum EntityType implements QNamed {
        // entity
        entity, local, relatedTo,
        // structure
@@ -19,19 +19,16 @@ public enum EntityType implements JcrName,QNamed {
        // ldap
        person, user;
 
-       
-       
        @Override
        public String getDefaultPrefix() {
-               // TODO Auto-generated method stub
                return "entity";
        }
 
-       @Override
-       public String getPrefix() {
-               return getDefaultPrefix();
-       }
-
+//     @Override
+//     public String getPrefix() {
+//             return getDefaultPrefix();
+//     }
+//
 //     public static String prefix() {
 //             return "entity";
 //     }
@@ -42,7 +39,7 @@ public enum EntityType implements JcrName,QNamed {
 
        @Override
        public String getNamespace() {
-               return  "http://www.argeo.org/ns/entity";
+               return "http://www.argeo.org/ns/entity";
        }
 
 //     public static String namespace() {
diff --git a/org.argeo.app.api/src/org/argeo/app/api/JcrName.java b/org.argeo.app.api/src/org/argeo/app/api/JcrName.java
deleted file mode 100644 (file)
index 182494a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.argeo.app.api;
-
-import java.util.function.Supplier;
-
-/** Can be applied to {@link Enum}s in order to generate prefixed names. */
-@FunctionalInterface
-public interface JcrName extends Supplier<String> {
-       String name();
-
-       default String getPrefix() {
-               return null;
-       }
-
-       default String getNamespace() {
-               return null;
-       }
-
-       @Override
-       default String get() {
-               String prefix = getPrefix();
-               return prefix != null ? prefix + ":" + name() : name();
-       }
-
-       default String withNamespace() {
-               String namespace = getNamespace();
-               if (namespace == null)
-                       throw new UnsupportedOperationException("No namespace is specified for " + getClass());
-               return "{" + namespace + "}" + name();
-       }
-}
index d956069f5b9be91545996df10c4f075e21e7a39f..8dda2b49dfb6e4d689c5fcf1abb2bd169ebfde30 100644 (file)
@@ -8,6 +8,21 @@ public class DbkAcrUtils {
                return content.isContentClass(type.qName());
        }
 
+       public static String getMediaFileref(Content node) {
+               Content mediadata;
+               if (node.hasChild(DbkType.imageobject)) {
+                       mediadata = node.child(DbkType.imageobject).child(DbkType.imagedata);
+               } else {
+                       mediadata = node.child(DbkType.videoobject).child(DbkType.videodata);
+               }
+
+               if (mediadata.containsKey(DbkAttr.fileref)) {
+                       return mediadata.attr(DbkAttr.fileref);
+               } else {
+                       return null;
+               }
+       }
+
        /** singleton */
        private DbkAcrUtils() {
        }
index d3948367eaa3b1d706b95c82e11853d0265cef5c..df10c8b17591238e167aa63c8268e7b4befc654e 100644 (file)
@@ -1,11 +1,9 @@
 package org.argeo.app.docbook;
 
-import javax.xml.XMLConstants;
-
-import org.argeo.util.naming.QNamed;
+import org.argeo.api.acr.QNamed;
 
 /** Supported DocBook attributes. */
-public enum DbkAttr implements QNamed {
+public enum DbkAttr implements QNamed.Unqualified {
        role,
        //
        fileref, contentwidth, contentdepth
@@ -14,14 +12,4 @@ public enum DbkAttr implements QNamed {
 
        public final static String XLINK_HREF = "xlink:href";
 
-       @Override
-       public String getNamespace() {
-               return XMLConstants.NULL_NS_URI;
-       }
-
-       @Override
-       public String getDefaultPrefix() {
-               return XMLConstants.DEFAULT_NS_PREFIX;
-       }
-
 }
index 66fdc7624cb8431d0fefec702409d37e660c49e7..ff83002f8eda20207903c3bd04eb0eb66890b589 100644 (file)
@@ -1,10 +1,9 @@
 package org.argeo.app.docbook;
 
-import org.argeo.app.api.JcrName;
-import org.argeo.util.naming.QNamed;
+import org.argeo.api.acr.QNamed;
 
 /** Supported DocBook elements */
-public enum DbkType implements JcrName, QNamed {
+public enum DbkType implements QNamed {
        book, article, section,
        //
        info, title, para,
@@ -15,10 +14,10 @@ public enum DbkType implements JcrName, QNamed {
        //
        ;
 
-       @Override
-       public String getPrefix() {
-               return prefix();
-       }
+//     @Override
+//     public String getPrefix() {
+//             return prefix();
+//     }
 
        @Deprecated
        public static String prefix() {
index ec9b6994b635776023ee70a9ed603dd15a05185a..3c432ad34b8020dde38c47de63b0e0e1eb0706ea 100644 (file)
@@ -1,28 +1,20 @@
 package org.argeo.app.odk;
 
-import org.argeo.app.api.JcrName;
+import org.argeo.api.acr.QNamed;
 
 /** Types related to the http://openrosa.org/xforms/xformsList namespace. */
-public enum OrxListName implements JcrName {
+public enum OrxListName implements QNamed {
        xform,
        // names
        formID, version;
 
        @Override
-       public String getPrefix() {
-               return prefix();
-       }
-
-       public static String prefix() {
+       public String getDefaultPrefix() {
                return "orxList";
        }
 
        @Override
        public String getNamespace() {
-               return namespace();
-       }
-
-       public static String namespace() {
                return "http://openrosa.org/xforms/xformsList";
        }
 
index 5c93c4158708db20f82075a888e719c5408aac5a..2b68b906e34d35da11feee7407697d9835980e1b 100644 (file)
@@ -1,26 +1,18 @@
 package org.argeo.app.odk;
 
-import org.argeo.app.api.JcrName;
+import org.argeo.api.acr.QNamed;
 
 /** Types related to the http://openrosa.org/xforms/xformsList namespace. */
-public enum OrxManifestName implements JcrName {
+public enum OrxManifestName implements QNamed {
        manifest, mediaFile;
 
        @Override
-       public String getPrefix() {
-               return prefix();
-       }
-
-       public static String prefix() {
+       public String getDefaultPrefix() {
                return "orxManifest";
        }
 
        @Override
        public String getNamespace() {
-               return namespace();
-       }
-
-       public static String namespace() {
                return "http://openrosa.org/xforms/xformsManifest";
        }
 
index cf88eb97f779fc9d3492e76f150a97ec9d18bd39..77ae7ae8cee143001ebace44db1e10d9da184d5a 100644 (file)
@@ -1,26 +1,18 @@
 package org.argeo.app.odk;
 
-import org.argeo.app.api.JcrName;
+import org.argeo.api.acr.QNamed;
 
 /** Types related to the http://openrosa.org/xforms/xformsList namespace. */
-public enum OrxType implements JcrName {
+public enum OrxType implements QNamed {
        submission, xml_submission_file;
 
        @Override
-       public String getPrefix() {
-               return prefix();
-       }
-
-       public static String prefix() {
+       public String getDefaultPrefix() {
                return "orx";
        }
 
        @Override
        public String getNamespace() {
-               return namespace();
-       }
-
-       public static String namespace() {
                return "http://openrosa.org/xforms";
        }
 
index f5cd2170acf14a74885ce71b9d8402d1482363a2..a32d5d368641926b9ec41ee29ba87a7c90dd1a84 100644 (file)
@@ -14,4 +14,5 @@ Import-Package:\
 org.osgi.service.http.context,\
 javax.jcr.nodetype,\
 javax.servlet.*;version="[3,5)",\
+org.argeo.api.acr,\
 *
diff --git a/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkImageManager.java b/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkImageManager.java
new file mode 100644 (file)
index 0000000..acdba64
--- /dev/null
@@ -0,0 +1,130 @@
+package org.argeo.app.swt.docbook;
+
+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 org.argeo.api.acr.Content;
+import org.argeo.api.acr.CrName;
+import org.argeo.api.acr.spi.ProvidedContent;
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.app.api.EntityNames;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.docbook.DbkAttr;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.cms.acr.SvgAttrs;
+import org.argeo.cms.swt.acr.AcrSwtImageManager;
+import org.eclipse.swt.graphics.ImageData;
+
+/** Add DocBook images support to {@link CmsImageManager}. */
+public class DbkImageManager extends AcrSwtImageManager {
+       private Content baseFolder = null;
+
+       public DbkImageManager(Content baseFolder) {
+               this.baseFolder = baseFolder;
+       }
+
+       Content getImageDataNode(Content mediaObjectNode) {
+               return mediaObjectNode.child(DbkType.imageobject).child(DbkType.imagedata);
+       }
+
+//     @Override
+//     public Binary getImageBinary(Node node) {
+//             Node fileNode = null;
+//             if (DbkUtils.isDbk(node, DbkType.mediaobject)) {
+//                     Node imageDataNode = getImageDataNode(node);
+//                     fileNode = getFileNode(imageDataNode);
+//             }
+//             try {
+//                     if (node.isNodeType(NT_FILE)) {
+//                             fileNode = node;
+//                     }
+//                     if (fileNode != null) {
+//                             return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();
+//                     } else {
+//                             return null;
+//                     }
+//             } catch (RepositoryException e) {
+//                     throw new JcrException(e);
+//             }
+//     }
+
+       public Cms2DSize getImageSize(Content mediaObjectNode) {
+               Content imageDataNode = getImageDataNode(mediaObjectNode);
+               Content fileNode = getFileNode(imageDataNode);
+               if (fileNode == null)
+                       return new Cms2DSize(0, 0);
+               Cms2DSize intrinsicSize;
+               if (fileNode.containsKey(SvgAttrs.width) && fileNode.containsKey(SvgAttrs.height)) {
+                       int width = fileNode.get(SvgAttrs.width, Integer.class).orElseThrow();
+                       int height = fileNode.get(SvgAttrs.height, Integer.class).orElseThrow();
+                       intrinsicSize = new Cms2DSize(width, height);
+               } else {
+                       try (InputStream in = fileNode.open(InputStream.class)) {
+                               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;
+       }
+
+       protected Cms2DSize updateSize(Content fileNode, ImageData id) {
+               fileNode.addContentClasses(EntityType.box.qName());
+               fileNode.put(SvgAttrs.width, id.width);
+               fileNode.put(SvgAttrs.height, id.height);
+               return new Cms2DSize(id.width, id.height);
+       }
+
+//     @Override
+//     protected void processNewImageFile(Content mediaObjectNode, Content fileNode, ImageData id) throws IOException {
+//             Node imageDataNode = getImageDataNode(mediaObjectNode);
+//             updateSize(fileNode, id);
+//             String filePath = fileNode.getPath();
+//             String relPath = filePath.substring(baseFolder.getPath().length() + 1);
+//             imageDataNode.setProperty(DbkAttr.fileref.name(), relPath);
+//     }
+
+       @Override
+       public String getImageUrl(Content mediaObjectNode) {
+               Content imageDataNode = getImageDataNode(mediaObjectNode);
+               // TODO factorise
+               String fileref = imageDataNode.get(DbkAttr.fileref, String.class).orElse(null);
+               if (fileref == null)
+                       return null;
+               URI fileUri;
+               try {
+                       // FIXME it messes up with the '/'
+                       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
+               Content fileNode = getFileNode(imageDataNode);
+               String url = getDataPathForUrl(fileNode);
+               return url;
+       }
+
+       protected Content getFileNode(Content imageDataNode) {
+               // FIXME make URL use case more robust
+               String fileref = imageDataNode.get(DbkAttr.fileref, String.class).orElse(null);
+               if (fileref == null)
+                       return null;
+               return ((ProvidedContent) baseFolder).getContent(fileref);
+       }
+
+       protected Content getMediaFolder() {
+               // TODO check edition status
+               Content mediaFolder = baseFolder.anyOrAddChild( EntityNames.MEDIA,CrName.collection.qName());
+               return mediaFolder;
+       }
+}
diff --git a/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkImg.java b/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkImg.java
new file mode 100644 (file)
index 0000000..9984209
--- /dev/null
@@ -0,0 +1,65 @@
+package org.argeo.app.swt.docbook;
+
+import org.argeo.api.acr.Content;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.acr.Img;
+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, Content imgNode, DbkImageManager imageManager) {
+               super(parent, swtStyle, imgNode, imageManager);
+               // FIXME deal with style and initialisation
+               setStyle((String) null);
+       }
+
+       @Override
+       protected Content getUploadFolder() {
+               Content mediaFolder = ((DbkImageManager) getImageManager()).getMediaFolder();
+               return mediaFolder;
+       }
+
+       @Override
+       protected String getUploadName() {
+               return null;
+       }
+
+       @Override
+       protected void setContainerLayoutData(Composite composite) {
+               composite.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+       }
+
+       @Override
+       protected void setControlLayoutData(Control control) {
+               control.setLayoutData(CmsSwtUtils.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/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkVideo.java b/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkVideo.java
new file mode 100644 (file)
index 0000000..17ed0e0
--- /dev/null
@@ -0,0 +1,211 @@
+package org.argeo.app.swt.docbook;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.spi.ProvidedContent;
+import org.argeo.app.docbook.DbkAcrUtils;
+import org.argeo.app.docbook.DbkAttr;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.Selected;
+import org.argeo.cms.swt.acr.SwtSection;
+import org.argeo.cms.swt.acr.SwtSectionPart;
+import org.argeo.cms.swt.widgets.StyledControl;
+import org.argeo.cms.ux.acr.ContentPart;
+import org.argeo.util.naming.NamingUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+public class DbkVideo extends StyledControl implements SwtSectionPart, ContentPart {
+       private static final long serialVersionUID = -8753232181570351880L;
+       private SwtSection section;
+
+       private int width = 640;
+       private int height = 360;
+
+       private boolean editable;
+
+       public DbkVideo(Composite parent, int style, Content node) {
+               this(SwtSection.findSection(parent), parent, style, node);
+       }
+
+       DbkVideo(SwtSection section, Composite parent, int style, Content node) {
+               super(parent, style);
+               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
+               this.section = section;
+               setStyle(DbkType.videoobject.name());
+               setData(node);
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               Content mediaobject = getNode();
+               Composite wrapper = new Composite(box, SWT.NONE);
+               wrapper.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+               Composite browserC = new Composite(wrapper, SWT.NONE);
+               browserC.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               GridData gd = new GridData(SWT.CENTER, SWT.FILL, true, true);
+               gd.widthHint = getWidth();
+               gd.heightHint = getHeight();
+               browserC.setLayoutData(gd);
+//             wrapper.setLayoutData(CmsUiUtils.fillAll());
+               Browser browser = new Browser(browserC, SWT.NONE);
+
+               if (editable) {
+                       Composite editor = new Composite(wrapper, SWT.BORDER);
+                       editor.setLayout(new GridLayout(3, false));
+                       editor.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+                       String fileref = DbkAcrUtils.getMediaFileref(mediaobject);
+                       Text text = new Text(editor, SWT.SINGLE);
+                       if (fileref != null)
+                               text.setText(fileref);
+                       else
+                               text.setMessage("Embed URL of the video");
+                       text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+                       Button updateB = new Button(editor, SWT.FLAT);
+                       updateB.setText("Update");
+                       updateB.addSelectionListener(new Selected() {
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       Content videodata = mediaobject.child(DbkType.videoobject).child(DbkType.videodata);
+                                       String txt = text.getText();
+                                       URI uri;
+                                       try {
+                                               uri = new URI(txt);
+                                       } catch (URISyntaxException e1) {
+                                               text.setText("");
+                                               text.setMessage("Invalid URL");
+                                               return;
+                                       }
+
+                                       // Transform watch URL in embed
+                                       // YouTube
+                                       String videoId = null;
+                                       if ("www.youtube.com".equals(uri.getHost()) || "youtube.com".equals(uri.getHost())
+                                                       || "youtu.be".equals(uri.getHost())) {
+                                               if ("www.youtube.com".equals(uri.getHost()) || "youtube.com".equals(uri.getHost())) {
+                                                       if ("/watch".equals(uri.getPath())) {
+                                                               Map<String, List<String>> map = NamingUtils.queryToMap(uri);
+                                                               videoId = map.get("v").get(0);
+                                                       }
+                                               } else if ("youtu.be".equals(uri.getHost())) {
+                                                       videoId = uri.getPath().substring(1);
+                                               }
+                                               if (videoId != null) {
+                                                       try {
+                                                               uri = new URI("https://www.youtube.com/embed/" + videoId);
+                                                               text.setText(uri.toString());
+                                                       } catch (URISyntaxException e1) {
+                                                               throw new IllegalStateException(e1);
+                                                       }
+                                               }
+                                       }
+
+                                       // Vimeo
+                                       if ("vimeo.com".equals(uri.getHost())) {
+                                               videoId = uri.getPath().substring(1);
+                                               if (videoId != null) {
+                                                       try {
+                                                               uri = new URI("https://player.vimeo.com/video/" + videoId);
+                                                               text.setText(uri.toString());
+                                                       } catch (URISyntaxException e1) {
+                                                               throw new IllegalStateException(e1);
+                                                       }
+                                               }
+                                       }
+
+                                       videodata.put(DbkAttr.fileref, uri.toString());
+                                       // TODO better integrate it in the edition lifecycle
+//                                     videodata.getSession().save();
+                                       load(browser);
+
+                               }
+                       });
+
+                       Button deleteB = new Button(editor, SWT.FLAT);
+                       deleteB.setText("Delete");
+                       deleteB.addSelectionListener(new Selected() {
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       mediaobject.remove();
+//                                     mediaobject.getSession().save();
+                                       dispose();
+                                       getSection().getParent().layout(true, true);
+
+                               }
+                       });
+               }
+
+               // TODO caption
+               return browser;
+       }
+
+       public void load(Control control) {
+               if (control instanceof Browser) {
+                       Browser browser = (Browser) control;
+//                     getNode().getSession();
+                       String fileref = DbkAcrUtils.getMediaFileref(getContent());
+                       if (fileref != null) {
+                               // TODO manage self-hosted videos
+                               // TODO for YouTube videos, check whether the URL starts with
+                               // https://www.youtube.com/embed/ and not https://www.youtube.com/watch?v=
+                               StringBuilder html = new StringBuilder();
+                               html.append(
+                                               "<iframe frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"true\"");
+                               // TODO make size configurable
+                               html.append("width=\"").append(width).append("\" height=\"").append(height).append("\" ");
+                               html.append("src=\"").append(fileref).append("\" ");
+                               html.append("/>");
+                               browser.setText(html.toString());
+                       }
+               }
+       }
+
+       @Override
+       protected void setContainerLayoutData(Composite composite) {
+               composite.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, true));
+       }
+
+       @Override
+       protected void setControlLayoutData(Control control) {
+               control.setLayoutData(CmsSwtUtils.fillAll());
+       }
+
+       @Override
+       public Content getContent() {
+               return (Content) getData();
+       }
+
+       @Override
+       public String getPartId() {
+               return ((ProvidedContent) getContent()).getSessionLocalId();
+       }
+
+       @Override
+       public SwtSection getSection() {
+               return section;
+       }
+
+       public int getWidth() {
+               return width;
+       }
+
+       public int getHeight() {
+               return height;
+       }
+
+}
index 5e94e48f1695a687840ca6597d5c70b30fb0780b..9956adeed1f873edcc329b0675bda22690bc0c9e 100644 (file)
@@ -6,6 +6,7 @@ import static org.argeo.app.docbook.DbkType.para;
 import java.util.Optional;
 
 import org.argeo.api.acr.Content;
+import org.argeo.api.cms.ux.Cms2DSize;
 import org.argeo.api.cms.ux.CmsEditable;
 import org.argeo.app.docbook.DbkAttr;
 import org.argeo.app.docbook.DbkType;
@@ -17,23 +18,28 @@ import org.argeo.cms.swt.acr.SwtSectionPart;
 import org.argeo.cms.swt.widgets.EditableText;
 import org.argeo.cms.swt.widgets.StyledControl;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 
 public class DocBookViewer extends AbstractPageViewer {
 
        private TextInterpreter textInterpreter = new DbkTextInterpreter();
+       private DbkImageManager imageManager;
 
        private TextSection mainSection;
 
        private boolean showMainTitle = true;
 
+       private Integer maxMediaWidth = null;
        private String defaultSectionStyle;
 
        public DocBookViewer(Composite parent, int style, Content item, CmsEditable cmsEditable) {
                super(parent, style, cmsEditable);
+               imageManager = new DbkImageManager(item);
+
                for (Content child : item) {
-                       if (child.hasContentClass(DbkType.article.qName())) {
+                       if (child.hasContentClass(DbkType.article)) {
                                if (mainSection != null)
                                        throw new IllegalStateException("Main section already created");
                                mainSection = new TextSection(parent, 0, child);
@@ -61,7 +67,7 @@ public class DocBookViewer extends AbstractPageViewer {
        protected void refreshTextSection(TextSection section) {
                Content sectionContent = section.getContent();
                // Style
-               Optional<String> roleAttr = sectionContent.get(DbkAttr.role.qName(), String.class);
+               Optional<String> roleAttr = sectionContent.get(DbkAttr.role, String.class);
                String style = roleAttr.orElse(section.getDefaultTextStyle());
                if (style != null)
                        CmsSwtUtils.style(section, style);
@@ -80,17 +86,36 @@ public class DocBookViewer extends AbstractPageViewer {
                        }
                }
 
+               boolean processingSubSections = false;
                for (Content child : section.getContent()) {
-                       if (child.hasContentClass(DbkType.section.qName())) {
+                       if (child.hasContentClass(DbkType.section)) {
+                               processingSubSections = true;
                                TextSection childSection = new TextSection(section, 0, child);
-                               childSection.setLayoutData(CmsSwtUtils.fillAll());
+                               childSection.setLayoutData(CmsSwtUtils.fillWidth());
                                refreshTextSection(childSection);
-                       } else if (child.hasContentClass(DbkType.para.qName())) {
-                               Paragraph para = new Paragraph(section, 0, child);
-                               para.setLayoutData(CmsSwtUtils.fillWidth());
-                               updateContent(para);
+                       } else {
+                               if (processingSubSections)
+                                       throw new IllegalStateException(child + " is below a subsection");
+                               SwtSectionPart sectionPart = null;
+                               if (child.hasContentClass(DbkType.para)) {
+                                       sectionPart = newParagraph(section, child);
+                               } else if (child.hasContentClass(DbkType.mediaobject)) {
+                                       if (child.hasChild(DbkType.imageobject)) {
+                                               sectionPart = newImg(section, child);
+                                       } else if (child.hasChild(DbkType.videoobject)) {
+                                               sectionPart = newVideo(section, child);
+                                       } else {
+                                               throw new IllegalArgumentException("Unsupported media object " + child);
+                                       }
+                               } else if (isDbk(child, DbkType.title)) {
+                                       // already managed
+                                       // TODO check that it is first?
+                               } else {
+                                       throw new IllegalArgumentException("Unsupported type for " + child);
+                               }
+                               if (sectionPart != null && sectionPart instanceof Control)
+                                       ((Control) sectionPart).setLayoutData(CmsSwtUtils.fillWidth());
                        }
-
                }
        }
 
@@ -118,14 +143,12 @@ public class DocBookViewer extends AbstractPageViewer {
                                        paragraph.setText(textInterpreter.readSimpleHtml(partContent));
                                // paragraph.setText(textInterpreter.readSimpleHtml(partContent));
 
-//                     } else if (part instanceof DbkImg) {
-//                             DbkImg editableImage = (DbkImg) part;
-//                             // imageManager.load(partNode, part.getControl(),
-//                             // editableImage.getPreferredImageSize());
-//                     } else if (part instanceof DbkVideo) {
-//                             DbkVideo video = (DbkVideo) part;
-//                             video.load(part.getControl());
-//                     }
+                       } else if (part instanceof DbkImg) {
+                               DbkImg editableImage = (DbkImg) part;
+//                             imageManager.load(partContent, part.getControl(), editableImage.getPreferredImageSize());
+                       } else if (part instanceof DbkVideo) {
+                               DbkVideo video = (DbkVideo) part;
+                               video.load(part.getControl());
                        }
                } else if (part instanceof DbkSectionTitle) {
                        DbkSectionTitle title = (DbkSectionTitle) part;
@@ -138,6 +161,15 @@ public class DocBookViewer extends AbstractPageViewer {
                }
        }
 
+       protected Paragraph newParagraph(TextSection parent, Content node) {
+               Paragraph paragraph = new Paragraph(parent, parent.getStyle(), node);
+               updateContent(paragraph);
+               paragraph.setLayoutData(CmsSwtUtils.fillWidth());
+               paragraph.setMouseListener(getMouseListener());
+               paragraph.setFocusListener(getFocusListener());
+               return paragraph;
+       }
+
        protected DbkSectionTitle newSectionTitle(TextSection parent, Content titleNode) {
                int style = parent.getStyle();
                Composite titleParent = newSectionHeader(parent);
@@ -150,6 +182,41 @@ public class DocBookViewer extends AbstractPageViewer {
                return title;
        }
 
+       protected DbkImg newImg(TextSection parent, Content node) {
+               DbkImg img = new DbkImg(parent, parent.getStyle(), node, imageManager);
+               GridData imgGd;
+               if (maxMediaWidth != null) {
+                       imgGd = new GridData(SWT.CENTER, SWT.FILL, false, false);
+                       imgGd.widthHint = maxMediaWidth;
+                       img.setPreferredSize(new Cms2DSize(maxMediaWidth, 0));
+               } else {
+                       imgGd = CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT);
+               }
+               img.setLayoutData(imgGd);
+               updateContent(img);
+               img.setMouseListener(getMouseListener());
+               img.setFocusListener(getFocusListener());
+               return img;
+       }
+
+       protected DbkVideo newVideo(TextSection parent, Content node) {
+               DbkVideo video = new DbkVideo(parent, getCmsEditable().canEdit() ? SWT.NONE : SWT.READ_ONLY, node);
+               GridData gd;
+               if (maxMediaWidth != null) {
+                       gd = new GridData(SWT.CENTER, SWT.FILL, false, false);
+                       // TODO, manage size
+//                             gd.widthHint = maxMediaWidth;
+//                             gd.heightHint = (int) (gd.heightHint * 0.5625);
+               } else {
+                       gd = new GridData(SWT.CENTER, SWT.FILL, false, false);
+//                             gd.widthHint = video.getWidth();
+//                             gd.heightHint = video.getHeight();
+               }
+               video.setLayoutData(gd);
+               updateContent(video);
+               return video;
+       }
+
        /**
         * To be overridden in order to provide additional processing at the section
         * level.
@@ -177,6 +244,10 @@ public class DocBookViewer extends AbstractPageViewer {
                this.defaultSectionStyle = defaultSectionStyle;
        }
 
+       public void setMaxMediaWidth(Integer maxMediaWidth) {
+               this.maxMediaWidth = maxMediaWidth;
+       }
+
        @Override
        public Control getControl() {
                return mainSection;
index ed7e1efe5750b589f7fa9c589caf05b1704e6784..1c770423ba386ff6b0f00d6a9aadf7456898d3b9 100644 (file)
@@ -3,7 +3,10 @@ package org.argeo.app.ui.publish;
 import org.argeo.api.acr.Content;
 import org.argeo.api.cms.ux.CmsEditable;
 import org.argeo.app.swt.docbook.DocBookViewer;
+import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.swt.acr.SwtUiProvider;
+import org.argeo.cms.swt.widgets.ScrolledPage;
+import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 
@@ -11,7 +14,10 @@ public class PublishUiProvider implements SwtUiProvider {
 
        @Override
        public Control createUiPart(Composite parent, Content context) {
-               DocBookViewer docBookViewer = new DocBookViewer(parent, 0, context, CmsEditable.NON_EDITABLE);
+               ScrolledPage page = new ScrolledPage(parent, SWT.NONE);
+               page.setLayoutData(CmsSwtUtils.fillAll());
+               page.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               DocBookViewer docBookViewer = new DocBookViewer(page, 0, context, CmsEditable.NON_EDITABLE);
 //             docBookViewer.setLayoutData(CmsSwtUtils.fillAll());
                docBookViewer.refresh();
                return docBookViewer.getControl();