Export DocBook to file system.
[gpl/argeo-suite.git] / publishing / org.argeo.publishing.ui / src / org / argeo / docbook / ui / AbstractDbkViewer.java
index 8a527793a3d47ade95684c5e73d092dc996e6919..6b0692f6f80c52735b30c1a6647ded04ea0ce876 100644 (file)
@@ -1,9 +1,13 @@
 package org.argeo.docbook.ui;
 
 import static org.argeo.cms.ui.util.CmsUiUtils.fillWidth;
+import static org.argeo.docbook.DbkType.para;
+import static org.argeo.docbook.DbkUtils.addDbk;
+import static org.argeo.docbook.DbkUtils.isDbk;
 
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Observer;
 
@@ -12,18 +16,13 @@ import javax.jcr.Node;
 import javax.jcr.NodeIterator;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
 import org.argeo.cms.text.Paragraph;
-import org.argeo.cms.text.SectionTitle;
 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;
@@ -31,10 +30,13 @@ 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.docbook.DbkAttr;
+import org.argeo.docbook.DbkType;
+import org.argeo.docbook.DbkUtils;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
 import org.argeo.jcr.JcrUtils;
 import org.eclipse.rap.fileupload.FileDetails;
 import org.eclipse.rap.fileupload.FileUploadEvent;
@@ -48,8 +50,10 @@ import org.eclipse.swt.events.MouseAdapter;
 import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
 import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Text;
 
 /** Base class for text viewers and editors. */
@@ -60,7 +64,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;
@@ -69,15 +73,17 @@ 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);
-               imageManager = cmsView.getImageManager();
+//             CmsView cmsView = CmsView.getCmsView(parent);
+//             imageManager = cmsView.getImageManager();
                flat = SWT.FLAT == (style & SWT.FLAT);
 
                if (getCmsEditable().canEdit()) {
                        fileUploadListener = new FUL();
-                       styledTools = new DbkContextMenu(this, parent.getDisplay());
+                       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);
        }
@@ -95,37 +101,39 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        CmsUiUtils.clear(section);
                        Node node = section.getNode();
                        TextSection textSection = (TextSection) section;
