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
.layout
.GridData
;
55 import org
.eclipse
.swt
.widgets
.Composite
;
56 import org
.eclipse
.swt
.widgets
.Control
;
57 import org
.eclipse
.swt
.widgets
.Label
;
58 import org
.eclipse
.swt
.widgets
.Text
;
60 /** Base class for text viewers and editors. */
61 public abstract class AbstractDbkViewer
extends AbstractPageViewer
implements KeyListener
, Observer
{
62 private static final long serialVersionUID
= -2401274679492339668L;
63 private final static Log log
= LogFactory
.getLog(AbstractDbkViewer
.class);
65 private final Section mainSection
;
67 private TextInterpreter textInterpreter
= new DbkTextInterpreter();
68 private DbkImageManager imageManager
;
70 private FileUploadListener fileUploadListener
;
71 private DbkContextMenu styledTools
;
73 private final boolean flat
;
75 private boolean showMainTitle
= true;
77 private Integer maxMediaWidth
= null;
78 private String defaultSectionStyle
;
80 protected AbstractDbkViewer(Section parent
, int style
, CmsEditable cmsEditable
) {
81 super(parent
, style
, cmsEditable
);
82 // CmsView cmsView = CmsView.getCmsView(parent);
83 // imageManager = cmsView.getImageManager();
84 flat
= SWT
.FLAT
== (style
& SWT
.FLAT
);
86 if (getCmsEditable().canEdit()) {
87 fileUploadListener
= new FUL();
88 styledTools
= new DbkContextMenu(this, parent
.getShell());
90 this.mainSection
= parent
;
91 Node baseFolder
= Jcr
.getParent(mainSection
.getNode());
92 imageManager
= new DbkImageManager(baseFolder
);
93 initModelIfNeeded(mainSection
.getNode());
94 // layout(this.mainSection);
98 public Control
getControl() {
102 protected void refresh(Control control
) throws RepositoryException
{
103 if (!(control
instanceof Section
))
105 Section section
= (Section
) control
;
106 if (section
instanceof TextSection
) {
107 CmsUiUtils
.clear(section
);
108 Node node
= section
.getNode();
109 TextSection textSection
= (TextSection
) section
;
110 String style
= node
.hasProperty(DbkAttr
.role
.name()) ? node
.getProperty(DbkAttr
.role
.name()).getString()
111 : getDefaultSectionStyle();
113 CmsUiUtils
.style(textSection
, style
);
115 if (node
.hasNode(DbkType
.title
.get())) {
116 boolean showTitle
= getMainSection() == section ? showMainTitle
: true;
118 if (section
.getHeader() == null)
119 section
.createHeader();
120 Node titleNode
= node
.getNode(DbkType
.title
.get());
121 DocBookSectionTitle title
= newSectionTitle(textSection
, titleNode
);
122 title
.setLayoutData(CmsUiUtils
.fillWidth());
123 updateContent(title
);
127 for (NodeIterator ni
= node
.getNodes(); ni
.hasNext();) {
128 Node child
= ni
.nextNode();
129 SectionPart sectionPart
= null;
130 if (isDbk(child
, DbkType
.mediaobject
)) {
131 sectionPart
= newImg(textSection
, child
);
132 // if (child.hasNode(DbkType.imageobject.get())) {
133 // Node imageDataNode = child.getNode(DbkType.imageobject.get()).getNode(DbkType.imagedata.get());
134 // sectionPart = newImg(textSection, imageDataNode);
136 } else if (isDbk(child
, para
)) {
137 sectionPart
= newParagraph(textSection
, child
);
139 sectionPart
= newSectionPart(textSection
, child
);
140 // if (sectionPart == null)
141 // throw new IllegalArgumentException("Unsupported node " + child);
142 // TODO list node types in exception
144 if (sectionPart
!= null && sectionPart
instanceof Control
)
145 ((Control
) sectionPart
).setLayoutData(CmsUiUtils
.fillWidth());
149 for (NodeIterator ni
= section
.getNode().getNodes(DbkType
.section
.get()); ni
.hasNext();) {
150 Node child
= ni
.nextNode();
151 if (isDbk(child
, DbkType
.section
)) {
152 TextSection newSection
= newTextSection(section
, child
);
153 newSection
.setLayoutData(CmsUiUtils
.fillWidth());
158 for (Section s
: section
.getSubSections().values())
161 // section.layout(true, true);
164 /** To be overridden in order to provide additional SectionPart types */
165 protected TextSection
newTextSection(Section section
, Node node
) {
166 return new TextSection(section
, SWT
.NONE
, node
);
169 /** To be overridden in order to provide additional SectionPart types */
170 protected SectionPart
newSectionPart(TextSection textSection
, Node node
) {
175 protected Paragraph
newParagraph(TextSection parent
, Node node
) throws RepositoryException
{
176 Paragraph paragraph
= new Paragraph(parent
, parent
.getStyle(), node
);
177 updateContent(paragraph
);
178 paragraph
.setLayoutData(fillWidth());
179 paragraph
.setMouseListener(getMouseListener());
180 paragraph
.setFocusListener(getFocusListener());
184 protected DbkImg
newImg(TextSection parent
, Node node
) {
186 DbkImg img
= new DbkImg(parent
, parent
.getStyle(), node
, imageManager
);
188 if (maxMediaWidth
!= null) {
189 imgGd
= new GridData(SWT
.CENTER
, SWT
.FILL
, false, false);
190 imgGd
.widthHint
= maxMediaWidth
;
191 img
.setPreferredSize(new Point(maxMediaWidth
, 0));
193 imgGd
= CmsUiUtils
.grabWidth(SWT
.CENTER
, SWT
.DEFAULT
);
195 img
.setLayoutData(imgGd
);
197 img
.setMouseListener(getMouseListener());
198 img
.setFocusListener(getFocusListener());
200 } catch (RepositoryException e
) {
201 throw new JcrException("Cannot add new image " + node
, e
);
205 protected DocBookSectionTitle
newSectionTitle(TextSection parent
, Node titleNode
) throws RepositoryException
{
206 int style
= parent
.getStyle();
207 Composite titleParent
= newSectionHeader(parent
);
208 if (parent
.isTitleReadOnly())
209 style
= style
| SWT
.READ_ONLY
;
210 DocBookSectionTitle title
= new DocBookSectionTitle(titleParent
, style
, titleNode
);
211 updateContent(title
);
212 title
.setMouseListener(getMouseListener());
213 title
.setFocusListener(getFocusListener());
218 * To be overridden in order to provide additional processing at the section
221 * @return the parent to use for the {@link DocBookSectionTitle}, by default
222 * {@link Section#getHeader()}
224 protected Composite
newSectionHeader(TextSection section
) {
225 return section
.getHeader();
228 protected DocBookSectionTitle
prepareSectionTitle(Section newSection
, String titleText
) throws RepositoryException
{
229 Node sectionNode
= newSection
.getNode();
230 Node titleNode
= DbkUtils
.getOrAddDbk(sectionNode
, DbkType
.title
);
231 getTextInterpreter().write(titleNode
, titleText
);
232 if (newSection
.getHeader() == null)
233 newSection
.createHeader();
234 DocBookSectionTitle sectionTitle
= newSectionTitle((TextSection
) newSection
, sectionNode
);
238 protected void updateContent(EditablePart part
) throws RepositoryException
{
239 if (part
instanceof SectionPart
) {
240 SectionPart sectionPart
= (SectionPart
) part
;
241 Node partNode
= sectionPart
.getNode();
243 if (part
instanceof StyledControl
&& (sectionPart
.getSection() instanceof TextSection
)) {
244 TextSection section
= (TextSection
) sectionPart
.getSection();
245 StyledControl styledControl
= (StyledControl
) part
;
246 if (isDbk(partNode
, para
)) {
247 String style
= partNode
.hasProperty(DbkAttr
.role
.name())
248 ? partNode
.getProperty(DbkAttr
.role
.name()).getString()
249 : section
.getDefaultTextStyle();
250 styledControl
.setStyle(style
);
253 // use control AFTER setting style, since it may have been reset
255 if (part
instanceof EditableText
) {
256 EditableText paragraph
= (EditableText
) part
;
257 if (paragraph
== getEdited())
258 paragraph
.setText(textInterpreter
.raw(partNode
));
260 paragraph
.setText(textInterpreter
.readSimpleHtml(partNode
));
261 } else if (part
instanceof DbkImg
) {
262 DbkImg editableImage
= (DbkImg
) part
;
263 imageManager
.load(partNode
, part
.getControl(), editableImage
.getPreferredImageSize());
265 } else if (part
instanceof DocBookSectionTitle
) {
266 DocBookSectionTitle title
= (DocBookSectionTitle
) part
;
267 title
.setStyle(title
.getSection().getTitleStyle());
268 // use control AFTER setting style
269 if (title
== getEdited())
270 title
.setText(textInterpreter
.read(title
.getNode()));
272 title
.setText(textInterpreter
.raw(title
.getNode()));
276 // OVERRIDDEN FROM PARENT VIEWER
278 protected void save(EditablePart part
) throws RepositoryException
{
279 if (part
instanceof EditableText
) {
280 EditableText et
= (EditableText
) part
;
281 if (!et
.getEditable())
283 String text
= ((Text
) et
.getControl()).getText();
285 // String[] lines = text.split("[\r\n]+");
286 String
[] lines
= { text
};
287 assert lines
.length
!= 0;
288 saveLine(part
, lines
[0]);
289 if (lines
.length
> 1) {
290 ArrayList
<Control
> toLayout
= new ArrayList
<Control
>();
291 if (part
instanceof Paragraph
) {
292 Paragraph currentParagraph
= (Paragraph
) et
;
293 Section section
= currentParagraph
.getSection();
294 Node sectionNode
= section
.getNode();
295 Node currentParagraphN
= currentParagraph
.getNode();
296 for (int i
= 1; i
< lines
.length
; i
++) {
297 Node newNode
= addDbk(sectionNode
, para
);
298 // newNode.addMixin(CmsTypes.CMS_STYLED);
299 saveLine(newNode
, lines
[i
]);
300 // second node was create as last, if it is not the next
302 // means there are some in between and we can take the
304 // index+1 for the re-order
305 if (newNode
.getIndex() > currentParagraphN
.getIndex() + 1) {
306 sectionNode
.orderBefore(p(newNode
.getIndex()), p(currentParagraphN
.getIndex() + 1));
308 Paragraph newParagraph
= newParagraph((TextSection
) section
, newNode
);
309 newParagraph
.moveBelow(currentParagraph
);
310 toLayout
.add(newParagraph
);
312 currentParagraph
= newParagraph
;
313 currentParagraphN
= newNode
;
316 // TODO or rather return the created paragraphs?
317 layout(toLayout
.toArray(new Control
[toLayout
.size()]));
319 persistChanges(et
.getNode());
323 protected void saveLine(EditablePart part
, String line
) {
324 if (part
instanceof NodePart
) {
325 saveLine(((NodePart
) part
).getNode(), line
);
326 } else if (part
instanceof PropertyPart
) {
327 saveLine(((PropertyPart
) part
).getProperty(), line
);
329 throw new IllegalArgumentException("Unsupported part " + part
);
333 protected void saveLine(Item item
, String line
) {
335 textInterpreter
.write(item
, line
);
339 protected void prepare(EditablePart part
, Object caretPosition
) {
340 Control control
= part
.getControl();
341 if (control
instanceof Text
) {
342 Text text
= (Text
) control
;
343 if (caretPosition
!= null)
344 if (caretPosition
instanceof Integer
)
345 text
.setSelection((Integer
) caretPosition
);
346 else if (caretPosition
instanceof Point
) {
348 // // TODO find a way to position the caret at the right place
349 // Point clickLocation = (Point) caretPosition;
350 // Point withinText = text.toControl(clickLocation);
351 // Rectangle bounds = text.getBounds();
352 // int width = bounds.width;
353 // int height = bounds.height;
354 // int textLength = text.getText().length();
355 // float area = width * height;
356 // float proportion = withinText.y * width + withinText.x;
357 // int pos = (int) (textLength * (proportion / area));
358 // text.setSelection(pos);
360 text
.setData(RWT
.ACTIVE_KEYS
, new String
[] { "BACKSPACE", "ESC", "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT",
361 "ALT+ARROW_RIGHT", "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", "ENTER", "DELETE" });
362 text
.setData(RWT
.CANCEL_KEYS
, new String
[] { "RETURN", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
363 text
.addKeyListener(this);
364 } else if (part
instanceof DbkImg
) {
365 ((DbkImg
) part
).setFileUploadListener(fileUploadListener
);
369 // REQUIRED BY CONTEXT MENU
370 void setParagraphStyle(Paragraph paragraph
, String style
) {
372 Node paragraphNode
= paragraph
.getNode();
373 if (style
== null) {// default
374 if (paragraphNode
.hasProperty(DbkAttr
.role
.name()))
375 paragraphNode
.getProperty(DbkAttr
.role
.name()).remove();
377 paragraphNode
.setProperty(DbkAttr
.role
.name(), style
);
379 persistChanges(paragraphNode
);
380 updateContent(paragraph
);
382 } catch (RepositoryException e1
) {
383 throw new JcrException("Cannot set style " + style
+ " on " + paragraph
, e1
);
387 SectionPart
insertPart(Section section
, Node node
) {
391 for (Control control
: section
.getChildren()) {
392 if (control
instanceof SectionPart
) {
393 SectionPart sectionPart
= (SectionPart
) control
;
394 Node partNode
= sectionPart
.getNode();
395 if (partNode
.getPath().equals(node
.getPath()))
399 throw new IllegalStateException("New section part " + node
+ "not found");
400 } catch (RepositoryException e
) {
401 throw new JcrException("Cannot insert part " + node
+ " in section " + section
.getNode(), e
);
405 void addParagraph(SectionPart partBefore
, String txt
) {
406 Section section
= partBefore
.getSection();
407 SectionPart nextSectionPart
= section
.nextSectionPart(partBefore
);
408 Node newNode
= addDbk(section
.getNode(), para
);
409 textInterpreter
.write(newNode
, txt
!= null ? txt
: "");
410 if (nextSectionPart
!= null) {
412 Node nextNode
= nextSectionPart
.getNode();
413 section
.getNode().orderBefore(Jcr
.getIndexedName(newNode
), Jcr
.getIndexedName(nextNode
));
414 } catch (RepositoryException e
) {
415 throw new JcrException("Cannot order " + newNode
+ " before " + nextSectionPart
.getNode(), e
);
419 Paragraph paragraph
= (Paragraph
) insertPart(partBefore
.getSection(), newNode
);
423 void deletePart(SectionPart sectionPart
) {
425 Node node
= sectionPart
.getNode();
426 Session session
= node
.getSession();
427 if (sectionPart
instanceof DbkImg
) {
428 if (!isDbk(node
, DbkType
.mediaobject
))
429 throw new IllegalArgumentException("Node " + node
+ " is not a media object.");
433 if (sectionPart
instanceof Control
)
434 ((Control
) sectionPart
).dispose();
436 } catch (RepositoryException e1
) {
437 throw new JcrException("Cannot delete " + sectionPart
, e1
);
441 void deleteSection(Section section
) {
443 Node node
= section
.getNode();
444 Session session
= node
.getSession();
449 } catch (RepositoryException e1
) {
450 throw new JcrException("Cannot delete " + section
, e1
);
454 String
getRawParagraphText(Paragraph paragraph
) {
455 return textInterpreter
.raw(paragraph
.getNode());
459 protected void splitEdit() {
462 if (getEdited() instanceof Paragraph
) {
463 Paragraph paragraph
= (Paragraph
) getEdited();
464 Text text
= (Text
) paragraph
.getControl();
465 int caretPosition
= text
.getCaretPosition();
466 String txt
= text
.getText();
467 String first
= txt
.substring(0, caretPosition
);
468 String second
= txt
.substring(caretPosition
);
469 Node firstNode
= paragraph
.getNode();
470 Node sectionNode
= firstNode
.getParent();
472 // FIXME set content the DocBook way
473 // firstNode.setProperty(CMS_CONTENT, first);
474 Node secondNode
= addDbk(sectionNode
, para
);
475 // secondNode.addMixin(CmsTypes.CMS_STYLED);
477 // second node was create as last, if it is not the next one, it
478 // means there are some in between and we can take the one at
479 // index+1 for the re-order
480 if (secondNode
.getIndex() > firstNode
.getIndex() + 1) {
481 sectionNode
.orderBefore(p(secondNode
.getIndex()), p(firstNode
.getIndex() + 1));
484 // if we die in between, at least we still have the whole text
487 textInterpreter
.write(secondNode
, second
);
488 textInterpreter
.write(firstNode
, first
);
489 } catch (Exception e
) {
490 // so that no additional nodes are created:
491 JcrUtils
.discardUnderlyingSessionQuietly(firstNode
);
495 persistChanges(firstNode
);
497 Paragraph secondParagraph
= paragraphSplitted(paragraph
, secondNode
);
498 edit(secondParagraph
, 0);
499 } else if (getEdited() instanceof DocBookSectionTitle
) {
500 DocBookSectionTitle sectionTitle
= (DocBookSectionTitle
) getEdited();
501 Text text
= (Text
) sectionTitle
.getControl();
502 String txt
= text
.getText();
503 int caretPosition
= text
.getCaretPosition();
504 Section section
= sectionTitle
.getSection();
505 Node sectionNode
= section
.getNode();
506 Node paragraphNode
= addDbk(sectionNode
, para
);
507 // paragraphNode.addMixin(CmsTypes.CMS_STYLED);
509 textInterpreter
.write(paragraphNode
, txt
.substring(caretPosition
));
510 textInterpreter
.write(sectionNode
.getNode(DbkType
.title
.get()), txt
.substring(0, caretPosition
));
511 sectionNode
.orderBefore(p(paragraphNode
.getIndex()), p(1));
512 persistChanges(sectionNode
);
514 Paragraph paragraph
= sectionTitleSplitted(sectionTitle
, paragraphNode
);
518 } catch (RepositoryException e
) {
519 throw new JcrException("Cannot split " + getEdited(), e
);
523 protected void mergeWithPrevious() {
526 Paragraph paragraph
= (Paragraph
) getEdited();
527 Text text
= (Text
) paragraph
.getControl();
528 String txt
= text
.getText();
529 Node paragraphNode
= paragraph
.getNode();
530 if (paragraphNode
.getIndex() == 1)
532 Node sectionNode
= paragraphNode
.getParent();
533 Node previousNode
= sectionNode
.getNode(p(paragraphNode
.getIndex() - 1));
534 String previousTxt
= textInterpreter
.read(previousNode
);
535 textInterpreter
.write(previousNode
, previousTxt
+ txt
);
536 paragraphNode
.remove();
537 persistChanges(sectionNode
);
539 Paragraph previousParagraph
= paragraphMergedWithPrevious(paragraph
, previousNode
);
540 edit(previousParagraph
, previousTxt
.length());
541 } catch (RepositoryException e
) {
542 throw new JcrException("Cannot stop editing", e
);
546 protected void mergeWithNext() {
549 Paragraph paragraph
= (Paragraph
) getEdited();
550 Text text
= (Text
) paragraph
.getControl();
551 String txt
= text
.getText();
552 Node paragraphNode
= paragraph
.getNode();
553 Node sectionNode
= paragraphNode
.getParent();
554 NodeIterator paragraphNodes
= sectionNode
.getNodes(DbkType
.para
.get());
555 long size
= paragraphNodes
.getSize();
556 if (paragraphNode
.getIndex() == size
)
558 Node nextNode
= sectionNode
.getNode(p(paragraphNode
.getIndex() + 1));
559 String nextTxt
= textInterpreter
.read(nextNode
);
560 textInterpreter
.write(paragraphNode
, txt
+ nextTxt
);
562 Section section
= paragraph
.getSection();
563 Paragraph removed
= (Paragraph
) section
.getSectionPart(nextNode
.getIdentifier());
566 persistChanges(sectionNode
);
568 paragraphMergedWithNext(paragraph
, removed
);
569 edit(paragraph
, txt
.length());
570 } catch (RepositoryException e
) {
571 throw new JcrException("Cannot stop editing", e
);
575 protected synchronized void upload(EditablePart part
) {
577 if (part
instanceof SectionPart
) {
578 SectionPart sectionPart
= (SectionPart
) part
;
579 Node partNode
= sectionPart
.getNode();
580 int partIndex
= partNode
.getIndex();
581 Section section
= sectionPart
.getSection();
582 Node sectionNode
= section
.getNode();
584 if (part
instanceof Paragraph
) {
585 // FIXME adapt to DocBook
586 // Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE);
587 // newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
588 // JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]);
589 // if (partIndex < newNode.getIndex() - 1) {
591 // sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1));
593 // // sectionNode.orderBefore(p(partNode.getIndex()),
594 // // p(newNode.getIndex()));
595 // persistChanges(sectionNode);
596 // DbkImg img = newImg((TextSection) section, newNode);
598 // layout(img.getControl());
599 } else if (part
instanceof DbkImg
) {
600 if (getEdited() == part
)
606 } catch (RepositoryException e
) {
607 throw new JcrException("Cannot upload", e
);
611 protected void deepen() {
616 if (getEdited() instanceof Paragraph
) {
617 Paragraph paragraph
= (Paragraph
) getEdited();
618 Text text
= (Text
) paragraph
.getControl();
619 String txt
= text
.getText();
620 Node paragraphNode
= paragraph
.getNode();
621 Section section
= paragraph
.getSection();
622 Node sectionNode
= section
.getNode();
624 if (section
== mainSection
&& section
instanceof TextSection
&& paragraphNode
.getIndex() == 1
625 && !sectionNode
.hasNode(DbkType
.title
.get())) {
626 DocBookSectionTitle sectionTitle
= prepareSectionTitle(section
, txt
);
627 edit(sectionTitle
, 0);
630 Node newSectionNode
= addDbk(sectionNode
, DbkType
.section
);
631 // newSectionNode.addMixin(NodeType.MIX_TITLE);
632 sectionNode
.orderBefore(h(newSectionNode
.getIndex()), h(1));
634 int paragraphIndex
= paragraphNode
.getIndex();
635 String sectionPath
= sectionNode
.getPath();
636 String newSectionPath
= newSectionNode
.getPath();
637 while (sectionNode
.hasNode(p(paragraphIndex
+ 1))) {
638 Node parag
= sectionNode
.getNode(p(paragraphIndex
+ 1));
639 sectionNode
.getSession().move(sectionPath
+ '/' + p(paragraphIndex
+ 1),
640 newSectionPath
+ '/' + DbkType
.para
.get());
641 SectionPart sp
= section
.getSectionPart(parag
.getIdentifier());
642 if (sp
instanceof Control
)
643 ((Control
) sp
).dispose();
646 Node titleNode
= DbkUtils
.addDbk(newSectionNode
, DbkType
.title
);
647 // newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE);
648 getTextInterpreter().write(titleNode
, txt
);
650 TextSection newSection
= new TextSection(section
, section
.getStyle(), newSectionNode
);
651 newSection
.setLayoutData(CmsUiUtils
.fillWidth());
652 newSection
.moveBelow(paragraph
);
655 paragraphNode
.remove();
659 newSection
.getParent().layout();
661 persistChanges(sectionNode
);
662 } else if (getEdited() instanceof DocBookSectionTitle
) {
663 DocBookSectionTitle sectionTitle
= (DocBookSectionTitle
) getEdited();
664 Section section
= sectionTitle
.getSection();
665 Section parentSection
= section
.getParentSection();
666 if (parentSection
== null)
667 return;// cannot deepen main section
668 Node sectionN
= section
.getNode();
669 Node parentSectionN
= parentSection
.getNode();
670 if (sectionN
.getIndex() == 1)
671 return;// cannot deepen first section
672 Node previousSectionN
= parentSectionN
.getNode(h(sectionN
.getIndex() - 1));
673 NodeIterator subSections
= previousSectionN
.getNodes(DbkType
.section
.get());
674 int subsectionsCount
= (int) subSections
.getSize();
675 previousSectionN
.getSession().move(sectionN
.getPath(),
676 previousSectionN
.getPath() + "/" + h(subsectionsCount
+ 1));
678 TextSection newSection
= new TextSection(section
, section
.getStyle(), sectionN
);
680 persistChanges(previousSectionN
);
682 } catch (RepositoryException e
) {
683 throw new JcrException("Cannot deepen " + getEdited(), e
);
687 protected void undeepen() {
692 if (getEdited() instanceof Paragraph
) {
694 } else if (getEdited() instanceof DocBookSectionTitle
) {
695 DocBookSectionTitle sectionTitle
= (DocBookSectionTitle
) getEdited();
696 Section section
= sectionTitle
.getSection();
697 Node sectionNode
= section
.getNode();
698 Section parentSection
= section
.getParentSection();
699 if (parentSection
== null)
700 return;// cannot undeepen main section
702 // choose in which section to merge
703 Section mergedSection
;
704 if (sectionNode
.getIndex() == 1)
705 mergedSection
= section
.getParentSection();
707 Map
<String
, Section
> parentSubsections
= parentSection
.getSubSections();
708 ArrayList
<Section
> lst
= new ArrayList
<Section
>(parentSubsections
.values());
709 mergedSection
= lst
.get(sectionNode
.getIndex() - 1);
711 Node mergedNode
= mergedSection
.getNode();
712 boolean mergedHasSubSections
= mergedNode
.hasNode(DbkType
.section
.get());
714 // title as paragraph
715 Node newParagrapheNode
= addDbk(mergedNode
, para
);
716 // newParagrapheNode.addMixin(CmsTypes.CMS_STYLED);
717 if (mergedHasSubSections
)
718 mergedNode
.orderBefore(p(newParagrapheNode
.getIndex()), h(1));
719 String txt
= getTextInterpreter().read(sectionNode
.getNode(DbkType
.title
.get()));
720 getTextInterpreter().write(newParagrapheNode
, txt
);
722 NodeIterator paragraphs
= sectionNode
.getNodes(para
.get());
723 while (paragraphs
.hasNext()) {
724 Node p
= paragraphs
.nextNode();
725 SectionPart sp
= section
.getSectionPart(p
.getIdentifier());
726 if (sp
instanceof Control
)
727 ((Control
) sp
).dispose();
728 mergedNode
.getSession().move(p
.getPath(), mergedNode
.getPath() + '/' + para
.get());
729 if (mergedHasSubSections
)
730 mergedNode
.orderBefore(p(p
.getIndex()), h(1));
733 Iterator
<Section
> subsections
= section
.getSubSections().values().iterator();
734 // NodeIterator sections = sectionNode.getNodes(CMS_H);
735 while (subsections
.hasNext()) {
736 Section subsection
= subsections
.next();
737 Node s
= subsection
.getNode();
738 mergedNode
.getSession().move(s
.getPath(), mergedNode
.getPath() + '/' + DbkType
.section
.get());
739 subsection
.dispose();
743 section
.getNode().remove();
746 refresh(mergedSection
);
747 mergedSection
.getParent().layout();
748 layout(mergedSection
);
749 persistChanges(mergedNode
);
751 } catch (RepositoryException e
) {
752 throw new JcrException("Cannot undeepen " + getEdited(), e
);
757 protected Paragraph
paragraphSplitted(Paragraph paragraph
, Node newNode
) throws RepositoryException
{
758 Section section
= paragraph
.getSection();
759 updateContent(paragraph
);
760 Paragraph newParagraph
= newParagraph((TextSection
) section
, newNode
);
761 newParagraph
.setLayoutData(CmsUiUtils
.fillWidth());
762 newParagraph
.moveBelow(paragraph
);
763 layout(paragraph
.getControl(), newParagraph
.getControl());
767 protected Paragraph
sectionTitleSplitted(DocBookSectionTitle sectionTitle
, Node newNode
)
768 throws RepositoryException
{
769 updateContent(sectionTitle
);
770 Paragraph newParagraph
= newParagraph(sectionTitle
.getSection(), newNode
);
771 // we assume beforeFirst is not null since there was a sectionTitle
772 newParagraph
.moveBelow(sectionTitle
.getSection().getHeader());
773 layout(sectionTitle
.getControl(), newParagraph
.getControl());
777 protected Paragraph
paragraphMergedWithPrevious(Paragraph removed
, Node remaining
) throws RepositoryException
{
778 Section section
= removed
.getSection();
781 Paragraph paragraph
= (Paragraph
) section
.getSectionPart(remaining
.getIdentifier());
782 updateContent(paragraph
);
783 layout(paragraph
.getControl());
787 protected void paragraphMergedWithNext(Paragraph remaining
, Paragraph removed
) throws RepositoryException
{
789 updateContent(remaining
);
790 layout(remaining
.getControl());
794 protected String
p(Integer index
) {
795 StringBuilder sb
= new StringBuilder(6);
796 sb
.append(para
.get()).append('[').append(index
).append(']');
797 return sb
.toString();
800 protected String
h(Integer index
) {
801 StringBuilder sb
= new StringBuilder(5);
802 sb
.append(DbkType
.section
.get()).append('[').append(index
).append(']');
803 return sb
.toString();
807 public Section
getMainSection() {
811 public boolean isFlat() {
815 public TextInterpreter
getTextInterpreter() {
816 return textInterpreter
;
821 public void keyPressed(KeyEvent ke
) {
822 if (log
.isTraceEnabled())
825 if (getEdited() == null)
827 boolean altPressed
= (ke
.stateMask
& SWT
.ALT
) != 0;
828 boolean shiftPressed
= (ke
.stateMask
& SWT
.SHIFT
) != 0;
829 boolean ctrlPressed
= (ke
.stateMask
& SWT
.CTRL
) != 0;
833 if (ke
.keyCode
== SWT
.ESC
) {
836 } else if (ke
.character
== '\r') {
839 } else if (ke
.character
== 'z') {
842 } else if (ke
.character
== 'S') {
845 } else if (ke
.character
== '\t') {
848 } else if (shiftPressed
) {
852 if (getEdited() instanceof Paragraph
) {
853 Paragraph paragraph
= (Paragraph
) getEdited();
854 Section section
= paragraph
.getSection();
855 if (altPressed
&& ke
.keyCode
== SWT
.ARROW_RIGHT
) {
856 edit(section
.nextSectionPart(paragraph
), 0);
857 } else if (altPressed
&& ke
.keyCode
== SWT
.ARROW_LEFT
) {
858 edit(section
.previousSectionPart(paragraph
), 0);
859 } else if (ke
.character
== SWT
.BS
) {
860 Text text
= (Text
) paragraph
.getControl();
861 int caretPosition
= text
.getCaretPosition();
862 if (caretPosition
== 0) {
865 } else if (ke
.character
== SWT
.DEL
) {
866 Text text
= (Text
) paragraph
.getControl();
867 int caretPosition
= text
.getCaretPosition();
868 int charcount
= text
.getCharCount();
869 if (caretPosition
== charcount
) {
875 } catch (Exception e
) {
877 notifyEditionException(e
);
882 public void keyReleased(KeyEvent e
) {
887 protected MouseListener
createMouseListener() {
891 private class ML
extends MouseAdapter
{
892 private static final long serialVersionUID
= 8526890859876770905L;
895 public void mouseDoubleClick(MouseEvent e
) {
897 Control source
= (Control
) e
.getSource();
898 EditablePart composite
= findDataParent(source
);
899 Point point
= new Point(e
.x
, e
.y
);
900 if (composite
instanceof DbkImg
) {
901 if (getCmsEditable().canEdit()) {
902 if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg
)) {
903 if (source
== mainSection
)
905 EditablePart part
= findDataParent(source
);
908 getCmsEditable().startEditing();
911 } else if (source
instanceof Label
) {
912 Label lbl
= (Label
) source
;
913 Rectangle bounds
= lbl
.getBounds();
914 float width
= bounds
.width
;
915 float height
= bounds
.height
;
916 float textLength
= lbl
.getText().length();
917 float area
= width
* height
;
918 float charArea
= area
/ textLength
;
919 float lines
= textLength
/ width
;
920 float proportion
= point
.y
* width
+ point
.x
;
921 int pos
= (int) (textLength
* (proportion
/ area
));
923 edit(composite
, (Integer
) pos
);
925 edit(composite
, source
.toDisplay(point
));
931 public void mouseDown(MouseEvent e
) {
932 if (getCmsEditable().isEditing()) {
934 EditablePart composite
= findDataParent((Control
) e
.getSource());
935 if (styledTools
!= null) {
936 List
<String
> styles
= getAvailableStyles(composite
);
937 styledTools
.show(composite
, new Point(e
.x
, e
.y
), styles
);
944 public void mouseUp(MouseEvent e
) {
948 protected List
<String
> getAvailableStyles(EditablePart editablePart
) {
949 return new ArrayList
<>();
952 public void setMaxMediaWidth(Integer maxMediaWidth
) {
953 this.maxMediaWidth
= maxMediaWidth
;
956 public void setShowMainTitle(boolean showMainTitle
) {
957 this.showMainTitle
= showMainTitle
;
960 public String
getDefaultSectionStyle() {
961 return defaultSectionStyle
;
964 public void setDefaultSectionStyle(String defaultSectionStyle
) {
965 this.defaultSectionStyle
= defaultSectionStyle
;
968 // FILE UPLOAD LISTENER
969 private class FUL
implements FileUploadListener
{
970 public void uploadProgress(FileUploadEvent event
) {
971 // TODO Monitor upload progress
974 public void uploadFailed(FileUploadEvent event
) {
975 throw new RuntimeException("Upload failed " + event
, event
.getException());
978 public void uploadFinished(FileUploadEvent event
) {
979 for (FileDetails file
: event
.getFileDetails()) {
980 if (log
.isDebugEnabled())
981 log
.debug("Received: " + file
.getFileName());
983 mainSection
.getDisplay().syncExec(new Runnable() {
989 FileUploadHandler uploadHandler
= (FileUploadHandler
) event
.getSource();
990 uploadHandler
.dispose();