1 package org
.argeo
.cms
.text
;
3 import static javax
.jcr
.Property
.JCR_TITLE
;
4 import static org
.argeo
.cms
.ui
.util
.CmsUiUtils
.fillWidth
;
6 import java
.util
.ArrayList
;
7 import java
.util
.Iterator
;
9 import java
.util
.Observer
;
11 import javax
.jcr
.Item
;
12 import javax
.jcr
.Node
;
13 import javax
.jcr
.NodeIterator
;
14 import javax
.jcr
.Property
;
15 import javax
.jcr
.RepositoryException
;
16 import javax
.jcr
.Session
;
17 import javax
.jcr
.nodetype
.NodeType
;
19 import org
.apache
.commons
.logging
.Log
;
20 import org
.apache
.commons
.logging
.LogFactory
;
21 import org
.argeo
.cms
.CmsException
;
22 import org
.argeo
.cms
.ui
.CmsEditable
;
23 import org
.argeo
.cms
.ui
.CmsImageManager
;
24 import org
.argeo
.cms
.ui
.util
.CmsUiUtils
;
25 import org
.argeo
.cms
.ui
.viewers
.AbstractPageViewer
;
26 import org
.argeo
.cms
.ui
.viewers
.EditablePart
;
27 import org
.argeo
.cms
.ui
.viewers
.NodePart
;
28 import org
.argeo
.cms
.ui
.viewers
.PropertyPart
;
29 import org
.argeo
.cms
.ui
.viewers
.Section
;
30 import org
.argeo
.cms
.ui
.viewers
.SectionPart
;
31 import org
.argeo
.cms
.ui
.widgets
.EditableImage
;
32 import org
.argeo
.cms
.ui
.widgets
.EditableText
;
33 import org
.argeo
.cms
.ui
.widgets
.Img
;
34 import org
.argeo
.cms
.ui
.widgets
.StyledControl
;
35 import org
.argeo
.jcr
.JcrUtils
;
36 import org
.eclipse
.rap
.fileupload
.FileDetails
;
37 import org
.eclipse
.rap
.fileupload
.FileUploadEvent
;
38 import org
.eclipse
.rap
.fileupload
.FileUploadHandler
;
39 import org
.eclipse
.rap
.fileupload
.FileUploadListener
;
40 import org
.eclipse
.rap
.rwt
.RWT
;
41 import org
.eclipse
.swt
.SWT
;
42 import org
.eclipse
.swt
.events
.KeyEvent
;
43 import org
.eclipse
.swt
.events
.KeyListener
;
44 import org
.eclipse
.swt
.events
.MouseAdapter
;
45 import org
.eclipse
.swt
.events
.MouseEvent
;
46 import org
.eclipse
.swt
.events
.MouseListener
;
47 import org
.eclipse
.swt
.graphics
.Point
;
48 import org
.eclipse
.swt
.widgets
.Composite
;
49 import org
.eclipse
.swt
.widgets
.Control
;
50 import org
.eclipse
.swt
.widgets
.Text
;
52 /** Base class for text viewers and editors. */
53 public abstract class AbstractTextViewer
extends AbstractPageViewer
implements
54 CmsNames
, KeyListener
, Observer
{
55 private static final long serialVersionUID
= -2401274679492339668L;
56 private final static Log log
= LogFactory
.getLog(AbstractTextViewer
.class);
58 private final Section mainSection
;
60 private TextInterpreter textInterpreter
= new TextInterpreterImpl();
61 private CmsImageManager imageManager
= CmsUiUtils
.getCmsView()
64 private FileUploadListener fileUploadListener
;
65 private TextContextMenu styledTools
;
67 private final boolean flat
;
69 protected AbstractTextViewer(Section parent
, int style
,
70 CmsEditable cmsEditable
) {
71 super(parent
, style
, cmsEditable
);
72 flat
= SWT
.FLAT
== (style
& SWT
.FLAT
);
74 if (getCmsEditable().canEdit()) {
75 fileUploadListener
= new FUL();
76 styledTools
= new TextContextMenu(this, parent
.getDisplay());
78 this.mainSection
= parent
;
79 initModelIfNeeded(mainSection
.getNode());
80 // layout(this.mainSection);
84 public Control
getControl() {
88 protected void refresh(Control control
) throws RepositoryException
{
89 if (!(control
instanceof Section
))
91 Section section
= (Section
) control
;
92 if (section
instanceof TextSection
) {
93 CmsUiUtils
.clear(section
);
94 Node node
= section
.getNode();
95 TextSection textSection
= (TextSection
) section
;
96 if (node
.hasProperty(Property
.JCR_TITLE
)) {
97 if (section
.getHeader() == null)
98 section
.createHeader();
99 if (node
.hasProperty(Property
.JCR_TITLE
)) {
100 SectionTitle title
= newSectionTitle(textSection
, node
);
101 title
.setLayoutData(CmsUiUtils
.fillWidth());
102 updateContent(title
);
106 for (NodeIterator ni
= node
.getNodes(CMS_P
); ni
.hasNext();) {
107 Node child
= ni
.nextNode();
108 final SectionPart sectionPart
;
109 if (child
.isNodeType(CmsTypes
.CMS_IMAGE
)
110 || child
.isNodeType(NodeType
.NT_FILE
)) {
111 sectionPart
= newImg(textSection
, child
);
112 } else if (child
.isNodeType(CmsTypes
.CMS_STYLED
)) {
113 sectionPart
= newParagraph(textSection
, child
);
115 sectionPart
= newSectionPart(textSection
, child
);
116 if (sectionPart
== null)
117 throw new CmsException("Unsupported node " + child
);
118 // TODO list node types in exception
120 if (sectionPart
instanceof Control
)
121 ((Control
) sectionPart
).setLayoutData(CmsUiUtils
.fillWidth());
125 for (NodeIterator ni
= section
.getNode().getNodes(CMS_H
); ni
127 Node child
= ni
.nextNode();
128 if (child
.isNodeType(CmsTypes
.CMS_SECTION
)) {
129 TextSection newSection
= new TextSection(section
,
131 newSection
.setLayoutData(CmsUiUtils
.fillWidth());
136 for (Section s
: section
.getSubSections().values())
142 /** To be overridden in order to provide additional SectionPart types */
143 protected SectionPart
newSectionPart(TextSection textSection
, Node node
) {
148 protected Paragraph
newParagraph(TextSection parent
, Node node
)
149 throws RepositoryException
{
150 Paragraph paragraph
= new Paragraph(parent
, parent
.getStyle(), node
);
151 updateContent(paragraph
);
152 paragraph
.setLayoutData(fillWidth());
153 paragraph
.setMouseListener(getMouseListener());
157 protected Img
newImg(TextSection parent
, Node node
)
158 throws RepositoryException
{
159 Img img
= new Img(parent
, parent
.getStyle(), node
) {
160 private static final long serialVersionUID
= 1297900641952417540L;
163 protected void setContainerLayoutData(Composite composite
) {
164 composite
.setLayoutData(CmsUiUtils
.grabWidth(SWT
.CENTER
,
169 protected void setControlLayoutData(Control control
) {
170 control
.setLayoutData(CmsUiUtils
.grabWidth(SWT
.CENTER
,
174 img
.setLayoutData(CmsUiUtils
.grabWidth(SWT
.CENTER
, SWT
.DEFAULT
));
176 img
.setMouseListener(getMouseListener());
180 protected SectionTitle
newSectionTitle(TextSection parent
, Node node
)
181 throws RepositoryException
{
182 SectionTitle title
= new SectionTitle(parent
.getHeader(),
183 parent
.getStyle(), node
.getProperty(JCR_TITLE
));
184 updateContent(title
);
185 title
.setMouseListener(getMouseListener());
189 protected SectionTitle
prepareSectionTitle(Section newSection
,
190 String titleText
) throws RepositoryException
{
191 Node sectionNode
= newSection
.getNode();
192 if (!sectionNode
.hasProperty(JCR_TITLE
))
193 sectionNode
.setProperty(Property
.JCR_TITLE
, "");
194 getTextInterpreter().write(sectionNode
.getProperty(Property
.JCR_TITLE
),
196 if (newSection
.getHeader() == null)
197 newSection
.createHeader();
198 SectionTitle sectionTitle
= newSectionTitle((TextSection
) newSection
,
203 protected void updateContent(EditablePart part
) throws RepositoryException
{
204 if (part
instanceof SectionPart
) {
205 SectionPart sectionPart
= (SectionPart
) part
;
206 Node partNode
= sectionPart
.getNode();
208 if (part
instanceof StyledControl
209 && (sectionPart
.getSection() instanceof TextSection
)) {
210 TextSection section
= (TextSection
) sectionPart
.getSection();
211 StyledControl styledControl
= (StyledControl
) part
;
212 if (partNode
.isNodeType(CmsTypes
.CMS_STYLED
)) {
213 String style
= partNode
.hasProperty(CMS_STYLE
) ? partNode
214 .getProperty(CMS_STYLE
).getString() : section
215 .getDefaultTextStyle();
216 styledControl
.setStyle(style
);
219 // use control AFTER setting style, since it may have been reset
221 if (part
instanceof EditableText
) {
222 EditableText paragraph
= (EditableText
) part
;
223 if (paragraph
== getEdited())
224 paragraph
.setText(textInterpreter
.read(partNode
));
226 paragraph
.setText(textInterpreter
.raw(partNode
));
227 } else if (part
instanceof EditableImage
) {
228 EditableImage editableImage
= (EditableImage
) part
;
229 imageManager
.load(partNode
, part
.getControl(),
230 editableImage
.getPreferredImageSize());
232 } else if (part
instanceof SectionTitle
) {
233 SectionTitle title
= (SectionTitle
) part
;
234 title
.setStyle(title
.getSection().getTitleStyle());
235 // use control AFTER setting style
236 if (title
== getEdited())
237 title
.setText(textInterpreter
.read(title
.getProperty()));
239 title
.setText(textInterpreter
.raw(title
.getProperty()));
243 // OVERRIDDEN FROM PARENT VIEWER
245 protected void save(EditablePart part
) throws RepositoryException
{
246 if (part
instanceof EditableText
) {
247 EditableText et
= (EditableText
) part
;
248 String text
= ((Text
) et
.getControl()).getText();
250 String
[] lines
= text
.split("[\r\n]+");
251 assert lines
.length
!= 0;
252 saveLine(part
, lines
[0]);
253 if (lines
.length
> 1) {
254 ArrayList
<Control
> toLayout
= new ArrayList
<Control
>();
255 if (part
instanceof Paragraph
) {
256 Paragraph currentParagraph
= (Paragraph
) et
;
257 Section section
= currentParagraph
.getSection();
258 Node sectionNode
= section
.getNode();
259 Node currentParagraphN
= currentParagraph
.getNode();
260 for (int i
= 1; i
< lines
.length
; i
++) {
261 Node newNode
= sectionNode
.addNode(CMS_P
);
262 newNode
.addMixin(CmsTypes
.CMS_STYLED
);
263 saveLine(newNode
, lines
[i
]);
264 // second node was create as last, if it is not the next
266 // means there are some in between and we can take the
268 // index+1 for the re-order
269 if (newNode
.getIndex() > currentParagraphN
.getIndex() + 1) {
270 sectionNode
.orderBefore(p(newNode
.getIndex()),
271 p(currentParagraphN
.getIndex() + 1));
273 Paragraph newParagraph
= newParagraph(
274 (TextSection
) section
, newNode
);
275 newParagraph
.moveBelow(currentParagraph
);
276 toLayout
.add(newParagraph
);
278 currentParagraph
= newParagraph
;
279 currentParagraphN
= newNode
;
281 persistChanges(sectionNode
);
283 // TODO or rather return the created paragarphs?
284 layout(toLayout
.toArray(new Control
[toLayout
.size()]));
289 protected void saveLine(EditablePart part
, String line
) {
290 if (part
instanceof NodePart
) {
291 saveLine(((NodePart
) part
).getNode(), line
);
292 } else if (part
instanceof PropertyPart
) {
293 saveLine(((PropertyPart
) part
).getProperty(), line
);
295 throw new CmsException("Unsupported part " + part
);
299 protected void saveLine(Item item
, String line
) {
301 textInterpreter
.write(item
, line
);
305 protected void prepare(EditablePart part
, Object caretPosition
) {
306 Control control
= part
.getControl();
307 if (control
instanceof Text
) {
308 Text text
= (Text
) control
;
309 if (caretPosition
!= null)
310 if (caretPosition
instanceof Integer
)
311 text
.setSelection((Integer
) caretPosition
);
312 else if (caretPosition
instanceof Point
) {
313 // TODO find a way to position the caret at the right place
315 text
.setData(RWT
.ACTIVE_KEYS
, new String
[] { "BACKSPACE", "ESC",
316 "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT",
317 "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN",
318 "ENTER", "DELETE" });
319 text
.setData(RWT
.CANCEL_KEYS
, new String
[] { "RETURN",
320 "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
321 text
.addKeyListener(this);
322 } else if (part
instanceof Img
) {
323 ((Img
) part
).setFileUploadListener(fileUploadListener
);
327 // REQUIRED BY CONTEXT MENU
328 void setParagraphStyle(Paragraph paragraph
, String style
) {
330 Node paragraphNode
= paragraph
.getNode();
331 paragraphNode
.setProperty(CMS_STYLE
, style
);
332 persistChanges(paragraphNode
);
333 updateContent(paragraph
);
335 } catch (RepositoryException e1
) {
336 throw new CmsException("Cannot set style " + style
+ " on "
341 void deletePart(SectionPart paragraph
) {
343 Node paragraphNode
= paragraph
.getNode();
344 Section section
= paragraph
.getSection();
345 Session session
= paragraphNode
.getSession();
346 paragraphNode
.remove();
348 if (paragraph
instanceof Control
)
349 ((Control
) paragraph
).dispose();
351 } catch (RepositoryException e1
) {
352 throw new CmsException("Cannot delete " + paragraph
, e1
);
356 String
getRawParagraphText(Paragraph paragraph
) {
357 return textInterpreter
.raw(paragraph
.getNode());
361 protected void splitEdit() {
364 if (getEdited() instanceof Paragraph
) {
365 Paragraph paragraph
= (Paragraph
) getEdited();
366 Text text
= (Text
) paragraph
.getControl();
367 int caretPosition
= text
.getCaretPosition();
368 String txt
= text
.getText();
369 String first
= txt
.substring(0, caretPosition
);
370 String second
= txt
.substring(caretPosition
);
371 Node firstNode
= paragraph
.getNode();
372 Node sectionNode
= firstNode
.getParent();
373 firstNode
.setProperty(CMS_CONTENT
, first
);
374 Node secondNode
= sectionNode
.addNode(CMS_P
);
375 secondNode
.addMixin(CmsTypes
.CMS_STYLED
);
376 // second node was create as last, if it is not the next one, it
377 // means there are some in between and we can take the one at
378 // index+1 for the re-order
379 if (secondNode
.getIndex() > firstNode
.getIndex() + 1) {
380 sectionNode
.orderBefore(p(secondNode
.getIndex()),
381 p(firstNode
.getIndex() + 1));
384 // if we die in between, at least we still have the whole text
387 textInterpreter
.write(secondNode
, second
);
388 textInterpreter
.write(firstNode
, first
);
389 } catch (Exception e
) {
390 // so that no additional nodes are created:
391 JcrUtils
.discardUnderlyingSessionQuietly(firstNode
);
395 persistChanges(firstNode
);
397 Paragraph secondParagraph
= paragraphSplitted(paragraph
,
399 edit(secondParagraph
, 0);
400 } else if (getEdited() instanceof SectionTitle
) {
401 SectionTitle sectionTitle
= (SectionTitle
) getEdited();
402 Text text
= (Text
) sectionTitle
.getControl();
403 String txt
= text
.getText();
404 int caretPosition
= text
.getCaretPosition();
405 Section section
= sectionTitle
.getSection();
406 Node sectionNode
= section
.getNode();
407 Node paragraphNode
= sectionNode
.addNode(CMS_P
);
408 paragraphNode
.addMixin(CmsTypes
.CMS_STYLED
);
409 textInterpreter
.write(paragraphNode
,
410 txt
.substring(caretPosition
));
411 textInterpreter
.write(
412 sectionNode
.getProperty(Property
.JCR_TITLE
),
413 txt
.substring(0, caretPosition
));
414 sectionNode
.orderBefore(p(paragraphNode
.getIndex()), p(1));
415 persistChanges(sectionNode
);
417 Paragraph paragraph
= sectionTitleSplitted(sectionTitle
,
422 } catch (RepositoryException e
) {
423 throw new CmsException("Cannot split " + getEdited(), e
);
427 protected void mergeWithPrevious() {
430 Paragraph paragraph
= (Paragraph
) getEdited();
431 Text text
= (Text
) paragraph
.getControl();
432 String txt
= text
.getText();
433 Node paragraphNode
= paragraph
.getNode();
434 if (paragraphNode
.getIndex() == 1)
436 Node sectionNode
= paragraphNode
.getParent();
437 Node previousNode
= sectionNode
438 .getNode(p(paragraphNode
.getIndex() - 1));
439 String previousTxt
= textInterpreter
.read(previousNode
);
440 textInterpreter
.write(previousNode
, previousTxt
+ txt
);
441 paragraphNode
.remove();
442 persistChanges(sectionNode
);
444 Paragraph previousParagraph
= paragraphMergedWithPrevious(
445 paragraph
, previousNode
);
446 edit(previousParagraph
, previousTxt
.length());
447 } catch (RepositoryException e
) {
448 throw new CmsException("Cannot stop editing", e
);
452 protected void mergeWithNext() {
455 Paragraph paragraph
= (Paragraph
) getEdited();
456 Text text
= (Text
) paragraph
.getControl();
457 String txt
= text
.getText();
458 Node paragraphNode
= paragraph
.getNode();
459 Node sectionNode
= paragraphNode
.getParent();
460 NodeIterator paragraphNodes
= sectionNode
.getNodes(CMS_P
);
461 long size
= paragraphNodes
.getSize();
462 if (paragraphNode
.getIndex() == size
)
464 Node nextNode
= sectionNode
465 .getNode(p(paragraphNode
.getIndex() + 1));
466 String nextTxt
= textInterpreter
.read(nextNode
);
467 textInterpreter
.write(paragraphNode
, txt
+ nextTxt
);
469 Section section
= paragraph
.getSection();
470 Paragraph removed
= (Paragraph
) section
.getSectionPart(nextNode
474 persistChanges(sectionNode
);
476 paragraphMergedWithNext(paragraph
, removed
);
477 edit(paragraph
, txt
.length());
478 } catch (RepositoryException e
) {
479 throw new CmsException("Cannot stop editing", e
);
483 protected synchronized void upload(EditablePart part
) {
485 if (part
instanceof SectionPart
) {
486 SectionPart sectionPart
= (SectionPart
) part
;
487 Node partNode
= sectionPart
.getNode();
488 int partIndex
= partNode
.getIndex();
489 Section section
= sectionPart
.getSection();
490 Node sectionNode
= section
.getNode();
492 if (part
instanceof Paragraph
) {
493 Node newNode
= sectionNode
.addNode(CMS_P
, NodeType
.NT_FILE
);
494 newNode
.addNode(Node
.JCR_CONTENT
, NodeType
.NT_RESOURCE
);
495 JcrUtils
.copyBytesAsFile(sectionNode
,
496 p(newNode
.getIndex()), new byte[0]);
497 if (partIndex
< newNode
.getIndex() - 1) {
499 sectionNode
.orderBefore(p(newNode
.getIndex()),
502 // sectionNode.orderBefore(p(partNode.getIndex()),
503 // p(newNode.getIndex()));
504 persistChanges(sectionNode
);
505 Img img
= newImg((TextSection
) section
, newNode
);
507 layout(img
.getControl());
508 } else if (part
instanceof Img
) {
509 if (getEdited() == part
)
512 layout(part
.getControl());
515 } catch (RepositoryException e
) {
516 throw new CmsException("Cannot upload", e
);
520 protected void deepen() {
525 if (getEdited() instanceof Paragraph
) {
526 Paragraph paragraph
= (Paragraph
) getEdited();
527 Text text
= (Text
) paragraph
.getControl();
528 String txt
= text
.getText();
529 Node paragraphNode
= paragraph
.getNode();
530 Section section
= paragraph
.getSection();
531 Node sectionNode
= section
.getNode();
533 if (section
== mainSection
&& section
instanceof TextSection
534 && paragraphNode
.getIndex() == 1
535 && !sectionNode
.hasProperty(JCR_TITLE
)) {
536 SectionTitle sectionTitle
= prepareSectionTitle(section
,
538 edit(sectionTitle
, 0);
541 Node newSectionNode
= sectionNode
.addNode(CMS_H
,
542 CmsTypes
.CMS_SECTION
);
543 sectionNode
.orderBefore(h(newSectionNode
.getIndex()), h(1));
545 int paragraphIndex
= paragraphNode
.getIndex();
546 String sectionPath
= sectionNode
.getPath();
547 String newSectionPath
= newSectionNode
.getPath();
548 while (sectionNode
.hasNode(p(paragraphIndex
+ 1))) {
549 Node parag
= sectionNode
.getNode(p(paragraphIndex
+ 1));
550 sectionNode
.getSession().move(
551 sectionPath
+ '/' + p(paragraphIndex
+ 1),
552 newSectionPath
+ '/' + CMS_P
);
553 SectionPart sp
= section
.getSectionPart(parag
555 if (sp
instanceof Control
)
556 ((Control
) sp
).dispose();
559 newSectionNode
.setProperty(Property
.JCR_TITLE
, "");
560 getTextInterpreter().write(
561 newSectionNode
.getProperty(Property
.JCR_TITLE
), txt
);
563 TextSection newSection
= new TextSection(section
,
564 section
.getStyle(), newSectionNode
);
565 newSection
.setLayoutData(CmsUiUtils
.fillWidth());
566 newSection
.moveBelow(paragraph
);
569 paragraphNode
.remove();
573 newSection
.getParent().layout();
575 persistChanges(sectionNode
);
576 } else if (getEdited() instanceof SectionTitle
) {
577 SectionTitle sectionTitle
= (SectionTitle
) getEdited();
578 Section section
= sectionTitle
.getSection();
579 Section parentSection
= section
.getParentSection();
580 if (parentSection
== null)
581 return;// cannot deepen main section
582 Node sectionN
= section
.getNode();
583 Node parentSectionN
= parentSection
.getNode();
584 if (sectionN
.getIndex() == 1)
585 return;// cannot deepen first section
586 Node previousSectionN
= parentSectionN
.getNode(h(sectionN
588 NodeIterator subSections
= previousSectionN
.getNodes(CMS_H
);
589 int subsectionsCount
= (int) subSections
.getSize();
590 previousSectionN
.getSession().move(
592 previousSectionN
.getPath() + "/"
593 + h(subsectionsCount
+ 1));
595 TextSection newSection
= new TextSection(section
,
596 section
.getStyle(), sectionN
);
598 persistChanges(previousSectionN
);
600 } catch (RepositoryException e
) {
601 throw new CmsException("Cannot deepen " + getEdited(), e
);
605 protected void undeepen() {
610 if (getEdited() instanceof Paragraph
) {
612 } else if (getEdited() instanceof SectionTitle
) {
613 SectionTitle sectionTitle
= (SectionTitle
) getEdited();
614 Section section
= sectionTitle
.getSection();
615 Node sectionNode
= section
.getNode();
616 Section parentSection
= section
.getParentSection();
617 if (parentSection
== null)
618 return;// cannot undeepen main section
620 // choose in which section to merge
621 Section mergedSection
;
622 if (sectionNode
.getIndex() == 1)
623 mergedSection
= section
.getParentSection();
625 Map
<String
, Section
> parentSubsections
= parentSection
627 ArrayList
<Section
> lst
= new ArrayList
<Section
>(
628 parentSubsections
.values());
629 mergedSection
= lst
.get(sectionNode
.getIndex() - 1);
631 Node mergedNode
= mergedSection
.getNode();
632 boolean mergedHasSubSections
= mergedNode
.hasNode(CMS_H
);
634 // title as paragraph
635 Node newParagrapheNode
= mergedNode
.addNode(CMS_P
);
636 newParagrapheNode
.addMixin(CmsTypes
.CMS_STYLED
);
637 if (mergedHasSubSections
)
638 mergedNode
.orderBefore(p(newParagrapheNode
.getIndex()),
640 String txt
= getTextInterpreter().read(
641 sectionNode
.getProperty(Property
.JCR_TITLE
));
642 getTextInterpreter().write(newParagrapheNode
, txt
);
644 NodeIterator paragraphs
= sectionNode
.getNodes(CMS_P
);
645 while (paragraphs
.hasNext()) {
646 Node p
= paragraphs
.nextNode();
647 SectionPart sp
= section
.getSectionPart(p
.getIdentifier());
648 if (sp
instanceof Control
)
649 ((Control
) sp
).dispose();
650 mergedNode
.getSession().move(p
.getPath(),
651 mergedNode
.getPath() + '/' + CMS_P
);
652 if (mergedHasSubSections
)
653 mergedNode
.orderBefore(p(p
.getIndex()), h(1));
656 Iterator
<Section
> subsections
= section
.getSubSections()
657 .values().iterator();
658 // NodeIterator sections = sectionNode.getNodes(CMS_H);
659 while (subsections
.hasNext()) {
660 Section subsection
= subsections
.next();
661 Node s
= subsection
.getNode();
662 mergedNode
.getSession().move(s
.getPath(),
663 mergedNode
.getPath() + '/' + CMS_H
);
664 subsection
.dispose();
668 section
.getNode().remove();
671 refresh(mergedSection
);
672 mergedSection
.getParent().layout();
673 layout(mergedSection
);
674 persistChanges(mergedNode
);
676 } catch (RepositoryException e
) {
677 throw new CmsException("Cannot undeepen " + getEdited(), e
);
682 protected Paragraph
paragraphSplitted(Paragraph paragraph
, Node newNode
)
683 throws RepositoryException
{
684 Section section
= paragraph
.getSection();
685 updateContent(paragraph
);
686 Paragraph newParagraph
= newParagraph((TextSection
) section
, newNode
);
687 newParagraph
.setLayoutData(CmsUiUtils
.fillWidth());
688 newParagraph
.moveBelow(paragraph
);
689 layout(paragraph
.getControl(), newParagraph
.getControl());
693 protected Paragraph
sectionTitleSplitted(SectionTitle sectionTitle
,
694 Node newNode
) throws RepositoryException
{
695 updateContent(sectionTitle
);
696 Paragraph newParagraph
= newParagraph(sectionTitle
.getSection(),
698 // we assume beforeFirst is not null since there was a sectionTitle
699 newParagraph
.moveBelow(sectionTitle
.getSection().getHeader());
700 layout(sectionTitle
.getControl(), newParagraph
.getControl());
704 protected Paragraph
paragraphMergedWithPrevious(Paragraph removed
,
705 Node remaining
) throws RepositoryException
{
706 Section section
= removed
.getSection();
709 Paragraph paragraph
= (Paragraph
) section
.getSectionPart(remaining
711 updateContent(paragraph
);
712 layout(paragraph
.getControl());
716 protected void paragraphMergedWithNext(Paragraph remaining
,
717 Paragraph removed
) throws RepositoryException
{
719 updateContent(remaining
);
720 layout(remaining
.getControl());
724 protected String
p(Integer index
) {
725 StringBuilder sb
= new StringBuilder(6);
726 sb
.append(CMS_P
).append('[').append(index
).append(']');
727 return sb
.toString();
730 protected String
h(Integer index
) {
731 StringBuilder sb
= new StringBuilder(5);
732 sb
.append(CMS_H
).append('[').append(index
).append(']');
733 return sb
.toString();
737 public Section
getMainSection() {
741 public boolean isFlat() {
745 public TextInterpreter
getTextInterpreter() {
746 return textInterpreter
;
751 public void keyPressed(KeyEvent ke
) {
752 if (log
.isTraceEnabled())
755 if (getEdited() == null)
757 boolean altPressed
= (ke
.stateMask
& SWT
.ALT
) != 0;
758 boolean shiftPressed
= (ke
.stateMask
& SWT
.SHIFT
) != 0;
759 boolean ctrlPressed
= (ke
.stateMask
& SWT
.CTRL
) != 0;
763 if (ke
.keyCode
== SWT
.ESC
) {
765 } else if (ke
.character
== '\r') {
767 } else if (ke
.character
== 'S') {
770 } else if (ke
.character
== '\t') {
773 } else if (shiftPressed
) {
777 if (getEdited() instanceof Paragraph
) {
778 Paragraph paragraph
= (Paragraph
) getEdited();
779 Section section
= paragraph
.getSection();
780 if (altPressed
&& ke
.keyCode
== SWT
.ARROW_RIGHT
) {
781 edit(section
.nextSectionPart(paragraph
), 0);
782 } else if (altPressed
&& ke
.keyCode
== SWT
.ARROW_LEFT
) {
783 edit(section
.previousSectionPart(paragraph
), 0);
784 } else if (ke
.character
== SWT
.BS
) {
785 Text text
= (Text
) paragraph
.getControl();
786 int caretPosition
= text
.getCaretPosition();
787 if (caretPosition
== 0) {
790 } else if (ke
.character
== SWT
.DEL
) {
791 Text text
= (Text
) paragraph
.getControl();
792 int caretPosition
= text
.getCaretPosition();
793 int charcount
= text
.getCharCount();
794 if (caretPosition
== charcount
) {
800 } catch (Exception e
) {
802 notifyEditionException(e
);
807 public void keyReleased(KeyEvent e
) {
812 protected MouseListener
createMouseListener() {
816 private class ML
extends MouseAdapter
{
817 private static final long serialVersionUID
= 8526890859876770905L;
820 public void mouseDoubleClick(MouseEvent e
) {
822 Control source
= (Control
) e
.getSource();
823 if (getCmsEditable().canEdit()) {
824 if (getCmsEditable().isEditing()
825 && !(getEdited() instanceof Img
)) {
826 if (source
== mainSection
)
828 EditablePart part
= findDataParent(source
);
831 getCmsEditable().startEditing();
838 public void mouseDown(MouseEvent e
) {
839 if (getCmsEditable().isEditing()) {
841 Control source
= (Control
) e
.getSource();
842 EditablePart composite
= findDataParent(source
);
843 Point point
= new Point(e
.x
, e
.y
);
844 if (!(composite
instanceof Img
))
845 edit(composite
, source
.toDisplay(point
));
846 } else if (e
.button
== 3) {
847 EditablePart composite
= findDataParent((Control
) e
849 if (styledTools
!= null)
850 styledTools
.show(composite
, new Point(e
.x
, e
.y
));
856 public void mouseUp(MouseEvent e
) {
860 // FILE UPLOAD LISTENER
861 private class FUL
implements FileUploadListener
{
862 public void uploadProgress(FileUploadEvent event
) {
863 // TODO Monitor upload progress
866 public void uploadFailed(FileUploadEvent event
) {
867 throw new CmsException("Upload failed " + event
,
868 event
.getException());
871 public void uploadFinished(FileUploadEvent event
) {
872 for (FileDetails file
: event
.getFileDetails()) {
873 if (log
.isDebugEnabled())
874 log
.debug("Received: " + file
.getFileName());
876 mainSection
.getDisplay().syncExec(new Runnable() {
882 FileUploadHandler uploadHandler
= (FileUploadHandler
) event
884 uploadHandler
.dispose();