-                       if (node.hasNode(DocBookTypes.TITLE)) {
+                       if (node.hasNode(DbkType.title.get())) {
                                if (section.getHeader() == null)
                                        section.createHeader();
-                               Node titleNode = node.getNode(DocBookTypes.TITLE);
+                               Node titleNode = node.getNode(DbkType.title.get());
                                DocBookSectionTitle title = newSectionTitle(textSection, titleNode);
                                title.setLayoutData(CmsUiUtils.fillWidth());
                                updateContent(title);
                        }
 
-                       for (NodeIterator ni = node.getNodes(DocBookNames.DBK_PARA); ni.hasNext();) {
+                       for (NodeIterator ni = node.getNodes(); ni.hasNext();) {
                                Node child = ni.nextNode();
-                               final SectionPart sectionPart;
-                               if (child.isNodeType(DocBookTypes.IMAGEDATA) || child.isNodeType(NodeType.NT_FILE)) {
-                                       // FIXME adapt to DocBook
-                                       sectionPart = newImg(textSection, child);
-                               } else if (child.isNodeType(DocBookTypes.PARA)) {
+                               SectionPart sectionPart = null;
+                               if (isDbk(child, DbkType.mediaobject)) {
+                                       if (child.hasNode(DbkType.imageobject.get())) {
+                                               Node imageDataNode = child.getNode(DbkType.imageobject.get()).getNode(DbkType.imagedata.get());
+                                               sectionPart = newImg(textSection, imageDataNode);
+                                       }
+                               } else if (isDbk(child, para)) {
                                        sectionPart = newParagraph(textSection, child);
                                } else {
                                        sectionPart = newSectionPart(textSection, child);
-                                       if (sectionPart == null)
-                                               throw new CmsException("Unsupported node " + child);
+//                                     if (sectionPart == null)
+//                                             throw new IllegalArgumentException("Unsupported node " + child);
                                        // TODO list node types in exception
                                }
-                               if (sectionPart instanceof Control)
+                               if (sectionPart != null && sectionPart instanceof Control)
                                        ((Control) sectionPart).setLayoutData(CmsUiUtils.fillWidth());
                        }
 
 //                     if (!flat)
-                       for (NodeIterator ni = section.getNode().getNodes(DocBookNames.DBK_SECTION); ni.hasNext();) {
+                       for (NodeIterator ni = section.getNode().getNodes(DbkType.section.get()); ni.hasNext();) {
                                Node child = ni.nextNode();
-                               if (child.isNodeType(DocBookTypes.SECTION)) {
+                               if (isDbk(child, DbkType.section)) {
                                        TextSection newSection = new TextSection(section, SWT.NONE, child);
                                        newSection.setLayoutData(CmsUiUtils.fillWidth());
                                        refresh(newSection);
@@ -135,7 +143,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        for (Section s : section.getSubSections().values())
                                refresh(s);
                }
-               // section.layout();
+               // section.layout(true, true);
        }
 
        /** To be overridden in order to provide additional SectionPart types */
@@ -152,44 +160,43 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                return paragraph;
        }
 
-       protected Img newImg(TextSection parent, Node node) throws RepositoryException {
-               Img img = new Img(parent, parent.getStyle(), node) {
-                       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));
-                       }
-               };
-               img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
-               updateContent(img);
-               img.setMouseListener(getMouseListener());
-               return img;
+       protected DbkImg newImg(TextSection parent, Node node) {
+               try {
+                       DbkImg img = new DbkImg(parent, parent.getStyle(), node, imageManager);
+                       img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+                       updateContent(img);
+                       img.setMouseListener(getMouseListener());
+                       return img;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot add new image " + node, e);
+               }
        }
 
        protected DocBookSectionTitle newSectionTitle(TextSection parent, Node titleNode) throws RepositoryException {
                int style = parent.getStyle();
+               Composite titleParent = newSectionHeader(parent);
                if (parent.isTitleReadOnly())
                        style = style | SWT.READ_ONLY;
-               DocBookSectionTitle title = new DocBookSectionTitle(parent.getHeader(), style, titleNode);
+               DocBookSectionTitle title = new DocBookSectionTitle(titleParent, style, titleNode);
                updateContent(title);
                title.setMouseListener(getMouseListener());
                return title;
        }
 
+       /**
+        * To be overridden in order to provide additional processing at the section
+        * level.
+        * 
+        * @return the parent to use for the {@link DocBookSectionTitle}, by default
+        *         {@link Section#getHeader()}
+        */
+       protected Composite newSectionHeader(TextSection section) {
+               return section.getHeader();
+       }
+
        protected DocBookSectionTitle prepareSectionTitle(Section newSection, String titleText) throws RepositoryException {
                Node sectionNode = newSection.getNode();
-               Node titleNode;
-               if (!sectionNode.hasNode(DocBookTypes.TITLE)) {
-                       titleNode = sectionNode.addNode(DocBookTypes.TITLE, DocBookTypes.TITLE);
-               } else {
-                       titleNode = sectionNode.getNode(DocBookTypes.TITLE);
-               }
+               Node titleNode = DbkUtils.getOrAddDbk(sectionNode, DbkType.title);
                getTextInterpreter().write(titleNode, titleText);
                if (newSection.getHeader() == null)
                        newSection.createHeader();
@@ -205,9 +212,9 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        if (part instanceof StyledControl && (sectionPart.getSection() instanceof TextSection)) {
                                TextSection section = (TextSection) sectionPart.getSection();
                                StyledControl styledControl = (StyledControl) part;
-                               if (partNode.isNodeType(DocBookTypes.PARA)) {
-                                       String style = partNode.hasProperty(DocBookNames.DBK_ROLE)
-                                                       ? partNode.getProperty(DocBookNames.DBK_ROLE).getString()
+                               if (isDbk(partNode, para)) {
+                                       String style = partNode.hasProperty(DbkAttr.role.name())
+                                                       ? partNode.getProperty(DbkAttr.role.name()).getString()
                                                        : section.getDefaultTextStyle();
                                        styledControl.setStyle(style);
                                }
@@ -217,11 +224,11 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        if (part instanceof EditableText) {
                                EditableText paragraph = (EditableText) part;
                                if (paragraph == getEdited())
-                                       paragraph.setText(textInterpreter.read(partNode));
-                               else
                                        paragraph.setText(textInterpreter.raw(partNode));
-                       } else if (part instanceof EditableImage) {
-                               EditableImage editableImage = (EditableImage) part;
+                               else
+                                       paragraph.setText(textInterpreter.readSimpleHtml(partNode));
+                       } else if (part instanceof DbkImg) {
+                               DbkImg editableImage = (DbkImg) part;
                                imageManager.load(partNode, part.getControl(), editableImage.getPreferredImageSize());
                        }
                } else if (part instanceof DocBookSectionTitle) {
@@ -244,7 +251,8 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                return;
                        String text = ((Text) et.getControl()).getText();
 
-                       String[] lines = text.split("[\r\n]+");
+                       // String[] lines = text.split("[\r\n]+");
+                       String[] lines = { text };
                        assert lines.length != 0;
                        saveLine(part, lines[0]);
                        if (lines.length > 1) {
@@ -255,7 +263,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                        Node sectionNode = section.getNode();
                                        Node currentParagraphN = currentParagraph.getNode();
                                        for (int i = 1; i < lines.length; i++) {
-                                               Node newNode = sectionNode.addNode(DocBookNames.DBK_PARA, DocBookTypes.PARA);
+                                               Node newNode = addDbk(sectionNode, para);
                                                // newNode.addMixin(CmsTypes.CMS_STYLED);
                                                saveLine(newNode, lines[i]);
                                                // second node was create as last, if it is not the next
@@ -274,7 +282,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                                currentParagraphN = newNode;
                                        }
                                }
-                               // TODO or rather return the created paragarphs?
+                               // TODO or rather return the created paragraphs?
                                layout(toLayout.toArray(new Control[toLayout.size()]));
                        }
                        persistChanges(et.getNode());
@@ -287,7 +295,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                } else if (part instanceof PropertyPart) {
                        saveLine(((PropertyPart) part).getProperty(), line);
                } else {
-                       throw new CmsException("Unsupported part " + part);
+                       throw new IllegalArgumentException("Unsupported part " + part);
                }
        }
 
@@ -305,14 +313,25 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                if (caretPosition instanceof Integer)
                                        text.setSelection((Integer) caretPosition);
                                else if (caretPosition instanceof Point) {
-                                       // TODO find a way to position the caret at the right place
+//                                     layout(text);
+//                                     // TODO find a way to position the caret at the right place
+//                                     Point clickLocation = (Point) caretPosition;
+//                                     Point withinText = text.toControl(clickLocation);
+//                                     Rectangle bounds = text.getBounds();
+//                                     int width = bounds.width;
+//                                     int height = bounds.height;
+//                                     int textLength = text.getText().length();
+//                                     float area = width * height;
+//                                     float proportion = withinText.y * width + withinText.x;
+//                                     int pos = (int) (textLength * (proportion / area));
+//                                     text.setSelection(pos);
                                }
                        text.setData(RWT.ACTIVE_KEYS, new String[] { "BACKSPACE", "ESC", "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT",
                                        "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);
                }
        }
 
@@ -320,27 +339,59 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
        void setParagraphStyle(Paragraph paragraph, String style) {
                try {
                        Node paragraphNode = paragraph.getNode();
-                       paragraphNode.setProperty(DocBookNames.DBK_ROLE, style);
+                       if (style == null) {// default
+                               if (paragraphNode.hasProperty(DbkAttr.role.name()))
+                                       paragraphNode.getProperty(DbkAttr.role.name()).remove();
+                       } else {
+                               paragraphNode.setProperty(DbkAttr.role.name(), style);
+                       }
                        persistChanges(paragraphNode);
                        updateContent(paragraph);
-                       layout(paragraph);
+                       layoutPage();
                } catch (RepositoryException e1) {
-                       throw new CmsException("Cannot set style " + style + " on " + paragraph, e1);
+                       throw new JcrException("Cannot set style " + style + " on " + paragraph, e1);
                }
        }
 
-       void deletePart(SectionPart paragraph) {
+       void insertPart(Section section, Node node) {
                try {
-                       Node paragraphNode = paragraph.getNode();
-                       Section section = paragraph.getSection();
-                       Session session = paragraphNode.getSession();
-                       paragraphNode.remove();
+                       refresh(section);
+                       layoutPage();
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot insert part " + node + " in section " + section.getNode(), e);
+               }
+       }
+
+       void deletePart(SectionPart sectionPart) {
+               try {
+                       Node node = sectionPart.getNode();
+                       Session session = node.getSession();
+                       if (sectionPart instanceof DbkImg) {
+                               // FIXME make it more robust
+                               node = node.getParent().getParent();
+                               if (!isDbk(node, DbkType.mediaobject))
+                                       throw new IllegalArgumentException("Node " + node + " is not a media object.");
+                       }
+                       node.remove();
                        session.save();
-                       if (paragraph instanceof Control)
-                               ((Control) paragraph).dispose();
-                       layout(section);
+                       if (sectionPart instanceof Control)
+                               ((Control) sectionPart).dispose();
+                       layoutPage();
                } catch (RepositoryException e1) {
-                       throw new CmsException("Cannot delete " + paragraph, e1);
+                       throw new JcrException("Cannot delete " + sectionPart, e1);
+               }
+       }
+
+       void deleteSection(Section section) {
+               try {
+                       Node node = section.getNode();
+                       Session session = node.getSession();
+                       node.remove();
+                       session.save();
+                       section.dispose();
+                       layoutPage();
+               } catch (RepositoryException e1) {
+                       throw new JcrException("Cannot delete " + section, e1);
                }
        }
 
@@ -364,7 +415,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
 
                                // FIXME set content the DocBook way
                                // firstNode.setProperty(CMS_CONTENT, first);
-                               Node secondNode = sectionNode.addNode(DocBookNames.DBK_PARA, DocBookTypes.PARA);
+                               Node secondNode = addDbk(sectionNode, para);
                                // secondNode.addMixin(CmsTypes.CMS_STYLED);
 
                                // second node was create as last, if it is not the next one, it
@@ -396,11 +447,11 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                int caretPosition = text.getCaretPosition();
                                Section section = sectionTitle.getSection();
                                Node sectionNode = section.getNode();
-                               Node paragraphNode = sectionNode.addNode(DocBookNames.DBK_PARA, DocBookTypes.PARA);
+                               Node paragraphNode = addDbk(sectionNode, para);
                                // paragraphNode.addMixin(CmsTypes.CMS_STYLED);
 
                                textInterpreter.write(paragraphNode, txt.substring(caretPosition));
-                               textInterpreter.write(sectionNode.getNode(DocBookTypes.TITLE), txt.substring(0, caretPosition));
+                               textInterpreter.write(sectionNode.getNode(DbkType.title.get()), txt.substring(0, caretPosition));
                                sectionNode.orderBefore(p(paragraphNode.getIndex()), p(1));
                                persistChanges(sectionNode);
 
@@ -409,7 +460,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                edit(paragraph, 0);
                        }
                } catch (RepositoryException e) {
-                       throw new CmsException("Cannot split " + getEdited(), e);
+                       throw new JcrException("Cannot split " + getEdited(), e);
                }
        }
 
