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 if (child
.hasNode(DbkType
.imageobject
.get())) {
118 Node imageDataNode
= child
.getNode(DbkType
.imageobject
.get()).getNode(DbkType
.imagedata
.get());
119 sectionPart
= newImg(textSection
, imageDataNode
);
121 } else if (isDbk(child
, para
)) {
122 sectionPart
= newParagraph(textSection
, child
);
124 sectionPart
= newSectionPart(textSection
, child
);
125 // if (sectionPart == null)
126 // throw new IllegalArgumentException("Unsupported node " + child);
127 // TODO list node types in exception
129 if (sectionPart
!= null && sectionPart
instanceof Control
)
130 ((Control
) sectionPart
).setLayoutData(CmsUiUtils
.fillWidth());
134 for (NodeIterator ni
= section
.getNode().getNodes(DbkType
.section
.get()); ni
.hasNext();) {
135 Node child
= ni
.nextNode();
136 if (isDbk(child
, DbkType
.section
)) {
137 TextSection newSection
= new TextSection(section
, SWT
.NONE
, child
);
138 newSection
.setLayoutData(CmsUiUtils
.fillWidth());
143 for (Section s
: section
.getSubSections().values())
146 // section.layout(true, true);
149 /** To be overridden in order to provide additional SectionPart types */
150 protected SectionPart
newSectionPart(TextSection textSection
, Node node
) {
155 protected Paragraph
newParagraph(TextSection parent
, Node node
) throws RepositoryException
{
156 Paragraph paragraph
= new Paragraph(parent
, parent
.getStyle(), node
);
157 updateContent(paragraph
);
158 paragraph
.setLayoutData(fillWidth());
159 paragraph
.setMouseListener(getMouseListener());
160 paragraph
.setFocusListener(getFocusListener());
164 protected DbkImg
newImg(TextSection parent
, Node node
) {
166 DbkImg img
= new DbkImg(parent
, parent
.getStyle(), node
, imageManager
);
167 img
.setLayoutData(CmsUiUtils
.grabWidth(SWT
.CENTER
, SWT
.DEFAULT
));
169 img
.setMouseListener(getMouseListener());
170 img
.setFocusListener(getFocusListener());
172 } catch (RepositoryException e
) {
173 throw new JcrException("Cannot add new image " + node
, e
);
177 protected DocBookSectionTitle
newSectionTitle(TextSection parent
, Node titleNode
) throws RepositoryException
{
178 int style
= parent
.getStyle();
179 Composite titleParent
= newSectionHeader(parent
);
180 if (parent
.isTitleReadOnly())
181 style
= style
| SWT
.READ_ONLY
;
182 DocBookSectionTitle title
= new DocBookSectionTitle(titleParent
, style
, titleNode
);
183 updateContent(title
);
184 title
.setMouseListener(getMouseListener());
185 title
.setFocusListener(getFocusListener());
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
, DbkType
.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(DbkAttr
.role
.name())
220 ? partNode
.getProperty(DbkAttr
.role
.name()).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
) {
320 // // TODO find a way to position the caret at the right place
321 // Point clickLocation = (Point) caretPosition;
322 // Point withinText = text.toControl(clickLocation);
323 // Rectangle bounds = text.getBounds();
324 // int width = bounds.width;
325 // int height = bounds.height;
326 // int textLength = text.getText().length();
327 // float area = width * height;
328 // float proportion = withinText.y * width + withinText.x;
329 // int pos = (int) (textLength * (proportion / area));
330 // text.setSelection(pos);
332 text
.setData(RWT
.ACTIVE_KEYS
, new String
[] { "BACKSPACE", "ESC", "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT",
333 "ALT+ARROW_RIGHT", "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", "ENTER", "DELETE" });
334 text
.setData(RWT
.CANCEL_KEYS
, new String
[] { "RETURN", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
335 text
.addKeyListener(this);
336 } else if (part
instanceof DbkImg
) {
337 ((DbkImg
) part
).setFileUploadListener(fileUploadListener
);
341 // REQUIRED BY CONTEXT MENU
342 void setParagraphStyle(Paragraph paragraph
, String style
) {
344 Node paragraphNode
= paragraph
.getNode();
345 if (style
== null) {// default
346 if (paragraphNode
.hasProperty(DbkAttr
.role
.name()))
347 paragraphNode
.getProperty(DbkAttr
.role
.name()).remove();
349 paragraphNode
.setProperty(DbkAttr
.role
.name(), style
);
351 persistChanges(paragraphNode
);
352 updateContent(paragraph
);
354 } catch (RepositoryException e1
) {
355 throw new JcrException("Cannot set style " + style
+ " on " + paragraph
, e1
);
359 void insertPart(Section section
, Node node
) {
363 } catch (RepositoryException e
) {
364 throw new JcrException("Cannot insert part " + node
+ " in section " + section
.getNode(), e
);
368 void deletePart(SectionPart sectionPart
) {
370 Node node
= sectionPart
.getNode();
371 Session session
= node
.getSession();
372 if (sectionPart
instanceof DbkImg
) {
373 // FIXME make it more robust
374 node
= node
.getParent().getParent();
375 if (!isDbk(node
, DbkType
.mediaobject
))
376 throw new IllegalArgumentException("Node " + node
+ " is not a media object.");
380 if (sectionPart
instanceof Control
)
381 ((Control
) sectionPart
).dispose();
383 } catch (RepositoryException e1
) {
384 throw new JcrException("Cannot delete " + sectionPart
, e1
);
388 void deleteSection(Section section
) {
390 Node node
= section
.getNode();
391 Session session
= node
.getSession();
396 } catch (RepositoryException e1
) {
397 throw new JcrException("Cannot delete " + section
, e1
);
401 String
getRawParagraphText(Paragraph paragraph
) {
402 return textInterpreter
.raw(paragraph
.getNode());
406 protected void splitEdit() {
409 if (getEdited() instanceof Paragraph
) {
410 Paragraph paragraph
= (Paragraph
) getEdited();
411 Text text
= (Text
) paragraph
.getControl();
412 int caretPosition
= text
.getCaretPosition();
413 String txt
= text
.getText();
414 String first
= txt
.substring(0, caretPosition
);
415 String second
= txt
.substring(caretPosition
);
416 Node firstNode
= paragraph
.getNode();
417 Node sectionNode
= firstNode
.getParent();
419 // FIXME set content the DocBook way
420 // firstNode.setProperty(CMS_CONTENT, first);
421 Node secondNode
= addDbk(sectionNode
, para
);
422 // secondNode.addMixin(CmsTypes.CMS_STYLED);
424 // second node was create as last, if it is not the next one, it
425 // means there are some in between and we can take the one at
426 // index+1 for the re-order
427 if (secondNode
.getIndex() > firstNode
.getIndex() + 1) {
428 sectionNode
.orderBefore(p(secondNode
.getIndex()), p(firstNode
.getIndex() + 1));
431 // if we die in between, at least we still have the whole text
434 textInterpreter
.write(secondNode
, second
);
435 textInterpreter
.write(firstNode
, first
);
436 } catch (Exception e
) {
437 // so that no additional nodes are created:
438 JcrUtils
.discardUnderlyingSessionQuietly(firstNode
);
442 persistChanges(firstNode
);
444 Paragraph secondParagraph
= paragraphSplitted(paragraph
, secondNode
);
445 edit(secondParagraph
, 0);
446 } else if (getEdited() instanceof DocBookSectionTitle
) {
447 DocBookSectionTitle sectionTitle
= (DocBookSectionTitle
) getEdited();
448 Text text
= (Text
) sectionTitle
.getControl();
449 String txt
= text
.getText();
450 int caretPosition
= text
.getCaretPosition();
451 Section section
= sectionTitle
.getSection();
452 Node sectionNode
= section
.getNode();
453 Node paragraphNode
= addDbk(sectionNode
, para
);
454 // paragraphNode.addMixin(CmsTypes.CMS_STYLED);
456 textInterpreter
.write(paragraphNode
, txt
.substring(caretPosition
));
457 textInterpreter
.write(sectionNode
.getNode(DbkType
.title
.get()), txt
.substring(0, caretPosition
));
458 sectionNode
.orderBefore(p(paragraphNode
.getIndex()), p(1));
459 persistChanges(sectionNode
);
461 Paragraph paragraph
= sectionTitleSplitted(sectionTitle
, paragraphNode
);
465 } catch (RepositoryException e
) {
466 throw new JcrException("Cannot split " + getEdited(), e
);
470 protected void mergeWithPrevious() {
473 Paragraph paragraph
= (Paragraph
) getEdited();
474 Text text
= (Text
) paragraph
.getControl();
475 String txt
= text
.getText();
476 Node paragraphNode
= paragraph
.getNode();
477 if (paragraphNode
.getIndex() == 1)
479 Node sectionNode
= paragraphNode
.getParent();
480 Node previousNode
= sectionNode
.getNode(p(paragraphNode
.getIndex() - 1));
481 String previousTxt
= textInterpreter
.read(previousNode
);
482 textInterpreter
.write(previousNode
, previousTxt
+ txt
);
483 paragraphNode
.remove();
484 persistChanges(sectionNode
);
486 Paragraph previousParagraph
= paragraphMergedWithPrevious(paragraph
, previousNode
);
487 edit(previousParagraph
, previousTxt
.length());
488 } catch (RepositoryException e
) {
489 throw new JcrException("Cannot stop editing", e
);
493 protected void mergeWithNext() {
496 Paragraph paragraph
= (Paragraph
) getEdited();
497 Text text
= (Text
) paragraph
.getControl();
498 String txt
= text
.getText();
499 Node paragraphNode
= paragraph
.getNode();
500 Node sectionNode
= paragraphNode
.getParent();
501 NodeIterator paragraphNodes
= sectionNode
.getNodes(DbkType
.para
.get());
502 long size
= paragraphNodes
.getSize();
503 if (paragraphNode
.getIndex() == size
)
505 Node nextNode
= sectionNode
.getNode(p(paragraphNode
.getIndex() + 1));
506 String nextTxt
= textInterpreter
.read(nextNode
);
507 textInterpreter
.write(paragraphNode
, txt
+ nextTxt
);
509 Section section
= paragraph
.getSection();
510 Paragraph removed
= (Paragraph
) section
.getSectionPart(nextNode
.getIdentifier());
513 persistChanges(sectionNode
);
515 paragraphMergedWithNext(paragraph
, removed
);
516 edit(paragraph
, txt
.length());
517 } catch (RepositoryException e
) {
518 throw new JcrException("Cannot stop editing", e
);
522 protected synchronized void upload(EditablePart part
) {
524 if (part
instanceof SectionPart
) {
525 SectionPart sectionPart
= (SectionPart
) part
;
526 Node partNode
= sectionPart
.getNode();
527 int partIndex
= partNode
.getIndex();
528 Section section
= sectionPart
.getSection();
529 Node sectionNode
= section
.getNode();
531 if (part
instanceof Paragraph
) {
532 // FIXME adapt to DocBook
533 // Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE);
534 // newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
535 // JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]);
536 // if (partIndex < newNode.getIndex() - 1) {
538 // sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1));
540 // // sectionNode.orderBefore(p(partNode.getIndex()),
541 // // p(newNode.getIndex()));
542 // persistChanges(sectionNode);
543 // DbkImg img = newImg((TextSection) section, newNode);
545 // layout(img.getControl());
546 } else if (part
instanceof DbkImg
) {
547 if (getEdited() == part
)
553 } catch (RepositoryException e
) {
554 throw new JcrException("Cannot upload", e
);
558 protected void deepen() {
563 if (getEdited() instanceof Paragraph
) {
564 Paragraph paragraph
= (Paragraph
) getEdited();
565 Text text
= (Text
) paragraph
.getControl();
566 String txt
= text
.getText();
567 Node paragraphNode
= paragraph
.getNode();
568 Section section
= paragraph
.getSection();
569 Node sectionNode
= section
.getNode();
571 if (section
== mainSection
&& section
instanceof TextSection
&& paragraphNode
.getIndex() == 1
572 && !sectionNode
.hasNode(DbkType
.title
.get())) {
573 DocBookSectionTitle sectionTitle
= prepareSectionTitle(section
, txt
);
574 edit(sectionTitle
, 0);
577 Node newSectionNode
= addDbk(sectionNode
, DbkType
.section
);
578 // newSectionNode.addMixin(NodeType.MIX_TITLE);
579 sectionNode
.orderBefore(h(newSectionNode
.getIndex()), h(1));
581 int paragraphIndex
= paragraphNode
.getIndex();
582 String sectionPath
= sectionNode
.getPath();
583 String newSectionPath
= newSectionNode
.getPath();
584 while (sectionNode
.hasNode(p(paragraphIndex
+ 1))) {
585 Node parag
= sectionNode
.getNode(p(paragraphIndex
+ 1));
586 sectionNode
.getSession().move(sectionPath
+ '/' + p(paragraphIndex
+ 1),
587 newSectionPath
+ '/' + DbkType
.para
.get());
588 SectionPart sp
= section
.getSectionPart(parag
.getIdentifier());
589 if (sp
instanceof Control
)
590 ((Control
) sp
).dispose();
593 Node titleNode
= DbkUtils
.addDbk(newSectionNode
, DbkType
.title
);
594 // newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE);
595 getTextInterpreter().write(titleNode
, txt
);
597 TextSection newSection
= new TextSection(section
, section
.getStyle(), newSectionNode
);
598 newSection
.setLayoutData(CmsUiUtils
.fillWidth());
599 newSection
.moveBelow(paragraph
);
602 paragraphNode
.remove();
606 newSection
.getParent().layout();
608 persistChanges(sectionNode
);
609 } else if (getEdited() instanceof DocBookSectionTitle
) {
610 DocBookSectionTitle sectionTitle
= (DocBookSectionTitle
) getEdited();
611 Section section
= sectionTitle
.getSection();
612 Section parentSection
= section
.getParentSection();
613 if (parentSection
== null)
614 return;// cannot deepen main section
615 Node sectionN
= section
.getNode();
616 Node parentSectionN
= parentSection
.getNode();
617 if (sectionN
.getIndex() == 1)
618 return;// cannot deepen first section
619 Node previousSectionN
= parentSectionN
.getNode(h(sectionN
.getIndex() - 1));
620 NodeIterator subSections
= previousSectionN
.getNodes(DbkType
.section
.get());
621 int subsectionsCount
= (int) subSections
.getSize();
622 previousSectionN
.getSession().move(sectionN
.getPath(),
623 previousSectionN
.getPath() + "/" + h(subsectionsCount
+ 1));
625 TextSection newSection
= new TextSection(section
, section
.getStyle(), sectionN
);
627 persistChanges(previousSectionN
);
629 } catch (RepositoryException e
) {
630 throw new JcrException("Cannot deepen " + getEdited(), e
);
634 protected void undeepen() {
639 if (getEdited() instanceof Paragraph
) {
641 } else if (getEdited() instanceof DocBookSectionTitle
) {
642 DocBookSectionTitle sectionTitle
= (DocBookSectionTitle
) getEdited();
643 Section section
= sectionTitle
.getSection();
644 Node sectionNode
= section
.getNode();
645 Section parentSection
= section
.getParentSection();
646 if (parentSection
== null)
647 return;// cannot undeepen main section
649 // choose in which section to merge
650 Section mergedSection
;
651 if (sectionNode
.getIndex() == 1)
652 mergedSection
= section
.getParentSection();
654 Map
<String
, Section
> parentSubsections
= parentSection
.getSubSections();
655 ArrayList
<Section
> lst
= new ArrayList
<Section
>(parentSubsections
.values());
656 mergedSection
= lst
.get(sectionNode
.getIndex() - 1);
658 Node mergedNode
= mergedSection
.getNode();
659 boolean mergedHasSubSections
= mergedNode
.hasNode(DbkType
.section
.get());
661 // title as paragraph
662 Node newParagrapheNode
= addDbk(mergedNode
, para
);
663 // newParagrapheNode.addMixin(CmsTypes.CMS_STYLED);
664 if (mergedHasSubSections
)
665 mergedNode
.orderBefore(p(newParagrapheNode
.getIndex()), h(1));
666 String txt
= getTextInterpreter().read(sectionNode
.getNode(DbkType
.title
.get()));
667 getTextInterpreter().write(newParagrapheNode
, txt
);
669 NodeIterator paragraphs
= sectionNode
.getNodes(para
.get());
670 while (paragraphs
.hasNext()) {
671 Node p
= paragraphs
.nextNode();
672 SectionPart sp
= section
.getSectionPart(p
.getIdentifier());
673 if (sp
instanceof Control
)
674 ((Control
) sp
).dispose();
675 mergedNode
.getSession().move(p
.getPath(), mergedNode
.getPath() + '/' + para
.get());
676 if (mergedHasSubSections
)
677 mergedNode
.orderBefore(p(p
.getIndex()), h(1));
680 Iterator
<Section
> subsections
= section
.getSubSections().values().iterator();
681 // NodeIterator sections = sectionNode.getNodes(CMS_H);
682 while (subsections
.hasNext()) {
683 Section subsection
= subsections
.next();
684 Node s
= subsection
.getNode();
685 mergedNode
.getSession().move(s
.getPath(), mergedNode
.getPath() + '/' + DbkType
.section
.get());
686 subsection
.dispose();
690 section
.getNode().remove();
693 refresh(mergedSection
);
694 mergedSection
.getParent().layout();
695 layout(mergedSection
);
696 persistChanges(mergedNode
);
698 } catch (RepositoryException e
) {
699 throw new JcrException("Cannot undeepen " + getEdited(), e
);
704 protected Paragraph
paragraphSplitted(Paragraph paragraph
, Node newNode
) throws RepositoryException
{
705 Section section
= paragraph
.getSection();
706 updateContent(paragraph
);
707 Paragraph newParagraph
= newParagraph((TextSection
) section
, newNode
);
708 newParagraph
.setLayoutData(CmsUiUtils
.fillWidth());
709 newParagraph
.moveBelow(paragraph
);
710 layout(paragraph
.getControl(), newParagraph
.getControl());
714 protected Paragraph
sectionTitleSplitted(DocBookSectionTitle sectionTitle
, Node newNode
)
715 throws RepositoryException
{
716 updateContent(sectionTitle
);
717 Paragraph newParagraph
= newParagraph(sectionTitle
.getSection(), newNode
);
718 // we assume beforeFirst is not null since there was a sectionTitle
719 newParagraph
.moveBelow(sectionTitle
.getSection().getHeader());
720 layout(sectionTitle
.getControl(), newParagraph
.getControl());
724 protected Paragraph
paragraphMergedWithPrevious(Paragraph removed
, Node remaining
) throws RepositoryException
{
725 Section section
= removed
.getSection();
728 Paragraph paragraph
= (Paragraph
) section
.getSectionPart(remaining
.getIdentifier());
729 updateContent(paragraph
);
730 layout(paragraph
.getControl());
734 protected void paragraphMergedWithNext(Paragraph remaining
, Paragraph removed
) throws RepositoryException
{
736 updateContent(remaining
);
737 layout(remaining
.getControl());
741 protected String
p(Integer index
) {
742 StringBuilder sb
= new StringBuilder(6);
743 sb
.append(para
.get()).append('[').append(index
).append(']');
744 return sb
.toString();
747 protected String
h(Integer index
) {
748 StringBuilder sb
= new StringBuilder(5);
749 sb
.append(DbkType
.section
.get()).append('[').append(index
).append(']');
750 return sb
.toString();
754 public Section
getMainSection() {
758 public boolean isFlat() {
762 public TextInterpreter
getTextInterpreter() {
763 return textInterpreter
;
768 public void keyPressed(KeyEvent ke
) {
769 if (log
.isTraceEnabled())
772 if (getEdited() == null)
774 boolean altPressed
= (ke
.stateMask
& SWT
.ALT
) != 0;
775 boolean shiftPressed
= (ke
.stateMask
& SWT
.SHIFT
) != 0;
776 boolean ctrlPressed
= (ke
.stateMask
& SWT
.CTRL
) != 0;
780 if (ke
.keyCode
== SWT
.ESC
) {
783 } else if (ke
.character
== '\r') {
786 } else if (ke
.character
== 'z') {
789 } else if (ke
.character
== 'S') {
792 } else if (ke
.character
== '\t') {
795 } else if (shiftPressed
) {
799 if (getEdited() instanceof Paragraph
) {
800 Paragraph paragraph
= (Paragraph
) getEdited();
801 Section section
= paragraph
.getSection();
802 if (altPressed
&& ke
.keyCode
== SWT
.ARROW_RIGHT
) {
803 edit(section
.nextSectionPart(paragraph
), 0);
804 } else if (altPressed
&& ke
.keyCode
== SWT
.ARROW_LEFT
) {
805 edit(section
.previousSectionPart(paragraph
), 0);
806 } else if (ke
.character
== SWT
.BS
) {
807 Text text
= (Text
) paragraph
.getControl();
808 int caretPosition
= text
.getCaretPosition();
809 if (caretPosition
== 0) {
812 } else if (ke
.character
== SWT
.DEL
) {
813 Text text
= (Text
) paragraph
.getControl();
814 int caretPosition
= text
.getCaretPosition();
815 int charcount
= text
.getCharCount();
816 if (caretPosition
== charcount
) {
822 } catch (Exception e
) {
824 notifyEditionException(e
);
829 public void keyReleased(KeyEvent e
) {
834 protected MouseListener
createMouseListener() {
838 private class ML
extends MouseAdapter
{
839 private static final long serialVersionUID
= 8526890859876770905L;
842 public void mouseDoubleClick(MouseEvent e
) {
844 Control source
= (Control
) e
.getSource();
845 EditablePart composite
= findDataParent(source
);
846 Point point
= new Point(e
.x
, e
.y
);
847 if (composite
instanceof DbkImg
) {
848 if (getCmsEditable().canEdit()) {
849 if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg
)) {
850 if (source
== mainSection
)
852 EditablePart part
= findDataParent(source
);
855 getCmsEditable().startEditing();
858 } else if (source
instanceof Label
) {
859 Label lbl
= (Label
) source
;
860 Rectangle bounds
= lbl
.getBounds();
861 float width
= bounds
.width
;
862 float height
= bounds
.height
;
863 float textLength
= lbl
.getText().length();
864 float area
= width
* height
;
865 float charArea
= area
/textLength
;
866 float lines
= textLength
/width
;
867 float proportion
= point
.y
* width
+ point
.x
;
868 int pos
= (int) (textLength
* (proportion
/ area
));
870 edit(composite
, (Integer
) pos
);
872 edit(composite
, source
.toDisplay(point
));
878 public void mouseDown(MouseEvent e
) {
879 if (getCmsEditable().isEditing()) {
881 EditablePart composite
= findDataParent((Control
) e
.getSource());
882 if (styledTools
!= null) {
883 List
<String
> styles
= getAvailableStyles(composite
);
884 styledTools
.show(composite
, new Point(e
.x
, e
.y
), styles
);
891 public void mouseUp(MouseEvent e
) {
895 protected List
<String
> getAvailableStyles(EditablePart editablePart
) {
896 return new ArrayList
<>();
899 // FILE UPLOAD LISTENER
900 private class FUL
implements FileUploadListener
{
901 public void uploadProgress(FileUploadEvent event
) {
902 // TODO Monitor upload progress
905 public void uploadFailed(FileUploadEvent event
) {
906 throw new RuntimeException("Upload failed " + event
, event
.getException());
909 public void uploadFinished(FileUploadEvent event
) {
910 for (FileDetails file
: event
.getFileDetails()) {
911 if (log
.isDebugEnabled())
912 log
.debug("Received: " + file
.getFileName());
914 mainSection
.getDisplay().syncExec(new Runnable() {
920 FileUploadHandler uploadHandler
= (FileUploadHandler
) event
.getSource();
921 uploadHandler
.dispose();