From: Mathieu Baudier Date: Wed, 19 Feb 2020 09:58:37 +0000 (+0100) Subject: Move CMS Text framework to Argeo Connect. X-Git-Tag: argeo-commons-2.1.86~9 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=040134a521a7952b7523e5c1a53310b40bbd1b60 Move CMS Text framework to Argeo Connect. --- diff --git a/org.argeo.cms.e4.rap/e4xmi/cms-demo-rap.e4xmi b/org.argeo.cms.e4.rap/e4xmi/cms-demo-rap.e4xmi deleted file mode 100644 index 0e2b994b6..000000000 --- a/org.argeo.cms.e4.rap/e4xmi/cms-demo-rap.e4xmi +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/CmsTextEditor.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/CmsTextEditor.java deleted file mode 100644 index 4021ead6c..000000000 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/CmsTextEditor.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.argeo.cms.e4.parts; - -import java.util.Observable; -import java.util.Observer; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.inject.Inject; -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.cms.CmsException; -import org.argeo.cms.CmsTypes; -import org.argeo.cms.text.StandardTextEditor; -import org.argeo.cms.viewers.JcrVersionCmsEditable; -import org.argeo.jcr.JcrUtils; -import org.eclipse.e4.ui.di.Persist; -import org.eclipse.e4.ui.model.application.ui.basic.MPart; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; - -public class CmsTextEditor implements Observer { - @Inject - Repository repository; - - @Inject - private MPart mpart; - - Session session; - JcrVersionCmsEditable cmsEditable; - - @PostConstruct - public void createUI(Composite parent) { - try { - parent.setLayout(new GridLayout()); - session = repository.login(); - JcrUtils.loginOrCreateWorkspace(repository, "demo"); - Node textNode = JcrUtils.getOrAdd(session.getRootNode(), "text", CmsTypes.CMS_TEXT); - cmsEditable = new JcrVersionCmsEditable(textNode); - if (session.hasPendingChanges()) - session.save(); - cmsEditable.addObserver(this); - StandardTextEditor textEditor = new StandardTextEditor(parent, SWT.NONE, textNode, cmsEditable); - mpart.setDirty(cmsEditable.isEditing()); - } catch (RepositoryException e) { - throw new CmsException("Cannot create text editor", e); - } - } - - @PreDestroy - public void dispose() { - JcrUtils.logoutQuietly(session); - } - - @Persist - public void save() { - cmsEditable.stopEditing(); - } - - @Override - public void update(Observable o, Object arg) { - // CmsEditable cmsEditable = (CmsEditable) o; - mpart.setDirty(isDirty()); - } - - boolean isDirty() { - return cmsEditable.isEditing(); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/forms/FormPageViewer.java b/org.argeo.cms.ui/src/org/argeo/cms/forms/FormPageViewer.java index d6de0464e..d2af709a8 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/forms/FormPageViewer.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/forms/FormPageViewer.java @@ -17,8 +17,6 @@ import javax.jcr.ValueFormatException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsException; -import org.argeo.cms.text.Img; -import org.argeo.cms.text.MarkupValidatorCopy; import org.argeo.cms.ui.CmsEditable; import org.argeo.cms.ui.CmsImageManager; import org.argeo.cms.util.CmsUtils; @@ -27,6 +25,7 @@ import org.argeo.cms.viewers.EditablePart; import org.argeo.cms.viewers.Section; import org.argeo.cms.viewers.SectionPart; import org.argeo.cms.widgets.EditableImage; +import org.argeo.cms.widgets.Img; import org.argeo.cms.widgets.StyledControl; import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.jcr.JcrUtils; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/forms/MarkupValidatorCopy.java b/org.argeo.cms.ui/src/org/argeo/cms/forms/MarkupValidatorCopy.java new file mode 100644 index 000000000..f1a5a8c41 --- /dev/null +++ b/org.argeo.cms.ui/src/org/argeo/cms/forms/MarkupValidatorCopy.java @@ -0,0 +1,169 @@ +package org.argeo.cms.forms; + +import java.io.StringReader; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.eclipse.rap.rwt.SingletonUtil; +import org.eclipse.swt.widgets.Widget; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Copy of RAP v2.3 since it is in an internal package. + */ +class MarkupValidatorCopy { + + // Used by Eclipse Scout project + public static final String MARKUP_VALIDATION_DISABLED = "org.eclipse.rap.rwt.markupValidationDisabled"; + + private static final String DTD = createDTD(); + private static final Map SUPPORTED_ELEMENTS = createSupportedElementsMap(); + private final SAXParser saxParser; + + public static MarkupValidatorCopy getInstance() { + return SingletonUtil.getSessionInstance(MarkupValidatorCopy.class); + } + + public MarkupValidatorCopy() { + saxParser = createSAXParser(); + } + + public void validate(String text) { + StringBuilder markup = new StringBuilder(); + markup.append(DTD); + markup.append(""); + markup.append(text); + markup.append(""); + InputSource inputSource = new InputSource(new StringReader(markup.toString())); + try { + saxParser.parse(inputSource, new MarkupHandler()); + } catch (RuntimeException exception) { + throw exception; + } catch (Exception exception) { + throw new IllegalArgumentException("Failed to parse markup text", exception); + } + } + + public static boolean isValidationDisabledFor(Widget widget) { + return Boolean.TRUE.equals(widget.getData(MARKUP_VALIDATION_DISABLED)); + } + + private static SAXParser createSAXParser() { + SAXParser result = null; + SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + try { + result = parserFactory.newSAXParser(); + } catch (Exception exception) { + throw new RuntimeException("Failed to create SAX parser", exception); + } + return result; + } + + private static String createDTD() { + StringBuilder result = new StringBuilder(); + result.append(""); + result.append(""); + result.append(""); + result.append(""); + result.append(""); + result.append(""); + result.append(""); + result.append(""); + result.append(""); + result.append(""); + result.append("]>"); + return result.toString(); + } + + private static Map createSupportedElementsMap() { + Map result = new HashMap(); + result.put("html", new String[0]); + result.put("br", new String[0]); + result.put("b", new String[] { "style" }); + result.put("strong", new String[] { "style" }); + result.put("i", new String[] { "style" }); + result.put("em", new String[] { "style" }); + result.put("sub", new String[] { "style" }); + result.put("sup", new String[] { "style" }); + result.put("big", new String[] { "style" }); + result.put("small", new String[] { "style" }); + result.put("del", new String[] { "style" }); + result.put("ins", new String[] { "style" }); + result.put("code", new String[] { "style" }); + result.put("samp", new String[] { "style" }); + result.put("kbd", new String[] { "style" }); + result.put("var", new String[] { "style" }); + result.put("cite", new String[] { "style" }); + result.put("dfn", new String[] { "style" }); + result.put("q", new String[] { "style" }); + result.put("abbr", new String[] { "style", "title" }); + result.put("span", new String[] { "style" }); + result.put("img", new String[] { "style", "src", "width", "height", "title", "alt" }); + result.put("a", new String[] { "style", "href", "target", "title" }); + return result; + } + + private static class MarkupHandler extends DefaultHandler { + + @Override + public void startElement(String uri, String localName, String name, Attributes attributes) { + checkSupportedElements(name, attributes); + checkSupportedAttributes(name, attributes); + checkMandatoryAttributes(name, attributes); + } + + private static void checkSupportedElements(String elementName, Attributes attributes) { + if (!SUPPORTED_ELEMENTS.containsKey(elementName)) { + throw new IllegalArgumentException("Unsupported element in markup text: " + elementName); + } + } + + private static void checkSupportedAttributes(String elementName, Attributes attributes) { + if (attributes.getLength() > 0) { + List supportedAttributes = Arrays.asList(SUPPORTED_ELEMENTS.get(elementName)); + int index = 0; + String attributeName = attributes.getQName(index); + while (attributeName != null) { + if (!supportedAttributes.contains(attributeName)) { + String message = "Unsupported attribute \"{0}\" for element \"{1}\" in markup text"; + message = MessageFormat.format(message, new Object[] { attributeName, elementName }); + throw new IllegalArgumentException(message); + } + index++; + attributeName = attributes.getQName(index); + } + } + } + + private static void checkMandatoryAttributes(String elementName, Attributes attributes) { + checkIntAttribute(elementName, attributes, "img", "width"); + checkIntAttribute(elementName, attributes, "img", "height"); + } + + private static void checkIntAttribute(String elementName, Attributes attributes, String checkedElementName, + String checkedAttributeName) { + if (checkedElementName.equals(elementName)) { + String attribute = attributes.getValue(checkedAttributeName); + try { + Integer.parseInt(attribute); + } catch (NumberFormatException exception) { + String message = "Mandatory attribute \"{0}\" for element \"{1}\" is missing or not a valid integer"; + Object[] arguments = new Object[] { checkedAttributeName, checkedElementName }; + message = MessageFormat.format(message, arguments); + throw new IllegalArgumentException(message); + } + } + } + + } + +} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/maintenance/Browse.java b/org.argeo.cms.ui/src/org/argeo/cms/maintenance/Browse.java index 0389205ca..384cd72ef 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/maintenance/Browse.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/maintenance/Browse.java @@ -1,6 +1,5 @@ package org.argeo.cms.maintenance; -import static javax.jcr.Node.JCR_CONTENT; import static org.eclipse.swt.SWT.RIGHT; import java.text.DateFormat; @@ -17,12 +16,11 @@ import javax.jcr.RepositoryException; import javax.jcr.Value; import org.argeo.cms.CmsException; -import org.argeo.cms.CmsTypes; -import org.argeo.cms.text.Img; import org.argeo.cms.ui.CmsUiProvider; import org.argeo.cms.util.CmsLink; import org.argeo.cms.util.CmsUtils; import org.argeo.cms.widgets.EditableImage; +import org.argeo.cms.widgets.Img; import org.argeo.jcr.JcrUtils; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ILazyContentProvider; @@ -59,8 +57,7 @@ public class Browse implements CmsUiProvider { private final static String BROWSE_PREFIX = "browse#"; private final static int THUMBNAIL_WIDTH = 400; private final static int COLUMN_WIDTH = 160; - private DateFormat timeFormatter = new SimpleDateFormat( - "dd-MM-yyyy', 'HH:mm"); + private DateFormat timeFormatter = new SimpleDateFormat("dd-MM-yyyy', 'HH:mm"); // keep a cache of the opened nodes // Key is the path @@ -75,8 +72,7 @@ public class Browse implements CmsUiProvider { private String initialPath; @Override - public Control createUi(Composite parent, Node context) - throws RepositoryException { + public Control createUi(Composite parent, Node context) throws RepositoryException { if (context == null) // return null; throw new CmsException("Context cannot be null"); @@ -106,8 +102,7 @@ public class Browse implements CmsUiProvider { return null; } - private void createBrowserPart(Composite parent, Node context) - throws RepositoryException { + private void createBrowserPart(Composite parent, Node context) throws RepositoryException { GridLayout layout = CmsUtils.noSpaceGridLayout(); parent.setLayout(layout); Composite filterCmp = new Composite(parent, SWT.NO_FOCUS); @@ -117,8 +112,7 @@ public class Browse implements CmsUiProvider { addFilterPanel(filterCmp); // scrolled composite - scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER - | SWT.NO_FOCUS); + scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER | SWT.NO_FOCUS); scrolledCmp.setLayoutData(CmsUtils.fillAll()); scrolledCmp.setExpandVertical(true); scrolledCmp.setExpandHorizontal(true); @@ -132,25 +126,21 @@ public class Browse implements CmsUiProvider { @Override public void controlResized(ControlEvent e) { Rectangle r = scrolledCmp.getClientArea(); - scrolledCmp.setMinSize(colViewer.computeSize(SWT.DEFAULT, - r.height)); + scrolledCmp.setMinSize(colViewer.computeSize(SWT.DEFAULT, r.height)); } }); initExplorer(colViewer, context); } - private Control initExplorer(Composite parent, Node context) - throws RepositoryException { + private Control initExplorer(Composite parent, Node context) throws RepositoryException { parent.setLayout(CmsUtils.noSpaceGridLayout()); createBrowserColumn(parent, context); return null; } - private Control createBrowserColumn(Composite parent, Node context) - throws RepositoryException { + private Control createBrowserColumn(Composite parent, Node context) throws RepositoryException { // TODO style is not correctly managed. - FilterEntitiesVirtualTable table = new FilterEntitiesVirtualTable( - parent, SWT.BORDER | SWT.NO_FOCUS, context); + FilterEntitiesVirtualTable table = new FilterEntitiesVirtualTable(parent, SWT.BORDER | SWT.NO_FOCUS, context); // CmsUtils.style(table, ArgeoOrgStyle.browserColumn.style()); table.filterList("*"); table.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true)); @@ -189,8 +179,7 @@ public class Browse implements CmsUiProvider { // boolean altPressed = (e.stateMask & SWT.ALT) != 0; FilterEntitiesVirtualTable currTable = null; if (currEdited != null) { - FilterEntitiesVirtualTable table = browserCols - .get(getPath(currEdited)); + FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited)); if (table != null && !table.isDisposed()) currTable = table; } @@ -200,26 +189,21 @@ public class Browse implements CmsUiProvider { currTable.setFocus(); else if (e.keyCode == SWT.BS) { if (filterTxt.getText().equals("") - && !(getPath(currEdited).equals("/") || getPath( - currEdited).equals(initialPath))) { + && !(getPath(currEdited).equals("/") || getPath(currEdited).equals(initialPath))) { setEdited(currEdited.getParent()); e.doit = false; filterTxt.setFocus(); } } else if (e.keyCode == SWT.TAB && !shiftPressed) { - if (currEdited.getNodes(filterTxt.getText() + "*") - .getSize() == 1) { - setEdited(currEdited.getNodes( - filterTxt.getText() + "*").nextNode()); + if (currEdited.getNodes(filterTxt.getText() + "*").getSize() == 1) { + setEdited(currEdited.getNodes(filterTxt.getText() + "*").nextNode()); } filterTxt.setFocus(); e.doit = false; } } catch (RepositoryException e1) { - throw new CmsException( - "Unexpected error in key management for " - + currEdited + "with filter " - + filterTxt.getText(), e1); + throw new CmsException("Unexpected error in key management for " + currEdited + "with filter " + + filterTxt.getText(), e1); } } @@ -255,9 +239,6 @@ public class Browse implements CmsUiProvider { currParPath = JcrUtils.parentPath(currNodePath); if ("".equals(currParPath)) currParPath = "/"; - - - Object[][] colMatrix = new Object[browserCols.size()][2]; @@ -271,13 +252,9 @@ public class Browse implements CmsUiProvider { // workaround for same name siblings // fix me weird side effect when we go left or click on anb // already selected, unfocused node - if (leaveOpened - && (path.lastIndexOf("/") == 0 - && currNodePath.lastIndexOf("/") == 0 || JcrUtils - .parentPath(path).equals( - JcrUtils.parentPath(currNodePath)))) - leaveOpened = JcrUtils.lastPathElement(path).equals( - JcrUtils.lastPathElement(currNodePath)); + if (leaveOpened && (path.lastIndexOf("/") == 0 && currNodePath.lastIndexOf("/") == 0 + || JcrUtils.parentPath(path).equals(JcrUtils.parentPath(currNodePath)))) + leaveOpened = JcrUtils.lastPathElement(path).equals(JcrUtils.lastPathElement(currNodePath)); if (!leaveOpened) k = i; @@ -306,8 +283,7 @@ public class Browse implements CmsUiProvider { if (!browserCols.containsKey(currNodePath)) createBrowserColumn(colViewer, node); - colViewer.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout( - browserCols.size(), false))); + colViewer.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false))); // colViewer.pack(); colViewer.layout(); // also resize the scrolled composite @@ -323,8 +299,7 @@ public class Browse implements CmsUiProvider { if (!fromOutside) if (currEdited != null) { String filter = filterTxt.getText() + "*"; - FilterEntitiesVirtualTable table = browserCols - .get(getPath(currEdited)); + FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited)); if (table != null && !table.isDisposed()) table.filterList(filter); } @@ -342,34 +317,29 @@ public class Browse implements CmsUiProvider { private Point imageWidth = new Point(250, 0); /** - * Recreates the content of the box that displays information about the - * current selected node. + * Recreates the content of the box that displays information about the current + * selected node. */ - private Control createNodeView(Composite parent, Node context) - throws RepositoryException { + private Control createNodeView(Composite parent, Node context) throws RepositoryException { parent.setLayout(new GridLayout(2, false)); if (isImg(context)) { EditableImage image = new Img(parent, RIGHT, context, imageWidth); - image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, - false, 2, 1)); + image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 2, 1)); } // Name and primary type Label contextL = new Label(parent, SWT.NONE); contextL.setData(RWT.MARKUP_ENABLED, true); contextL.setText("" + context.getName() + ""); - new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType() - .getName()); + new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType().getName()); // Children for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) { Node child = nIt.nextNode(); - new CmsLink(child.getName(), BROWSE_PREFIX + child.getPath()) - .createUi(parent, context); - new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType() - .getName()); + new CmsLink(child.getName(), BROWSE_PREFIX + child.getPath()).createUi(parent, context); + new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType().getName()); } // Properties @@ -377,8 +347,7 @@ public class Browse implements CmsUiProvider { Property property = pIt.nextProperty(); Label label = new Label(parent, SWT.NONE); label.setText(property.getName()); - label.setToolTipText(JcrUtils - .getPropertyDefinitionAsString(property)); + label.setToolTipText(JcrUtils.getPropertyDefinitionAsString(property)); new Label(parent, SWT.NONE).setText(getPropAsString(property)); } @@ -386,11 +355,12 @@ public class Browse implements CmsUiProvider { } private boolean isImg(Node node) throws RepositoryException { - return node.hasNode(JCR_CONTENT) && node.isNodeType(CmsTypes.CMS_IMAGE); + // TODO support images + return false; +// return node.hasNode(JCR_CONTENT) && node.isNodeType(CmsTypes.CMS_IMAGE); } - private String getPropAsString(Property property) - throws RepositoryException { + private String getPropAsString(Property property) throws RepositoryException { String result = ""; if (property.isMultiple()) { result = getMultiAsString(property, ", "); @@ -406,8 +376,7 @@ public class Browse implements CmsUiProvider { return result; } - private String getMultiAsString(Property property, String separator) - throws RepositoryException { + private String getMultiAsString(Property property, String separator) throws RepositoryException { if (separator == null) separator = "; "; Value[] values = property.getValues(); @@ -445,8 +414,7 @@ public class Browse implements CmsUiProvider { if (entityViewer.getSelection().isEmpty()) { Object first = entityViewer.getElementAt(0); if (first != null) { - entityViewer.setSelection(new StructuredSelection(first), - true); + entityViewer.setSelection(new StructuredSelection(first), true); } } return entityViewer.getTable().setFocus(); @@ -457,14 +425,12 @@ public class Browse implements CmsUiProvider { NodeIterator nit = context.getNodes(filter); refreshFilteredList(nit); } catch (RepositoryException e) { - throw new CmsException("Unable to filter " + getNode() - + " children with filter " + filter, e); + throw new CmsException("Unable to filter " + getNode() + " children with filter " + filter, e); } } - public FilterEntitiesVirtualTable(Composite parent, int style, - Node context) { + public FilterEntitiesVirtualTable(Composite parent, int style, Node context) { super(parent, SWT.NO_FOCUS); this.context = context; populate(); @@ -500,28 +466,25 @@ public class Browse implements CmsUiProvider { CmsUtils.style(table, MaintenanceStyles.BROWSER_COLUMN); // first column - TableViewerColumn column = new TableViewerColumn(entityViewer, - SWT.NONE); + TableViewerColumn column = new TableViewerColumn(entityViewer, SWT.NONE); TableColumn tcol = column.getColumn(); tcol.setWidth(COLUMN_WIDTH); tcol.setResizable(true); column.setLabelProvider(new SimpleNameLP()); entityViewer.setContentProvider(new MyLazyCP(entityViewer)); - entityViewer - .addSelectionChangedListener(new ISelectionChangedListener() { - - @Override - public void selectionChanged(SelectionChangedEvent event) { - IStructuredSelection selection = (IStructuredSelection) entityViewer - .getSelection(); - if (selection.isEmpty()) - return; - else - setEdited((Node) selection.getFirstElement()); + entityViewer.addSelectionChangedListener(new ISelectionChangedListener() { - } - }); + @Override + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection(); + if (selection.isEmpty()) + return; + else + setEdited((Node) selection.getFirstElement()); + + } + }); table.addKeyListener(new KeyListener() { private static final long serialVersionUID = -330694313896036230L; @@ -533,8 +496,7 @@ public class Browse implements CmsUiProvider { @Override public void keyPressed(KeyEvent e) { - IStructuredSelection selection = (IStructuredSelection) entityViewer - .getSelection(); + IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection(); Node selected = null; if (!selection.isEmpty()) selected = ((Node) selection.getFirstElement()); @@ -556,8 +518,8 @@ public class Browse implements CmsUiProvider { } } } catch (RepositoryException ie) { - throw new CmsException("Error while managing arrow " - + "events in the browser for " + selected, ie); + throw new CmsException("Error while managing arrow " + "events in the browser for " + selected, + ie); } } }); @@ -575,8 +537,7 @@ public class Browse implements CmsUiProvider { public void dispose() { } - public void inputChanged(Viewer viewer, Object oldInput, - Object newInput) { + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // IMPORTANT: don't forget this: an exception will be thrown if // a selected object is not part of the results anymore. viewer.setSelection(null); @@ -605,8 +566,7 @@ public class Browse implements CmsUiProvider { try { return curr.getName(); } catch (RepositoryException e) { - throw new CmsException("Unable to get name for" - + curr); + throw new CmsException("Unable to get name for" + curr); } } return super.getText(element); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/AbstractTextViewer.java b/org.argeo.cms.ui/src/org/argeo/cms/text/AbstractTextViewer.java deleted file mode 100644 index 2416cbcd8..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/AbstractTextViewer.java +++ /dev/null @@ -1,888 +0,0 @@ -package org.argeo.cms.text; - -import static javax.jcr.Property.JCR_TITLE; -import static org.argeo.cms.util.CmsUtils.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.CmsNames; -import org.argeo.cms.CmsTypes; -import org.argeo.cms.ui.CmsEditable; -import org.argeo.cms.ui.CmsImageManager; -import org.argeo.cms.util.CmsUtils; -import org.argeo.cms.viewers.AbstractPageViewer; -import org.argeo.cms.viewers.EditablePart; -import org.argeo.cms.viewers.NodePart; -import org.argeo.cms.viewers.PropertyPart; -import org.argeo.cms.viewers.Section; -import org.argeo.cms.viewers.SectionPart; -import org.argeo.cms.widgets.EditableImage; -import org.argeo.cms.widgets.EditableText; -import org.argeo.cms.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 = CmsUtils.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) { - CmsUtils.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(CmsUtils.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(CmsUtils.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(CmsUtils.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(CmsUtils.grabWidth(SWT.CENTER, - SWT.DEFAULT)); - } - - @Override - protected void setControlLayoutData(Control control) { - control.setLayoutData(CmsUtils.grabWidth(SWT.CENTER, - SWT.DEFAULT)); - } - }; - img.setLayoutData(CmsUtils.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(CmsUtils.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(CmsUtils.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 diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/CustomTextEditor.java b/org.argeo.cms.ui/src/org/argeo/cms/text/CustomTextEditor.java deleted file mode 100644 index 94be4209a..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/CustomTextEditor.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.argeo.cms.text; - -import static org.argeo.cms.util.CmsUtils.fillWidth; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.cms.ui.CmsEditable; -import org.argeo.cms.viewers.Section; -import org.eclipse.swt.widgets.Composite; - -/** - * Manages hardcoded sections as an arbitrary hierarchy under the main section, - * which contains no text and no title. - */ -public class CustomTextEditor extends AbstractTextViewer { - private static final long serialVersionUID = 5277789504209413500L; - - public CustomTextEditor(Composite parent, int style, Node textNode, - CmsEditable cmsEditable) throws RepositoryException { - this(new Section(parent, style, textNode), style, cmsEditable); - } - - public CustomTextEditor(Section mainSection, int style, - CmsEditable cmsEditable) throws RepositoryException { - super(mainSection, style, cmsEditable); - mainSection.setLayoutData(fillWidth()); - } - - @Override - public Section getMainSection() { - return super.getMainSection(); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/IdentityTextInterpreter.java b/org.argeo.cms.ui/src/org/argeo/cms/text/IdentityTextInterpreter.java deleted file mode 100644 index 79f6ede2c..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/IdentityTextInterpreter.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.argeo.cms.text; - -import javax.jcr.Item; -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.RepositoryException; - -import org.argeo.cms.CmsException; -import org.argeo.cms.CmsNames; -import org.argeo.cms.CmsTypes; - -/** Based on HTML with a few Wiki-like shortcuts. */ -public class IdentityTextInterpreter implements TextInterpreter, CmsNames { - - @Override - public void write(Item item, String content) { - try { - if (item instanceof Node) { - Node node = (Node) item; - if (node.isNodeType(CmsTypes.CMS_STYLED)) { - String raw = convertToStorage(node, content); - validateBeforeStoring(raw); - node.setProperty(CMS_CONTENT, raw); - } else { - throw new CmsException("Don't know how to interpret " - + node); - } - } else {// property - Property property = (Property) item; - property.setValue(content); - } - // item.getSession().save(); - } catch (RepositoryException e) { - throw new CmsException("Cannot set content on " + item, e); - } - } - - @Override - public String read(Item item) { - try { - String raw = raw(item); - return convertFromStorage(item, raw); - } catch (RepositoryException e) { - throw new CmsException("Cannot get " + item + " for edit", e); - } - } - - @Override - public String raw(Item item) { - try { - item.getSession().refresh(true); - if (item instanceof Node) { - Node node = (Node) item; - if (node.isNodeType(CmsTypes.CMS_STYLED)) { - // WORKAROUND FOR BROKEN PARARAPHS - if (!node.hasProperty(CMS_CONTENT)) { - node.setProperty(CMS_CONTENT, ""); - node.getSession().save(); - } - - return node.getProperty(CMS_CONTENT).getString(); - } else { - throw new CmsException("Don't know how to interpret " - + node); - } - } else {// property - Property property = (Property) item; - return property.getString(); - } - } catch (RepositoryException e) { - throw new CmsException("Cannot get " + item + " content", e); - } - } - - // EXTENSIBILITY - /** - * To be overridden, in order to make sure that only valid strings are being - * stored. - */ - protected void validateBeforeStoring(String raw) { - } - - /** To be overridden, in order to support additional formatting. */ - protected String convertToStorage(Item item, String content) - throws RepositoryException { - return content; - - } - - /** To be overridden, in order to support additional formatting. */ - protected String convertFromStorage(Item item, String content) - throws RepositoryException { - return content; - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/Img.java b/org.argeo.cms.ui/src/org/argeo/cms/text/Img.java deleted file mode 100644 index 12f65f35e..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/Img.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.argeo.cms.text; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.cms.CmsException; -import org.argeo.cms.ui.CmsImageManager; -import org.argeo.cms.ui.internal.JcrFileUploadReceiver; -import org.argeo.cms.util.CmsUtils; -import org.argeo.cms.viewers.NodePart; -import org.argeo.cms.viewers.Section; -import org.argeo.cms.viewers.SectionPart; -import org.argeo.cms.widgets.EditableImage; -import org.eclipse.rap.fileupload.FileUploadHandler; -import org.eclipse.rap.fileupload.FileUploadListener; -import org.eclipse.rap.fileupload.FileUploadReceiver; -import org.eclipse.rap.rwt.service.ServerPushSession; -import org.eclipse.rap.rwt.widgets.FileUpload; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; - -/** An image within the Argeo Text framework */ -public class Img extends EditableImage implements SectionPart, NodePart { - private static final long serialVersionUID = 6233572783968188476L; - - private final Section section; - - private final CmsImageManager imageManager; - private FileUploadHandler currentUploadHandler = null; - private FileUploadListener fileUploadListener; - - public Img(Composite parent, int swtStyle, Node imgNode, - Point preferredImageSize) throws RepositoryException { - this(Section.findSection(parent), parent, swtStyle, imgNode, - preferredImageSize); - setStyle(TextStyles.TEXT_IMAGE); - } - - public Img(Composite parent, int swtStyle, Node imgNode) - throws RepositoryException { - this(Section.findSection(parent), parent, swtStyle, imgNode, null); - setStyle(TextStyles.TEXT_IMAGE); - } - - Img(Section section, Composite parent, int swtStyle, Node imgNode, - Point preferredImageSize) throws RepositoryException { - super(parent, swtStyle, imgNode, false, preferredImageSize); - this.section = section; - imageManager = CmsUtils.getCmsView().getImageManager(); - CmsUtils.style(this, TextStyles.TEXT_IMG); - } - - @Override - protected Control createControl(Composite box, String style) { - if (isEditing()) { - try { - return createImageChooser(box, style); - } catch (RepositoryException e) { - throw new CmsException("Cannot create image chooser", e); - } - } else { - return createLabel(box, style); - } - } - - @Override - public synchronized void stopEditing() { - super.stopEditing(); - fileUploadListener = null; - } - - @Override - protected synchronized Boolean load(Control lbl) { - try { - Node imgNode = getNode(); - boolean loaded = imageManager.load(imgNode, lbl, - getPreferredImageSize()); - // getParent().layout(); - return loaded; - } catch (RepositoryException e) { - throw new CmsException("Cannot load " + getNodeId() - + " from image manager", e); - } - } - - protected Control createImageChooser(Composite box, String style) - throws RepositoryException { - // FileDialog fileDialog = new FileDialog(getShell()); - // fileDialog.open(); - // String fileName = fileDialog.getFileName(); - CmsImageManager imageManager = CmsUtils.getCmsView().getImageManager(); - Node node = getNode(); - JcrFileUploadReceiver receiver = new JcrFileUploadReceiver( - node.getParent(), node.getName() + '[' + node.getIndex() + ']', - imageManager); - if (currentUploadHandler != null) - currentUploadHandler.dispose(); - currentUploadHandler = prepareUpload(receiver); - final ServerPushSession pushSession = new ServerPushSession(); - final FileUpload fileUpload = new FileUpload(box, SWT.NONE); - CmsUtils.style(fileUpload, style); - fileUpload.addSelectionListener(new SelectionAdapter() { - private static final long serialVersionUID = -9158471843941668562L; - - @Override - public void widgetSelected(SelectionEvent e) { - pushSession.start(); - fileUpload.submit(currentUploadHandler.getUploadUrl()); - } - }); - return fileUpload; - } - - protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) { - final FileUploadHandler uploadHandler = new FileUploadHandler(receiver); - if (fileUploadListener != null) - uploadHandler.addUploadListener(fileUploadListener); - return uploadHandler; - } - - @Override - public Section getSection() { - return section; - } - - public void setFileUploadListener(FileUploadListener fileUploadListener) { - this.fileUploadListener = fileUploadListener; - if (currentUploadHandler != null) - currentUploadHandler.addUploadListener(fileUploadListener); - } - - @Override - public Node getItem() throws RepositoryException { - return getNode(); - } - - @Override - public String getPartId() { - return getNodeId(); - } - - @Override - public String toString() { - return "Img #" + getPartId(); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/MarkupValidatorCopy.java b/org.argeo.cms.ui/src/org/argeo/cms/text/MarkupValidatorCopy.java deleted file mode 100644 index 26b77cb4e..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/MarkupValidatorCopy.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.argeo.cms.text; - -import java.io.StringReader; -import java.text.MessageFormat; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.argeo.cms.forms.FormPageViewer; -import org.eclipse.rap.rwt.SingletonUtil; -import org.eclipse.swt.widgets.Widget; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.helpers.DefaultHandler; - -/** - * Copy of RAP v2.3 since it is in an internal package. - * - * FIXME made public to enable validation from the {@link FormPageViewer} - */ -public class MarkupValidatorCopy { - - // Used by Eclipse Scout project - public static final String MARKUP_VALIDATION_DISABLED = "org.eclipse.rap.rwt.markupValidationDisabled"; - - private static final String DTD = createDTD(); - private static final Map SUPPORTED_ELEMENTS = createSupportedElementsMap(); - private final SAXParser saxParser; - - public static MarkupValidatorCopy getInstance() { - return SingletonUtil.getSessionInstance(MarkupValidatorCopy.class); - } - - public MarkupValidatorCopy() { - saxParser = createSAXParser(); - } - - public void validate(String text) { - StringBuilder markup = new StringBuilder(); - markup.append(DTD); - markup.append(""); - markup.append(text); - markup.append(""); - InputSource inputSource = new InputSource(new StringReader( - markup.toString())); - try { - saxParser.parse(inputSource, new MarkupHandler()); - } catch (RuntimeException exception) { - throw exception; - } catch (Exception exception) { - throw new IllegalArgumentException("Failed to parse markup text", - exception); - } - } - - public static boolean isValidationDisabledFor(Widget widget) { - return Boolean.TRUE.equals(widget.getData(MARKUP_VALIDATION_DISABLED)); - } - - private static SAXParser createSAXParser() { - SAXParser result = null; - SAXParserFactory parserFactory = SAXParserFactory.newInstance(); - try { - result = parserFactory.newSAXParser(); - } catch (Exception exception) { - throw new RuntimeException("Failed to create SAX parser", exception); - } - return result; - } - - private static String createDTD() { - StringBuilder result = new StringBuilder(); - result.append(""); - result.append(""); - result.append(""); - result.append(""); - result.append(""); - result.append(""); - result.append(""); - result.append(""); - result.append(""); - result.append(""); - result.append("]>"); - return result.toString(); - } - - private static Map createSupportedElementsMap() { - Map result = new HashMap(); - result.put("html", new String[0]); - result.put("br", new String[0]); - result.put("b", new String[] { "style" }); - result.put("strong", new String[] { "style" }); - result.put("i", new String[] { "style" }); - result.put("em", new String[] { "style" }); - result.put("sub", new String[] { "style" }); - result.put("sup", new String[] { "style" }); - result.put("big", new String[] { "style" }); - result.put("small", new String[] { "style" }); - result.put("del", new String[] { "style" }); - result.put("ins", new String[] { "style" }); - result.put("code", new String[] { "style" }); - result.put("samp", new String[] { "style" }); - result.put("kbd", new String[] { "style" }); - result.put("var", new String[] { "style" }); - result.put("cite", new String[] { "style" }); - result.put("dfn", new String[] { "style" }); - result.put("q", new String[] { "style" }); - result.put("abbr", new String[] { "style", "title" }); - result.put("span", new String[] { "style" }); - result.put("img", new String[] { "style", "src", "width", "height", - "title", "alt" }); - result.put("a", new String[] { "style", "href", "target", "title" }); - return result; - } - - private static class MarkupHandler extends DefaultHandler { - - @Override - public void startElement(String uri, String localName, String name, - Attributes attributes) { - checkSupportedElements(name, attributes); - checkSupportedAttributes(name, attributes); - checkMandatoryAttributes(name, attributes); - } - - private static void checkSupportedElements(String elementName, - Attributes attributes) { - if (!SUPPORTED_ELEMENTS.containsKey(elementName)) { - throw new IllegalArgumentException( - "Unsupported element in markup text: " + elementName); - } - } - - private static void checkSupportedAttributes(String elementName, - Attributes attributes) { - if (attributes.getLength() > 0) { - List supportedAttributes = Arrays - .asList(SUPPORTED_ELEMENTS.get(elementName)); - int index = 0; - String attributeName = attributes.getQName(index); - while (attributeName != null) { - if (!supportedAttributes.contains(attributeName)) { - String message = "Unsupported attribute \"{0}\" for element \"{1}\" in markup text"; - message = MessageFormat.format(message, new Object[] { - attributeName, elementName }); - throw new IllegalArgumentException(message); - } - index++; - attributeName = attributes.getQName(index); - } - } - } - - private static void checkMandatoryAttributes(String elementName, - Attributes attributes) { - checkIntAttribute(elementName, attributes, "img", "width"); - checkIntAttribute(elementName, attributes, "img", "height"); - } - - private static void checkIntAttribute(String elementName, - Attributes attributes, String checkedElementName, - String checkedAttributeName) { - if (checkedElementName.equals(elementName)) { - String attribute = attributes.getValue(checkedAttributeName); - try { - Integer.parseInt(attribute); - } catch (NumberFormatException exception) { - String message = "Mandatory attribute \"{0}\" for element \"{1}\" is missing or not a valid integer"; - Object[] arguments = new Object[] { checkedAttributeName, - checkedElementName }; - message = MessageFormat.format(message, arguments); - throw new IllegalArgumentException(message); - } - } - } - - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/Paragraph.java b/org.argeo.cms.ui/src/org/argeo/cms/text/Paragraph.java deleted file mode 100644 index a7a7964f4..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/Paragraph.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.argeo.cms.text; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.cms.util.CmsUtils; -import org.argeo.cms.viewers.Section; -import org.argeo.cms.viewers.SectionPart; -import org.argeo.cms.widgets.EditableText; - -public class Paragraph extends EditableText implements SectionPart { - private static final long serialVersionUID = 3746457776229542887L; - - private final TextSection section; - - public Paragraph(TextSection section, int style, Node node) - throws RepositoryException { - super(section, style, node); - this.section = section; - CmsUtils.style(this, TextStyles.TEXT_PARAGRAPH); - } - - public Section getSection() { - return section; - } - - @Override - public String getPartId() { - return getNodeId(); - } - - @Override - public Node getItem() throws RepositoryException { - return getNode(); - } - - @Override - public String toString() { - return "Paragraph #" + getPartId(); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/SectionTitle.java b/org.argeo.cms.ui/src/org/argeo/cms/text/SectionTitle.java deleted file mode 100644 index 15be32b3e..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/SectionTitle.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.argeo.cms.text; - -import javax.jcr.Property; -import javax.jcr.RepositoryException; - -import org.argeo.cms.viewers.EditablePart; -import org.argeo.cms.viewers.PropertyPart; -import org.argeo.cms.widgets.EditableText; -import org.eclipse.swt.widgets.Composite; - -/** The title of a section. */ -public class SectionTitle extends EditableText implements EditablePart, - PropertyPart { - private static final long serialVersionUID = -1787983154946583171L; - - private final TextSection section; - - public SectionTitle(Composite parent, int swtStyle, Property title) - throws RepositoryException { - super(parent, swtStyle, title); - section = (TextSection) TextSection.findSection(this); - } - - public TextSection getSection() { - return section; - } - - // @Override - // public Property getProperty() throws RepositoryException { - // return getSection().getNode().getProperty(Property.JCR_TITLE); - // } - - @Override - public Property getItem() throws RepositoryException { - return getProperty(); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/StandardTextEditor.java b/org.argeo.cms.ui/src/org/argeo/cms/text/StandardTextEditor.java deleted file mode 100644 index 8a4fd111b..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/StandardTextEditor.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.argeo.cms.text; - -import static javax.jcr.Property.JCR_TITLE; - -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.RepositoryException; - -import org.argeo.cms.CmsTypes; -import org.argeo.cms.ui.CmsEditable; -import org.argeo.cms.util.CmsUtils; -import org.argeo.cms.viewers.Section; -import org.eclipse.swt.widgets.Composite; - -/** Text editor where sections and subsections can be managed by the user. */ -public class StandardTextEditor extends AbstractTextViewer { - private static final long serialVersionUID = 6049661610883342325L; - - public StandardTextEditor(Composite parent, int style, Node textNode, - CmsEditable cmsEditable) throws RepositoryException { - super(new TextSection(parent, style, textNode), style, cmsEditable); - refresh(); - getMainSection().setLayoutData(CmsUtils.fillWidth()); - } - - @Override - protected void initModel(Node textNode) throws RepositoryException { - if (isFlat()) - textNode.addNode(CMS_P).addMixin(CmsTypes.CMS_STYLED); - else - textNode.setProperty(JCR_TITLE, textNode.getName()); - } - - @Override - protected Boolean isModelInitialized(Node textNode) - throws RepositoryException { - return textNode.hasProperty(Property.JCR_TITLE) - || textNode.hasNode(CMS_P) - || (!isFlat() && textNode.hasNode(CMS_H)); - } - - @Override - public Section getMainSection() { - // TODO Auto-generated method stub - return super.getMainSection(); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/TextContextMenu.java b/org.argeo.cms.ui/src/org/argeo/cms/text/TextContextMenu.java deleted file mode 100644 index eb85bde42..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/TextContextMenu.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.argeo.cms.text; - -import java.util.ArrayList; -import java.util.List; - -import org.argeo.cms.CmsNames; -import org.argeo.cms.viewers.EditablePart; -import org.argeo.cms.viewers.SectionPart; -import org.eclipse.rap.rwt.RWT; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.MouseAdapter; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.ShellEvent; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; - -/** Dialog to edit a text part. */ -class TextContextMenu extends Shell implements CmsNames, TextStyles { - private final static String[] DEFAULT_TEXT_STYLES = { - TextStyles.TEXT_DEFAULT, TextStyles.TEXT_PRE, TextStyles.TEXT_QUOTE }; - - private final AbstractTextViewer textViewer; - - private static final long serialVersionUID = -3826246895162050331L; - private List styleButtons = new ArrayList(); - - private Label deleteButton, publishButton, editButton; - - private EditablePart currentTextPart; - - public TextContextMenu(AbstractTextViewer textViewer, Display display) { - super(display, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP); - this.textViewer = textViewer; - setLayout(new GridLayout()); - setData(RWT.CUSTOM_VARIANT, TEXT_STYLED_TOOLS_DIALOG); - - StyledToolMouseListener stml = new StyledToolMouseListener(); - if (textViewer.getCmsEditable().isEditing()) { - for (String style : DEFAULT_TEXT_STYLES) { - StyleButton styleButton = new StyleButton(this, SWT.WRAP); - styleButton.setData(RWT.CUSTOM_VARIANT, style); - styleButton.setData(RWT.MARKUP_ENABLED, true); - styleButton.addMouseListener(stml); - styleButtons.add(styleButton); - } - - // Delete - deleteButton = new Label(this, SWT.NONE); - deleteButton.setText("Delete"); - deleteButton.addMouseListener(stml); - - // Publish - publishButton = new Label(this, SWT.NONE); - publishButton.setText("Publish"); - publishButton.addMouseListener(stml); - } else if (textViewer.getCmsEditable().canEdit()) { - // Edit - editButton = new Label(this, SWT.NONE); - editButton.setText("Edit"); - editButton.addMouseListener(stml); - } - addShellListener(new ToolsShellListener()); - } - - public void show(EditablePart source, Point location) { - if (isVisible()) - setVisible(false); - - this.currentTextPart = source; - - if (currentTextPart instanceof Paragraph) { - final int size = 32; - String text = textViewer - .getRawParagraphText((Paragraph) currentTextPart); - String textToShow = text.length() > size ? text.substring(0, - size - 3) + "..." : text; - for (StyleButton styleButton : styleButtons) { - styleButton.setText(textToShow); - } - } - pack(); - layout(); - if (source instanceof Control) - setLocation(((Control) source).toDisplay(location.x, location.y)); - open(); - } - - class StyleButton extends Label { - private static final long serialVersionUID = 7731102609123946115L; - - public StyleButton(Composite parent, int swtStyle) { - super(parent, swtStyle); - } - - } - - class StyledToolMouseListener extends MouseAdapter { - private static final long serialVersionUID = 8516297091549329043L; - - @Override - public void mouseDown(MouseEvent e) { - Object eventSource = e.getSource(); - if (eventSource instanceof StyleButton) { - StyleButton sb = (StyleButton) e.getSource(); - String style = sb.getData(RWT.CUSTOM_VARIANT).toString(); - textViewer - .setParagraphStyle((Paragraph) currentTextPart, style); - } else if (eventSource == deleteButton) { - textViewer.deletePart((SectionPart) currentTextPart); - } else if (eventSource == editButton) { - textViewer.getCmsEditable().startEditing(); - } else if (eventSource == publishButton) { - textViewer.getCmsEditable().stopEditing(); - } - setVisible(false); - } - } - - class ToolsShellListener extends org.eclipse.swt.events.ShellAdapter { - private static final long serialVersionUID = 8432350564023247241L; - - @Override - public void shellDeactivated(ShellEvent e) { - setVisible(false); - } - - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/TextEditorHeader.java b/org.argeo.cms.ui/src/org/argeo/cms/text/TextEditorHeader.java deleted file mode 100644 index 5ae053683..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/TextEditorHeader.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.argeo.cms.text; - -import java.util.Observable; -import java.util.Observer; - -import org.argeo.cms.ui.CmsEditable; -import org.argeo.cms.util.CmsUtils; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; - -/** Adds editing capabilities to a page editing text */ -public class TextEditorHeader implements SelectionListener, Observer { - private static final long serialVersionUID = 4186756396045701253L; - - private final CmsEditable cmsEditable; - private Button publish; - - private Composite parent; - private Composite display; - private Object layoutData; - - public TextEditorHeader(CmsEditable cmsEditable, Composite parent, int style) { - this.cmsEditable = cmsEditable; - this.parent = parent; - if (this.cmsEditable instanceof Observable) - ((Observable) this.cmsEditable).addObserver(this); - refresh(); - } - - protected void refresh() { - if (display != null && !display.isDisposed()) - display.dispose(); - display = null; - publish = null; - if (cmsEditable.isEditing()) { - display = new Composite(parent, SWT.NONE); - // display.setBackgroundMode(SWT.INHERIT_NONE); - display.setLayoutData(layoutData); - display.setLayout(CmsUtils.noSpaceGridLayout()); - CmsUtils.style(display, TextStyles.TEXT_EDITOR_HEADER); - publish = new Button(display, SWT.FLAT | SWT.PUSH); - publish.setText(getPublishButtonLabel()); - CmsUtils.style(publish, TextStyles.TEXT_EDITOR_HEADER); - publish.addSelectionListener(this); - display.moveAbove(null); - } - parent.layout(); - } - - private String getPublishButtonLabel() { - if (cmsEditable.isEditing()) - return "Publish"; - else - return "Edit"; - } - - @Override - public void widgetSelected(SelectionEvent e) { - if (e.getSource() == publish) { - if (cmsEditable.isEditing()) { - cmsEditable.stopEditing(); - } else { - cmsEditable.startEditing(); - } - // publish.setText(getPublishButtonLabel()); - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - @Override - public void update(Observable o, Object arg) { - if (o == cmsEditable) { - // publish.setText(getPublishButtonLabel()); - refresh(); - } - } - - public void setLayoutData(Object layoutData) { - this.layoutData = layoutData; - if (display != null && !display.isDisposed()) - display.setLayoutData(layoutData); - } - -} \ No newline at end of file diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/TextInterpreter.java b/org.argeo.cms.ui/src/org/argeo/cms/text/TextInterpreter.java deleted file mode 100644 index f39a2b329..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/TextInterpreter.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.argeo.cms.text; - -import javax.jcr.Item; - -/** Convert from/to data layer to/from presentation layer. */ -public interface TextInterpreter { - public String raw(Item item); - - public String read(Item item); - - public void write(Item item, String content); -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/TextInterpreterImpl.java b/org.argeo.cms.ui/src/org/argeo/cms/text/TextInterpreterImpl.java deleted file mode 100644 index f9ee195a7..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/TextInterpreterImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.argeo.cms.text; - -import javax.jcr.Item; -import javax.jcr.RepositoryException; - -/** - * Text interpreter that sanitise and validates before saving, and support CMS - * specific formatting and integration. - */ -class TextInterpreterImpl extends IdentityTextInterpreter { - private MarkupValidatorCopy markupValidator = MarkupValidatorCopy - .getInstance(); - - @Override - protected void validateBeforeStoring(String raw) { - markupValidator.validate(raw); - } - - @Override - protected String convertToStorage(Item item, String content) - throws RepositoryException { - return super.convertToStorage(item, content); - } - - @Override - protected String convertFromStorage(Item item, String content) - throws RepositoryException { - return super.convertFromStorage(item, content); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/TextSection.java b/org.argeo.cms.ui/src/org/argeo/cms/text/TextSection.java deleted file mode 100644 index ac93e4b65..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/TextSection.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.argeo.cms.text; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.cms.CmsNames; -import org.argeo.cms.util.CmsUtils; -import org.argeo.cms.viewers.Section; -import org.eclipse.swt.widgets.Composite; - -public class TextSection extends Section implements CmsNames { - private static final long serialVersionUID = -8625209546243220689L; - private String defaultTextStyle = TextStyles.TEXT_DEFAULT; - private String titleStyle; - - public TextSection(Composite parent, int style, Node node) - throws RepositoryException { - this(parent, findSection(parent), style, node); - } - - public TextSection(TextSection section, int style, Node node) - throws RepositoryException { - this(section, section.getParentSection(), style, node); - } - - private TextSection(Composite parent, Section parentSection, int style, - Node node) throws RepositoryException { - super(parent, parentSection, style, node); - CmsUtils.style(this, TextStyles.TEXT_SECTION); - } - - public String getDefaultTextStyle() { - return defaultTextStyle; - } - - public String getTitleStyle() { - if (titleStyle != null) - return titleStyle; - // TODO make base H styles configurable - Integer relativeDepth = getRelativeDepth(); - return relativeDepth == 0 ? TextStyles.TEXT_TITLE : TextStyles.TEXT_H - + relativeDepth; - } - - public void setDefaultTextStyle(String defaultTextStyle) { - this.defaultTextStyle = defaultTextStyle; - } - - public void setTitleStyle(String titleStyle) { - this.titleStyle = titleStyle; - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/TextStyles.java b/org.argeo.cms.ui/src/org/argeo/cms/text/TextStyles.java deleted file mode 100644 index 44c3ad054..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/TextStyles.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.argeo.cms.text; - -/** Styles references in the CSS. */ -public interface TextStyles { - /** The whole page area */ - public final static String TEXT_AREA = "text_area"; - /** Area providing controls for editing text */ - public final static String TEXT_EDITOR_HEADER = "text_editor_header"; - /** The styled composite for editing the text */ - public final static String TEXT_STYLED_COMPOSITE = "text_styled_composite"; - /** A section */ - public final static String TEXT_SECTION = "text_section"; - /** A paragraph */ - public final static String TEXT_PARAGRAPH = "text_paragraph"; - /** An image */ - public final static String TEXT_IMG = "text_img"; - /** The dialog to edit styled paragraph */ - public final static String TEXT_STYLED_TOOLS_DIALOG = "text_styled_tools_dialog"; - - /* - * DEFAULT TEXT STYLES - */ - /** Default style for text body */ - public final static String TEXT_DEFAULT = "text_default"; - /** Fixed-width, typically code */ - public final static String TEXT_PRE = "text_pre"; - /** Quote */ - public final static String TEXT_QUOTE = "text_quote"; - /** Title */ - public final static String TEXT_TITLE = "text_title"; - /** Header (to be dynamically completed with the depth, e.g. text_h1) */ - public final static String TEXT_H = "text_h"; - - /** Default style for images */ - public final static String TEXT_IMAGE = "text_image"; - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/text/WikiPage.java b/org.argeo.cms.ui/src/org/argeo/cms/text/WikiPage.java deleted file mode 100644 index a01cc3551..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/text/WikiPage.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.argeo.cms.text; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; - -import org.argeo.cms.CmsNames; -import org.argeo.cms.CmsTypes; -import org.argeo.cms.ui.CmsEditable; -import org.argeo.cms.ui.CmsUiProvider; -import org.argeo.cms.util.CmsLink; -import org.argeo.cms.util.CmsUtils; -import org.argeo.cms.viewers.JcrVersionCmsEditable; -import org.argeo.cms.widgets.ScrolledPage; -import org.argeo.jcr.JcrUtils; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; - -/** Display the text of the context, and provide an editor if the user can edit. */ -public class WikiPage implements CmsUiProvider, CmsNames { - @Override - public Control createUi(Composite parent, Node context) - throws RepositoryException { - CmsEditable cmsEditable = new JcrVersionCmsEditable(context); - if (cmsEditable.canEdit()) - new TextEditorHeader(cmsEditable, parent, SWT.NONE) - .setLayoutData(CmsUtils.fillWidth()); - - ScrolledPage page = new ScrolledPage(parent, SWT.NONE); - page.setLayout(CmsUtils.noSpaceGridLayout()); - GridData textGd = CmsUtils.fillAll(); - page.setLayoutData(textGd); - - if (context.isNodeType(CmsTypes.CMS_TEXT)) { - new StandardTextEditor(page, SWT.NONE, context, cmsEditable); - } else if (context.isNodeType(NodeType.NT_FOLDER) - || context.getPath().equals("/")) { - parent.setBackgroundMode(SWT.INHERIT_NONE); - if (context.getSession().hasPermission(context.getPath(), - Session.ACTION_ADD_NODE)) { - Node indexNode = JcrUtils.getOrAdd(context, CMS_INDEX, - CmsTypes.CMS_TEXT); - new StandardTextEditor(page, SWT.NONE, indexNode, cmsEditable); - textGd.heightHint = 400; - - for (NodeIterator ni = context.getNodes(); ni.hasNext();) { - Node textNode = ni.nextNode(); - if (textNode.isNodeType(NodeType.NT_FOLDER)) - new CmsLink(textNode.getName() + "/", - textNode.getPath()).createUi(parent, textNode); - } - for (NodeIterator ni = context.getNodes(); ni.hasNext();) { - Node textNode = ni.nextNode(); - if (textNode.isNodeType(CmsTypes.CMS_TEXT) - && !textNode.getName().equals(CMS_INDEX)) - new CmsLink(textNode.getName(), textNode.getPath()) - .createUi(parent, textNode); - } - } - } - return page; - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/img/Dummy.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/img/Dummy.java new file mode 100644 index 000000000..4c48f7114 --- /dev/null +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/img/Dummy.java @@ -0,0 +1,5 @@ +package org.argeo.cms.ui.img; + +public class Dummy { + +} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/ImageManagerImpl.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/ImageManagerImpl.java deleted file mode 100644 index 48c5812c9..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/ImageManagerImpl.java +++ /dev/null @@ -1,251 +0,0 @@ -package org.argeo.cms.ui.internal; - -import static javax.jcr.Node.JCR_CONTENT; -import static javax.jcr.Property.JCR_DATA; -import static javax.jcr.nodetype.NodeType.NT_FILE; -import static javax.jcr.nodetype.NodeType.NT_RESOURCE; -import static org.argeo.cms.CmsNames.CMS_IMAGE_HEIGHT; -import static org.argeo.cms.CmsNames.CMS_IMAGE_WIDTH; -import static org.argeo.cms.ui.CmsConstants.NO_IMAGE_SIZE; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; - -import javax.jcr.Binary; -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.RepositoryException; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.cms.CmsException; -import org.argeo.cms.CmsNames; -import org.argeo.cms.CmsTypes; -import org.argeo.cms.ui.CmsImageManager; -import org.argeo.cms.util.CmsUtils; -import org.argeo.jcr.JcrUtils; -import org.eclipse.rap.rwt.RWT; -import org.eclipse.rap.rwt.service.ResourceManager; -import org.eclipse.rap.rwt.widgets.FileUpload; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; - -/** Manages only public images so far. */ -public class ImageManagerImpl implements CmsImageManager { - private final static Log log = LogFactory.getLog(ImageManagerImpl.class); -// private MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap(); - - public Boolean load(Node node, Control control, Point preferredSize) throws RepositoryException { - Point imageSize = getImageSize(node); - Point size; - String imgTag = null; - if (preferredSize == null || imageSize.x == 0 || imageSize.y == 0 - || (preferredSize.x == 0 && preferredSize.y == 0)) { - if (imageSize.x != 0 && imageSize.y != 0) { - // actual image size if completely known - size = imageSize; - } else { - // no image if not completely known - size = resizeTo(NO_IMAGE_SIZE, preferredSize != null ? preferredSize : imageSize); - imgTag = CmsUtils.noImg(size); - } - - } else if (preferredSize.x != 0 && preferredSize.y != 0) { - // given size if completely provided - size = preferredSize; - } else { - // at this stage : - // image is completely known - assert imageSize.x != 0 && imageSize.y != 0; - // one and only one of the dimension as been specified - assert preferredSize.x == 0 || preferredSize.y == 0; - size = resizeTo(imageSize, preferredSize); - } - - boolean loaded = false; - if (control == null) - return loaded; - - if (control instanceof Label) { - if (imgTag == null) { - // IMAGE RETRIEVED HERE - imgTag = getImageTag(node, size); - // - if (imgTag == null) - imgTag = CmsUtils.noImg(size); - else - loaded = true; - } - - Label lbl = (Label) control; - lbl.setText(imgTag); - // lbl.setSize(size); - } else if (control instanceof FileUpload) { - FileUpload lbl = (FileUpload) control; - lbl.setImage(CmsUtils.noImage(size)); - lbl.setSize(size); - return loaded; - } else - loaded = false; - - return loaded; - } - - private Point resizeTo(Point orig, Point constraints) { - if (constraints.x != 0 && constraints.y != 0) { - return constraints; - } else if (constraints.x == 0 && constraints.y == 0) { - return orig; - } else if (constraints.y == 0) {// force width - return new Point(constraints.x, scale(orig.y, orig.x, constraints.x)); - } else if (constraints.x == 0) {// force height - return new Point(scale(orig.x, orig.y, constraints.y), constraints.y); - } - throw new CmsException("Cannot resize " + orig + " to " + constraints); - } - - private int scale(int origDimension, int otherDimension, int otherConstraint) { - return Math.round(origDimension * divide(otherConstraint, otherDimension)); - } - - private float divide(int a, int b) { - return ((float) a) / ((float) b); - } - - public Point getImageSize(Node node) throws RepositoryException { - return new Point(node.hasProperty(CMS_IMAGE_WIDTH) ? (int) node.getProperty(CMS_IMAGE_WIDTH).getLong() : 0, - node.hasProperty(CMS_IMAGE_HEIGHT) ? (int) node.getProperty(CMS_IMAGE_HEIGHT).getLong() : 0); - } - - /** @return null if not available */ - @Override - public String getImageTag(Node node) throws RepositoryException { - return getImageTag(node, getImageSize(node)); - } - - private String getImageTag(Node node, Point size) throws RepositoryException { - StringBuilder buf = getImageTagBuilder(node, size); - if (buf == null) - return null; - return buf.append("/>").toString(); - } - - /** @return null if not available */ - @Override - public StringBuilder getImageTagBuilder(Node node, Point size) throws RepositoryException { - return getImageTagBuilder(node, Integer.toString(size.x), Integer.toString(size.y)); - } - - /** @return null if not available */ - private StringBuilder getImageTagBuilder(Node node, String width, String height) throws RepositoryException { - String url = getImageUrl(node); - if (url == null) - return null; - return CmsUtils.imgBuilder(url, width, height); - } - - /** @return null if not available */ - @Override - public String getImageUrl(Node node) throws RepositoryException { - return CmsUtils.getDataPath(node); - // String name = getResourceName(node); - // ResourceManager resourceManager = RWT.getResourceManager(); - // if (!resourceManager.isRegistered(name)) { - // InputStream inputStream = null; - // Binary binary = getImageBinary(node); - // if (binary == null) - // return null; - // try { - // inputStream = binary.getStream(); - // resourceManager.register(name, inputStream); - // } finally { - // IOUtils.closeQuietly(inputStream); - // JcrUtils.closeQuietly(binary); - // } - // if (log.isTraceEnabled()) - // log.trace("Registered image " + name); - // } - // return resourceManager.getLocation(name); - } - - protected String getResourceName(Node node) throws RepositoryException { - String workspace = node.getSession().getWorkspace().getName(); - if (node.hasNode(JCR_CONTENT)) - return workspace + '_' + node.getNode(JCR_CONTENT).getIdentifier(); - else - return workspace + '_' + node.getIdentifier(); - } - - public Binary getImageBinary(Node node) throws RepositoryException { - if (node.isNodeType(NT_FILE)) { - return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary(); - } else if (node.isNodeType(CmsTypes.CMS_STYLED) && node.hasProperty(CmsNames.CMS_DATA)) { - return node.getProperty(CmsNames.CMS_DATA).getBinary(); - } else { - return null; - } - } - - public Image getSwtImage(Node node) throws RepositoryException { - InputStream inputStream = null; - Binary binary = getImageBinary(node); - if (binary == null) - return null; - try { - inputStream = binary.getStream(); - return new Image(Display.getCurrent(), inputStream); - } finally { - IOUtils.closeQuietly(inputStream); - JcrUtils.closeQuietly(binary); - } - } - - @Override - public String uploadImage(Node parentNode, String fileName, InputStream in) throws RepositoryException { - InputStream inputStream = null; - try { - String previousResourceName = null; - if (parentNode.hasNode(fileName)) { - Node node = parentNode.getNode(fileName); - previousResourceName = getResourceName(node); - if (node.hasNode(JCR_CONTENT)) { - node.getNode(JCR_CONTENT).remove(); - node.addNode(JCR_CONTENT, NT_RESOURCE); - } - } - - byte[] arr = IOUtils.toByteArray(in); - Node fileNode = JcrUtils.copyBytesAsFile(parentNode, fileName, arr); - fileNode.addMixin(CmsTypes.CMS_IMAGE); - - inputStream = new ByteArrayInputStream(arr); - ImageData id = new ImageData(inputStream); - fileNode.setProperty(CMS_IMAGE_WIDTH, id.width); - fileNode.setProperty(CMS_IMAGE_HEIGHT, id.height); - String mime = Files.probeContentType(Paths.get(fileName)); - fileNode.setProperty(Property.JCR_MIMETYPE, mime); - fileNode.getSession().save(); - - // reset resource manager - ResourceManager resourceManager = RWT.getResourceManager(); - if (previousResourceName != null && resourceManager.isRegistered(previousResourceName)) { - resourceManager.unregister(previousResourceName); - if (log.isDebugEnabled()) - log.debug("Unregistered image " + previousResourceName); - } - return getImageUrl(fileNode); - } catch (IOException e) { - throw new CmsException("Cannot upload image " + fileName + " in " + parentNode, e); - } finally { - IOUtils.closeQuietly(inputStream); - } - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/util/DefaultImageManager.java b/org.argeo.cms.ui/src/org/argeo/cms/util/DefaultImageManager.java new file mode 100644 index 000000000..015ca1ce9 --- /dev/null +++ b/org.argeo.cms.ui/src/org/argeo/cms/util/DefaultImageManager.java @@ -0,0 +1,246 @@ +package org.argeo.cms.util; + +import static javax.jcr.Node.JCR_CONTENT; +import static javax.jcr.Property.JCR_DATA; +import static javax.jcr.nodetype.NodeType.NT_FILE; +import static javax.jcr.nodetype.NodeType.NT_RESOURCE; +import static org.argeo.cms.ui.CmsConstants.NO_IMAGE_SIZE; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; + +import javax.jcr.Binary; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.cms.CmsException; +import org.argeo.cms.ui.CmsImageManager; +import org.argeo.jcr.JcrUtils; +import org.eclipse.rap.rwt.RWT; +import org.eclipse.rap.rwt.service.ResourceManager; +import org.eclipse.rap.rwt.widgets.FileUpload; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; + +/** Manages only public images so far. */ +public class DefaultImageManager implements CmsImageManager { + private final static Log log = LogFactory.getLog(DefaultImageManager.class); +// private MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap(); + + public Boolean load(Node node, Control control, Point preferredSize) throws RepositoryException { + Point imageSize = getImageSize(node); + Point size; + String imgTag = null; + if (preferredSize == null || imageSize.x == 0 || imageSize.y == 0 + || (preferredSize.x == 0 && preferredSize.y == 0)) { + if (imageSize.x != 0 && imageSize.y != 0) { + // actual image size if completely known + size = imageSize; + } else { + // no image if not completely known + size = resizeTo(NO_IMAGE_SIZE, preferredSize != null ? preferredSize : imageSize); + imgTag = CmsUtils.noImg(size); + } + + } else if (preferredSize.x != 0 && preferredSize.y != 0) { + // given size if completely provided + size = preferredSize; + } else { + // at this stage : + // image is completely known + assert imageSize.x != 0 && imageSize.y != 0; + // one and only one of the dimension as been specified + assert preferredSize.x == 0 || preferredSize.y == 0; + size = resizeTo(imageSize, preferredSize); + } + + boolean loaded = false; + if (control == null) + return loaded; + + if (control instanceof Label) { + if (imgTag == null) { + // IMAGE RETRIEVED HERE + imgTag = getImageTag(node, size); + // + if (imgTag == null) + imgTag = CmsUtils.noImg(size); + else + loaded = true; + } + + Label lbl = (Label) control; + lbl.setText(imgTag); + // lbl.setSize(size); + } else if (control instanceof FileUpload) { + FileUpload lbl = (FileUpload) control; + lbl.setImage(CmsUtils.noImage(size)); + lbl.setSize(size); + return loaded; + } else + loaded = false; + + return loaded; + } + + private Point resizeTo(Point orig, Point constraints) { + if (constraints.x != 0 && constraints.y != 0) { + return constraints; + } else if (constraints.x == 0 && constraints.y == 0) { + return orig; + } else if (constraints.y == 0) {// force width + return new Point(constraints.x, scale(orig.y, orig.x, constraints.x)); + } else if (constraints.x == 0) {// force height + return new Point(scale(orig.x, orig.y, constraints.y), constraints.y); + } + throw new CmsException("Cannot resize " + orig + " to " + constraints); + } + + private int scale(int origDimension, int otherDimension, int otherConstraint) { + return Math.round(origDimension * divide(otherConstraint, otherDimension)); + } + + private float divide(int a, int b) { + return ((float) a) / ((float) b); + } + + public Point getImageSize(Node node) throws RepositoryException { + // TODO load the SWT image ? + return new Point(0, 0); + } + + /** @return null if not available */ + @Override + public String getImageTag(Node node) throws RepositoryException { + return getImageTag(node, getImageSize(node)); + } + + private String getImageTag(Node node, Point size) throws RepositoryException { + StringBuilder buf = getImageTagBuilder(node, size); + if (buf == null) + return null; + return buf.append("/>").toString(); + } + + /** @return null if not available */ + @Override + public StringBuilder getImageTagBuilder(Node node, Point size) throws RepositoryException { + return getImageTagBuilder(node, Integer.toString(size.x), Integer.toString(size.y)); + } + + /** @return null if not available */ + private StringBuilder getImageTagBuilder(Node node, String width, String height) throws RepositoryException { + String url = getImageUrl(node); + if (url == null) + return null; + return CmsUtils.imgBuilder(url, width, height); + } + + /** @return null if not available */ + @Override + public String getImageUrl(Node node) throws RepositoryException { + return CmsUtils.getDataPath(node); + // String name = getResourceName(node); + // ResourceManager resourceManager = RWT.getResourceManager(); + // if (!resourceManager.isRegistered(name)) { + // InputStream inputStream = null; + // Binary binary = getImageBinary(node); + // if (binary == null) + // return null; + // try { + // inputStream = binary.getStream(); + // resourceManager.register(name, inputStream); + // } finally { + // IOUtils.closeQuietly(inputStream); + // JcrUtils.closeQuietly(binary); + // } + // if (log.isTraceEnabled()) + // log.trace("Registered image " + name); + // } + // return resourceManager.getLocation(name); + } + + protected String getResourceName(Node node) throws RepositoryException { + String workspace = node.getSession().getWorkspace().getName(); + if (node.hasNode(JCR_CONTENT)) + return workspace + '_' + node.getNode(JCR_CONTENT).getIdentifier(); + else + return workspace + '_' + node.getIdentifier(); + } + + public Binary getImageBinary(Node node) throws RepositoryException { + if (node.isNodeType(NT_FILE)) { + return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary(); + } else { + return null; + } + } + + public Image getSwtImage(Node node) throws RepositoryException { + InputStream inputStream = null; + Binary binary = getImageBinary(node); + if (binary == null) + return null; + try { + inputStream = binary.getStream(); + return new Image(Display.getCurrent(), inputStream); + } finally { + IOUtils.closeQuietly(inputStream); + JcrUtils.closeQuietly(binary); + } + } + + @Override + public String uploadImage(Node parentNode, String fileName, InputStream in) throws RepositoryException { + InputStream inputStream = null; + try { + String previousResourceName = null; + if (parentNode.hasNode(fileName)) { + Node node = parentNode.getNode(fileName); + previousResourceName = getResourceName(node); + if (node.hasNode(JCR_CONTENT)) { + node.getNode(JCR_CONTENT).remove(); + node.addNode(JCR_CONTENT, NT_RESOURCE); + } + } + + byte[] arr = IOUtils.toByteArray(in); + Node fileNode = JcrUtils.copyBytesAsFile(parentNode, fileName, arr); + inputStream = new ByteArrayInputStream(arr); + ImageData id = new ImageData(inputStream); + processNewImageFile(fileNode, id); + + String mime = Files.probeContentType(Paths.get(fileName)); + fileNode.setProperty(Property.JCR_MIMETYPE, mime); + fileNode.getSession().save(); + + // reset resource manager + ResourceManager resourceManager = RWT.getResourceManager(); + if (previousResourceName != null && resourceManager.isRegistered(previousResourceName)) { + resourceManager.unregister(previousResourceName); + if (log.isDebugEnabled()) + log.debug("Unregistered image " + previousResourceName); + } + return getImageUrl(fileNode); + } catch (IOException e) { + throw new CmsException("Cannot upload image " + fileName + " in " + parentNode, e); + } finally { + IOUtils.closeQuietly(inputStream); + } + } + + /** Does nothign by default. */ + protected void processNewImageFile(Node fileNode, ImageData id) throws RepositoryException, IOException { + } +} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleErgonomics.java b/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleErgonomics.java index ca563600c..3f06d88e8 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleErgonomics.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleErgonomics.java @@ -14,7 +14,6 @@ import org.argeo.cms.ui.CmsImageManager; import org.argeo.cms.ui.CmsStyles; import org.argeo.cms.ui.CmsUiProvider; import org.argeo.cms.ui.UxContext; -import org.argeo.cms.ui.internal.ImageManagerImpl; import org.eclipse.rap.rwt.RWT; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; @@ -44,7 +43,7 @@ public class SimpleErgonomics extends AbstractCmsEntryPoint { private CmsUiProvider end; private CmsUiProvider footer; - private CmsImageManager imageManager = new ImageManagerImpl(); + private CmsImageManager imageManager = new DefaultImageManager(); private UxContext uxContext = null; public SimpleErgonomics(Repository repository, String workspace, String defaultPath, CmsUiProvider uiProvider, diff --git a/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleImageManager.java b/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleImageManager.java index 77d61cb4f..4e90766a6 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleImageManager.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleImageManager.java @@ -1,7 +1,5 @@ package org.argeo.cms.util; -import org.argeo.cms.ui.internal.ImageManagerImpl; - -public class SimpleImageManager extends ImageManagerImpl { +public class SimpleImageManager extends DefaultImageManager { } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/widgets/Img.java b/org.argeo.cms.ui/src/org/argeo/cms/widgets/Img.java new file mode 100644 index 000000000..59c4823b2 --- /dev/null +++ b/org.argeo.cms.ui/src/org/argeo/cms/widgets/Img.java @@ -0,0 +1,150 @@ +package org.argeo.cms.widgets; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +import org.argeo.cms.CmsException; +import org.argeo.cms.ui.CmsImageManager; +import org.argeo.cms.ui.internal.JcrFileUploadReceiver; +import org.argeo.cms.util.CmsUtils; +import org.argeo.cms.viewers.NodePart; +import org.argeo.cms.viewers.Section; +import org.argeo.cms.viewers.SectionPart; +import org.eclipse.rap.fileupload.FileUploadHandler; +import org.eclipse.rap.fileupload.FileUploadListener; +import org.eclipse.rap.fileupload.FileUploadReceiver; +import org.eclipse.rap.rwt.service.ServerPushSession; +import org.eclipse.rap.rwt.widgets.FileUpload; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** An image within the Argeo Text framework */ +public class Img extends EditableImage implements SectionPart, NodePart { + private static final long serialVersionUID = 6233572783968188476L; + + private final Section section; + + private final CmsImageManager imageManager; + private FileUploadHandler currentUploadHandler = null; + private FileUploadListener fileUploadListener; + + public Img(Composite parent, int swtStyle, Node imgNode, + Point preferredImageSize) throws RepositoryException { + this(Section.findSection(parent), parent, swtStyle, imgNode, + preferredImageSize); + setStyle(TextStyles.TEXT_IMAGE); + } + + public Img(Composite parent, int swtStyle, Node imgNode) + throws RepositoryException { + this(Section.findSection(parent), parent, swtStyle, imgNode, null); + setStyle(TextStyles.TEXT_IMAGE); + } + + Img(Section section, Composite parent, int swtStyle, Node imgNode, + Point preferredImageSize) throws RepositoryException { + super(parent, swtStyle, imgNode, false, preferredImageSize); + this.section = section; + imageManager = CmsUtils.getCmsView().getImageManager(); + CmsUtils.style(this, TextStyles.TEXT_IMG); + } + + @Override + protected Control createControl(Composite box, String style) { + if (isEditing()) { + try { + return createImageChooser(box, style); + } catch (RepositoryException e) { + throw new CmsException("Cannot create image chooser", e); + } + } else { + return createLabel(box, style); + } + } + + @Override + public synchronized void stopEditing() { + super.stopEditing(); + fileUploadListener = null; + } + + @Override + protected synchronized Boolean load(Control lbl) { + try { + Node imgNode = getNode(); + boolean loaded = imageManager.load(imgNode, lbl, + getPreferredImageSize()); + // getParent().layout(); + return loaded; + } catch (RepositoryException e) { + throw new CmsException("Cannot load " + getNodeId() + + " from image manager", e); + } + } + + protected Control createImageChooser(Composite box, String style) + throws RepositoryException { + // FileDialog fileDialog = new FileDialog(getShell()); + // fileDialog.open(); + // String fileName = fileDialog.getFileName(); + CmsImageManager imageManager = CmsUtils.getCmsView().getImageManager(); + Node node = getNode(); + JcrFileUploadReceiver receiver = new JcrFileUploadReceiver( + node.getParent(), node.getName() + '[' + node.getIndex() + ']', + imageManager); + if (currentUploadHandler != null) + currentUploadHandler.dispose(); + currentUploadHandler = prepareUpload(receiver); + final ServerPushSession pushSession = new ServerPushSession(); + final FileUpload fileUpload = new FileUpload(box, SWT.NONE); + CmsUtils.style(fileUpload, style); + fileUpload.addSelectionListener(new SelectionAdapter() { + private static final long serialVersionUID = -9158471843941668562L; + + @Override + public void widgetSelected(SelectionEvent e) { + pushSession.start(); + fileUpload.submit(currentUploadHandler.getUploadUrl()); + } + }); + return fileUpload; + } + + protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) { + final FileUploadHandler uploadHandler = new FileUploadHandler(receiver); + if (fileUploadListener != null) + uploadHandler.addUploadListener(fileUploadListener); + return uploadHandler; + } + + @Override + public Section getSection() { + return section; + } + + public void setFileUploadListener(FileUploadListener fileUploadListener) { + this.fileUploadListener = fileUploadListener; + if (currentUploadHandler != null) + currentUploadHandler.addUploadListener(fileUploadListener); + } + + @Override + public Node getItem() throws RepositoryException { + return getNode(); + } + + @Override + public String getPartId() { + return getNodeId(); + } + + @Override + public String toString() { + return "Img #" + getPartId(); + } + +} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/widgets/StyledControl.java b/org.argeo.cms.ui/src/org/argeo/cms/widgets/StyledControl.java index da4d949a4..4d999d501 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/widgets/StyledControl.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/widgets/StyledControl.java @@ -3,7 +3,6 @@ package org.argeo.cms.widgets; import javax.jcr.Item; import javax.jcr.RepositoryException; -import org.argeo.cms.CmsNames; import org.argeo.cms.ui.CmsConstants; import org.argeo.cms.util.CmsUtils; import org.eclipse.swt.SWT; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/widgets/TextStyles.java b/org.argeo.cms.ui/src/org/argeo/cms/widgets/TextStyles.java new file mode 100644 index 000000000..be5bc5fea --- /dev/null +++ b/org.argeo.cms.ui/src/org/argeo/cms/widgets/TextStyles.java @@ -0,0 +1,37 @@ +package org.argeo.cms.widgets; + +/** Styles references in the CSS. */ +public interface TextStyles { + /** The whole page area */ + public final static String TEXT_AREA = "text_area"; + /** Area providing controls for editing text */ + public final static String TEXT_EDITOR_HEADER = "text_editor_header"; + /** The styled composite for editing the text */ + public final static String TEXT_STYLED_COMPOSITE = "text_styled_composite"; + /** A section */ + public final static String TEXT_SECTION = "text_section"; + /** A paragraph */ + public final static String TEXT_PARAGRAPH = "text_paragraph"; + /** An image */ + public final static String TEXT_IMG = "text_img"; + /** The dialog to edit styled paragraph */ + public final static String TEXT_STYLED_TOOLS_DIALOG = "text_styled_tools_dialog"; + + /* + * DEFAULT TEXT STYLES + */ + /** Default style for text body */ + public final static String TEXT_DEFAULT = "text_default"; + /** Fixed-width, typically code */ + public final static String TEXT_PRE = "text_pre"; + /** Quote */ + public final static String TEXT_QUOTE = "text_quote"; + /** Title */ + public final static String TEXT_TITLE = "text_title"; + /** Header (to be dynamically completed with the depth, e.g. text_h1) */ + public final static String TEXT_H = "text_h"; + + /** Default style for images */ + public final static String TEXT_IMAGE = "text_image"; + +} diff --git a/org.argeo.cms/bnd.bnd b/org.argeo.cms/bnd.bnd index f32e1fafc..ab54cd60e 100644 --- a/org.argeo.cms/bnd.bnd +++ b/org.argeo.cms/bnd.bnd @@ -10,6 +10,4 @@ org.apache.commons.httpclient.cookie;resolution:=optional,\ org.osgi.*;version=0.0.0,\ * -Provide-Capability: cms.datamodel;name=argeo;cnd=/org/argeo/cms/argeo.cnd;abstract=true,\ -cms.datamodel;name=cms;cnd=/org/argeo/cms/cms.cnd;abstract=true,\ -cms.datamodel;name=dn;cnd=/org/argeo/cms/dn.cnd;abstract=true \ No newline at end of file +Provide-Capability: cms.datamodel;name=argeo;cnd=/org/argeo/cms/argeo.cnd;abstract=true diff --git a/org.argeo.cms/src/org/argeo/cms/CmsNames.java b/org.argeo.cms/src/org/argeo/cms/CmsNames.java deleted file mode 100644 index be10b7601..000000000 --- a/org.argeo.cms/src/org/argeo/cms/CmsNames.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.argeo.cms; - -/** JCR names. */ -public interface CmsNames { - /* - * TEXT - */ - public final static String CMS_DRAFTS = "cms:drafts"; - - public final static String CMS_P = "cms:p"; - public final static String CMS_H = "cms:h"; - - public final static String CMS_CONTENT = "cms:content"; - public final static String CMS_STYLE = "cms:style"; - - public final static String CMS_INDEX = "cms:index"; - - /* - * IMAGES - */ - public final static String CMS_IMAGE_WIDTH = "cms:imageWidth"; - public final static String CMS_IMAGE_HEIGHT = "cms:imageHeight"; - public final static String CMS_DATA = "cms:data"; -} diff --git a/org.argeo.cms/src/org/argeo/cms/CmsTypes.java b/org.argeo.cms/src/org/argeo/cms/CmsTypes.java deleted file mode 100644 index a8ef07618..000000000 --- a/org.argeo.cms/src/org/argeo/cms/CmsTypes.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.argeo.cms; - -/** JCR types. */ -public interface CmsTypes { - public final static String CMS_TEXT = "cms:text"; - public final static String CMS_IMAGE = "cms:image"; - public final static String CMS_SECTION = "cms:section"; - public final static String CMS_STYLED = "cms:styled"; - -} diff --git a/org.argeo.cms/src/org/argeo/cms/cms.cnd b/org.argeo.cms/src/org/argeo/cms/cms.cnd deleted file mode 100644 index 0e420f516..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cms.cnd +++ /dev/null @@ -1,22 +0,0 @@ - - -// TEXT -[cms:styled] -mixin -- cms:style (STRING) -- cms:content (STRING) -- cms:data (BINARY) - -[cms:image] > mix:title, mix:mimeType -mixin -- cms:imageWidth (STRING) -- cms:imageHeight (STRING) - -[cms:section] > nt:folder, mix:created, mix:lastModified, mix:title -orderable -+ cms:p (nt:base) = nt:unstructured * -+ cms:h (cms:section) * -+ cms:attached (nt:folder) - -[cms:text] > cms:section -+ cms:history (nt:folder) diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/LinkServlet.java b/org.argeo.cms/src/org/argeo/cms/internal/http/LinkServlet.java index 34bdcaa17..f9e17a107 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/http/LinkServlet.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/http/LinkServlet.java @@ -3,7 +3,6 @@ package org.argeo.cms.internal.http; import static javax.jcr.Property.JCR_DESCRIPTION; import static javax.jcr.Property.JCR_LAST_MODIFIED; import static javax.jcr.Property.JCR_TITLE; -import static org.argeo.cms.CmsTypes.CMS_IMAGE; import java.io.IOException; import java.io.PrintWriter; @@ -102,14 +101,15 @@ public class LinkServlet extends HttpServlet { : null; String url = getCanonicalUrl(node, request); String imgUrl = null; - loop: for (NodeIterator it = node.getNodes(); it.hasNext();) { - // Takes the first found cms:image - Node child = it.nextNode(); - if (child.isNodeType(CMS_IMAGE)) { - imgUrl = getDataUrl(child, request); - break loop; - } - } + // TODO support images +// loop: for (NodeIterator it = node.getNodes(); it.hasNext();) { +// // Takes the first found cms:image +// Node child = it.nextNode(); +// if (child.isNodeType(CMS_IMAGE)) { +// imgUrl = getDataUrl(child, request); +// break loop; +// } +// } StringBuilder buf = new StringBuilder(); buf.append(""); buf.append("");