@@ -432,7 +483,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        Paragraph previousParagraph = paragraphMergedWithPrevious(paragraph, previousNode);
                        edit(previousParagraph, previousTxt.length());
                } catch (RepositoryException e) {
-                       throw new CmsException("Cannot stop editing", e);
+                       throw new JcrException("Cannot stop editing", e);
                }
        }
 
@@ -444,7 +495,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        String txt = text.getText();
                        Node paragraphNode = paragraph.getNode();
                        Node sectionNode = paragraphNode.getParent();
-                       NodeIterator paragraphNodes = sectionNode.getNodes(DocBookNames.DBK_PARA);
+                       NodeIterator paragraphNodes = sectionNode.getNodes(DbkType.para.get());
                        long size = paragraphNodes.getSize();
                        if (paragraphNode.getIndex() == size)
                                return;// do nothing
@@ -461,7 +512,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        paragraphMergedWithNext(paragraph, removed);
                        edit(paragraph, txt.length());
                } catch (RepositoryException e) {
-                       throw new CmsException("Cannot stop editing", e);
+                       throw new JcrException("Cannot stop editing", e);
                }
        }
 
@@ -476,28 +527,28 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
 
                                if (part instanceof Paragraph) {
                                        // FIXME adapt to DocBook
-                                       Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE);
-                                       newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
-                                       JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]);
-                                       if (partIndex < newNode.getIndex() - 1) {
-                                               // was not last
-                                               sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1));
-                                       }
-                                       // sectionNode.orderBefore(p(partNode.getIndex()),
-                                       // p(newNode.getIndex()));
-                                       persistChanges(sectionNode);
-                                       Img img = newImg((TextSection) section, newNode);
-                                       edit(img, null);
-                                       layout(img.getControl());
-                               } else if (part instanceof Img) {
+//                                     Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE);
+//                                     newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
+//                                     JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]);
+//                                     if (partIndex < newNode.getIndex() - 1) {
+//                                             // was not last
+//                                             sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1));
+//                                     }
+//                                     // sectionNode.orderBefore(p(partNode.getIndex()),
+//                                     // p(newNode.getIndex()));
+//                                     persistChanges(sectionNode);
+//                                     DbkImg img = newImg((TextSection) section, newNode);
+//                                     edit(img, null);
+//                                     layout(img.getControl());
+                               } else if (part instanceof DbkImg) {
                                        if (getEdited() == part)
                                                return;
                                        edit(part, null);
-                                       layout(part.getControl());
+                                       layoutPage();
                                }
                        }
                } catch (RepositoryException e) {
-                       throw new CmsException("Cannot upload", e);
+                       throw new JcrException("Cannot upload", e);
                }
        }
 
