1 package org.argeo.docbook.ui;
3 import static org.argeo.cms.ui.util.CmsUiUtils.fillWidth;
4 import static org.argeo.docbook.DbkType.para;
5 import static org.argeo.docbook.DbkUtils.addDbk;
6 import static org.argeo.docbook.DbkUtils.isDbk;
8 import java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
12 import java.util.Observer;
14 import javax.jcr.Item;
15 import javax.jcr.Node;
16 import javax.jcr.NodeIterator;
17 import javax.jcr.RepositoryException;
18 import javax.jcr.Session;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.argeo.cms.text.Paragraph;
23 import org.argeo.cms.text.TextInterpreter;
24 import org.argeo.cms.text.TextSection;
25 import org.argeo.cms.ui.CmsEditable;
26 import org.argeo.cms.ui.util.CmsUiUtils;
27 import org.argeo.cms.ui.viewers.AbstractPageViewer;
28 import org.argeo.cms.ui.viewers.EditablePart;
29 import org.argeo.cms.ui.viewers.NodePart;
30 import org.argeo.cms.ui.viewers.PropertyPart;
31 import org.argeo.cms.ui.viewers.Section;
32 import org.argeo.cms.ui.viewers.SectionPart;
33 import org.argeo.cms.ui.widgets.EditableText;
34 import org.argeo.cms.ui.widgets.StyledControl;
35 import org.argeo.docbook.DbkAttr;
36 import org.argeo.docbook.DbkType;
37 import org.argeo.docbook.DbkUtils;
38 import org.argeo.jcr.Jcr;
39 import org.argeo.jcr.JcrException;
40 import org.argeo.jcr.JcrUtils;
41 import org.eclipse.rap.fileupload.FileDetails;
42 import org.eclipse.rap.fileupload.FileUploadEvent;
43 import org.eclipse.rap.fileupload.FileUploadHandler;
44 import org.eclipse.rap.fileupload.FileUploadListener;
45 import org.eclipse.rap.rwt.RWT;
46 import org.eclipse.swt.SWT;
47 import org.eclipse.swt.events.KeyEvent;
48 import org.eclipse.swt.events.KeyListener;
49 import org.eclipse.swt.events.MouseAdapter;
50 import org.eclipse.swt.events.MouseEvent;
51 import org.eclipse.swt.events.MouseListener;
52 import org.eclipse.swt.graphics.Point;
53 import org.eclipse.swt.graphics.Rectangle;
54 import org.eclipse.swt.widgets.Composite;
55 import org.eclipse.swt.widgets.Control;
56 import org.eclipse.swt.widgets.Label;
57 import org.eclipse.swt.widgets.Text;
59 /** Base class for text viewers and editors. */
60 public abstract class AbstractDbkViewer extends AbstractPageViewer implements KeyListener, Observer {
61 private static final long serialVersionUID = -2401274679492339668L;
62 private final static Log log = LogFactory.getLog(AbstractDbkViewer.class);
64 private final Section mainSection;
66 private TextInterpreter textInterpreter = new DbkTextInterpreter();
67 private DbkImageManager imageManager;
69 private FileUploadListener fileUploadListener;
70 private DbkContextMenu styledTools;
72 private final boolean flat;
74 protected AbstractDbkViewer(Section parent, int style, CmsEditable cmsEditable) {
75 super(parent, style, cmsEditable);
76 // CmsView cmsView = CmsView.getCmsView(parent);
77 // imageManager = cmsView.getImageManager();
78 flat = SWT.FLAT == (style & SWT.FLAT);
80 if (getCmsEditable().canEdit()) {
81 fileUploadListener = new FUL();
82 styledTools = new DbkContextMenu(this, parent.getShell());
84 this.mainSection = parent;
85 Node baseFolder = Jcr.getParent(mainSection.getNode());
86 imageManager = new DbkImageManager(baseFolder);
87 initModelIfNeeded(mainSection.getNode());
88 // layout(this.mainSection);
92 public Control getControl() {
96 protected void refresh(Control control) throws RepositoryException {
97 if (!(control instanceof Section))
99 Section section = (Section) control;
100 if (section instanceof TextSection) {
101 CmsUiUtils.clear(section);
102 Node node = section.getNode();
103 TextSection textSection = (TextSection) section;
104 if (node.hasNode(DbkType.title.get())) {
105 if (section.getHeader() == null)
106 section.createHeader();
107 Node titleNode = node.getNode(DbkType.title.get());
108 DocBookSectionTitle title = newSectionTitle(textSection, titleNode);
109 title.setLayoutData(CmsUiUtils.fillWidth());
110 updateContent(title);
113 for (NodeIterator ni = node.getNodes(); ni.hasNext();) {
114 Node child = ni.nextNode();
115 SectionPart sectionPart = null;
116 if (isDbk(child, DbkType.mediaobject)) {
117 sectionPart = newImg(textSection, child);
118 // if (child.hasNode(DbkType.imageobject.get())) {
119 // Node imageDataNode = child.getNode(DbkType.imageobject.get()).getNode(DbkType.imagedata.get());
120 // sectionPart = newImg(textSection, imageDataNode);
122 } else if (isDbk(child, para)) {
123 sectionPart = newParagraph(textSection, child);
125 sectionPart = newSectionPart(textSection, child);
126 // if (sectionPart == null)
127 // throw new IllegalArgumentException("Unsupported node " + child);
128 // TODO list node types in exception
130 if (sectionPart != null && sectionPart instanceof Control)
131 ((Control) sectionPart).setLayoutData(CmsUiUtils.fillWidth());
135 for (NodeIterator ni = section.getNode().getNodes(DbkType.section.get()); ni.hasNext();) {
136 Node child = ni.nextNode();
137 if (isDbk(child, DbkType.section)) {
138 TextSection newSection = new TextSection(section, SWT.NONE, child);
139 newSection.setLayoutData(CmsUiUtils.fillWidth());
144 for (Section s : section.getSubSections().values())
147 // section.layout(true, true);
150 /** To be overridden in order to provide additional SectionPart types */
151 protected SectionPart newSectionPart(TextSection textSection, Node node) {
156 protected Paragraph newParagraph(TextSection parent, Node node) throws RepositoryException {
157 Paragraph paragraph = new Paragraph(parent, parent.getStyle(), node);
158 updateContent(paragraph);
159 paragraph.setLayoutData(fillWidth());
160 paragraph.setMouseListener(getMouseListener());
161 paragraph.setFocusListener(getFocusListener());
165 protected DbkImg newImg(TextSection parent, Node node) {
167 DbkImg img = new DbkImg(parent, parent.getStyle(), node, imageManager);
168 img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
170 img.setMouseListener(getMouseListener());
171 img.setFocusListener(getFocusListener());
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());
186 title.setFocusListener(getFocusListener());
191 * To be overridden in order to provide additional processing at the section
194 * @return the parent to use for the {@link DocBookSectionTitle}, by default
195 * {@link Section#getHeader()}
197 protected Composite newSectionHeader(TextSection section) {
198 return section.getHeader();
201 protected DocBookSectionTitle prepareSectionTitle(Section newSection, String titleText) throws RepositoryException {
202 Node sectionNode = newSection.getNode();
203 Node titleNode = DbkUtils.getOrAddDbk(sectionNode, DbkType.title);
204 getTextInterpreter().write(titleNode, titleText);
205 if (newSection.getHeader() == null)
206 newSection.createHeader();
207 DocBookSectionTitle sectionTitle = newSectionTitle((TextSection) newSection, sectionNode);
211 protected void updateContent(EditablePart part) throws RepositoryException {
212 if (part instanceof SectionPart) {
213 SectionPart sectionPart = (SectionPart) part;
214 Node partNode = sectionPart.getNode();
216 if (part instanceof StyledControl && (sectionPart.getSection() instanceof TextSection)) {
217 TextSection section = (TextSection) sectionPart.getSection();
218 StyledControl styledControl = (StyledControl) part;
219 if (isDbk(partNode, para)) {
220 String style = partNode.hasProperty(DbkAttr.role.name())
221 ? partNode.getProperty(DbkAttr.role.name()).getString()
222 : section.getDefaultTextStyle();
223 styledControl.setStyle(style);
226 // use control AFTER setting style, since it may have been reset
228 if (part instanceof EditableText) {
229 EditableText paragraph = (EditableText) part;
230 if (paragraph == getEdited())
231 paragraph.setText(textInterpreter.raw(partNode));
233 paragraph.setText(textInterpreter.readSimpleHtml(partNode));
234 } else if (part instanceof DbkImg) {
235 DbkImg editableImage = (DbkImg) part;
236 imageManager.load(partNode, part.getControl(), editableImage.getPreferredImageSize());
238 } else if (part instanceof DocBookSectionTitle) {
239 DocBookSectionTitle title = (DocBookSectionTitle) part;
240 title.setStyle(title.getSection().getTitleStyle());
241 // use control AFTER setting style
242 if (title == getEdited())
243 title.setText(textInterpreter.read(title.getNode()));
245 title.setText(textInterpreter.raw(title.getNode()));
249 // OVERRIDDEN FROM PARENT VIEWER
251 protected void save(EditablePart part) throws RepositoryException {
252 if (part instanceof EditableText) {
253 EditableText et = (EditableText) part;
254 if (!et.getEditable())
256 String text = ((Text) et.getControl()).getText();
258 // String[] lines = text.split("[\r\n]+");
259 String[] lines = { text };
260 assert lines.length != 0;
261 saveLine(part, lines[0]);
262 if (lines.length > 1) {
263 ArrayList<Control> toLayout = new ArrayList<Control>();
264 if (part instanceof Paragraph) {
265 Paragraph currentParagraph = (Paragraph) et;
266 Section section = currentParagraph.getSection();
267 Node sectionNode = section.getNode();
268 Node currentParagraphN = currentParagraph.getNode();
269 for (int i = 1; i < lines.length; i++) {
270 Node newNode = addDbk(sectionNode, para);
271 // newNode.addMixin(CmsTypes.CMS_STYLED);
272 saveLine(newNode, lines[i]);
273 // second node was create as last, if it is not the next
275 // means there are some in between and we can take the
277 // index+1 for the re-order
278 if (newNode.getIndex() > currentParagraphN.getIndex() + 1) {
279 sectionNode.orderBefore(p(newNode.getIndex()), p(currentParagraphN.getIndex() + 1));
281 Paragraph newParagraph = newParagraph((TextSection) section, newNode);
282 newParagraph.moveBelow(currentParagraph);
283 toLayout.add(newParagraph);
285 currentParagraph = newParagraph;
286 currentParagraphN = newNode;
289 // TODO or rather return the created paragraphs?
290 layout(toLayout.toArray(new Control[toLayout.size()]));
292 persistChanges(et.getNode());
296 protected void saveLine(EditablePart part, String line) {
297 if (part instanceof NodePart) {
298 saveLine(((NodePart) part).getNode(), line);
299 } else if (part instanceof PropertyPart) {
300 saveLine(((PropertyPart) part).getProperty(), line);
302 throw new IllegalArgumentException("Unsupported part " + part);
306 protected void saveLine(Item item, String line) {
308 textInterpreter.write(item, line);
312 protected void prepare(EditablePart part, Object caretPosition) {
313 Control control = part.getControl();
314 if (control instanceof Text) {
315 Text text = (Text) control;
316 if (caretPosition != null)
317 if (caretPosition instanceof Integer)
318 text.setSelection((Integer) caretPosition);
319 else if (caretPosition instanceof Point) {
321 // // TODO find a way to position the caret at the right place
322 // Point clickLocation = (Point) caretPosition;
323 // Point withinText = text.toControl(clickLocation);
324 // Rectangle bounds = text.getBounds();
325 // int width = bounds.width;
326 // int height = bounds.height;
327 // int textLength = text.getText().length();
328 // float area = width * height;
329 // float proportion = withinText.y * width + withinText.x;
330 // int pos = (int) (textLength * (proportion / area));
331 // text.setSelection(pos);
333 text.setData(RWT.ACTIVE_KEYS, new String[] { "BACKSPACE", "ESC", "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT",
334 "ALT+ARROW_RIGHT", "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", "ENTER", "DELETE" });
335 text.setData(RWT.CANCEL_KEYS, new String[] { "RETURN", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
336 text.addKeyListener(this);
337 } else if (part instanceof DbkImg) {
338 ((DbkImg) part).setFileUploadListener(fileUploadListener);
342 // REQUIRED BY CONTEXT MENU
343 void setParagraphStyle(Paragraph paragraph, String style) {
345 Node paragraphNode = paragraph.getNode();
346 if (style == null) {// default
347 if (paragraphNode.hasProperty(DbkAttr.role.name()))
348 paragraphNode.getProperty(DbkAttr.role.name()).remove();
350 paragraphNode.setProperty(DbkAttr.role.name(), style);
352 persistChanges(paragraphNode);
353 updateContent(paragraph);
355 } catch (RepositoryException e1) {
356 throw new JcrException("Cannot set style " + style + " on " + paragraph, e1);
360 SectionPart insertPart(Section section, Node node) {
364 for (Control control : section.getChildren()) {
365 if (control instanceof SectionPart) {
366 SectionPart sectionPart = (SectionPart) control;
367 Node partNode = sectionPart.getNode();
368 if (partNode.getPath().equals(node.getPath()))
372 throw new IllegalStateException("New section part " + node + "not found");
373 } catch (RepositoryException e) {
374 throw new JcrException("Cannot insert part " + node + " in section " + section.getNode(), e);
378 void addParagraph(SectionPart partBefore, String txt) {
379 Section section = partBefore.getSection();
380 SectionPart nextSectionPart = section.nextSectionPart(partBefore);
381 Node newNode = addDbk(section.getNode(), para);
382 textInterpreter.write(newNode, txt != null ? txt : "");
383 if (nextSectionPart != null) {
385 Node nextNode = nextSectionPart.getNode();
386 section.getNode().orderBefore(Jcr.getIndexedName(newNode), Jcr.getIndexedName(nextNode));
387 } catch (RepositoryException e) {
388 throw new JcrException("Cannot order " + newNode + " before " + nextSectionPart.getNode(), e);
392 Paragraph paragraph = (Paragraph) insertPart(partBefore.getSection(), newNode);
396 void deletePart(SectionPart sectionPart) {
398 Node node = sectionPart.getNode();
399 Session session = node.getSession();
400 if (sectionPart instanceof DbkImg) {
401 if (!isDbk(node, DbkType.mediaobject))
402 throw new IllegalArgumentException("Node " + node + " is not a media object.");
406 if (sectionPart instanceof Control)
407 ((Control) sectionPart).dispose();
409 } catch (RepositoryException e1) {
410 throw new JcrException("Cannot delete " + sectionPart, e1);
414 void deleteSection(Section section) {
416 Node node = section.getNode();
417 Session session = node.getSession();
422 } catch (RepositoryException e1) {
423 throw new JcrException("Cannot delete " + section, e1);
427 String getRawParagraphText(Paragraph paragraph) {
428 return textInterpreter.raw(paragraph.getNode());
432 protected void splitEdit() {
435 if (getEdited() instanceof Paragraph) {
436 Paragraph paragraph = (Paragraph) getEdited();
437 Text text = (Text) paragraph.getControl();
438 int caretPosition = text.getCaretPosition();
439 String txt = text.getText();
440 String first = txt.substring(0, caretPosition);
441 String second = txt.substring(caretPosition);
442 Node firstNode = paragraph.getNode();
443 Node sectionNode = firstNode.getParent();
445 // FIXME set content the DocBook way
446 // firstNode.setProperty(CMS_CONTENT, first);
447 Node secondNode = addDbk(sectionNode, para);
448 // secondNode.addMixin(CmsTypes.CMS_STYLED);
450 // second node was create as last, if it is not the next one, it
451 // means there are some in between and we can take the one at
452 // index+1 for the re-order
453 if (secondNode.getIndex() > firstNode.getIndex() + 1) {
454 sectionNode.orderBefore(p(secondNode.getIndex()), p(firstNode.getIndex() + 1));
457 // if we die in between, at least we still have the whole text
460 textInterpreter.write(secondNode, second);
461 textInterpreter.write(firstNode, first);
462 } catch (Exception e) {
463 // so that no additional nodes are created:
464 JcrUtils.discardUnderlyingSessionQuietly(firstNode);
468 persistChanges(firstNode);
470 Paragraph secondParagraph = paragraphSplitted(paragraph, secondNode);
471 edit(secondParagraph, 0);
472 } else if (getEdited() instanceof DocBookSectionTitle) {
473 DocBookSectionTitle sectionTitle = (DocBookSectionTitle) getEdited();
474 Text text = (Text) sectionTitle.getControl();
475 String txt = text.getText();
476 int caretPosition = text.getCaretPosition();
477 Section section = sectionTitle.getSection();
478 Node sectionNode = section.getNode();
479 Node paragraphNode = addDbk(sectionNode, para);
480 // paragraphNode.addMixin(CmsTypes.CMS_STYLED);
482 textInterpreter.write(paragraphNode, txt.substring(caretPosition));
483 textInterpreter.write(sectionNode.getNode(DbkType.title.get()), txt.substring(0, caretPosition));
484 sectionNode.orderBefore(p(paragraphNode.getIndex()), p(1));
485 persistChanges(sectionNode);
487 Paragraph paragraph = sectionTitleSplitted(sectionTitle, paragraphNode);
491 } catch (RepositoryException e) {
492 throw new JcrException("Cannot split " + getEdited(), e);
496 protected void mergeWithPrevious() {
499 Paragraph paragraph = (Paragraph) getEdited();
500 Text text = (Text) paragraph.getControl();
501 String txt = text.getText();
502 Node paragraphNode = paragraph.getNode();
503 if (paragraphNode.getIndex() == 1)
505 Node sectionNode = paragraphNode.getParent();
506 Node previousNode = sectionNode.getNode(p(paragraphNode.getIndex() - 1));
507 String previousTxt = textInterpreter.read(previousNode);
508 textInterpreter.write(previousNode, previousTxt + txt);
509 paragraphNode.remove();
510 persistChanges(sectionNode);
512 Paragraph previousParagraph = paragraphMergedWithPrevious(paragraph, previousNode);
513 edit(previousParagraph, previousTxt.length());
514 } catch (RepositoryException e) {
515 throw new JcrException("Cannot stop editing", e);
519 protected void mergeWithNext() {
522 Paragraph paragraph = (Paragraph) getEdited();
523 Text text = (Text) paragraph.getControl();
524 String txt = text.getText();
525 Node paragraphNode = paragraph.getNode();
526 Node sectionNode = paragraphNode.getParent();
527 NodeIterator paragraphNodes = sectionNode.getNodes(DbkType.para.get());
528 long size = paragraphNodes.getSize();
529 if (paragraphNode.getIndex() == size)
531 Node nextNode = sectionNode.getNode(p(paragraphNode.getIndex() + 1));
532 String nextTxt = textInterpreter.read(nextNode);
533 textInterpreter.write(paragraphNode, txt + nextTxt);
535 Section section = paragraph.getSection();
536 Paragraph removed = (Paragraph) section.getSectionPart(nextNode.getIdentifier());
539 persistChanges(sectionNode);
541 paragraphMergedWithNext(paragraph, removed);
542 edit(paragraph, txt.length());
543 } catch (RepositoryException e) {
544 throw new JcrException("Cannot stop editing", e);
548 protected synchronized void upload(EditablePart part) {
550 if (part instanceof SectionPart) {
551 SectionPart sectionPart = (SectionPart) part;
552 Node partNode = sectionPart.getNode();
553 int partIndex = partNode.getIndex();
554 Section section = sectionPart.getSection();
555 Node sectionNode = section.getNode();
557 if (part instanceof Paragraph) {
558 // FIXME adapt to DocBook
559 // Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE);
560 // newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
561 // JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]);
562 // if (partIndex < newNode.getIndex() - 1) {
564 // sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1));
566 // // sectionNode.orderBefore(p(partNode.getIndex()),
567 // // p(newNode.getIndex()));
568 // persistChanges(sectionNode);
569 // DbkImg img = newImg((TextSection) section, newNode);
571 // layout(img.getControl());
572 } else if (part instanceof DbkImg) {
573 if (getEdited() == part)
579 } catch (RepositoryException e) {
580 throw new JcrException("Cannot upload", e);
584 protected void deepen() {
589 if (getEdited() instanceof Paragraph) {
590 Paragraph paragraph = (Paragraph) getEdited();
591 Text text = (Text) paragraph.getControl();
592 String txt = text.getText();
593 Node paragraphNode = paragraph.getNode();
594 Section section = paragraph.getSection();
595 Node sectionNode = section.getNode();
597 if (section == mainSection && section instanceof TextSection && paragraphNode.getIndex() == 1
598 && !sectionNode.hasNode(DbkType.title.get())) {
599 DocBookSectionTitle sectionTitle = prepareSectionTitle(section, txt);
600 edit(sectionTitle, 0);
603 Node newSectionNode = addDbk(sectionNode, DbkType.section);
604 // newSectionNode.addMixin(NodeType.MIX_TITLE);
605 sectionNode.orderBefore(h(newSectionNode.getIndex()), h(1));
607 int paragraphIndex = paragraphNode.getIndex();
608 String sectionPath = sectionNode.getPath();
609 String newSectionPath = newSectionNode.getPath();
610 while (sectionNode.hasNode(p(paragraphIndex + 1))) {
611 Node parag = sectionNode.getNode(p(paragraphIndex + 1));
612 sectionNode.getSession().move(sectionPath + '/' + p(paragraphIndex + 1),
613 newSectionPath + '/' + DbkType.para.get());
614 SectionPart sp = section.getSectionPart(parag.getIdentifier());
615 if (sp instanceof Control)
616 ((Control) sp).dispose();
619 Node titleNode = DbkUtils.addDbk(newSectionNode, DbkType.title);
620 // newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE);
621 getTextInterpreter().write(titleNode, txt);
623 TextSection newSection = new TextSection(section, section.getStyle(), newSectionNode);
624 newSection.setLayoutData(CmsUiUtils.fillWidth());
625 newSection.moveBelow(paragraph);
628 paragraphNode.remove();
632 newSection.getParent().layout();
634 persistChanges(sectionNode);
635 } else if (getEdited() instanceof DocBookSectionTitle) {
636 DocBookSectionTitle sectionTitle = (DocBookSectionTitle) getEdited();
637 Section section = sectionTitle.getSection();
638 Section parentSection = section.getParentSection();
639 if (parentSection == null)
640 return;// cannot deepen main section
641 Node sectionN = section.getNode();
642 Node parentSectionN = parentSection.getNode();
643 if (sectionN.getIndex() == 1)
644 return;// cannot deepen first section
645 Node previousSectionN = parentSectionN.getNode(h(sectionN.getIndex() - 1));
646 NodeIterator subSections = previousSectionN.getNodes(DbkType.section.get());
647 int subsectionsCount = (int) subSections.getSize();
648 previousSectionN.getSession().move(sectionN.getPath(),
649 previousSectionN.getPath() + "/" + h(subsectionsCount + 1));
651 TextSection newSection = new TextSection(section, section.getStyle(), sectionN);
653 persistChanges(previousSectionN);
655 } catch (RepositoryException e) {
656 throw new JcrException("Cannot deepen " + getEdited(), e);
660 protected void undeepen() {
665 if (getEdited() instanceof Paragraph) {
667 } else if (getEdited() instanceof DocBookSectionTitle) {
668 DocBookSectionTitle sectionTitle = (DocBookSectionTitle) getEdited();
669 Section section = sectionTitle.getSection();
670 Node sectionNode = section.getNode();
671 Section parentSection = section.getParentSection();
672 if (parentSection == null)
673 return;// cannot undeepen main section
675 // choose in which section to merge
676 Section mergedSection;
677 if (sectionNode.getIndex() == 1)
678 mergedSection = section.getParentSection();
680 Map<String, Section> parentSubsections = parentSection.getSubSections();
681 ArrayList<Section> lst = new ArrayList<Section>(parentSubsections.values());
682 mergedSection = lst.get(sectionNode.getIndex() - 1);
684 Node mergedNode = mergedSection.getNode();
685 boolean mergedHasSubSections = mergedNode.hasNode(DbkType.section.get());
687 // title as paragraph
688 Node newParagrapheNode = addDbk(mergedNode, para);
689 // newParagrapheNode.addMixin(CmsTypes.CMS_STYLED);
690 if (mergedHasSubSections)
691 mergedNode.orderBefore(p(newParagrapheNode.getIndex()), h(1));
692 String txt = getTextInterpreter().read(sectionNode.getNode(DbkType.title.get()));
693 getTextInterpreter().write(newParagrapheNode, txt);
695 NodeIterator paragraphs = sectionNode.getNodes(para.get());
696 while (paragraphs.hasNext()) {
697 Node p = paragraphs.nextNode();
698 SectionPart sp = section.getSectionPart(p.getIdentifier());
699 if (sp instanceof Control)
700 ((Control) sp).dispose();
701 mergedNode.getSession().move(p.getPath(), mergedNode.getPath() + '/' + para.get());
702 if (mergedHasSubSections)
703 mergedNode.orderBefore(p(p.getIndex()), h(1));
706 Iterator<Section> subsections = section.getSubSections().values().iterator();
707 // NodeIterator sections = sectionNode.getNodes(CMS_H);
708 while (subsections.hasNext()) {
709 Section subsection = subsections.next();
710 Node s = subsection.getNode();
711 mergedNode.getSession().move(s.getPath(), mergedNode.getPath() + '/' + DbkType.section.get());
712 subsection.dispose();
716 section.getNode().remove();
719 refresh(mergedSection);
720 mergedSection.getParent().layout();
721 layout(mergedSection);
722 persistChanges(mergedNode);
724 } catch (RepositoryException e) {
725 throw new JcrException("Cannot undeepen " + getEdited(), e);
730 protected Paragraph paragraphSplitted(Paragraph paragraph, Node newNode) throws RepositoryException {
731 Section section = paragraph.getSection();
732 updateContent(paragraph);
733 Paragraph newParagraph = newParagraph((TextSection) section, newNode);
734 newParagraph.setLayoutData(CmsUiUtils.fillWidth());
735 newParagraph.moveBelow(paragraph);
736 layout(paragraph.getControl(), newParagraph.getControl());
740 protected Paragraph sectionTitleSplitted(DocBookSectionTitle sectionTitle, Node newNode)
741 throws RepositoryException {
742 updateContent(sectionTitle);
743 Paragraph newParagraph = newParagraph(sectionTitle.getSection(), newNode);
744 // we assume beforeFirst is not null since there was a sectionTitle
745 newParagraph.moveBelow(sectionTitle.getSection().getHeader());
746 layout(sectionTitle.getControl(), newParagraph.getControl());
750 protected Paragraph paragraphMergedWithPrevious(Paragraph removed, Node remaining) throws RepositoryException {
751 Section section = removed.getSection();
754 Paragraph paragraph = (Paragraph) section.getSectionPart(remaining.getIdentifier());
755 updateContent(paragraph);
756 layout(paragraph.getControl());
760 protected void paragraphMergedWithNext(Paragraph remaining, Paragraph removed) throws RepositoryException {
762 updateContent(remaining);
763 layout(remaining.getControl());
767 protected String p(Integer index) {
768 StringBuilder sb = new StringBuilder(6);
769 sb.append(para.get()).append('[').append(index).append(']');
770 return sb.toString();
773 protected String h(Integer index) {
774 StringBuilder sb = new StringBuilder(5);
775 sb.append(DbkType.section.get()).append('[').append(index).append(']');
776 return sb.toString();
780 public Section getMainSection() {
784 public boolean isFlat() {
788 public TextInterpreter getTextInterpreter() {
789 return textInterpreter;
794 public void keyPressed(KeyEvent ke) {
795 if (log.isTraceEnabled())
798 if (getEdited() == null)
800 boolean altPressed = (ke.stateMask & SWT.ALT) != 0;
801 boolean shiftPressed = (ke.stateMask & SWT.SHIFT) != 0;
802 boolean ctrlPressed = (ke.stateMask & SWT.CTRL) != 0;
806 if (ke.keyCode == SWT.ESC) {
809 } else if (ke.character == '\r') {
812 } else if (ke.character == 'z') {
815 } else if (ke.character == 'S') {
818 } else if (ke.character == '\t') {
821 } else if (shiftPressed) {
825 if (getEdited() instanceof Paragraph) {
826 Paragraph paragraph = (Paragraph) getEdited();
827 Section section = paragraph.getSection();
828 if (altPressed && ke.keyCode == SWT.ARROW_RIGHT) {
829 edit(section.nextSectionPart(paragraph), 0);
830 } else if (altPressed && ke.keyCode == SWT.ARROW_LEFT) {
831 edit(section.previousSectionPart(paragraph), 0);
832 } else if (ke.character == SWT.BS) {
833 Text text = (Text) paragraph.getControl();
834 int caretPosition = text.getCaretPosition();
835 if (caretPosition == 0) {
838 } else if (ke.character == SWT.DEL) {
839 Text text = (Text) paragraph.getControl();
840 int caretPosition = text.getCaretPosition();
841 int charcount = text.getCharCount();
842 if (caretPosition == charcount) {
848 } catch (Exception e) {
850 notifyEditionException(e);
855 public void keyReleased(KeyEvent e) {
860 protected MouseListener createMouseListener() {
864 private class ML extends MouseAdapter {
865 private static final long serialVersionUID = 8526890859876770905L;
868 public void mouseDoubleClick(MouseEvent e) {
870 Control source = (Control) e.getSource();
871 EditablePart composite = findDataParent(source);
872 Point point = new Point(e.x, e.y);
873 if (composite instanceof DbkImg) {
874 if (getCmsEditable().canEdit()) {
875 if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg)) {
876 if (source == mainSection)
878 EditablePart part = findDataParent(source);
881 getCmsEditable().startEditing();
884 } else if (source instanceof Label) {
885 Label lbl = (Label) source;
886 Rectangle bounds = lbl.getBounds();
887 float width = bounds.width;
888 float height = bounds.height;
889 float textLength = lbl.getText().length();
890 float area = width * height;
891 float charArea = area / textLength;
892 float lines = textLength / width;
893 float proportion = point.y * width + point.x;
894 int pos = (int) (textLength * (proportion / area));
896 edit(composite, (Integer) pos);
898 edit(composite, source.toDisplay(point));
904 public void mouseDown(MouseEvent e) {
905 if (getCmsEditable().isEditing()) {
907 EditablePart composite = findDataParent((Control) e.getSource());
908 if (styledTools != null) {
909 List<String> styles = getAvailableStyles(composite);
910 styledTools.show(composite, new Point(e.x, e.y), styles);
917 public void mouseUp(MouseEvent e) {
921 protected List<String> getAvailableStyles(EditablePart editablePart) {
922 return new ArrayList<>();
925 // FILE UPLOAD LISTENER
926 private class FUL implements FileUploadListener {
927 public void uploadProgress(FileUploadEvent event) {
928 // TODO Monitor upload progress
931 public void uploadFailed(FileUploadEvent event) {
932 throw new RuntimeException("Upload failed " + event, event.getException());
935 public void uploadFinished(FileUploadEvent event) {
936 for (FileDetails file : event.getFileDetails()) {
937 if (log.isDebugEnabled())
938 log.debug("Received: " + file.getFileName());
940 mainSection.getDisplay().syncExec(new Runnable() {
946 FileUploadHandler uploadHandler = (FileUploadHandler) event.getSource();
947 uploadHandler.dispose();