1 package org.argeo.docbook.ui;
3 import static org.argeo.cms.ui.util.CmsUiUtils.fillWidth;
4 import static org.argeo.docbook.DbkUtils.addDbk;
5 import static org.argeo.docbook.DbkUtils.isDbk;
6 import static org.argeo.docbook.DocBookType.para;
8 import java.io.IOException;
9 import java.io.OutputStream;
10 import java.nio.file.Files;
11 import java.nio.file.Path;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
16 import java.util.Observer;
18 import javax.jcr.Item;
19 import javax.jcr.Node;
20 import javax.jcr.NodeIterator;
21 import javax.jcr.RepositoryException;
22 import javax.jcr.Session;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.argeo.cms.text.Paragraph;
27 import org.argeo.cms.text.TextInterpreter;
28 import org.argeo.cms.text.TextSection;
29 import org.argeo.cms.ui.CmsEditable;
30 import org.argeo.cms.ui.util.CmsUiUtils;
31 import org.argeo.cms.ui.viewers.AbstractPageViewer;
32 import org.argeo.cms.ui.viewers.EditablePart;
33 import org.argeo.cms.ui.viewers.NodePart;
34 import org.argeo.cms.ui.viewers.PropertyPart;
35 import org.argeo.cms.ui.viewers.Section;
36 import org.argeo.cms.ui.viewers.SectionPart;
37 import org.argeo.cms.ui.widgets.EditableText;
38 import org.argeo.cms.ui.widgets.StyledControl;
39 import org.argeo.docbook.DbkUtils;
40 import org.argeo.docbook.DocBookNames;
41 import org.argeo.docbook.DocBookType;
42 import org.argeo.jcr.Jcr;
43 import org.argeo.jcr.JcrException;
44 import org.argeo.jcr.JcrUtils;
45 import org.eclipse.rap.fileupload.FileDetails;
46 import org.eclipse.rap.fileupload.FileUploadEvent;
47 import org.eclipse.rap.fileupload.FileUploadHandler;
48 import org.eclipse.rap.fileupload.FileUploadListener;
49 import org.eclipse.rap.rwt.RWT;
50 import org.eclipse.swt.SWT;
51 import org.eclipse.swt.events.KeyEvent;
52 import org.eclipse.swt.events.KeyListener;
53 import org.eclipse.swt.events.MouseAdapter;
54 import org.eclipse.swt.events.MouseEvent;
55 import org.eclipse.swt.events.MouseListener;
56 import org.eclipse.swt.graphics.Point;
57 import org.eclipse.swt.widgets.Composite;
58 import org.eclipse.swt.widgets.Control;
59 import org.eclipse.swt.widgets.Text;
61 /** Base class for text viewers and editors. */
62 public abstract class AbstractDbkViewer extends AbstractPageViewer implements KeyListener, Observer {
63 private static final long serialVersionUID = -2401274679492339668L;
64 private final static Log log = LogFactory.getLog(AbstractDbkViewer.class);
66 private final Section mainSection;
68 private TextInterpreter textInterpreter = new DbkTextInterpreter();
69 private DbkImageManager imageManager;
71 private FileUploadListener fileUploadListener;
72 private DbkContextMenu styledTools;
74 private final boolean flat;
76 protected AbstractDbkViewer(Section parent, int style, CmsEditable cmsEditable) {
77 super(parent, style, cmsEditable);
78 // CmsView cmsView = CmsView.getCmsView(parent);
79 // imageManager = cmsView.getImageManager();
80 flat = SWT.FLAT == (style & SWT.FLAT);
82 if (getCmsEditable().canEdit()) {
83 fileUploadListener = new FUL();
84 styledTools = new DbkContextMenu(this, parent.getShell());
86 this.mainSection = parent;
87 Node baseFolder = Jcr.getParent(mainSection.getNode());
88 imageManager = new DbkImageManager(baseFolder);
89 initModelIfNeeded(mainSection.getNode());
90 // layout(this.mainSection);
94 public Control getControl() {
98 protected void refresh(Control control) throws RepositoryException {
99 if (!(control instanceof Section))
101 Section section = (Section) control;
102 if (section instanceof TextSection) {
103 CmsUiUtils.clear(section);
104 Node node = section.getNode();
105 TextSection textSection = (TextSection) section;
106 if (node.hasNode(DocBookType.title.get())) {
107 if (section.getHeader() == null)
108 section.createHeader();
109 Node titleNode = node.getNode(DocBookType.title.get());
110 DocBookSectionTitle title = newSectionTitle(textSection, titleNode);
111 title.setLayoutData(CmsUiUtils.fillWidth());
112 updateContent(title);
115 for (NodeIterator ni = node.getNodes(); ni.hasNext();) {
116 Node child = ni.nextNode();
117 SectionPart sectionPart = null;
118 if (isDbk(child, DocBookType.mediaobject)) {
119 if (child.hasNode(DocBookType.imageobject.get())) {
120 Node imageDataNode = child.getNode(DocBookType.imageobject.get())
121 .getNode(DocBookType.imagedata.get());
122 sectionPart = newImg(textSection, imageDataNode);
124 } else if (isDbk(child, para)) {
125 sectionPart = newParagraph(textSection, child);
127 sectionPart = newSectionPart(textSection, child);
128 // if (sectionPart == null)
129 // throw new IllegalArgumentException("Unsupported node " + child);
130 // TODO list node types in exception
132 if (sectionPart != null && sectionPart instanceof Control)
133 ((Control) sectionPart).setLayoutData(CmsUiUtils.fillWidth());
137 for (NodeIterator ni = section.getNode().getNodes(DocBookType.section.get()); ni.hasNext();) {
138 Node child = ni.nextNode();
139 if (isDbk(child, DocBookType.section)) {
140 TextSection newSection = new TextSection(section, SWT.NONE, child);
141 newSection.setLayoutData(CmsUiUtils.fillWidth());
146 for (Section s : section.getSubSections().values())
149 // section.layout(true, true);
152 /** To be overridden in order to provide additional SectionPart types */
153 protected SectionPart newSectionPart(TextSection textSection, Node node) {
158 protected Paragraph newParagraph(TextSection parent, Node node) throws RepositoryException {
159 Paragraph paragraph = new Paragraph(parent, parent.getStyle(), node);
160 updateContent(paragraph);
161 paragraph.setLayoutData(fillWidth());
162 paragraph.setMouseListener(getMouseListener());
166 protected DbkImg newImg(TextSection parent, Node node) {
168 DbkImg img = new DbkImg(parent, parent.getStyle(), node, imageManager);
169 img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
171 img.setMouseListener(getMouseListener());
173 } catch (RepositoryException e) {
174 throw new JcrException("Cannot add new image " + node, e);
178 protected DocBookSectionTitle newSectionTitle(TextSection parent, Node titleNode) throws RepositoryException {
179 int style = parent.getStyle();
180 Composite titleParent = newSectionHeader(parent);
181 if (parent.isTitleReadOnly())
182 style = style | SWT.READ_ONLY;
183 DocBookSectionTitle title = new DocBookSectionTitle(titleParent, style, titleNode);
184 updateContent(title);
185 title.setMouseListener(getMouseListener());
190 * To be overridden in order to provide additional processing at the section
193 * @return the parent to use for the {@link DocBookSectionTitle}, by default
194 * {@link Section#getHeader()}
196 protected Composite newSectionHeader(TextSection section) {
197 return section.getHeader();
200 protected DocBookSectionTitle prepareSectionTitle(Section newSection, String titleText) throws RepositoryException {
201 Node sectionNode = newSection.getNode();
202 Node titleNode = DbkUtils.getOrAddDbk(sectionNode, DocBookType.title);
203 getTextInterpreter().write(titleNode, titleText);
204 if (newSection.getHeader() == null)
205 newSection.createHeader();
206 DocBookSectionTitle sectionTitle = newSectionTitle((TextSection) newSection, sectionNode);
210 protected void updateContent(EditablePart part) throws RepositoryException {
211 if (part instanceof SectionPart) {
212 SectionPart sectionPart = (SectionPart) part;
213 Node partNode = sectionPart.getNode();
215 if (part instanceof StyledControl && (sectionPart.getSection() instanceof TextSection)) {
216 TextSection section = (TextSection) sectionPart.getSection();
217 StyledControl styledControl = (StyledControl) part;
218 if (isDbk(partNode, para)) {
219 String style = partNode.hasProperty(DocBookNames.DBK_ROLE)
220 ? partNode.getProperty(DocBookNames.DBK_ROLE).getString()
221 : section.getDefaultTextStyle();
222 styledControl.setStyle(style);
225 // use control AFTER setting style, since it may have been reset
227 if (part instanceof EditableText) {
228 EditableText paragraph = (EditableText) part;
229 if (paragraph == getEdited())
230 paragraph.setText(textInterpreter.raw(partNode));
232 paragraph.setText(textInterpreter.readSimpleHtml(partNode));
233 } else if (part instanceof DbkImg) {
234 DbkImg editableImage = (DbkImg) part;
235 imageManager.load(partNode, part.getControl(), editableImage.getPreferredImageSize());
237 } else if (part instanceof DocBookSectionTitle) {
238 DocBookSectionTitle title = (DocBookSectionTitle) part;
239 title.setStyle(title.getSection().getTitleStyle());
240 // use control AFTER setting style
241 if (title == getEdited())
242 title.setText(textInterpreter.read(title.getNode()));
244 title.setText(textInterpreter.raw(title.getNode()));
248 // OVERRIDDEN FROM PARENT VIEWER
250 protected void save(EditablePart part) throws RepositoryException {
251 if (part instanceof EditableText) {
252 EditableText et = (EditableText) part;
253 if (!et.getEditable())
255 String text = ((Text) et.getControl()).getText();
257 // String[] lines = text.split("[\r\n]+");
258 String[] lines = { text };
259 assert lines.length != 0;
260 saveLine(part, lines[0]);
261 if (lines.length > 1) {
262 ArrayList<Control> toLayout = new ArrayList<Control>();
263 if (part instanceof Paragraph) {
264 Paragraph currentParagraph = (Paragraph) et;
265 Section section = currentParagraph.getSection();
266 Node sectionNode = section.getNode();
267 Node currentParagraphN = currentParagraph.getNode();
268 for (int i = 1; i < lines.length; i++) {
269 Node newNode = addDbk(sectionNode, para);
270 // newNode.addMixin(CmsTypes.CMS_STYLED);
271 saveLine(newNode, lines[i]);
272 // second node was create as last, if it is not the next
274 // means there are some in between and we can take the
276 // index+1 for the re-order
277 if (newNode.getIndex() > currentParagraphN.getIndex() + 1) {
278 sectionNode.orderBefore(p(newNode.getIndex()), p(currentParagraphN.getIndex() + 1));
280 Paragraph newParagraph = newParagraph((TextSection) section, newNode);
281 newParagraph.moveBelow(currentParagraph);
282 toLayout.add(newParagraph);
284 currentParagraph = newParagraph;
285 currentParagraphN = newNode;
288 // TODO or rather return the created paragraphs?
289 layout(toLayout.toArray(new Control[toLayout.size()]));
291 persistChanges(et.getNode());
295 protected void saveLine(EditablePart part, String line) {
296 if (part instanceof NodePart) {
297 saveLine(((NodePart) part).getNode(), line);
298 } else if (part instanceof PropertyPart) {
299 saveLine(((PropertyPart) part).getProperty(), line);
301 throw new IllegalArgumentException("Unsupported part " + part);
305 protected void saveLine(Item item, String line) {
307 textInterpreter.write(item, line);
311 protected void prepare(EditablePart part, Object caretPosition) {
312 Control control = part.getControl();
313 if (control instanceof Text) {
314 Text text = (Text) control;
315 if (caretPosition != null)
316 if (caretPosition instanceof Integer)
317 text.setSelection((Integer) caretPosition);
318 else if (caretPosition instanceof Point) {
319 // TODO find a way to position the caret at the right place
321 text.setData(RWT.ACTIVE_KEYS, new String[] { "BACKSPACE", "ESC", "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT",
322 "ALT+ARROW_RIGHT", "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", "ENTER", "DELETE" });
323 text.setData(RWT.CANCEL_KEYS, new String[] { "RETURN", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
324 text.addKeyListener(this);
325 } else if (part instanceof DbkImg) {
326 ((DbkImg) part).setFileUploadListener(fileUploadListener);
330 // REQUIRED BY CONTEXT MENU
331 void setParagraphStyle(Paragraph paragraph, String style) {
333 Node paragraphNode = paragraph.getNode();
334 if (style == null) {// default
335 if (paragraphNode.hasProperty(DocBookNames.DBK_ROLE))
336 paragraphNode.getProperty(DocBookNames.DBK_ROLE).remove();
338 paragraphNode.setProperty(DocBookNames.DBK_ROLE, style);
340 persistChanges(paragraphNode);
341 updateContent(paragraph);
343 } catch (RepositoryException e1) {
344 throw new JcrException("Cannot set style " + style + " on " + paragraph, e1);
348 void insertPart(Section section, Node node) {
352 } catch (RepositoryException e) {
353 throw new JcrException("Cannot insert part " + node + " in section " + section.getNode(), e);
357 void deletePart(SectionPart sectionPart) {
359 Node node = sectionPart.getNode();
360 Session session = node.getSession();
361 if (sectionPart instanceof DbkImg) {
362 // FIXME make it more robust
363 node = node.getParent().getParent();
364 if (!isDbk(node, DocBookType.mediaobject))
365 throw new IllegalArgumentException("Node " + node + " is not a media object.");
369 if (sectionPart instanceof Control)
370 ((Control) sectionPart).dispose();
372 } catch (RepositoryException e1) {
373 throw new JcrException("Cannot delete " + sectionPart, e1);
377 void deleteSection(Section section) {
379 Node node = section.getNode();
380 Session session = node.getSession();
385 } catch (RepositoryException e1) {
386 throw new JcrException("Cannot delete " + section, e1);
390 String getRawParagraphText(Paragraph paragraph) {
391 return textInterpreter.raw(paragraph.getNode());
395 protected void splitEdit() {
398 if (getEdited() instanceof Paragraph) {
399 Paragraph paragraph = (Paragraph) getEdited();
400 Text text = (Text) paragraph.getControl();
401 int caretPosition = text.getCaretPosition();
402 String txt = text.getText();
403 String first = txt.substring(0, caretPosition);
404 String second = txt.substring(caretPosition);
405 Node firstNode = paragraph.getNode();
406 Node sectionNode = firstNode.getParent();
408 // FIXME set content the DocBook way
409 // firstNode.setProperty(CMS_CONTENT, first);
410 Node secondNode = addDbk(sectionNode, para);
411 // secondNode.addMixin(CmsTypes.CMS_STYLED);
413 // second node was create as last, if it is not the next one, it
414 // means there are some in between and we can take the one at
415 // index+1 for the re-order
416 if (secondNode.getIndex() > firstNode.getIndex() + 1) {
417 sectionNode.orderBefore(p(secondNode.getIndex()), p(firstNode.getIndex() + 1));
420 // if we die in between, at least we still have the whole text
423 textInterpreter.write(secondNode, second);
424 textInterpreter.write(firstNode, first);
425 } catch (Exception e) {
426 // so that no additional nodes are created:
427 JcrUtils.discardUnderlyingSessionQuietly(firstNode);
431 persistChanges(firstNode);
433 Paragraph secondParagraph = paragraphSplitted(paragraph, secondNode);
434 edit(secondParagraph, 0);
435 } else if (getEdited() instanceof DocBookSectionTitle) {
436 DocBookSectionTitle sectionTitle = (DocBookSectionTitle) getEdited();
437 Text text = (Text) sectionTitle.getControl();
438 String txt = text.getText();
439 int caretPosition = text.getCaretPosition();
440 Section section = sectionTitle.getSection();
441 Node sectionNode = section.getNode();
442 Node paragraphNode = addDbk(sectionNode, para);
443 // paragraphNode.addMixin(CmsTypes.CMS_STYLED);
445 textInterpreter.write(paragraphNode, txt.substring(caretPosition));
446 textInterpreter.write(sectionNode.getNode(DocBookType.title.get()), txt.substring(0, caretPosition));
447 sectionNode.orderBefore(p(paragraphNode.getIndex()), p(1));
448 persistChanges(sectionNode);
450 Paragraph paragraph = sectionTitleSplitted(sectionTitle, paragraphNode);
454 } catch (RepositoryException e) {
455 throw new JcrException("Cannot split " + getEdited(), e);
459 protected void mergeWithPrevious() {
462 Paragraph paragraph = (Paragraph) getEdited();
463 Text text = (Text) paragraph.getControl();
464 String txt = text.getText();
465 Node paragraphNode = paragraph.getNode();
466 if (paragraphNode.getIndex() == 1)
468 Node sectionNode = paragraphNode.getParent();
469 Node previousNode = sectionNode.getNode(p(paragraphNode.getIndex() - 1));
470 String previousTxt = textInterpreter.read(previousNode);
471 textInterpreter.write(previousNode, previousTxt + txt);
472 paragraphNode.remove();
473 persistChanges(sectionNode);
475 Paragraph previousParagraph = paragraphMergedWithPrevious(paragraph, previousNode);
476 edit(previousParagraph, previousTxt.length());
477 } catch (RepositoryException e) {
478 throw new JcrException("Cannot stop editing", e);
482 protected void mergeWithNext() {
485 Paragraph paragraph = (Paragraph) getEdited();
486 Text text = (Text) paragraph.getControl();
487 String txt = text.getText();
488 Node paragraphNode = paragraph.getNode();
489 Node sectionNode = paragraphNode.getParent();
490 NodeIterator paragraphNodes = sectionNode.getNodes(DocBookType.para.get());
491 long size = paragraphNodes.getSize();
492 if (paragraphNode.getIndex() == size)
494 Node nextNode = sectionNode.getNode(p(paragraphNode.getIndex() + 1));
495 String nextTxt = textInterpreter.read(nextNode);
496 textInterpreter.write(paragraphNode, txt + nextTxt);
498 Section section = paragraph.getSection();
499 Paragraph removed = (Paragraph) section.getSectionPart(nextNode.getIdentifier());
502 persistChanges(sectionNode);
504 paragraphMergedWithNext(paragraph, removed);
505 edit(paragraph, txt.length());
506 } catch (RepositoryException e) {
507 throw new JcrException("Cannot stop editing", e);
511 protected synchronized void upload(EditablePart part) {
513 if (part instanceof SectionPart) {
514 SectionPart sectionPart = (SectionPart) part;
515 Node partNode = sectionPart.getNode();
516 int partIndex = partNode.getIndex();
517 Section section = sectionPart.getSection();
518 Node sectionNode = section.getNode();
520 if (part instanceof Paragraph) {
521 // FIXME adapt to DocBook
522 // Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE);
523 // newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
524 // JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]);
525 // if (partIndex < newNode.getIndex() - 1) {
527 // sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1));
529 // // sectionNode.orderBefore(p(partNode.getIndex()),
530 // // p(newNode.getIndex()));
531 // persistChanges(sectionNode);
532 // DbkImg img = newImg((TextSection) section, newNode);
534 // layout(img.getControl());
535 } else if (part instanceof DbkImg) {
536 if (getEdited() == part)
542 } catch (RepositoryException e) {
543 throw new JcrException("Cannot upload", e);
547 protected void deepen() {
552 if (getEdited() instanceof Paragraph) {
553 Paragraph paragraph = (Paragraph) getEdited();
554 Text text = (Text) paragraph.getControl();
555 String txt = text.getText();
556 Node paragraphNode = paragraph.getNode();
557 Section section = paragraph.getSection();
558 Node sectionNode = section.getNode();
560 if (section == mainSection && section instanceof TextSection && paragraphNode.getIndex() == 1
561 && !sectionNode.hasNode(DocBookType.title.get())) {
562 DocBookSectionTitle sectionTitle = prepareSectionTitle(section, txt);
563 edit(sectionTitle, 0);
566 Node newSectionNode = addDbk(sectionNode, DocBookType.section);
567 // newSectionNode.addMixin(NodeType.MIX_TITLE);
568 sectionNode.orderBefore(h(newSectionNode.getIndex()), h(1));
570 int paragraphIndex = paragraphNode.getIndex();
571 String sectionPath = sectionNode.getPath();
572 String newSectionPath = newSectionNode.getPath();
573 while (sectionNode.hasNode(p(paragraphIndex + 1))) {
574 Node parag = sectionNode.getNode(p(paragraphIndex + 1));
575 sectionNode.getSession().move(sectionPath + '/' + p(paragraphIndex + 1),
576 newSectionPath + '/' + DocBookType.para.get());
577 SectionPart sp = section.getSectionPart(parag.getIdentifier());
578 if (sp instanceof Control)
579 ((Control) sp).dispose();
582 Node titleNode = DbkUtils.addDbk(newSectionNode, DocBookType.title);
583 // newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE);
584 getTextInterpreter().write(titleNode, txt);
586 TextSection newSection = new TextSection(section, section.getStyle(), newSectionNode);
587 newSection.setLayoutData(CmsUiUtils.fillWidth());
588 newSection.moveBelow(paragraph);
591 paragraphNode.remove();
595 newSection.getParent().layout();
597 persistChanges(sectionNode);
598 } else if (getEdited() instanceof DocBookSectionTitle) {
599 DocBookSectionTitle sectionTitle = (DocBookSectionTitle) getEdited();
600 Section section = sectionTitle.getSection();
601 Section parentSection = section.getParentSection();
602 if (parentSection == null)
603 return;// cannot deepen main section
604 Node sectionN = section.getNode();
605 Node parentSectionN = parentSection.getNode();
606 if (sectionN.getIndex() == 1)
607 return;// cannot deepen first section
608 Node previousSectionN = parentSectionN.getNode(h(sectionN.getIndex() - 1));
609 NodeIterator subSections = previousSectionN.getNodes(DocBookType.section.get());
610 int subsectionsCount = (int) subSections.getSize();
611 previousSectionN.getSession().move(sectionN.getPath(),
612 previousSectionN.getPath() + "/" + h(subsectionsCount + 1));
614 TextSection newSection = new TextSection(section, section.getStyle(), sectionN);
616 persistChanges(previousSectionN);
618 } catch (RepositoryException e) {
619 throw new JcrException("Cannot deepen " + getEdited(), e);
623 protected void undeepen() {
628 if (getEdited() instanceof Paragraph) {
630 } else if (getEdited() instanceof DocBookSectionTitle) {
631 DocBookSectionTitle sectionTitle = (DocBookSectionTitle) getEdited();
632 Section section = sectionTitle.getSection();
633 Node sectionNode = section.getNode();
634 Section parentSection = section.getParentSection();
635 if (parentSection == null)
636 return;// cannot undeepen main section
638 // choose in which section to merge
639 Section mergedSection;
640 if (sectionNode.getIndex() == 1)
641 mergedSection = section.getParentSection();
643 Map<String, Section> parentSubsections = parentSection.getSubSections();
644 ArrayList<Section> lst = new ArrayList<Section>(parentSubsections.values());
645 mergedSection = lst.get(sectionNode.getIndex() - 1);
647 Node mergedNode = mergedSection.getNode();
648 boolean mergedHasSubSections = mergedNode.hasNode(DocBookType.section.get());
650 // title as paragraph
651 Node newParagrapheNode = addDbk(mergedNode, para);
652 // newParagrapheNode.addMixin(CmsTypes.CMS_STYLED);
653 if (mergedHasSubSections)
654 mergedNode.orderBefore(p(newParagrapheNode.getIndex()), h(1));
655 String txt = getTextInterpreter().read(sectionNode.getNode(DocBookType.title.get()));
656 getTextInterpreter().write(newParagrapheNode, txt);
658 NodeIterator paragraphs = sectionNode.getNodes(para.get());
659 while (paragraphs.hasNext()) {
660 Node p = paragraphs.nextNode();
661 SectionPart sp = section.getSectionPart(p.getIdentifier());
662 if (sp instanceof Control)
663 ((Control) sp).dispose();
664 mergedNode.getSession().move(p.getPath(), mergedNode.getPath() + '/' + para.get());
665 if (mergedHasSubSections)
666 mergedNode.orderBefore(p(p.getIndex()), h(1));
669 Iterator<Section> subsections = section.getSubSections().values().iterator();
670 // NodeIterator sections = sectionNode.getNodes(CMS_H);
671 while (subsections.hasNext()) {
672 Section subsection = subsections.next();
673 Node s = subsection.getNode();
674 mergedNode.getSession().move(s.getPath(), mergedNode.getPath() + '/' + DocBookType.section.get());
675 subsection.dispose();
679 section.getNode().remove();
682 refresh(mergedSection);
683 mergedSection.getParent().layout();
684 layout(mergedSection);
685 persistChanges(mergedNode);
687 } catch (RepositoryException e) {
688 throw new JcrException("Cannot undeepen " + getEdited(), e);
693 protected Paragraph paragraphSplitted(Paragraph paragraph, Node newNode) throws RepositoryException {
694 Section section = paragraph.getSection();
695 updateContent(paragraph);
696 Paragraph newParagraph = newParagraph((TextSection) section, newNode);
697 newParagraph.setLayoutData(CmsUiUtils.fillWidth());
698 newParagraph.moveBelow(paragraph);
699 layout(paragraph.getControl(), newParagraph.getControl());
703 protected Paragraph sectionTitleSplitted(DocBookSectionTitle sectionTitle, Node newNode)
704 throws RepositoryException {
705 updateContent(sectionTitle);
706 Paragraph newParagraph = newParagraph(sectionTitle.getSection(), newNode);
707 // we assume beforeFirst is not null since there was a sectionTitle
708 newParagraph.moveBelow(sectionTitle.getSection().getHeader());
709 layout(sectionTitle.getControl(), newParagraph.getControl());
713 protected Paragraph paragraphMergedWithPrevious(Paragraph removed, Node remaining) throws RepositoryException {
714 Section section = removed.getSection();
717 Paragraph paragraph = (Paragraph) section.getSectionPart(remaining.getIdentifier());
718 updateContent(paragraph);
719 layout(paragraph.getControl());
723 protected void paragraphMergedWithNext(Paragraph remaining, Paragraph removed) throws RepositoryException {
725 updateContent(remaining);
726 layout(remaining.getControl());
730 protected String p(Integer index) {
731 StringBuilder sb = new StringBuilder(6);
732 sb.append(para.get()).append('[').append(index).append(']');
733 return sb.toString();
736 protected String h(Integer index) {
737 StringBuilder sb = new StringBuilder(5);
738 sb.append(DocBookType.section.get()).append('[').append(index).append(']');
739 return sb.toString();
743 public Section getMainSection() {
747 public boolean isFlat() {
751 public TextInterpreter getTextInterpreter() {
752 return textInterpreter;
757 public void keyPressed(KeyEvent ke) {
758 if (log.isTraceEnabled())
761 if (getEdited() == null)
763 boolean altPressed = (ke.stateMask & SWT.ALT) != 0;
764 boolean shiftPressed = (ke.stateMask & SWT.SHIFT) != 0;
765 boolean ctrlPressed = (ke.stateMask & SWT.CTRL) != 0;
769 if (ke.keyCode == SWT.ESC) {
772 } else if (ke.character == '\r') {
775 } else if (ke.character == 'z') {
778 } else if (ke.character == 'S') {
781 } else if (ke.character == '\t') {
784 } else if (shiftPressed) {
788 if (getEdited() instanceof Paragraph) {
789 Paragraph paragraph = (Paragraph) getEdited();
790 Section section = paragraph.getSection();
791 if (altPressed && ke.keyCode == SWT.ARROW_RIGHT) {
792 edit(section.nextSectionPart(paragraph), 0);
793 } else if (altPressed && ke.keyCode == SWT.ARROW_LEFT) {
794 edit(section.previousSectionPart(paragraph), 0);
795 } else if (ke.character == SWT.BS) {
796 Text text = (Text) paragraph.getControl();
797 int caretPosition = text.getCaretPosition();
798 if (caretPosition == 0) {
801 } else if (ke.character == SWT.DEL) {
802 Text text = (Text) paragraph.getControl();
803 int caretPosition = text.getCaretPosition();
804 int charcount = text.getCharCount();
805 if (caretPosition == charcount) {
811 } catch (Exception e) {
813 notifyEditionException(e);
818 public void keyReleased(KeyEvent e) {
823 protected MouseListener createMouseListener() {
827 private class ML extends MouseAdapter {
828 private static final long serialVersionUID = 8526890859876770905L;
831 public void mouseDoubleClick(MouseEvent e) {
833 Control source = (Control) e.getSource();
834 EditablePart composite = findDataParent(source);
835 Point point = new Point(e.x, e.y);
836 if (composite instanceof DbkImg) {
837 if (getCmsEditable().canEdit()) {
838 if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg)) {
839 if (source == mainSection)
841 EditablePart part = findDataParent(source);
844 getCmsEditable().startEditing();
848 edit(composite, source.toDisplay(point));
853 public void mouseDown(MouseEvent e) {
854 if (getCmsEditable().isEditing()) {
856 EditablePart composite = findDataParent((Control) e.getSource());
857 if (styledTools != null) {
858 List<String> styles = getAvailableStyles(composite);
859 styledTools.show(composite, new Point(e.x, e.y), styles);
866 public void mouseUp(MouseEvent e) {
870 protected List<String> getAvailableStyles(EditablePart editablePart) {
871 return new ArrayList<>();
874 public void export(Path directory, String fileName) {
875 Path filePath = directory.resolve(fileName);
877 Files.createDirectories(directory);
878 try (OutputStream out = Files.newOutputStream(filePath)) {
881 if (log.isDebugEnabled())
882 log.debug("DocBook " + getMainSection().getNode() + " exported to " + filePath.toAbsolutePath());
883 } catch (IOException e) {
884 throw new RuntimeException(e);
888 public void exportXml(OutputStream out) throws IOException {
889 Node node = getMainSection().getNode();
891 node.getSession().exportDocumentView(node.getPath(), out, false, false);
892 } catch (RepositoryException e) {
893 throw new JcrException("Cannot export " + node + " to XML", e);
897 // FILE UPLOAD LISTENER
898 private class FUL implements FileUploadListener {
899 public void uploadProgress(FileUploadEvent event) {
900 // TODO Monitor upload progress
903 public void uploadFailed(FileUploadEvent event) {
904 throw new RuntimeException("Upload failed " + event, event.getException());
907 public void uploadFinished(FileUploadEvent event) {
908 for (FileDetails file : event.getFileDetails()) {
909 if (log.isDebugEnabled())
910 log.debug("Received: " + file.getFileName());
912 mainSection.getDisplay().syncExec(new Runnable() {
918 FileUploadHandler uploadHandler = (FileUploadHandler) event.getSource();
919 uploadHandler.dispose();