@@ -515,12 +566,12 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                Node sectionNode = section.getNode();
                                // main title
                                if (section == mainSection && section instanceof TextSection && paragraphNode.getIndex() == 1
-                                               && !sectionNode.hasNode(DocBookTypes.TITLE)) {
+                                               && !sectionNode.hasNode(DbkType.title.get())) {
                                        DocBookSectionTitle sectionTitle = prepareSectionTitle(section, txt);
                                        edit(sectionTitle, 0);
                                        return;
                                }
-                               Node newSectionNode = sectionNode.addNode(DocBookNames.DBK_SECTION, DocBookTypes.SECTION);
+                               Node newSectionNode = addDbk(sectionNode, DbkType.section);
                                // newSectionNode.addMixin(NodeType.MIX_TITLE);
                                sectionNode.orderBefore(h(newSectionNode.getIndex()), h(1));
 
@@ -530,13 +581,14 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                while (sectionNode.hasNode(p(paragraphIndex + 1))) {
                                        Node parag = sectionNode.getNode(p(paragraphIndex + 1));
                                        sectionNode.getSession().move(sectionPath + '/' + p(paragraphIndex + 1),
-                                                       newSectionPath + '/' + DocBookNames.DBK_PARA);
+                                                       newSectionPath + '/' + DbkType.para.get());
                                        SectionPart sp = section.getSectionPart(parag.getIdentifier());
                                        if (sp instanceof Control)
                                                ((Control) sp).dispose();
                                }
                                // create title
