Introduce ACR-based DocBook viewer
authorMathieu Baudier <mbaudier@argeo.org>
Mon, 12 Sep 2022 06:01:14 +0000 (08:01 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Mon, 12 Sep 2022 06:01:14 +0000 (08:01 +0200)
22 files changed:
Makefile
org.argeo.app.core/src/org/argeo/app/docbook/DbkAcrUtils.java [new file with mode: 0644]
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.swt/.classpath [new file with mode: 0644]
org.argeo.app.swt/.project [new file with mode: 0644]
org.argeo.app.swt/bnd.bnd [new file with mode: 0644]
org.argeo.app.swt/build.properties [new file with mode: 0644]
org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkTextInterpreter.java [new file with mode: 0644]
org.argeo.app.swt/src/org/argeo/app/swt/docbook/DocBookViewer.java [new file with mode: 0644]
org.argeo.app.swt/src/org/argeo/app/swt/docbook/Paragraph.java [new file with mode: 0644]
org.argeo.app.swt/src/org/argeo/app/swt/docbook/TextInterpreter.java [new file with mode: 0644]
org.argeo.app.swt/src/org/argeo/app/swt/docbook/TextSection.java [new file with mode: 0644]
org.argeo.app.ui/config/documentUiProvider.properties
org.argeo.app.ui/config/publishUiProvider.properties
org.argeo.app.ui/src/org/argeo/app/ui/library/ContentEntryArea.java
org.argeo.app.ui/src/org/argeo/app/ui/publish/PublishUiProvider.java
org.argeo.app.ux/.classpath [deleted file]
org.argeo.app.ux/.project [deleted file]
org.argeo.app.ux/bnd.bnd [deleted file]
org.argeo.app.ux/build.properties [deleted file]
org.argeo.app.ux/src/org/argeo/app/ux/docbook/DocBookViewer.java [deleted file]

index 444b30085df0b529757137ad26bb871a61750e7a..8c6d83c8dc4422a6a8b8b01c89f3f1bd1f064ae2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ org.argeo.app.api \
 org.argeo.app.core \
 org.argeo.app.servlet.odk \
 org.argeo.app.servlet.publish \
-org.argeo.app.ux \
+org.argeo.app.swt \
 org.argeo.app.ui \
 org.argeo.app.theme.default \
 org.argeo.app.profile.acr.fs \
diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkAcrUtils.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkAcrUtils.java
new file mode 100644 (file)
index 0000000..d956069
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.app.docbook;
+
+import org.argeo.api.acr.Content;
+
+public class DbkAcrUtils {
+       /** Whether this DocBook element is of this type. */
+       public static boolean isDbk(Content content, DbkType type) {
+               return content.isContentClass(type.qName());
+       }
+
+       /** singleton */
+       private DbkAcrUtils() {
+       }
+}
index f6cf839a38ecac79f194f28d8d13d732f987d2a2..d3948367eaa3b1d706b95c82e11853d0265cef5c 100644 (file)
@@ -1,7 +1,11 @@
 package org.argeo.app.docbook;
 
+import javax.xml.XMLConstants;
+
+import org.argeo.util.naming.QNamed;
+
 /** Supported DocBook attributes. */
-public enum DbkAttr {
+public enum DbkAttr implements QNamed {
        role,
        //
        fileref, contentwidth, contentdepth
@@ -10,4 +14,14 @@ public enum DbkAttr {
 
        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 3e3585f4b8f523f7c5ce0d5af38714949d5f1091..66fdc7624cb8431d0fefec702409d37e660c49e7 100644 (file)
@@ -1,9 +1,10 @@
 package org.argeo.app.docbook;
 
 import org.argeo.app.api.JcrName;
+import org.argeo.util.naming.QNamed;
 
 /** Supported DocBook elements */
-public enum DbkType implements JcrName {
+public enum DbkType implements JcrName, QNamed {
        book, article, section,
        //
        info, title, para,
@@ -19,6 +20,7 @@ public enum DbkType implements JcrName {
                return prefix();
        }
 
+       @Deprecated
        public static String prefix() {
                return "dbk";
        }
@@ -32,4 +34,9 @@ public enum DbkType implements JcrName {
                return "http://docbook.org/ns/docbook";
        }
 
+       @Override
+       public String getDefaultPrefix() {
+               return "dbk";
+       }
+
 }
diff --git a/org.argeo.app.swt/.classpath b/org.argeo.app.swt/.classpath
new file mode 100644 (file)
index 0000000..81fe078
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.argeo.app.swt/.project b/org.argeo.app.swt/.project
new file mode 100644 (file)
index 0000000..11c6368
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.app.swt</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/org.argeo.app.swt/bnd.bnd b/org.argeo.app.swt/bnd.bnd
new file mode 100644 (file)
index 0000000..bbc81c5
--- /dev/null
@@ -0,0 +1,7 @@
+Import-Package:\
+org.eclipse.swt,\
+org.argeo.util.naming,\
+org.argeo.api.cms.ux,\
+org.argeo.cms.ux.acr,\
+org.argeo.app.api,\
+*
\ No newline at end of file
diff --git a/org.argeo.app.swt/build.properties b/org.argeo.app.swt/build.properties
new file mode 100644 (file)
index 0000000..34d2e4d
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkTextInterpreter.java b/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DbkTextInterpreter.java
new file mode 100644 (file)
index 0000000..2fac3bb
--- /dev/null
@@ -0,0 +1,261 @@
+package org.argeo.app.swt.docbook;
+
+import static org.argeo.app.docbook.DbkAcrUtils.isDbk;
+import static org.argeo.app.docbook.DbkType.para;
+import static org.argeo.app.docbook.DbkType.title;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.api.acr.Content;
+import org.argeo.app.docbook.DbkType;
+
+/** Based on HTML with a few Wiki-like shortcuts. */
+public class DbkTextInterpreter implements TextInterpreter {
+
+       private TransformerFactory transformerFactory = TransformerFactory.newDefaultInstance();
+
+       private String linkCssClass = DbkType.link.name();
+
+       @Override
+       public void write(Content node, String content) {
+               if (isDbk(node, para) || isDbk(node, title)) {
+                       String raw = convertToStorage(node, content);
+                       validateBeforeStoring(raw);
+
+                       String jcrUuid = null;// node.getIdentifier();
+//                                     if (node.hasProperty(Property.JCR_UUID))
+//                                             jcrUuid = node.getProperty(Property.JCR_UUID).getString();
+//                                     else {
+//                                             // TODO use time based
+//                                             jcrUuid = UUID.randomUUID().toString();
+//                                             node.setProperty(Property.JCR_UUID, jcrUuid);
+//                                             node.getSession().save();
+//                                     }
+
+                       StringBuilder namespaces = new StringBuilder();
+                       namespaces.append(" xmlns:dbk=\"http://docbook.org/ns/docbook\"");
+                       namespaces.append(" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\"");
+                       namespaces.append(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
+                       raw = "<" + node.getName() + " jcr:uuid=\"" + jcrUuid + "\"" + namespaces + ">" + raw + "</"
+                                       + node.getName() + ">";
+//                                     System.out.println(raw);
+//                                     try (InputStream in = new ByteArrayInputStream(raw.getBytes(StandardCharsets.UTF_8))) {
+//                                             node.getSession().importXML(node.getParent().getPath(), in,
+//                                                             ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+//                                             // node.getSession().save();
+//                                     } catch (IOException e) {
+//                                             throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
+//                                     }
+
+//                                     try {
+//                                             DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+//                                             Document document;
+//                                             try (Reader in = new StringReader(raw)) {
+//                                                     document = documentBuilder.parse(new InputSource(in));
+//                                             }
+//                                             NodeList nl = document.getChildNodes();
+//                                             for (int i = 0; i < nl.getLength(); i++) {
+//                                                     org.w3c.dom.Node n = nl.item(i);
+//                                                     if (node instanceof Text) {
+//
+//                                                     }
+//                                             }
+//                                     } catch (ParserConfigurationException | SAXException | IOException e) {
+//                                             throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
+//                                     }
+
+//                                     Node jcrText;
+//                                     if (!node.hasNode(Jcr.JCR_XMLTEXT))
+//                                             jcrText = node.addNode(Jcr.JCR_XMLTEXT, JcrxType.JCRX_XMLTEXT);
+//                                     else
+//                                             jcrText = node.getNode(Jcr.JCR_XMLTEXT);
+//                                     jcrText.setProperty(Jcr.JCR_XMLCHARACTERS, raw);
+               } else {
+                       throw new IllegalArgumentException("Don't know how to interpret " + node);
+               }
+       }
+
+       @Override
+       public String read(Content item) {
+               String raw = raw(item);
+               return convertFromStorage(item, raw);
+       }
+
+       @Override
+       public String raw(Content node) {
+               if (isDbk(node, para) || isDbk(node, title)) {
+                       Source source = node.adapt(Source.class);
+
+                       StringWriter stringWriter = new StringWriter();
+                       Result result = new StreamResult(stringWriter);
+
+                       try {
+                               transformerFactory.newTransformer().transform(source, result);
+                               return stringWriter.toString();
+                       } catch (TransformerException e) {
+                               throw new RuntimeException("Could not convert " + node + " to XML", e);
+                       }
+
+//                                     StringBuilder sb = new StringBuilder();
+//                                     readXml(node, sb);
+//                                     NodeIterator nit = node.getNodes();
+//                                     while (nit.hasNext()) {
+//                                             Node child = nit.nextNode();
+//                                             if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
+//                                                     Node jcrText = node.getNode(Jcr.JCR_XMLTEXT);
+//                                                     String txt = jcrText.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
+//                                                     // TODO make it more robust
+//                                                     // txt = txt.replace("\n", "").replace("\t", "");
+//                                                     txt = txt.replace("\t", "  ");
+//                                                     sb.append(txt);
+//                                             } else {
+//                                                     try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+//                                                             child.getSession().exportDocumentView(child.getPath(), out, true, false);
+//                                                             sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
+//                                                     } catch (IOException e) {
+//                                                             throw new IllegalStateException("Cannot export " + child, e);
+//                                                     }
+//                                             }
+//                                     }
+//                                     return sb.toString();
+               } else {
+                       throw new IllegalArgumentException("Don't know how to interpret " + node);
+               }
+       }
+
+//     private void readXml(Content node, StringBuilder sb){
+//             
+//             NodeIterator nit = node.getNodes();
+//             while (nit.hasNext()) {
+//                     Node child = nit.nextNode();
+//                     if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
+//                             String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
+//                             // TODO make it more robust
+//                             // txt = txt.replace("\n", "").replace("\t", "");
+//                             txt = txt.replace("\t", "  ");
+//                             sb.append(txt);
+//                     } else {
+//                             sb.append('<').append(child.getName());
+//                             PropertyIterator pit = child.getProperties();
+//                             properties: while (pit.hasNext()) {
+//                                     Property p = pit.nextProperty();
+//                                     if (p.getName().startsWith("jcr:"))
+//                                             continue properties;
+//                                     sb.append(' ').append(p.getName()).append("=\"").append(p.getString()).append('\"');
+//                             }
+//                             sb.append('>');
+//                             readXml(child, sb);
+////                           try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+////                                   child.getSession().exportDocumentView(child.getPath(), out, true, false);
+////                                   sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
+////                           } catch (IOException e) {
+////                                   throw new IllegalStateException("Cannot export " + child, e);
+////                           }
+//                             sb.append("</").append(child.getName()).append('>');
+//                     }
+//             }
+//     }
+
+       private void readAsSimpleHtml(Content node, StringBuilder sb) {
+//             NodeIterator nit = node.getNodes();
+//             while (nit.hasNext()) {
+//                     Node child = nit.nextNode();
+//                     if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
+//                             String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
+//                             // TODO make it more robust
+//                             // txt = txt.replace("\n", "").replace("\t", "");
+//                             txt = txt.replace("\t", "  ");
+//                             String html = textToSimpleHtml(txt);
+//                             sb.append(html);
+//                     } else if (child.getName().equals(DbkType.link.get())) {
+//                             if (child.hasProperty(DbkAttr.XLINK_HREF)) {
+//                                     String href = child.getProperty(DbkAttr.XLINK_HREF).getString();
+//                                     // TODO deal with other forbidden XML characters?
+//                                     href = href.replace("&", "&amp;");
+//                                     sb.append("<a class='" + linkCssClass + "' href='").append(href).append("'>");
+//                                     readAsSimpleHtml(child, sb);
+//                                     sb.append("</a>");
+//                             }
+//                     } else {
+//                             // ignore
+//                     }
+//             }
+       }
+
+       private String textToSimpleHtml(String raw) {
+               // FIXME the saved data should be corrected instead.
+               if (raw.indexOf('&') >= 0) {
+                       raw = raw.replace("&", "&amp;");
+               }
+               if (raw.indexOf('<') >= 0) {
+                       raw = raw.replace("<", "&lt;");
+               }
+               if (raw.indexOf('>') >= 0) {
+                       raw = raw.replace(">", "&gt;");
+               }
+               if (raw.indexOf('\"') >= 0) {
+                       raw = raw.replace("\"", "&quot;");
+               }
+               if (raw.indexOf('\'') >= 0) {
+                       raw = raw.replace("\'", "&apos;");
+               }
+//             raw = "<span style='text-align:justify'>" + raw + "</span>";
+               if (raw.length() == 0)
+                       return raw;
+               try (StringReader reader = new StringReader(raw)) {
+                       List<String> lines = IOUtils.readLines(reader);
+                       if (lines.size() == 1)
+                               return lines.get(0);
+                       StringBuilder sb = new StringBuilder(raw.length() + lines.size() * BR_LENGTH);
+                       for (int i = 0; i < lines.size(); i++) {
+                               if (i != 0)
+                                       sb.append("<br/>");
+                               sb.append(lines.get(i));
+                       }
+                       return sb.toString();
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       final static int BR_LENGTH = "<br/>".length();
+
+       public String readSimpleHtml(Content item) {
+               StringBuilder sb = new StringBuilder();
+//                     sb.append("<div style='text-align: justify;'>");
+               readAsSimpleHtml(item, sb);
+//                     sb.append("</div>");
+//                     System.out.println(sb);
+               return sb.toString();
+       }
+
+       // EXTENSIBILITY
+       /**
+        * To be overridden, in order to make sure that only valid strings are being
+        * stored.
+        */
+       protected void validateBeforeStoring(String raw) {
+       }
+
+       /** To be overridden, in order to support additional formatting. */
+       protected String convertToStorage(Content item, String content) {
+               return content;
+
+       }
+
+       /** To be overridden, in order to support additional formatting. */
+       protected String convertFromStorage(Content item, String content) {
+               return content;
+       }
+}
diff --git a/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DocBookViewer.java b/org.argeo.app.swt/src/org/argeo/app/swt/docbook/DocBookViewer.java
new file mode 100644 (file)
index 0000000..6cd5172
--- /dev/null
@@ -0,0 +1,121 @@
+package org.argeo.app.swt.docbook;
+
+import static org.argeo.app.docbook.DbkAcrUtils.isDbk;
+import static org.argeo.app.docbook.DbkType.para;
+
+import java.util.Optional;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.cms.ux.CmsEditable;
+import org.argeo.app.docbook.DbkAttr;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.cms.swt.acr.AbstractPageViewer;
+import org.argeo.cms.swt.acr.SwtSection;
+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.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+public class DocBookViewer extends AbstractPageViewer {
+
+       private TextInterpreter textInterpreter = new DbkTextInterpreter();
+
+       private TextSection mainSection;
+
+       public DocBookViewer(Composite parent, int style, Content item, CmsEditable cmsEditable) {
+               super(parent, style, cmsEditable);
+               for (Content child : item) {
+                       if (child.hasContentClass(DbkType.article.qName())) {
+                               if (mainSection != null)
+                                       throw new IllegalStateException("Main section already created");
+                               mainSection = new TextSection(parent, 0, child);
+                               mainSection.setLayoutData(CmsSwtUtils.fillAll());
+                       }
+               }
+       }
+
+       @Override
+       protected void refresh(Control control) {
+               if (!(control instanceof SwtSection))
+                       return;
+               long begin = System.currentTimeMillis();
+               SwtSection section = (SwtSection) control;
+               if (section instanceof TextSection) {
+                       CmsSwtUtils.clear(mainSection);
+                       refreshTextSection(mainSection);
+
+               }
+               long duration = System.currentTimeMillis() - begin;
+//             System.out.println(duration + " ms - " + DbkUtils.getTitle(section.getNode()));
+
+       }
+
+       protected void refreshTextSection(TextSection section) {
+               for (Content child : section.getContent()) {
+                       if (child.hasContentClass(DbkType.section.qName())) {
+                               TextSection childSection = new TextSection(section, 0, child);
+                               childSection.setLayoutData(CmsSwtUtils.fillAll());
+                               refreshTextSection(childSection);
+                       } else if (child.hasContentClass(DbkType.para.qName())) {
+                               Paragraph para = new Paragraph(section, 0, child);
+                               para.setLayoutData(CmsSwtUtils.fillWidth());
+                               updateContent(para);
+                       }
+
+               }
+       }
+
+       protected void updateContent(SwtEditablePart part) {
+               if (part instanceof SwtSectionPart) {
+                       SwtSectionPart sectionPart = (SwtSectionPart) part;
+                       Content partContent = sectionPart.getContent();
+
+                       if (part instanceof StyledControl && (sectionPart.getSection() instanceof TextSection)) {
+                               TextSection section = (TextSection) sectionPart.getSection();
+                               StyledControl styledControl = (StyledControl) part;
+                               if (isDbk(partContent, para)) {
+                                       Optional<String> roleAttr = partContent.get(DbkAttr.role.qName(), String.class);
+                                       String style = roleAttr.orElse(section.getDefaultTextStyle());
+                                       styledControl.setStyle(style);
+                               }
+                       }
+                       // use control AFTER setting style, since it may have been reset
+
+                       if (part instanceof EditableText) {
+                               EditableText paragraph = (EditableText) part;
+                               if (paragraph == getEdited())
+                                       paragraph.setText(textInterpreter.raw(partContent));
+                               else
+                                       paragraph.setText(textInterpreter.raw(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 DbkSectionTitle) {
+//                     DbkSectionTitle title = (DbkSectionTitle) part;
+//                     title.setStyle(title.getSection().getTitleStyle());
+//                     // use control AFTER setting style
+//                     if (title == getEdited())
+//                             title.setText(textInterpreter.read(title.getNode()));
+//                     else
+//                             title.setText(textInterpreter.readSimpleHtml(title.getNode()));
+//             }
+       }
+
+       @Override
+       public Control getControl() {
+               return mainSection;
+       }
+
+}
diff --git a/org.argeo.app.swt/src/org/argeo/app/swt/docbook/Paragraph.java b/org.argeo.app.swt/src/org/argeo/app/swt/docbook/Paragraph.java
new file mode 100644 (file)
index 0000000..60bfc77
--- /dev/null
@@ -0,0 +1,50 @@
+package org.argeo.app.swt.docbook;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.spi.ProvidedContent;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.acr.SwtSectionPart;
+import org.argeo.cms.swt.widgets.EditableText;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/** An editable paragraph. */
+public class Paragraph extends EditableText implements SwtSectionPart {
+       private static final long serialVersionUID = 3746457776229542887L;
+
+       private final TextSection section;
+
+       public Paragraph(TextSection section, int style, Content node) {
+               super(section, style);
+               this.section = section;
+               setData(node);
+               CmsSwtUtils.style(this, DbkType.para.name());
+       }
+
+       public TextSection getSection() {
+               return section;
+       }
+
+       @Override
+       protected Label createLabel(Composite box, String style) {
+               Label lbl = super.createLabel(box, style);
+               CmsSwtUtils.disableMarkupValidation(lbl);
+               return lbl;
+       }
+
+       @Override
+       public String getPartId() {
+               return ((ProvidedContent) getContent()).getSessionLocalId();
+       }
+
+       @Override
+       public Content getContent() {
+               return (Content) getData();
+       }
+
+       @Override
+       public String toString() {
+               return "Paragraph #" + getPartId();
+       }
+}
diff --git a/org.argeo.app.swt/src/org/argeo/app/swt/docbook/TextInterpreter.java b/org.argeo.app.swt/src/org/argeo/app/swt/docbook/TextInterpreter.java
new file mode 100644 (file)
index 0000000..0470a6d
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.app.swt.docbook;
+
+import org.argeo.api.acr.Content;
+
+/** Convert from/to data layer to/from presentation layer. */
+public interface TextInterpreter {
+       String raw(Content content);
+
+       String read(Content content);
+
+       String readSimpleHtml(Content content);
+
+       void write(Content content, String txt);
+}
diff --git a/org.argeo.app.swt/src/org/argeo/app/swt/docbook/TextSection.java b/org.argeo.app.swt/src/org/argeo/app/swt/docbook/TextSection.java
new file mode 100644 (file)
index 0000000..e062ad2
--- /dev/null
@@ -0,0 +1,78 @@
+package org.argeo.app.swt.docbook;
+
+import org.argeo.api.acr.Content;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.acr.SwtSection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+
+/** An editable section. */
+public class TextSection extends SwtSection {
+       private static final long serialVersionUID = -8625209546243220689L;
+       private String defaultTextStyle = DbkType.para.name();
+       private String titleStyle;
+
+       private final boolean flat;
+
+       private boolean titleReadOnly = false;
+
+       private final int level;
+
+       public TextSection(Composite parent, int style, Content node) {
+               this(parent, findSection(parent), style, node);
+       }
+
+       public TextSection(TextSection section, int style, Content node) {
+               this(section, section.getParentSection(), style, node);
+       }
+
+       private TextSection(Composite parent, SwtSection parentSection, int style, Content node) {
+               super(parent, parentSection, style, node);
+               flat = SWT.FLAT == (style & SWT.FLAT);
+               if (parentSection instanceof TextSection) {
+                       level = ((TextSection) parentSection).getLevel() + 1;
+               } else {
+                       level = 0;
+               }
+               CmsSwtUtils.style(this, DbkType.section.name());
+       }
+
+       public String getDefaultTextStyle() {
+               return defaultTextStyle;
+       }
+
+       public boolean isFlat() {
+               return flat;
+       }
+
+       /** The level of this section, similar to h1, h2, etc. in HTML. */
+       public int getLevel() {
+               return level;
+       }
+
+       public String getTitleStyle() {
+               if (titleStyle != null)
+                       return titleStyle;
+               // TODO make base H styles configurable
+//             Integer relativeDepth = getRelativeDepth();
+//             System.out.println("Level: " + getLevel());
+               return "h" + (getLevel() + 1);
+       }
+
+       public void setDefaultTextStyle(String defaultTextStyle) {
+               this.defaultTextStyle = defaultTextStyle;
+       }
+
+       public void setTitleStyle(String titleStyle) {
+               this.titleStyle = titleStyle;
+       }
+
+       public boolean isTitleReadOnly() {
+               return titleReadOnly;
+       }
+
+       public void setTitleReadOnly(boolean titleReadOnly) {
+               this.titleReadOnly = titleReadOnly;
+       }
+}
index 855735da5030d65a3baee11830a93d4e2c22172d..339a4440ccabd4901e3eb535935a8ebf76ffb9fa 100644 (file)
@@ -1,3 +1,3 @@
 service.pid=argeo.publishing.ui.documentUiProvider
 
-entity.type=entity:document,nt:file
\ No newline at end of file
+entity.type=nt:file
\ No newline at end of file
index 64ca3195d1832c2d8c42dfe3bbce884b8a83ea0f..7555eda971f6e966ece0176617994f8cb2454c1f 100644 (file)
@@ -1,3 +1,3 @@
 service.pid=argeo.publishing.ui.publishUiProvider
 
-#entity.type=entity:document,nt:file
\ No newline at end of file
+entity.type=entity:document
\ No newline at end of file
index 6b50e931633afb04ccabd2159bf58b9a2c1b5858..d1a349fb9b61e93d0d0328739fe5ec664e0a8c9b 100644 (file)
@@ -46,8 +46,7 @@ public class ContentEntryArea implements SwtUiProvider {
                contentPart.onSelected((o) -> {
                        Content c = (Content) o;
                        log.debug(c.getPath());
-                       // cmsView.sendEvent(SuiteEvent.refreshPart.topic(),
-                       // SuiteEvent.eventProperties(c));
+                       cmsView.sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(c));
                });
                return view;
        }
index a077372260fc666de890cf7812729ee648182ab6..ed7e1efe5750b589f7fa9c589caf05b1704e6784 100644 (file)
@@ -1,7 +1,8 @@
 package org.argeo.app.ui.publish;
 
 import org.argeo.api.acr.Content;
-import org.argeo.app.ux.docbook.DocBookViewer;
+import org.argeo.api.cms.ux.CmsEditable;
+import org.argeo.app.swt.docbook.DocBookViewer;
 import org.argeo.cms.swt.acr.SwtUiProvider;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
@@ -10,8 +11,10 @@ public class PublishUiProvider implements SwtUiProvider {
 
        @Override
        public Control createUiPart(Composite parent, Content context) {
-               DocBookViewer docBookViewer = new DocBookViewer(parent, 0, context);
-               return docBookViewer;
+               DocBookViewer docBookViewer = new DocBookViewer(parent, 0, context, CmsEditable.NON_EDITABLE);
+//             docBookViewer.setLayoutData(CmsSwtUtils.fillAll());
+               docBookViewer.refresh();
+               return docBookViewer.getControl();
        }
 
 }
diff --git a/org.argeo.app.ux/.classpath b/org.argeo.app.ux/.classpath
deleted file mode 100644 (file)
index 81fe078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/org.argeo.app.ux/.project b/org.argeo.app.ux/.project
deleted file mode 100644 (file)
index 8ba2daf..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.app.ux</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/org.argeo.app.ux/bnd.bnd b/org.argeo.app.ux/bnd.bnd
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/org.argeo.app.ux/build.properties b/org.argeo.app.ux/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/org.argeo.app.ux/src/org/argeo/app/ux/docbook/DocBookViewer.java b/org.argeo.app.ux/src/org/argeo/app/ux/docbook/DocBookViewer.java
deleted file mode 100644 (file)
index d53b2a7..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.app.ux.docbook;
-
-import org.argeo.api.acr.Content;
-import org.argeo.cms.swt.acr.ContentComposite;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-
-public class DocBookViewer extends ContentComposite {
-
-       public DocBookViewer(Composite parent, int style, Content item) {
-               super(parent, style, item);
-               new Label(parent, 0).setText(item.toString());
-       }
-
-}