X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=publishing%2Forg.argeo.publishing.ui%2Fsrc%2Forg%2Fargeo%2Fcms%2Ftext%2FAbstractTextViewer.java;fp=publishing%2Forg.argeo.publishing.ui%2Fsrc%2Forg%2Fargeo%2Fcms%2Ftext%2FAbstractTextViewer.java;h=c0a35d8817bff2d4b65e74c23c36ce4e278f1d95;hb=147ada7da5bf6292569f17a53a77fca04c97f707;hp=0000000000000000000000000000000000000000;hpb=5431f941fd6161e89f495a330c2ecddaf4f6bfb1;p=gpl%2Fargeo-suite.git diff --git a/publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/AbstractTextViewer.java b/publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/AbstractTextViewer.java new file mode 100644 index 0000000..c0a35d8 --- /dev/null +++ b/publishing/org.argeo.publishing.ui/src/org/argeo/cms/text/AbstractTextViewer.java @@ -0,0 +1,887 @@ +package org.argeo.cms.text; + +import static javax.jcr.Property.JCR_TITLE; +import static org.argeo.cms.ui.util.CmsUiUtils.fillWidth; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; +import java.util.Observer; + +import javax.jcr.Item; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.cms.CmsException; +import org.argeo.cms.ui.CmsEditable; +import org.argeo.cms.ui.CmsImageManager; +import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.ui.viewers.AbstractPageViewer; +import org.argeo.cms.ui.viewers.EditablePart; +import org.argeo.cms.ui.viewers.NodePart; +import org.argeo.cms.ui.viewers.PropertyPart; +import org.argeo.cms.ui.viewers.Section; +import org.argeo.cms.ui.viewers.SectionPart; +import org.argeo.cms.ui.widgets.EditableImage; +import org.argeo.cms.ui.widgets.EditableText; +import org.argeo.cms.ui.widgets.Img; +import org.argeo.cms.ui.widgets.StyledControl; +import org.argeo.jcr.JcrUtils; +import org.eclipse.rap.fileupload.FileDetails; +import org.eclipse.rap.fileupload.FileUploadEvent; +import org.eclipse.rap.fileupload.FileUploadHandler; +import org.eclipse.rap.fileupload.FileUploadListener; +import org.eclipse.rap.rwt.RWT; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Text; + +/** Base class for text viewers and editors. */ +public abstract class AbstractTextViewer extends AbstractPageViewer implements + CmsNames, KeyListener, Observer { + private static final long serialVersionUID = -2401274679492339668L; + private final static Log log = LogFactory.getLog(AbstractTextViewer.class); + + private final Section mainSection; + + private TextInterpreter textInterpreter = new TextInterpreterImpl(); + private CmsImageManager imageManager = CmsUiUtils.getCmsView() + .getImageManager(); + + private FileUploadListener fileUploadListener; + private TextContextMenu styledTools; + + private final boolean flat; + + protected AbstractTextViewer(Section parent, int style, + CmsEditable cmsEditable) { + super(parent, style, cmsEditable); + flat = SWT.FLAT == (style & SWT.FLAT); + + if (getCmsEditable().canEdit()) { + fileUploadListener = new FUL(); + styledTools = new TextContextMenu(this, parent.getDisplay()); + } + this.mainSection = parent; + initModelIfNeeded(mainSection.getNode()); + // layout(this.mainSection); + } + + @Override + public Control getControl() { + return mainSection; + } + + protected void refresh(Control control) throws RepositoryException { + if (!(control instanceof Section)) + return; + Section section = (Section) control; + if (section instanceof TextSection) { + CmsUiUtils.clear(section); + Node node = section.getNode(); + TextSection textSection = (TextSection) section; + if (node.hasProperty(Property.JCR_TITLE)) { + if (section.getHeader() == null) + section.createHeader(); + if (node.hasProperty(Property.JCR_TITLE)) { + SectionTitle title = newSectionTitle(textSection, node); + title.setLayoutData(CmsUiUtils.fillWidth()); + updateContent(title); + } + } + + for (NodeIterator ni = node.getNodes(CMS_P); ni.hasNext();) { + Node child = ni.nextNode(); + final SectionPart sectionPart; + if (child.isNodeType(CmsTypes.CMS_IMAGE) + || child.isNodeType(NodeType.NT_FILE)) { + sectionPart = newImg(textSection, child); + } else if (child.isNodeType(CmsTypes.CMS_STYLED)) { + sectionPart = newParagraph(textSection, child); + } else { + sectionPart = newSectionPart(textSection, child); + if (sectionPart == null) + throw new CmsException("Unsupported node " + child); + // TODO list node types in exception + } + if (sectionPart instanceof Control) + ((Control) sectionPart).setLayoutData(CmsUiUtils.fillWidth()); + } + + if (!flat) + for (NodeIterator ni = section.getNode().getNodes(CMS_H); ni + .hasNext();) { + Node child = ni.nextNode(); + if (child.isNodeType(CmsTypes.CMS_SECTION)) { + TextSection newSection = new TextSection(section, + SWT.NONE, child); + newSection.setLayoutData(CmsUiUtils.fillWidth()); + refresh(newSection); + } + } + } else { + for (Section s : section.getSubSections().values()) + refresh(s); + } + // section.layout(); + } + + /** To be overridden in order to provide additional SectionPart types */ + protected SectionPart newSectionPart(TextSection textSection, Node node) { + return null; + } + + // CRUD + protected Paragraph newParagraph(TextSection parent, Node node) + throws RepositoryException { + Paragraph paragraph = new Paragraph(parent, parent.getStyle(), node); + updateContent(paragraph); + paragraph.setLayoutData(fillWidth()); + paragraph.setMouseListener(getMouseListener()); + return paragraph; + } + + protected Img newImg(TextSection parent, Node node) + throws RepositoryException { + Img img = new Img(parent, parent.getStyle(), node) { + private static final long serialVersionUID = 1297900641952417540L; + + @Override + protected void setContainerLayoutData(Composite composite) { + composite.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, + SWT.DEFAULT)); + } + + @Override + protected void setControlLayoutData(Control control) { + control.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, + SWT.DEFAULT)); + } + }; + img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); + updateContent(img); + img.setMouseListener(getMouseListener()); + return img; + } + + protected SectionTitle newSectionTitle(TextSection parent, Node node) + throws RepositoryException { + SectionTitle title = new SectionTitle(parent.getHeader(), + parent.getStyle(), node.getProperty(JCR_TITLE)); + updateContent(title); + title.setMouseListener(getMouseListener()); + return title; + } + + protected SectionTitle prepareSectionTitle(Section newSection, + String titleText) throws RepositoryException { + Node sectionNode = newSection.getNode(); + if (!sectionNode.hasProperty(JCR_TITLE)) + sectionNode.setProperty(Property.JCR_TITLE, ""); + getTextInterpreter().write(sectionNode.getProperty(Property.JCR_TITLE), + titleText); + if (newSection.getHeader() == null) + newSection.createHeader(); + SectionTitle sectionTitle = newSectionTitle((TextSection) newSection, + sectionNode); + return sectionTitle; + } + + protected void updateContent(EditablePart part) throws RepositoryException { + if (part instanceof SectionPart) { + SectionPart sectionPart = (SectionPart) part; + Node partNode = sectionPart.getNode(); + + if (part instanceof StyledControl + && (sectionPart.getSection() instanceof TextSection)) { + TextSection section = (TextSection) sectionPart.getSection(); + StyledControl styledControl = (StyledControl) part; + if (partNode.isNodeType(CmsTypes.CMS_STYLED)) { + String style = partNode.hasProperty(CMS_STYLE) ? partNode + .getProperty(CMS_STYLE).getString() : section + .getDefaultTextStyle(); + styledControl.setStyle(style); + } + } + // use control AFTER setting style, since it may have been reset + + if (part instanceof EditableText) { + EditableText paragraph = (EditableText) part; + if (paragraph == getEdited()) + paragraph.setText(textInterpreter.read(partNode)); + else + paragraph.setText(textInterpreter.raw(partNode)); + } else if (part instanceof EditableImage) { + EditableImage editableImage = (EditableImage) part; + imageManager.load(partNode, part.getControl(), + editableImage.getPreferredImageSize()); + } + } else if (part instanceof SectionTitle) { + SectionTitle title = (SectionTitle) part; + title.setStyle(title.getSection().getTitleStyle()); + // use control AFTER setting style + if (title == getEdited()) + title.setText(textInterpreter.read(title.getProperty())); + else + title.setText(textInterpreter.raw(title.getProperty())); + } + } + + // OVERRIDDEN FROM PARENT VIEWER + @Override + protected void save(EditablePart part) throws RepositoryException { + if (part instanceof EditableText) { + EditableText et = (EditableText) part; + String text = ((Text) et.getControl()).getText(); + + String[] lines = text.split("[\r\n]+"); + assert lines.length != 0; + saveLine(part, lines[0]); + if (lines.length > 1) { + ArrayList toLayout = new ArrayList(); + if (part instanceof Paragraph) { + Paragraph currentParagraph = (Paragraph) et; + Section section = currentParagraph.getSection(); + Node sectionNode = section.getNode(); + Node currentParagraphN = currentParagraph.getNode(); + for (int i = 1; i < lines.length; i++) { + Node newNode = sectionNode.addNode(CMS_P); + newNode.addMixin(CmsTypes.CMS_STYLED); + saveLine(newNode, lines[i]); + // second node was create as last, if it is not the next + // one, it + // means there are some in between and we can take the + // one at + // index+1 for the re-order + if (newNode.getIndex() > currentParagraphN.getIndex() + 1) { + sectionNode.orderBefore(p(newNode.getIndex()), + p(currentParagraphN.getIndex() + 1)); + } + Paragraph newParagraph = newParagraph( + (TextSection) section, newNode); + newParagraph.moveBelow(currentParagraph); + toLayout.add(newParagraph); + + currentParagraph = newParagraph; + currentParagraphN = newNode; + } + persistChanges(sectionNode); + } + // TODO or rather return the created paragarphs? + layout(toLayout.toArray(new Control[toLayout.size()])); + } + } + } + + protected void saveLine(EditablePart part, String line) { + if (part instanceof NodePart) { + saveLine(((NodePart) part).getNode(), line); + } else if (part instanceof PropertyPart) { + saveLine(((PropertyPart) part).getProperty(), line); + } else { + throw new CmsException("Unsupported part " + part); + } + } + + protected void saveLine(Item item, String line) { + line = line.trim(); + textInterpreter.write(item, line); + } + + @Override + protected void prepare(EditablePart part, Object caretPosition) { + Control control = part.getControl(); + if (control instanceof Text) { + Text text = (Text) control; + if (caretPosition != null) + if (caretPosition instanceof Integer) + text.setSelection((Integer) caretPosition); + else if (caretPosition instanceof Point) { + // TODO find a way to position the caret at the right place + } + text.setData(RWT.ACTIVE_KEYS, new String[] { "BACKSPACE", "ESC", + "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT", + "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", + "ENTER", "DELETE" }); + text.setData(RWT.CANCEL_KEYS, new String[] { "RETURN", + "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" }); + text.addKeyListener(this); + } else if (part instanceof Img) { + ((Img) part).setFileUploadListener(fileUploadListener); + } + } + + // REQUIRED BY CONTEXT MENU + void setParagraphStyle(Paragraph paragraph, String style) { + try { + Node paragraphNode = paragraph.getNode(); + paragraphNode.setProperty(CMS_STYLE, style); + persistChanges(paragraphNode); + updateContent(paragraph); + layout(paragraph); + } catch (RepositoryException e1) { + throw new CmsException("Cannot set style " + style + " on " + + paragraph, e1); + } + } + + void deletePart(SectionPart paragraph) { + try { + Node paragraphNode = paragraph.getNode(); + Section section = paragraph.getSection(); + Session session = paragraphNode.getSession(); + paragraphNode.remove(); + session.save(); + if (paragraph instanceof Control) + ((Control) paragraph).dispose(); + layout(section); + } catch (RepositoryException e1) { + throw new CmsException("Cannot delete " + paragraph, e1); + } + } + + String getRawParagraphText(Paragraph paragraph) { + return textInterpreter.raw(paragraph.getNode()); + } + + // COMMANDS + protected void splitEdit() { + checkEdited(); + try { + if (getEdited() instanceof Paragraph) { + Paragraph paragraph = (Paragraph) getEdited(); + Text text = (Text) paragraph.getControl(); + int caretPosition = text.getCaretPosition(); + String txt = text.getText(); + String first = txt.substring(0, caretPosition); + String second = txt.substring(caretPosition); + Node firstNode = paragraph.getNode(); + Node sectionNode = firstNode.getParent(); + firstNode.setProperty(CMS_CONTENT, first); + Node secondNode = sectionNode.addNode(CMS_P); + secondNode.addMixin(CmsTypes.CMS_STYLED); + // second node was create as last, if it is not the next one, it + // means there are some in between and we can take the one at + // index+1 for the re-order + if (secondNode.getIndex() > firstNode.getIndex() + 1) { + sectionNode.orderBefore(p(secondNode.getIndex()), + p(firstNode.getIndex() + 1)); + } + + // if we die in between, at least we still have the whole text + // in the first node + try { + textInterpreter.write(secondNode, second); + textInterpreter.write(firstNode, first); + } catch (Exception e) { + // so that no additional nodes are created: + JcrUtils.discardUnderlyingSessionQuietly(firstNode); + throw e; + } + + persistChanges(firstNode); + + Paragraph secondParagraph = paragraphSplitted(paragraph, + secondNode); + edit(secondParagraph, 0); + } else if (getEdited() instanceof SectionTitle) { + SectionTitle sectionTitle = (SectionTitle) getEdited(); + Text text = (Text) sectionTitle.getControl(); + String txt = text.getText(); + int caretPosition = text.getCaretPosition(); + Section section = sectionTitle.getSection(); + Node sectionNode = section.getNode(); + Node paragraphNode = sectionNode.addNode(CMS_P); + paragraphNode.addMixin(CmsTypes.CMS_STYLED); + textInterpreter.write(paragraphNode, + txt.substring(caretPosition)); + textInterpreter.write( + sectionNode.getProperty(Property.JCR_TITLE), + txt.substring(0, caretPosition)); + sectionNode.orderBefore(p(paragraphNode.getIndex()), p(1)); + persistChanges(sectionNode); + + Paragraph paragraph = sectionTitleSplitted(sectionTitle, + paragraphNode); + // section.layout(); + edit(paragraph, 0); + } + } catch (RepositoryException e) { + throw new CmsException("Cannot split " + getEdited(), e); + } + } + + protected void mergeWithPrevious() { + checkEdited(); + try { + Paragraph paragraph = (Paragraph) getEdited(); + Text text = (Text) paragraph.getControl(); + String txt = text.getText(); + Node paragraphNode = paragraph.getNode(); + if (paragraphNode.getIndex() == 1) + return;// do nothing + Node sectionNode = paragraphNode.getParent(); + Node previousNode = sectionNode + .getNode(p(paragraphNode.getIndex() - 1)); + String previousTxt = textInterpreter.read(previousNode); + textInterpreter.write(previousNode, previousTxt + txt); + paragraphNode.remove(); + persistChanges(sectionNode); + + Paragraph previousParagraph = paragraphMergedWithPrevious( + paragraph, previousNode); + edit(previousParagraph, previousTxt.length()); + } catch (RepositoryException e) { + throw new CmsException("Cannot stop editing", e); + } + } + + protected void mergeWithNext() { + checkEdited(); + try { + Paragraph paragraph = (Paragraph) getEdited(); + Text text = (Text) paragraph.getControl(); + String txt = text.getText(); + Node paragraphNode = paragraph.getNode(); + Node sectionNode = paragraphNode.getParent(); + NodeIterator paragraphNodes = sectionNode.getNodes(CMS_P); + long size = paragraphNodes.getSize(); + if (paragraphNode.getIndex() == size) + return;// do nothing + Node nextNode = sectionNode + .getNode(p(paragraphNode.getIndex() + 1)); + String nextTxt = textInterpreter.read(nextNode); + textInterpreter.write(paragraphNode, txt + nextTxt); + + Section section = paragraph.getSection(); + Paragraph removed = (Paragraph) section.getSectionPart(nextNode + .getIdentifier()); + + nextNode.remove(); + persistChanges(sectionNode); + + paragraphMergedWithNext(paragraph, removed); + edit(paragraph, txt.length()); + } catch (RepositoryException e) { + throw new CmsException("Cannot stop editing", e); + } + } + + protected synchronized void upload(EditablePart part) { + try { + if (part instanceof SectionPart) { + SectionPart sectionPart = (SectionPart) part; + Node partNode = sectionPart.getNode(); + int partIndex = partNode.getIndex(); + Section section = sectionPart.getSection(); + Node sectionNode = section.getNode(); + + if (part instanceof Paragraph) { + Node newNode = sectionNode.addNode(CMS_P, NodeType.NT_FILE); + newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE); + JcrUtils.copyBytesAsFile(sectionNode, + p(newNode.getIndex()), new byte[0]); + if (partIndex < newNode.getIndex() - 1) { + // was not last + sectionNode.orderBefore(p(newNode.getIndex()), + p(partIndex - 1)); + } + // sectionNode.orderBefore(p(partNode.getIndex()), + // p(newNode.getIndex())); + persistChanges(sectionNode); + Img img = newImg((TextSection) section, newNode); + edit(img, null); + layout(img.getControl()); + } else if (part instanceof Img) { + if (getEdited() == part) + return; + edit(part, null); + layout(part.getControl()); + } + } + } catch (RepositoryException e) { + throw new CmsException("Cannot upload", e); + } + } + + protected void deepen() { + if (flat) + return; + checkEdited(); + try { + if (getEdited() instanceof Paragraph) { + Paragraph paragraph = (Paragraph) getEdited(); + Text text = (Text) paragraph.getControl(); + String txt = text.getText(); + Node paragraphNode = paragraph.getNode(); + Section section = paragraph.getSection(); + Node sectionNode = section.getNode(); + // main title + if (section == mainSection && section instanceof TextSection + && paragraphNode.getIndex() == 1 + && !sectionNode.hasProperty(JCR_TITLE)) { + SectionTitle sectionTitle = prepareSectionTitle(section, + txt); + edit(sectionTitle, 0); + return; + } + Node newSectionNode = sectionNode.addNode(CMS_H, + CmsTypes.CMS_SECTION); + sectionNode.orderBefore(h(newSectionNode.getIndex()), h(1)); + + int paragraphIndex = paragraphNode.getIndex(); + String sectionPath = sectionNode.getPath(); + String newSectionPath = newSectionNode.getPath(); + while (sectionNode.hasNode(p(paragraphIndex + 1))) { + Node parag = sectionNode.getNode(p(paragraphIndex + 1)); + sectionNode.getSession().move( + sectionPath + '/' + p(paragraphIndex + 1), + newSectionPath + '/' + CMS_P); + SectionPart sp = section.getSectionPart(parag + .getIdentifier()); + if (sp instanceof Control) + ((Control) sp).dispose(); + } + // create property + newSectionNode.setProperty(Property.JCR_TITLE, ""); + getTextInterpreter().write( + newSectionNode.getProperty(Property.JCR_TITLE), txt); + + TextSection newSection = new TextSection(section, + section.getStyle(), newSectionNode); + newSection.setLayoutData(CmsUiUtils.fillWidth()); + newSection.moveBelow(paragraph); + + // dispose + paragraphNode.remove(); + paragraph.dispose(); + + refresh(newSection); + newSection.getParent().layout(); + layout(newSection); + persistChanges(sectionNode); + } else if (getEdited() instanceof SectionTitle) { + SectionTitle sectionTitle = (SectionTitle) getEdited(); + Section section = sectionTitle.getSection(); + Section parentSection = section.getParentSection(); + if (parentSection == null) + return;// cannot deepen main section + Node sectionN = section.getNode(); + Node parentSectionN = parentSection.getNode(); + if (sectionN.getIndex() == 1) + return;// cannot deepen first section + Node previousSectionN = parentSectionN.getNode(h(sectionN + .getIndex() - 1)); + NodeIterator subSections = previousSectionN.getNodes(CMS_H); + int subsectionsCount = (int) subSections.getSize(); + previousSectionN.getSession().move( + sectionN.getPath(), + previousSectionN.getPath() + "/" + + h(subsectionsCount + 1)); + section.dispose(); + TextSection newSection = new TextSection(section, + section.getStyle(), sectionN); + refresh(newSection); + persistChanges(previousSectionN); + } + } catch (RepositoryException e) { + throw new CmsException("Cannot deepen " + getEdited(), e); + } + } + + protected void undeepen() { + if (flat) + return; + checkEdited(); + try { + if (getEdited() instanceof Paragraph) { + upload(getEdited()); + } else if (getEdited() instanceof SectionTitle) { + SectionTitle sectionTitle = (SectionTitle) getEdited(); + Section section = sectionTitle.getSection(); + Node sectionNode = section.getNode(); + Section parentSection = section.getParentSection(); + if (parentSection == null) + return;// cannot undeepen main section + + // choose in which section to merge + Section mergedSection; + if (sectionNode.getIndex() == 1) + mergedSection = section.getParentSection(); + else { + Map parentSubsections = parentSection + .getSubSections(); + ArrayList
lst = new ArrayList
( + parentSubsections.values()); + mergedSection = lst.get(sectionNode.getIndex() - 1); + } + Node mergedNode = mergedSection.getNode(); + boolean mergedHasSubSections = mergedNode.hasNode(CMS_H); + + // title as paragraph + Node newParagrapheNode = mergedNode.addNode(CMS_P); + newParagrapheNode.addMixin(CmsTypes.CMS_STYLED); + if (mergedHasSubSections) + mergedNode.orderBefore(p(newParagrapheNode.getIndex()), + h(1)); + String txt = getTextInterpreter().read( + sectionNode.getProperty(Property.JCR_TITLE)); + getTextInterpreter().write(newParagrapheNode, txt); + // move + NodeIterator paragraphs = sectionNode.getNodes(CMS_P); + while (paragraphs.hasNext()) { + Node p = paragraphs.nextNode(); + SectionPart sp = section.getSectionPart(p.getIdentifier()); + if (sp instanceof Control) + ((Control) sp).dispose(); + mergedNode.getSession().move(p.getPath(), + mergedNode.getPath() + '/' + CMS_P); + if (mergedHasSubSections) + mergedNode.orderBefore(p(p.getIndex()), h(1)); + } + + Iterator
subsections = section.getSubSections() + .values().iterator(); + // NodeIterator sections = sectionNode.getNodes(CMS_H); + while (subsections.hasNext()) { + Section subsection = subsections.next(); + Node s = subsection.getNode(); + mergedNode.getSession().move(s.getPath(), + mergedNode.getPath() + '/' + CMS_H); + subsection.dispose(); + } + + // remove section + section.getNode().remove(); + section.dispose(); + + refresh(mergedSection); + mergedSection.getParent().layout(); + layout(mergedSection); + persistChanges(mergedNode); + } + } catch (RepositoryException e) { + throw new CmsException("Cannot undeepen " + getEdited(), e); + } + } + + // UI CHANGES + protected Paragraph paragraphSplitted(Paragraph paragraph, Node newNode) + throws RepositoryException { + Section section = paragraph.getSection(); + updateContent(paragraph); + Paragraph newParagraph = newParagraph((TextSection) section, newNode); + newParagraph.setLayoutData(CmsUiUtils.fillWidth()); + newParagraph.moveBelow(paragraph); + layout(paragraph.getControl(), newParagraph.getControl()); + return newParagraph; + } + + protected Paragraph sectionTitleSplitted(SectionTitle sectionTitle, + Node newNode) throws RepositoryException { + updateContent(sectionTitle); + Paragraph newParagraph = newParagraph(sectionTitle.getSection(), + newNode); + // we assume beforeFirst is not null since there was a sectionTitle + newParagraph.moveBelow(sectionTitle.getSection().getHeader()); + layout(sectionTitle.getControl(), newParagraph.getControl()); + return newParagraph; + } + + protected Paragraph paragraphMergedWithPrevious(Paragraph removed, + Node remaining) throws RepositoryException { + Section section = removed.getSection(); + removed.dispose(); + + Paragraph paragraph = (Paragraph) section.getSectionPart(remaining + .getIdentifier()); + updateContent(paragraph); + layout(paragraph.getControl()); + return paragraph; + } + + protected void paragraphMergedWithNext(Paragraph remaining, + Paragraph removed) throws RepositoryException { + removed.dispose(); + updateContent(remaining); + layout(remaining.getControl()); + } + + // UTILITIES + protected String p(Integer index) { + StringBuilder sb = new StringBuilder(6); + sb.append(CMS_P).append('[').append(index).append(']'); + return sb.toString(); + } + + protected String h(Integer index) { + StringBuilder sb = new StringBuilder(5); + sb.append(CMS_H).append('[').append(index).append(']'); + return sb.toString(); + } + + // GETTERS / SETTERS + public Section getMainSection() { + return mainSection; + } + + public boolean isFlat() { + return flat; + } + + public TextInterpreter getTextInterpreter() { + return textInterpreter; + } + + // KEY LISTENER + @Override + public void keyPressed(KeyEvent ke) { + if (log.isTraceEnabled()) + log.trace(ke); + + if (getEdited() == null) + return; + boolean altPressed = (ke.stateMask & SWT.ALT) != 0; + boolean shiftPressed = (ke.stateMask & SWT.SHIFT) != 0; + boolean ctrlPressed = (ke.stateMask & SWT.CTRL) != 0; + + try { + // Common + if (ke.keyCode == SWT.ESC) { + cancelEdit(); + } else if (ke.character == '\r') { + splitEdit(); + } else if (ke.character == 'S') { + if (ctrlPressed) + saveEdit(); + } else if (ke.character == '\t') { + if (!shiftPressed) { + deepen(); + } else if (shiftPressed) { + undeepen(); + } + } else { + if (getEdited() instanceof Paragraph) { + Paragraph paragraph = (Paragraph) getEdited(); + Section section = paragraph.getSection(); + if (altPressed && ke.keyCode == SWT.ARROW_RIGHT) { + edit(section.nextSectionPart(paragraph), 0); + } else if (altPressed && ke.keyCode == SWT.ARROW_LEFT) { + edit(section.previousSectionPart(paragraph), 0); + } else if (ke.character == SWT.BS) { + Text text = (Text) paragraph.getControl(); + int caretPosition = text.getCaretPosition(); + if (caretPosition == 0) { + mergeWithPrevious(); + } + } else if (ke.character == SWT.DEL) { + Text text = (Text) paragraph.getControl(); + int caretPosition = text.getCaretPosition(); + int charcount = text.getCharCount(); + if (caretPosition == charcount) { + mergeWithNext(); + } + } + } + } + } catch (Exception e) { + ke.doit = false; + notifyEditionException(e); + } + } + + @Override + public void keyReleased(KeyEvent e) { + } + + // MOUSE LISTENER + @Override + protected MouseListener createMouseListener() { + return new ML(); + } + + private class ML extends MouseAdapter { + private static final long serialVersionUID = 8526890859876770905L; + + @Override + public void mouseDoubleClick(MouseEvent e) { + if (e.button == 1) { + Control source = (Control) e.getSource(); + if (getCmsEditable().canEdit()) { + if (getCmsEditable().isEditing() + && !(getEdited() instanceof Img)) { + if (source == mainSection) + return; + EditablePart part = findDataParent(source); + upload(part); + } else { + getCmsEditable().startEditing(); + } + } + } + } + + @Override + public void mouseDown(MouseEvent e) { + if (getCmsEditable().isEditing()) { + if (e.button == 1) { + Control source = (Control) e.getSource(); + EditablePart composite = findDataParent(source); + Point point = new Point(e.x, e.y); + if (!(composite instanceof Img)) + edit(composite, source.toDisplay(point)); + } else if (e.button == 3) { + EditablePart composite = findDataParent((Control) e + .getSource()); + if (styledTools != null) + styledTools.show(composite, new Point(e.x, e.y)); + } + } + } + + @Override + public void mouseUp(MouseEvent e) { + } + } + + // FILE UPLOAD LISTENER + private class FUL implements FileUploadListener { + public void uploadProgress(FileUploadEvent event) { + // TODO Monitor upload progress + } + + public void uploadFailed(FileUploadEvent event) { + throw new CmsException("Upload failed " + event, + event.getException()); + } + + public void uploadFinished(FileUploadEvent event) { + for (FileDetails file : event.getFileDetails()) { + if (log.isDebugEnabled()) + log.debug("Received: " + file.getFileName()); + } + mainSection.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + saveEdit(); + } + }); + FileUploadHandler uploadHandler = (FileUploadHandler) event + .getSource(); + uploadHandler.dispose(); + } + } +} \ No newline at end of file