-                               Node titleNode = newSectionNode.addNode(DocBookTypes.TITLE, DocBookTypes.TITLE);
+                               Node titleNode = DbkUtils.addDbk(newSectionNode, DbkType.title);
+                               // newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE);
                                getTextInterpreter().write(titleNode, txt);
 
                                TextSection newSection = new TextSection(section, section.getStyle(), newSectionNode);
@@ -562,7 +614,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                if (sectionN.getIndex() == 1)
                                        return;// cannot deepen first section
                                Node previousSectionN = parentSectionN.getNode(h(sectionN.getIndex() - 1));
-                               NodeIterator subSections = previousSectionN.getNodes(DocBookNames.DBK_SECTION);
+                               NodeIterator subSections = previousSectionN.getNodes(DbkType.section.get());
                                int subsectionsCount = (int) subSections.getSize();
                                previousSectionN.getSession().move(sectionN.getPath(),
                                                previousSectionN.getPath() + "/" + h(subsectionsCount + 1));
@@ -572,7 +624,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                persistChanges(previousSectionN);
                        }
                } catch (RepositoryException e) {
-                       throw new CmsException("Cannot deepen " + getEdited(), e);
+                       throw new JcrException("Cannot deepen " + getEdited(), e);
                }
        }
 
@@ -583,8 +635,8 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                try {
                        if (getEdited() instanceof Paragraph) {
                                upload(getEdited());
-                       } else if (getEdited() instanceof SectionTitle) {
-                               SectionTitle sectionTitle = (SectionTitle) getEdited();
+                       } else if (getEdited() instanceof DocBookSectionTitle) {
+                               DocBookSectionTitle sectionTitle = (DocBookSectionTitle) getEdited();
                                Section section = sectionTitle.getSection();
                                Node sectionNode = section.getNode();
                                Section parentSection = section.getParentSection();
@@ -601,23 +653,23 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                        mergedSection = lst.get(sectionNode.getIndex() - 1);
                                }
                                Node mergedNode = mergedSection.getNode();
-                               boolean mergedHasSubSections = mergedNode.hasNode(DocBookNames.DBK_SECTION);
+                               boolean mergedHasSubSections = mergedNode.hasNode(DbkType.section.get());
 
                                // title as paragraph
-                               Node newParagrapheNode = mergedNode.addNode(DocBookNames.DBK_PARA, DocBookTypes.PARA);
+                               Node newParagrapheNode = addDbk(mergedNode, para);
                                // newParagrapheNode.addMixin(CmsTypes.CMS_STYLED);
                                if (mergedHasSubSections)
                                        mergedNode.orderBefore(p(newParagrapheNode.getIndex()), h(1));
-                               String txt = getTextInterpreter().read(sectionNode.getNode(DocBookTypes.TITLE));
+                               String txt = getTextInterpreter().read(sectionNode.getNode(DbkType.title.get()));
                                getTextInterpreter().write(newParagrapheNode, txt);
                                // move
-                               NodeIterator paragraphs = sectionNode.getNodes(DocBookNames.DBK_PARA);
+                               NodeIterator paragraphs = sectionNode.getNodes(para.get());
                                while (paragraphs.hasNext()) {
                                        Node p = paragraphs.nextNode();
                                        SectionPart sp = section.getSectionPart(p.getIdentifier());
                                        if (sp instanceof Control)
                                                ((Control) sp).dispose();
-                                       mergedNode.getSession().move(p.getPath(), mergedNode.getPath() + '/' + DocBookNames.DBK_PARA);
+                                       mergedNode.getSession().move(p.getPath(), mergedNode.getPath() + '/' + para.get());
                                        if (mergedHasSubSections)
                                                mergedNode.orderBefore(p(p.getIndex()), h(1));
                                }
@@ -627,7 +679,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                while (subsections.hasNext()) {
                                        Section subsection = subsections.next();
                                        Node s = subsection.getNode();
-                                       mergedNode.getSession().move(s.getPath(), mergedNode.getPath() + '/' + DocBookNames.DBK_SECTION);
+                                       mergedNode.getSession().move(s.getPath(), mergedNode.getPath() + '/' + DbkType.section.get());
                                        subsection.dispose();
                                }
 
@@ -641,7 +693,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                                persistChanges(mergedNode);
                        }
                } catch (RepositoryException e) {
-                       throw new CmsException("Cannot undeepen " + getEdited(), e);
+                       throw new JcrException("Cannot undeepen " + getEdited(), e);
                }
        }
 
