]> git.argeo.org Git - gpl/argeo-suite.git/blob - publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/AbstractTextViewer.java
Use released Argeo Commons.
[gpl/argeo-suite.git] / publishing / org.argeo.publishing.ui / src / org / argeo / cms / text / AbstractTextViewer.java
1 package org.argeo.cms.text;
2
3 import static javax.jcr.Property.JCR_TITLE;
4 import static org.argeo.cms.ui.util.CmsUiUtils.fillWidth;
5
6 import java.util.ArrayList;
7 import java.util.Iterator;
8 import java.util.Map;
9 import java.util.Observer;
10
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;
18
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;
51
52 /** Base class for text viewers and editors. */
53 @Deprecated
54 public abstract class AbstractTextViewer extends AbstractPageViewer implements
55 CmsNames, KeyListener, Observer {
56 private static final long serialVersionUID = -2401274679492339668L;
57 private final static Log log = LogFactory.getLog(AbstractTextViewer.class);
58
59 private final Section mainSection;
60
61 private TextInterpreter textInterpreter = new TextInterpreterImpl();
62 private CmsImageManager imageManager = CmsUiUtils.getCmsView()
63 .getImageManager();
64
65 private FileUploadListener fileUploadListener;
66 private TextContextMenu styledTools;
67
68 private final boolean flat;
69
70 protected AbstractTextViewer(Section parent, int style,
71 CmsEditable cmsEditable) {
72 super(parent, style, cmsEditable);
73 flat = SWT.FLAT == (style & SWT.FLAT);
74
75 if (getCmsEditable().canEdit()) {
76 fileUploadListener = new FUL();
77 styledTools = new TextContextMenu(this, parent.getDisplay());
78 }
79 this.mainSection = parent;
80 initModelIfNeeded(mainSection.getNode());
81 // layout(this.mainSection);
82 }
83
84 @Override
85 public Control getControl() {
86 return mainSection;
87 }
88
89 protected void refresh(Control control) throws RepositoryException {
90 if (!(control instanceof Section))
91 return;
92 Section section = (Section) control;
93 if (section instanceof TextSection) {
94 CmsUiUtils.clear(section);
95 Node node = section.getNode();
96 TextSection textSection = (TextSection) section;
97 if (node.hasProperty(Property.JCR_TITLE)) {
98 if (section.getHeader() == null)
99 section.createHeader();
100 if (node.hasProperty(Property.JCR_TITLE)) {
101 SectionTitle title = newSectionTitle(textSection, node);
102 title.setLayoutData(CmsUiUtils.fillWidth());
103 updateContent(title);
104 }
105 }
106
107 for (NodeIterator ni = node.getNodes(CMS_P); ni.hasNext();) {
108 Node child = ni.nextNode();
109 final SectionPart sectionPart;
110 if (child.isNodeType(CmsTypes.CMS_IMAGE)
111 || child.isNodeType(NodeType.NT_FILE)) {
112 sectionPart = newImg(textSection, child);
113 } else if (child.isNodeType(CmsTypes.CMS_STYLED)) {
114 sectionPart = newParagraph(textSection, child);
115 } else {
116 sectionPart = newSectionPart(textSection, child);
117 if (sectionPart == null)
118 throw new CmsException("Unsupported node " + child);
119 // TODO list node types in exception
120 }
121 if (sectionPart instanceof Control)
122 ((Control) sectionPart).setLayoutData(CmsUiUtils.fillWidth());
123 }
124
125 if (!flat)
126 for (NodeIterator ni = section.getNode().getNodes(CMS_H); ni
127 .hasNext();) {
128 Node child = ni.nextNode();
129 if (child.isNodeType(CmsTypes.CMS_SECTION)) {
130 TextSection newSection = new TextSection(section,
131 SWT.NONE, child);
132 newSection.setLayoutData(CmsUiUtils.fillWidth());
133 refresh(newSection);
134 }
135 }
136 } else {
137 for (Section s : section.getSubSections().values())
138 refresh(s);
139 }
140 // section.layout();
141 }
142
143 /** To be overridden in order to provide additional SectionPart types */
144 protected SectionPart newSectionPart(TextSection textSection, Node node) {
145 return null;
146 }
147
148 // CRUD
149 protected Paragraph newParagraph(TextSection parent, Node node)
150 throws RepositoryException {
151 Paragraph paragraph = new Paragraph(parent, parent.getStyle(), node);
152 updateContent(paragraph);
153 paragraph.setLayoutData(fillWidth());
154 paragraph.setMouseListener(getMouseListener());
155 return paragraph;
156 }
157
158 protected Img newImg(TextSection parent, Node node)
159 throws RepositoryException {
160 Img img = new Img(parent, parent.getStyle(), node) {
161 private static final long serialVersionUID = 1297900641952417540L;
162
163 @Override
164 protected void setContainerLayoutData(Composite composite) {
165 composite.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER,
166 SWT.DEFAULT));
167 }
168
169 @Override
170 protected void setControlLayoutData(Control control) {
171 control.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER,
172 SWT.DEFAULT));
173 }
174 };
175 img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
176 updateContent(img);
177 img.setMouseListener(getMouseListener());
178 return img;
179 }
180
181 protected SectionTitle newSectionTitle(TextSection parent, Node node)
182 throws RepositoryException {
183 SectionTitle title = new SectionTitle(parent.getHeader(),
184 parent.getStyle(), node.getProperty(JCR_TITLE));
185 updateContent(title);
186 title.setMouseListener(getMouseListener());
187 return title;
188 }
189
190 protected SectionTitle prepareSectionTitle(Section newSection,
191 String titleText) throws RepositoryException {
192 Node sectionNode = newSection.getNode();
193 if (!sectionNode.hasProperty(JCR_TITLE))
194 sectionNode.setProperty(Property.JCR_TITLE, "");
195 getTextInterpreter().write(sectionNode.getProperty(Property.JCR_TITLE),
196 titleText);
197 if (newSection.getHeader() == null)
198 newSection.createHeader();
199 SectionTitle sectionTitle = newSectionTitle((TextSection) newSection,
200 sectionNode);
201 return sectionTitle;
202 }
203
204 protected void updateContent(EditablePart part) throws RepositoryException {
205 if (part instanceof SectionPart) {
206 SectionPart sectionPart = (SectionPart) part;
207 Node partNode = sectionPart.getNode();
208
209 if (part instanceof StyledControl
210 && (sectionPart.getSection() instanceof TextSection)) {
211 TextSection section = (TextSection) sectionPart.getSection();
212 StyledControl styledControl = (StyledControl) part;
213 if (partNode.isNodeType(CmsTypes.CMS_STYLED)) {
214 String style = partNode.hasProperty(CMS_STYLE) ? partNode
215 .getProperty(CMS_STYLE).getString() : section
216 .getDefaultTextStyle();
217 styledControl.setStyle(style);
218 }
219 }
220 // use control AFTER setting style, since it may have been reset
221
222 if (part instanceof EditableText) {
223 EditableText paragraph = (EditableText) part;
224 if (paragraph == getEdited())
225 paragraph.setText(textInterpreter.read(partNode));
226 else
227 paragraph.setText(textInterpreter.raw(partNode));
228 } else if (part instanceof EditableImage) {
229 EditableImage editableImage = (EditableImage) part;
230 imageManager.load(partNode, part.getControl(),
231 editableImage.getPreferredImageSize());
232 }
233 } else if (part instanceof SectionTitle) {
234 SectionTitle title = (SectionTitle) part;
235 title.setStyle(title.getSection().getTitleStyle());
236 // use control AFTER setting style
237 if (title == getEdited())
238 title.setText(textInterpreter.read(title.getProperty()));
239 else
240 title.setText(textInterpreter.raw(title.getProperty()));
241 }
242 }
243
244 // OVERRIDDEN FROM PARENT VIEWER
245 @Override
246 protected void save(EditablePart part) throws RepositoryException {
247 if (part instanceof EditableText) {
248 EditableText et = (EditableText) part;
249 String text = ((Text) et.getControl()).getText();
250
251 String[] lines = text.split("[\r\n]+");
252 assert lines.length != 0;
253 saveLine(part, lines[0]);
254 if (lines.length > 1) {
255 ArrayList<Control> toLayout = new ArrayList<Control>();
256 if (part instanceof Paragraph) {
257 Paragraph currentParagraph = (Paragraph) et;
258 Section section = currentParagraph.getSection();
259 Node sectionNode = section.getNode();
260 Node currentParagraphN = currentParagraph.getNode();
261 for (int i = 1; i < lines.length; i++) {
262 Node newNode = sectionNode.addNode(CMS_P);
263 newNode.addMixin(CmsTypes.CMS_STYLED);
264 saveLine(newNode, lines[i]);
265 // second node was create as last, if it is not the next
266 // one, it
267 // means there are some in between and we can take the
268 // one at
269 // index+1 for the re-order
270 if (newNode.getIndex() > currentParagraphN.getIndex() + 1) {
271 sectionNode.orderBefore(p(newNode.getIndex()),
272 p(currentParagraphN.getIndex() + 1));
273 }
274 Paragraph newParagraph = newParagraph(
275 (TextSection) section, newNode);
276 newParagraph.moveBelow(currentParagraph);
277 toLayout.add(newParagraph);
278
279 currentParagraph = newParagraph;
280 currentParagraphN = newNode;
281 }
282 persistChanges(sectionNode);
283 }
284 // TODO or rather return the created paragarphs?
285 layout(toLayout.toArray(new Control[toLayout.size()]));
286 }
287 }
288 }
289
290 protected void saveLine(EditablePart part, String line) {
291 if (part instanceof NodePart) {
292 saveLine(((NodePart) part).getNode(), line);
293 } else if (part instanceof PropertyPart) {
294 saveLine(((PropertyPart) part).getProperty(), line);
295 } else {
296 throw new CmsException("Unsupported part " + part);
297 }
298 }
299
300 protected void saveLine(Item item, String line) {
301 line = line.trim();
302 textInterpreter.write(item, line);
303 }
304
305 @Override
306 protected void prepare(EditablePart part, Object caretPosition) {
307 Control control = part.getControl();
308 if (control instanceof Text) {
309 Text text = (Text) control;
310 if (caretPosition != null)
311 if (caretPosition instanceof Integer)
312 text.setSelection((Integer) caretPosition);
313 else if (caretPosition instanceof Point) {
314 // TODO find a way to position the caret at the right place
315 }
316 text.setData(RWT.ACTIVE_KEYS, new String[] { "BACKSPACE", "ESC",
317 "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT",
318 "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN",
319 "ENTER", "DELETE" });
320 text.setData(RWT.CANCEL_KEYS, new String[] { "RETURN",
321 "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
322 text.addKeyListener(this);
323 } else if (part instanceof Img) {
324 ((Img) part).setFileUploadListener(fileUploadListener);
325 }
326 }
327
328 // REQUIRED BY CONTEXT MENU
329 void setParagraphStyle(Paragraph paragraph, String style) {
330 try {
331 Node paragraphNode = paragraph.getNode();
332 paragraphNode.setProperty(CMS_STYLE, style);
333 persistChanges(paragraphNode);
334 updateContent(paragraph);
335 layout(paragraph);
336 } catch (RepositoryException e1) {
337 throw new CmsException("Cannot set style " + style + " on "
338 + paragraph, e1);
339 }
340 }
341
342 void deletePart(SectionPart paragraph) {
343 try {
344 Node paragraphNode = paragraph.getNode();
345 Section section = paragraph.getSection();
346 Session session = paragraphNode.getSession();
347 paragraphNode.remove();
348 session.save();
349 if (paragraph instanceof Control)
350 ((Control) paragraph).dispose();
351 layout(section);
352 } catch (RepositoryException e1) {
353 throw new CmsException("Cannot delete " + paragraph, e1);
354 }
355 }
356
357 String getRawParagraphText(Paragraph paragraph) {
358 return textInterpreter.raw(paragraph.getNode());
359 }
360
361 // COMMANDS
362 protected void splitEdit() {
363 checkEdited();
364 try {
365 if (getEdited() instanceof Paragraph) {
366 Paragraph paragraph = (Paragraph) getEdited();
367 Text text = (Text) paragraph.getControl();
368 int caretPosition = text.getCaretPosition();
369 String txt = text.getText();
370 String first = txt.substring(0, caretPosition);
371 String second = txt.substring(caretPosition);
372 Node firstNode = paragraph.getNode();
373 Node sectionNode = firstNode.getParent();
374 firstNode.setProperty(CMS_CONTENT, first);
375 Node secondNode = sectionNode.addNode(CMS_P);
376 secondNode.addMixin(CmsTypes.CMS_STYLED);
377 // second node was create as last, if it is not the next one, it
378 // means there are some in between and we can take the one at
379 // index+1 for the re-order
380 if (secondNode.getIndex() > firstNode.getIndex() + 1) {
381 sectionNode.orderBefore(p(secondNode.getIndex()),
382 p(firstNode.getIndex() + 1));
383 }
384
385 // if we die in between, at least we still have the whole text
386 // in the first node
387 try {
388 textInterpreter.write(secondNode, second);
389 textInterpreter.write(firstNode, first);
390 } catch (Exception e) {
391 // so that no additional nodes are created:
392 JcrUtils.discardUnderlyingSessionQuietly(firstNode);
393 throw e;
394 }
395
396 persistChanges(firstNode);
397
398 Paragraph secondParagraph = paragraphSplitted(paragraph,
399 secondNode);
400 edit(secondParagraph, 0);
401 } else if (getEdited() instanceof SectionTitle) {
402 SectionTitle sectionTitle = (SectionTitle) getEdited();
403 Text text = (Text) sectionTitle.getControl();
404 String txt = text.getText();
405 int caretPosition = text.getCaretPosition();
406 Section section = sectionTitle.getSection();
407 Node sectionNode = section.getNode();
408 Node paragraphNode = sectionNode.addNode(CMS_P);
409 paragraphNode.addMixin(CmsTypes.CMS_STYLED);
410 textInterpreter.write(paragraphNode,
411 txt.substring(caretPosition));
412 textInterpreter.write(
413 sectionNode.getProperty(Property.JCR_TITLE),
414 txt.substring(0, caretPosition));
415 sectionNode.orderBefore(p(paragraphNode.getIndex()), p(1));
416 persistChanges(sectionNode);
417
418 Paragraph paragraph = sectionTitleSplitted(sectionTitle,
419 paragraphNode);
420 // section.layout();
421 edit(paragraph, 0);
422 }
423 } catch (RepositoryException e) {
424 throw new CmsException("Cannot split " + getEdited(), e);
425 }
426 }
427
428 protected void mergeWithPrevious() {
429 checkEdited();
430 try {
431 Paragraph paragraph = (Paragraph) getEdited();
432 Text text = (Text) paragraph.getControl();
433 String txt = text.getText();
434 Node paragraphNode = paragraph.getNode();
435 if (paragraphNode.getIndex() == 1)
436 return;// do nothing
437 Node sectionNode = paragraphNode.getParent();
438 Node previousNode = sectionNode
439 .getNode(p(paragraphNode.getIndex() - 1));
440 String previousTxt = textInterpreter.read(previousNode);
441 textInterpreter.write(previousNode, previousTxt + txt);
442 paragraphNode.remove();
443 persistChanges(sectionNode);
444
445 Paragraph previousParagraph = paragraphMergedWithPrevious(
446 paragraph, previousNode);
447 edit(previousParagraph, previousTxt.length());
448 } catch (RepositoryException e) {
449 throw new CmsException("Cannot stop editing", e);
450 }
451 }
452
453 protected void mergeWithNext() {
454 checkEdited();
455 try {
456 Paragraph paragraph = (Paragraph) getEdited();
457 Text text = (Text) paragraph.getControl();
458 String txt = text.getText();
459 Node paragraphNode = paragraph.getNode();
460 Node sectionNode = paragraphNode.getParent();
461 NodeIterator paragraphNodes = sectionNode.getNodes(CMS_P);
462 long size = paragraphNodes.getSize();
463 if (paragraphNode.getIndex() == size)
464 return;// do nothing
465 Node nextNode = sectionNode
466 .getNode(p(paragraphNode.getIndex() + 1));
467 String nextTxt = textInterpreter.read(nextNode);
468 textInterpreter.write(paragraphNode, txt + nextTxt);
469
470 Section section = paragraph.getSection();
471 Paragraph removed = (Paragraph) section.getSectionPart(nextNode
472 .getIdentifier());
473
474 nextNode.remove();
475 persistChanges(sectionNode);
476
477 paragraphMergedWithNext(paragraph, removed);
478 edit(paragraph, txt.length());
479 } catch (RepositoryException e) {
480 throw new CmsException("Cannot stop editing", e);
481 }
482 }
483
484 protected synchronized void upload(EditablePart part) {
485 try {
486 if (part instanceof SectionPart) {
487 SectionPart sectionPart = (SectionPart) part;
488 Node partNode = sectionPart.getNode();
489 int partIndex = partNode.getIndex();
490 Section section = sectionPart.getSection();
491 Node sectionNode = section.getNode();
492
493 if (part instanceof Paragraph) {
494 Node newNode = sectionNode.addNode(CMS_P, NodeType.NT_FILE);
495 newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
496 JcrUtils.copyBytesAsFile(sectionNode,
497 p(newNode.getIndex()), new byte[0]);
498 if (partIndex < newNode.getIndex() - 1) {
499 // was not last
500 sectionNode.orderBefore(p(newNode.getIndex()),
501 p(partIndex - 1));
502 }
503 // sectionNode.orderBefore(p(partNode.getIndex()),
504 // p(newNode.getIndex()));
505 persistChanges(sectionNode);
506 Img img = newImg((TextSection) section, newNode);
507 edit(img, null);
508 layout(img.getControl());
509 } else if (part instanceof Img) {
510 if (getEdited() == part)
511 return;
512 edit(part, null);
513 layout(part.getControl());
514 }
515 }
516 } catch (RepositoryException e) {
517 throw new CmsException("Cannot upload", e);
518 }
519 }
520
521 protected void deepen() {
522 if (flat)
523 return;
524 checkEdited();
525 try {
526 if (getEdited() instanceof Paragraph) {
527 Paragraph paragraph = (Paragraph) getEdited();
528 Text text = (Text) paragraph.getControl();
529 String txt = text.getText();
530 Node paragraphNode = paragraph.getNode();
531 Section section = paragraph.getSection();
532 Node sectionNode = section.getNode();
533 // main title
534 if (section == mainSection && section instanceof TextSection
535 && paragraphNode.getIndex() == 1
536 && !sectionNode.hasProperty(JCR_TITLE)) {
537 SectionTitle sectionTitle = prepareSectionTitle(section,
538 txt);
539 edit(sectionTitle, 0);
540 return;
541 }
542 Node newSectionNode = sectionNode.addNode(CMS_H,
543 CmsTypes.CMS_SECTION);
544 sectionNode.orderBefore(h(newSectionNode.getIndex()), h(1));
545
546 int paragraphIndex = paragraphNode.getIndex();
547 String sectionPath = sectionNode.getPath();
548 String newSectionPath = newSectionNode.getPath();
549 while (sectionNode.hasNode(p(paragraphIndex + 1))) {
550 Node parag = sectionNode.getNode(p(paragraphIndex + 1));
551 sectionNode.getSession().move(
552 sectionPath + '/' + p(paragraphIndex + 1),
553 newSectionPath + '/' + CMS_P);
554 SectionPart sp = section.getSectionPart(parag
555 .getIdentifier());
556 if (sp instanceof Control)
557 ((Control) sp).dispose();
558 }
559 // create property
560 newSectionNode.setProperty(Property.JCR_TITLE, "");
561 getTextInterpreter().write(
562 newSectionNode.getProperty(Property.JCR_TITLE), txt);
563
564 TextSection newSection = new TextSection(section,
565 section.getStyle(), newSectionNode);
566 newSection.setLayoutData(CmsUiUtils.fillWidth());
567 newSection.moveBelow(paragraph);
568
569 // dispose
570 paragraphNode.remove();
571 paragraph.dispose();
572
573 refresh(newSection);
574 newSection.getParent().layout();
575 layout(newSection);
576 persistChanges(sectionNode);
577 } else if (getEdited() instanceof SectionTitle) {
578 SectionTitle sectionTitle = (SectionTitle) getEdited();
579 Section section = sectionTitle.getSection();
580 Section parentSection = section.getParentSection();
581 if (parentSection == null)
582 return;// cannot deepen main section
583 Node sectionN = section.getNode();
584 Node parentSectionN = parentSection.getNode();
585 if (sectionN.getIndex() == 1)
586 return;// cannot deepen first section
587 Node previousSectionN = parentSectionN.getNode(h(sectionN
588 .getIndex() - 1));
589 NodeIterator subSections = previousSectionN.getNodes(CMS_H);
590 int subsectionsCount = (int) subSections.getSize();
591 previousSectionN.getSession().move(
592 sectionN.getPath(),
593 previousSectionN.getPath() + "/"
594 + h(subsectionsCount + 1));
595 section.dispose();
596 TextSection newSection = new TextSection(section,
597 section.getStyle(), sectionN);
598 refresh(newSection);
599 persistChanges(previousSectionN);
600 }
601 } catch (RepositoryException e) {
602 throw new CmsException("Cannot deepen " + getEdited(), e);
603 }
604 }
605
606 protected void undeepen() {
607 if (flat)
608 return;
609 checkEdited();
610 try {
611 if (getEdited() instanceof Paragraph) {
612 upload(getEdited());
613 } else if (getEdited() instanceof SectionTitle) {
614 SectionTitle sectionTitle = (SectionTitle) getEdited();
615 Section section = sectionTitle.getSection();
616 Node sectionNode = section.getNode();
617 Section parentSection = section.getParentSection();
618 if (parentSection == null)
619 return;// cannot undeepen main section
620
621 // choose in which section to merge
622 Section mergedSection;
623 if (sectionNode.getIndex() == 1)
624 mergedSection = section.getParentSection();
625 else {
626 Map<String, Section> parentSubsections = parentSection
627 .getSubSections();
628 ArrayList<Section> lst = new ArrayList<Section>(
629 parentSubsections.values());
630 mergedSection = lst.get(sectionNode.getIndex() - 1);
631 }
632 Node mergedNode = mergedSection.getNode();
633 boolean mergedHasSubSections = mergedNode.hasNode(CMS_H);
634
635 // title as paragraph
636 Node newParagrapheNode = mergedNode.addNode(CMS_P);
637 newParagrapheNode.addMixin(CmsTypes.CMS_STYLED);
638 if (mergedHasSubSections)
639 mergedNode.orderBefore(p(newParagrapheNode.getIndex()),
640 h(1));
641 String txt = getTextInterpreter().read(
642 sectionNode.getProperty(Property.JCR_TITLE));
643 getTextInterpreter().write(newParagrapheNode, txt);
644 // move
645 NodeIterator paragraphs = sectionNode.getNodes(CMS_P);
646 while (paragraphs.hasNext()) {
647 Node p = paragraphs.nextNode();
648 SectionPart sp = section.getSectionPart(p.getIdentifier());
649 if (sp instanceof Control)
650 ((Control) sp).dispose();
651 mergedNode.getSession().move(p.getPath(),
652 mergedNode.getPath() + '/' + CMS_P);
653 if (mergedHasSubSections)
654 mergedNode.orderBefore(p(p.getIndex()), h(1));
655 }
656
657 Iterator<Section> subsections = section.getSubSections()
658 .values().iterator();
659 // NodeIterator sections = sectionNode.getNodes(CMS_H);
660 while (subsections.hasNext()) {
661 Section subsection = subsections.next();
662 Node s = subsection.getNode();
663 mergedNode.getSession().move(s.getPath(),
664 mergedNode.getPath() + '/' + CMS_H);
665 subsection.dispose();
666 }
667
668 // remove section
669 section.getNode().remove();
670 section.dispose();
671
672 refresh(mergedSection);
673 mergedSection.getParent().layout();
674 layout(mergedSection);
675 persistChanges(mergedNode);
676 }
677 } catch (RepositoryException e) {
678 throw new CmsException("Cannot undeepen " + getEdited(), e);
679 }
680 }
681
682 // UI CHANGES
683 protected Paragraph paragraphSplitted(Paragraph paragraph, Node newNode)
684 throws RepositoryException {
685 Section section = paragraph.getSection();
686 updateContent(paragraph);
687 Paragraph newParagraph = newParagraph((TextSection) section, newNode);
688 newParagraph.setLayoutData(CmsUiUtils.fillWidth());
689 newParagraph.moveBelow(paragraph);
690 layout(paragraph.getControl(), newParagraph.getControl());
691 return newParagraph;
692 }
693
694 protected Paragraph sectionTitleSplitted(SectionTitle sectionTitle,
695 Node newNode) throws RepositoryException {
696 updateContent(sectionTitle);
697 Paragraph newParagraph = newParagraph(sectionTitle.getSection(),
698 newNode);
699 // we assume beforeFirst is not null since there was a sectionTitle
700 newParagraph.moveBelow(sectionTitle.getSection().getHeader());
701 layout(sectionTitle.getControl(), newParagraph.getControl());
702 return newParagraph;
703 }
704
705 protected Paragraph paragraphMergedWithPrevious(Paragraph removed,
706 Node remaining) throws RepositoryException {
707 Section section = removed.getSection();
708 removed.dispose();
709
710 Paragraph paragraph = (Paragraph) section.getSectionPart(remaining
711 .getIdentifier());
712 updateContent(paragraph);
713 layout(paragraph.getControl());
714 return paragraph;
715 }
716
717 protected void paragraphMergedWithNext(Paragraph remaining,
718 Paragraph removed) throws RepositoryException {
719 removed.dispose();
720 updateContent(remaining);
721 layout(remaining.getControl());
722 }
723
724 // UTILITIES
725 protected String p(Integer index) {
726 StringBuilder sb = new StringBuilder(6);
727 sb.append(CMS_P).append('[').append(index).append(']');
728 return sb.toString();
729 }
730
731 protected String h(Integer index) {
732 StringBuilder sb = new StringBuilder(5);
733 sb.append(CMS_H).append('[').append(index).append(']');
734 return sb.toString();
735 }
736
737 // GETTERS / SETTERS
738 public Section getMainSection() {
739 return mainSection;
740 }
741
742 public boolean isFlat() {
743 return flat;
744 }
745
746 public TextInterpreter getTextInterpreter() {
747 return textInterpreter;
748 }
749
750 // KEY LISTENER
751 @Override
752 public void keyPressed(KeyEvent ke) {
753 if (log.isTraceEnabled())
754 log.trace(ke);
755
756 if (getEdited() == null)
757 return;
758 boolean altPressed = (ke.stateMask & SWT.ALT) != 0;
759 boolean shiftPressed = (ke.stateMask & SWT.SHIFT) != 0;
760 boolean ctrlPressed = (ke.stateMask & SWT.CTRL) != 0;
761
762 try {
763 // Common
764 if (ke.keyCode == SWT.ESC) {
765 cancelEdit();
766 } else if (ke.character == '\r') {
767 splitEdit();
768 } else if (ke.character == 'S') {
769 if (ctrlPressed)
770 saveEdit();
771 } else if (ke.character == '\t') {
772 if (!shiftPressed) {
773 deepen();
774 } else if (shiftPressed) {
775 undeepen();
776 }
777 } else {
778 if (getEdited() instanceof Paragraph) {
779 Paragraph paragraph = (Paragraph) getEdited();
780 Section section = paragraph.getSection();
781 if (altPressed && ke.keyCode == SWT.ARROW_RIGHT) {
782 edit(section.nextSectionPart(paragraph), 0);
783 } else if (altPressed && ke.keyCode == SWT.ARROW_LEFT) {
784 edit(section.previousSectionPart(paragraph), 0);
785 } else if (ke.character == SWT.BS) {
786 Text text = (Text) paragraph.getControl();
787 int caretPosition = text.getCaretPosition();
788 if (caretPosition == 0) {
789 mergeWithPrevious();
790 }
791 } else if (ke.character == SWT.DEL) {
792 Text text = (Text) paragraph.getControl();
793 int caretPosition = text.getCaretPosition();
794 int charcount = text.getCharCount();
795 if (caretPosition == charcount) {
796 mergeWithNext();
797 }
798 }
799 }
800 }
801 } catch (Exception e) {
802 ke.doit = false;
803 notifyEditionException(e);
804 }
805 }
806
807 @Override
808 public void keyReleased(KeyEvent e) {
809 }
810
811 // MOUSE LISTENER
812 @Override
813 protected MouseListener createMouseListener() {
814 return new ML();
815 }
816
817 private class ML extends MouseAdapter {
818 private static final long serialVersionUID = 8526890859876770905L;
819
820 @Override
821 public void mouseDoubleClick(MouseEvent e) {
822 if (e.button == 1) {
823 Control source = (Control) e.getSource();
824 if (getCmsEditable().canEdit()) {
825 if (getCmsEditable().isEditing()
826 && !(getEdited() instanceof Img)) {
827 if (source == mainSection)
828 return;
829 EditablePart part = findDataParent(source);
830 upload(part);
831 } else {
832 getCmsEditable().startEditing();
833 }
834 }
835 }
836 }
837
838 @Override
839 public void mouseDown(MouseEvent e) {
840 if (getCmsEditable().isEditing()) {
841 if (e.button == 1) {
842 Control source = (Control) e.getSource();
843 EditablePart composite = findDataParent(source);
844 Point point = new Point(e.x, e.y);
845 if (!(composite instanceof Img))
846 edit(composite, source.toDisplay(point));
847 } else if (e.button == 3) {
848 EditablePart composite = findDataParent((Control) e
849 .getSource());
850 if (styledTools != null)
851 styledTools.show(composite, new Point(e.x, e.y));
852 }
853 }
854 }
855
856 @Override
857 public void mouseUp(MouseEvent e) {
858 }
859 }
860
861 // FILE UPLOAD LISTENER
862 private class FUL implements FileUploadListener {
863 public void uploadProgress(FileUploadEvent event) {
864 // TODO Monitor upload progress
865 }
866
867 public void uploadFailed(FileUploadEvent event) {
868 throw new CmsException("Upload failed " + event,
869 event.getException());
870 }
871
872 public void uploadFinished(FileUploadEvent event) {
873 for (FileDetails file : event.getFileDetails()) {
874 if (log.isDebugEnabled())
875 log.debug("Received: " + file.getFileName());
876 }
877 mainSection.getDisplay().syncExec(new Runnable() {
878 @Override
879 public void run() {
880 saveEdit();
881 }
882 });
883 FileUploadHandler uploadHandler = (FileUploadHandler) event
884 .getSource();
885 uploadHandler.dispose();
886 }
887 }
888 }