@@ -685,13 +737,13 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
        // UTILITIES
        protected String p(Integer index) {
                StringBuilder sb = new StringBuilder(6);
-               sb.append(DocBookNames.DBK_PARA).append('[').append(index).append(']');
+               sb.append(para.get()).append('[').append(index).append(']');
                return sb.toString();
        }
 
        protected String h(Integer index) {
                StringBuilder sb = new StringBuilder(5);
-               sb.append(DocBookNames.DBK_SECTION).append('[').append(index).append(']');
+               sb.append(DbkType.section.get()).append('[').append(index).append(']');
                return sb.toString();
        }
 
@@ -723,9 +775,14 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                try {
                        // Common
                        if (ke.keyCode == SWT.ESC) {
-                               cancelEdit();
+//                             cancelEdit();
+                               saveEdit();
                        } else if (ke.character == '\r') {
-                               splitEdit();
+                               if (!shiftPressed)
+                                       splitEdit();
+                       } else if (ke.character == 'z') {
+                               if (ctrlPressed)
+                                       cancelEdit();
                        } else if (ke.character == 'S') {
                                if (ctrlPressed)
                                        saveEdit();
@@ -782,15 +839,34 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                public void mouseDoubleClick(MouseEvent e) {
                        if (e.button == 1) {
                                Control source = (Control) e.getSource();
-                               if (getCmsEditable().canEdit()) {
-                                       if (getCmsEditable().isEditing() && !(getEdited() instanceof Img)) {
-                                               if (source == mainSection)
-                                                       return;
-                                               EditablePart part = findDataParent(source);
-                                               upload(part);
-                                       } else {
-                                               getCmsEditable().startEditing();
+                               EditablePart composite = findDataParent(source);
+                               Point point = new Point(e.x, e.y);
+                               if (composite instanceof DbkImg) {
+                                       if (getCmsEditable().canEdit()) {
+                                               if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg)) {
+                                                       if (source == mainSection)
+                                                               return;
+                                                       EditablePart part = findDataParent(source);
+                                                       upload(part);
+                                               } else {
+                                                       getCmsEditable().startEditing();
+                                               }
                                        }
+                               } else if (source instanceof Label) {
+                                       Label lbl = (Label) source;
+                                       Rectangle bounds = lbl.getBounds();
+                                       float width = bounds.width;
+                                       float height = bounds.height;
+                                       float textLength = lbl.getText().length();
+                                       float area = width * height;
+                                       float charArea = area/textLength;
+                                       float lines = textLength/width;
+                                       float proportion = point.y * width + point.x;
+                                       int pos = (int) (textLength * (proportion / area));
+                                       // TODO refine it
+                                       edit(composite, (Integer) pos);
+                               } else {
+                                       edit(composite, source.toDisplay(point));
                                }
                        }
                }
@@ -798,16 +874,12 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                @Override
                public void mouseDown(MouseEvent e) {
                        if (getCmsEditable().isEditing()) {
-                               if (e.button == 1) {
-                                       Control source = (Control) e.getSource();
-                                       EditablePart composite = findDataParent(source);
-                                       Point point = new Point(e.x, e.y);
-                                       if (!(composite instanceof Img))
-                                               edit(composite, source.toDisplay(point));
-                               } else if (e.button == 3) {
+                               if (e.button == 3) {
                                        EditablePart composite = findDataParent((Control) e.getSource());
-                                       if (styledTools != null)
-                                               styledTools.show(composite, new Point(e.x, e.y));
+                                       if (styledTools != null) {
+                                               List<String> styles = getAvailableStyles(composite);
+                                               styledTools.show(composite, new Point(e.x, e.y), styles);
+                                       }
                                }
                        }
                }
@@ -817,6 +889,10 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                }
        }
 
+       protected List<String> getAvailableStyles(EditablePart editablePart) {
+               return new ArrayList<>();
+       }
+
        // FILE UPLOAD LISTENER
        private class FUL implements FileUploadListener {
                public void uploadProgress(FileUploadEvent event) {
@@ -824,7 +900,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                }
 
                public void uploadFailed(FileUploadEvent event) {
-                       throw new CmsException("Upload failed " + event, event.getException());
+                       throw new RuntimeException("Upload failed " + event, event.getException());
                }
 
                public void uploadFinished(FileUploadEvent event) {