Improve image management and ACR
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 25 Jun 2023 08:37:59 +0000 (10:37 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 25 Jun 2023 08:37:59 +0000 (10:37 +0200)
17 files changed:
org.argeo.api.acr/src/org/argeo/api/acr/Content.java
org.argeo.api.acr/src/org/argeo/api/acr/spi/ProvidedContent.java
org.argeo.api.cms/src/org/argeo/api/cms/ux/Cms2DSize.java
org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsImageManager.java
org.argeo.cms.ux/src/org/argeo/cms/ux/AbstractImageManager.java
org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java
org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java
org.argeo.cms/src/org/argeo/cms/acr/ContentUtils.java
org.argeo.cms/src/org/argeo/cms/acr/SvgAttrs.java
org.argeo.cms/src/org/argeo/cms/acr/fs/FsContent.java
org.argeo.cms/src/org/argeo/cms/acr/xml/DomContent.java
org.argeo.cms/src/org/argeo/cms/acr/xml/DomContentProvider.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/AbstractSwtImageManager.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/Img.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/LinkedControl.java [new file with mode: 0644]
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/EditableImage.java

index 865705f64cde265bfc08dbb8862a91f526a4429a..df5c149e6fc1fc696187d197766ad5f9cf0c2c52 100644 (file)
@@ -16,6 +16,8 @@ import javax.xml.namespace.QName;
  * A semi-structured content, with attributes, within a hierarchical structure.
  */
 public interface Content extends Iterable<Content>, Map<QName, Object> {
+       /** The base of a repository path. */
+       String ROOT_PATH = "/";
 
        QName getName();
 
@@ -208,6 +210,14 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
                return res;
        }
 
+       default List<Content> children(QNamed name) {
+               return children(name.qName());
+       }
+
+       default Optional<Content> soleChild(QNamed name) {
+               return soleChild(name.qName());
+       }
+
        default Optional<Content> soleChild(QName name) {
                List<Content> res = children(name);
                if (res.isEmpty())
@@ -270,9 +280,9 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
        /**
         * A content within this repository
         * 
-        * @param path either an abolute path or a path relative to this content
+        * @param path either an absolute path or a path relative to this content
         */
-       Content getContent(String path);
+       Optional<Content> getContent(String path);
 
        /*
         * EXPERIMENTAL UNSUPPORTED
index d4162afb0d09d9db7ac8ebccc9ea8d7ea938861d..f1e5aaaa80f24af4dce505a935b342645d9910c8 100644 (file)
@@ -1,11 +1,11 @@
 package org.argeo.api.acr.spi;
 
+import java.util.Optional;
+
 import org.argeo.api.acr.Content;
 
 /** A {@link Content} implementation. */
 public interface ProvidedContent extends Content {
-       final static String ROOT_PATH = "/";
-
        /** The related {@link ProvidedSession}. */
        ProvidedSession getSession();
 
@@ -39,15 +39,14 @@ public interface ProvidedContent extends Content {
        }
 
        @Override
-       default ProvidedContent getContent(String path) {
-               Content fileNode;
-               if (path.startsWith(ROOT_PATH)) {// absolute
-                       fileNode = getSession().get(path);
+       default Optional<Content> getContent(String path) {
+               String absolutePath;
+               if (path.startsWith(Content.ROOT_PATH)) {// absolute
+                       absolutePath = path;
                } else {// relative
-                       String absolutePath = getPath() + '/' + path;
-                       fileNode = getSession().get(absolutePath);
+                       absolutePath = getPath() + '/' + path;
                }
-               return (ProvidedContent) fileNode;
+               return getSession().exists(absolutePath) ? Optional.of(getSession().get(absolutePath)) : Optional.empty();
        }
 
        /*
index 1ec753a187770d4d6f67c02476754dadc6a05a9e..f35e98c5022bb730b343d4e4a1b003c5c0aef0ac 100644 (file)
@@ -1,38 +1,9 @@
 package org.argeo.api.cms.ux;
 
 /** A 2D size. */
-public class Cms2DSize {
-       private Integer width;
-       private Integer height;
-
-       public Cms2DSize() {
-       }
-
-       public Cms2DSize(Integer width, Integer height) {
-               super();
-               this.width = width;
-               this.height = height;
-       }
-
-       public Integer getWidth() {
-               return width;
-       }
-
-       public void setWidth(Integer width) {
-               this.width = width;
-       }
-
-       public Integer getHeight() {
-               return height;
-       }
-
-       public void setHeight(Integer height) {
-               this.height = height;
-       }
-
+public record Cms2DSize(int width, int height) {
        @Override
        public String toString() {
                return Cms2DSize.class.getSimpleName() + "[" + width + "," + height + "]";
        }
-
 }
index 1ec54a9d9666534d571100bff10ecc166ec2b544..4fb393a569cc74aa6bd78ce8fda5041cc45b002e 100644 (file)
@@ -1,11 +1,12 @@
 package org.argeo.api.cms.ux;
 
 import java.io.InputStream;
+import java.net.URI;
 
 /** Read and write access to images. */
 public interface CmsImageManager<V, M> {
        /** Load image in control */
-       public Boolean load(M node, V control, Cms2DSize size);
+       public Boolean load(M node, V control, Cms2DSize size, URI link);
 
        /** @return (0,0) if not available */
        public Cms2DSize getImageSize(M node);
index 41c905ef6c56b18199b697ffc89e6525b1b6e225..31a0d6bed044288176d03166f6cb1a1fe36606e6 100644 (file)
@@ -10,16 +10,16 @@ public abstract class AbstractImageManager<V, M> implements CmsImageManager<V, M
        public final static Float NO_IMAGE_RATIO = 1f;
 
        protected Cms2DSize resizeTo(Cms2DSize orig, Cms2DSize constraints) {
-               if (constraints.getWidth() != 0 && constraints.getHeight() != 0) {
+               if (constraints.width() != 0 && constraints.height() != 0) {
                        return constraints;
-               } else if (constraints.getWidth() == 0 && constraints.getHeight() == 0) {
+               } else if (constraints.width() == 0 && constraints.height() == 0) {
                        return orig;
-               } else if (constraints.getHeight() == 0) {// force width
-                       return new Cms2DSize(constraints.getWidth(),
-                                       scale(orig.getHeight(), orig.getWidth(), constraints.getWidth()));
-               } else if (constraints.getWidth() == 0) {// force height
-                       return new Cms2DSize(scale(orig.getWidth(), orig.getHeight(), constraints.getHeight()),
-                                       constraints.getHeight());
+               } else if (constraints.height() == 0) {// force width
+                       return new Cms2DSize(constraints.width(),
+                                       scale(orig.height(), orig.width(), constraints.width()));
+               } else if (constraints.width() == 0) {// force height
+                       return new Cms2DSize(scale(orig.width(), orig.height(), constraints.height()),
+                                       constraints.height());
                }
                throw new IllegalArgumentException("Cannot resize " + orig + " to " + constraints);
        }
@@ -48,7 +48,7 @@ public abstract class AbstractImageManager<V, M> implements CmsImageManager<V, M
        /** @return null if not available */
        @Override
        public StringBuilder getImageTagBuilder(M node, Cms2DSize size) {
-               return getImageTagBuilder(node, Integer.toString(size.getWidth()), Integer.toString(size.getHeight()));
+               return getImageTagBuilder(node, Integer.toString(size.width()), Integer.toString(size.height()));
        }
 
        /** @return null if not available */
index 087b4ff7c725116eb8fe4f8be1b5536d9bb23681..84e471aafbe2103403a24ed7535c941469f0ff36 100644 (file)
@@ -31,6 +31,6 @@ public class CmsUxUtils {
        }
 
        public static String img(String src, Cms2DSize size) {
-               return img(src, Integer.toString(size.getWidth()), Integer.toString(size.getHeight()));
+               return img(src, Integer.toString(size.width()), Integer.toString(size.height()));
        }
 }
index be4ffea746bf1b32a1fc2cc18aa6c116b300d468..daefe9835e371c4210bf6487ce108ac04700e05d 100644 (file)
@@ -70,7 +70,7 @@ class CmsContentSession implements ProvidedSession, UuidIdentified {
 
        @Override
        public Content get(String path) {
-               if (!path.startsWith(ContentUtils.ROOT_SLASH))
+               if (!path.startsWith(Content.ROOT_PATH))
                        throw new IllegalArgumentException(path + " is not an absolute path");
                ContentProvider contentProvider = contentRepository.getMountManager().findContentProvider(path);
                String mountPath = contentProvider.getMountPath();
@@ -81,7 +81,7 @@ class CmsContentSession implements ProvidedSession, UuidIdentified {
 
        @Override
        public boolean exists(String path) {
-               if (!path.startsWith(ContentUtils.ROOT_SLASH))
+               if (!path.startsWith(Content.ROOT_PATH))
                        throw new IllegalArgumentException(path + " is not an absolute path");
                ContentProvider contentProvider = contentRepository.getMountManager().findContentProvider(path);
                String mountPath = contentProvider.getMountPath();
index cfd90f93c1d5e77aa86e900985646095204adf4c..0513a0d3e4354a447c125b21559da75953fe873a 100644 (file)
@@ -67,7 +67,6 @@ public class ContentUtils {
 
        public static final char SLASH = '/';
        public static final String SLASH_STRING = Character.toString(SLASH);
-       public static final String ROOT_SLASH = "" + SLASH;
        public static final String EMPTY = "";
 
        /**
@@ -103,7 +102,7 @@ public class ContentUtils {
 
        public static List<String> toPathSegments(String path) {
                List<String> res = new ArrayList<>();
-               if (EMPTY.equals(path) || ROOT_SLASH.equals(path))
+               if (EMPTY.equals(path) || Content.ROOT_PATH.equals(path))
                        return res;
                collectPathSegments(path, res);
                return res;
index 61d8e04298971802987b1a1a1f99f0e50ba57d82..18527f5909759d3960fc454dab839c028f3071f3 100644 (file)
@@ -2,6 +2,10 @@ package org.argeo.cms.acr;
 
 import org.argeo.api.acr.QNamed;
 
+/**
+ * Some core SVG attributes, which are used to standardise generic concepts such
+ * as width, height, etc.
+ */
 public enum SvgAttrs implements QNamed {
        /** */
        width,
index 4b94abf1eb5143b1ee5074d5f1b1126ae1de001b..13b19aabb901a468b4c20ef25df9e3bcf82e3500 100644 (file)
@@ -80,7 +80,7 @@ public class FsContent extends AbstractContent implements ProvidedContent {
                // TODO check file names with ':' ?
                if (isMountBase) {
                        String mountPath = provider.getMountPath();
-                       if (mountPath != null && !mountPath.equals(ContentUtils.ROOT_SLASH)) {
+                       if (mountPath != null && !mountPath.equals(Content.ROOT_PATH)) {
                                Content mountPoint = session.getMountPoint(mountPath);
                                this.name = mountPoint.getName();
                        } else {
index 22c15702907485cc7f773843640dd4295c3ee2dd..0686be7cb59b2cf63d034fc8331a1d1884e39f08 100644 (file)
@@ -69,7 +69,7 @@ public class DomContent extends AbstractContent implements ProvidedContent {
                if (isLocalRoot()) {// root
                        String mountPath = provider.getMountPath();
                        if (mountPath != null) {
-                               if (ContentUtils.ROOT_SLASH.equals(mountPath)) {
+                               if (Content.ROOT_PATH.equals(mountPath)) {
                                        return CrName.root.qName();
                                }
                                Content mountPoint = getSession().getMountPoint(mountPath);
@@ -236,7 +236,7 @@ public class DomContent extends AbstractContent implements ProvidedContent {
                        String mountPath = provider.getMountPath();
                        if (mountPath == null)
                                return null;
-                       if (ContentUtils.ROOT_SLASH.equals(mountPath)) {
+                       if (Content.ROOT_PATH.equals(mountPath)) {
                                return null;
                        }
                        String[] parent = ContentUtils.getParentPath(mountPath);
@@ -386,7 +386,7 @@ public class DomContent extends AbstractContent implements ProvidedContent {
                List<QName> res = new ArrayList<>();
                if (isLocalRoot()) {
                        String mountPath = provider.getMountPath();
-                       if (ContentUtils.SLASH_STRING.equals(mountPath)) {// repository root
+                       if (Content.ROOT_PATH.equals(mountPath)) {// repository root
                                res.add(CrName.root.qName());
                        } else {
                                Content mountPoint = getSession().getMountPoint(mountPath);
@@ -402,7 +402,7 @@ public class DomContent extends AbstractContent implements ProvidedContent {
        public void addContentClasses(QName... contentClass) {
                if (isLocalRoot()) {
                        String mountPath = provider.getMountPath();
-                       if (ContentUtils.SLASH_STRING.equals(mountPath)) {// repository root
+                       if (Content.ROOT_PATH.equals(mountPath)) {// repository root
                                throw new IllegalArgumentException("Cannot add content classes to repository root");
                        } else {
                                Content mountPoint = getSession().getMountPoint(mountPath);
index 39d9c2a90b56d5a8483c9813fb5637e0b94dc7d3..a5abe8dd47f165f170d98154ee559d80987bec97 100644 (file)
@@ -22,7 +22,6 @@ import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.acr.spi.ProvidedSession;
 import org.argeo.cms.acr.CmsContentRepository;
-import org.argeo.cms.acr.ContentUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
@@ -77,7 +76,7 @@ public class DomContentProvider implements ContentProvider, NamespaceContext {
                if (relativePath.startsWith("/"))
                        throw new IllegalArgumentException("Relative path cannot start with /");
                String xPathExpression = '/' + relativePath;
-               if (ContentUtils.SLASH_STRING.equals(mountPath)) // repository root
+               if (Content.ROOT_PATH.equals(mountPath)) // repository root
                        xPathExpression = "/" + CrName.root.qName() + xPathExpression;
                try {
                        NodeList nodes = (NodeList) xPath.get().evaluate(xPathExpression, document, XPathConstants.NODESET);
index 00a51ef921f9cc62a27e6bd6609b78b5f549b414..30d6bc907b54229a2d00a4263878c13e3ccbaf22 100644 (file)
@@ -1,24 +1,29 @@
 package org.argeo.cms.swt;
 
+import java.net.URI;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
 import org.argeo.api.cms.ux.Cms2DSize;
 import org.argeo.cms.ux.AbstractImageManager;
-import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Label;
 
 /** Manages only public images so far. */
 public abstract class AbstractSwtImageManager<M> extends AbstractImageManager<Control, M> {
-       protected abstract Image getSwtImage(M node);
+       protected abstract ImageData getSwtImageData(M node);
 
        protected abstract String noImg(Cms2DSize size);
 
-       public Boolean load(M node, Control control, Cms2DSize preferredSize) {
+       @Override
+       public Boolean load(M node, Control control, Cms2DSize preferredSize, URI link) {
                Cms2DSize imageSize = getImageSize(node);
                Cms2DSize size;
                String imgTag = null;
-               if (preferredSize == null || imageSize.getWidth() == 0 || imageSize.getHeight() == 0
-                               || (preferredSize.getWidth() == 0 && preferredSize.getHeight() == 0)) {
-                       if (imageSize.getWidth() != 0 && imageSize.getHeight() != 0) {
+               if (preferredSize == null || imageSize.width() == 0 || imageSize.height() == 0
+                               || (preferredSize.width() == 0 && preferredSize.height() == 0)) {
+                       if (imageSize.width() != 0 && imageSize.height() != 0) {
                                // actual image size if completely known
                                size = imageSize;
                        } else {
@@ -27,15 +32,15 @@ public abstract class AbstractSwtImageManager<M> extends AbstractImageManager<Co
                                imgTag = noImg(size);
                        }
 
-               } else if (preferredSize.getWidth() != 0 && preferredSize.getHeight() != 0) {
+               } else if (preferredSize.width() != 0 && preferredSize.height() != 0) {
                        // given size if completely provided
                        size = preferredSize;
                } else {
                        // at this stage :
                        // image is completely known
-                       assert imageSize.getWidth() != 0 && imageSize.getHeight() != 0;
+                       assert imageSize.width() != 0 && imageSize.height() != 0;
                        // one and only one of the dimension as been specified
-                       assert preferredSize.getWidth() == 0 || preferredSize.getHeight() == 0;
+                       assert preferredSize.width() == 0 || preferredSize.height() == 0;
                        size = resizeTo(imageSize, preferredSize);
                }
 
@@ -55,6 +60,13 @@ public abstract class AbstractSwtImageManager<M> extends AbstractImageManager<Co
                        }
 
                        Label lbl = (Label) control;
+                       StringBuilder sb = new StringBuilder();
+                       if (link != null)
+                               sb.append("<a href='").append(URLEncoder.encode(link.toString(), StandardCharsets.UTF_8)).append("'>");
+                       sb.append(imgTag);
+                       if (link != null)
+                               sb.append("</a>");
+
                        lbl.setText(imgTag);
                        // lbl.setSize(size);
 //             } else if (control instanceof FileUpload) {
@@ -70,8 +82,8 @@ public abstract class AbstractSwtImageManager<M> extends AbstractImageManager<Co
 
        public Cms2DSize getImageSize(M node) {
                // TODO optimise
-               Image image = getSwtImage(node);
-               return new Cms2DSize(image.getBounds().width, image.getBounds().height);
+               ImageData imageData = getSwtImageData(node);
+               return new Cms2DSize(imageData.width, imageData.height);
        }
 
 }
index 78a9930051657ed4669f4caf196113f6c2c44ee7..0984f57fb2786a5366f833ac9f551c3ba9e31348 100644 (file)
@@ -1,15 +1,19 @@
 package org.argeo.cms.swt.acr;
 
+import java.io.IOException;
 import java.io.InputStream;
+import java.util.Optional;
 
 import org.argeo.api.acr.Content;
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.cms.acr.SvgAttrs;
 import org.argeo.cms.swt.AbstractSwtImageManager;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.ux.CmsUxUtils;
-import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
 
+/** Implementation of {@link AbstractSwtImageManager} based on ACR. */
 public class AcrSwtImageManager extends AbstractSwtImageManager<Content> {
 
        @Override
@@ -24,8 +28,13 @@ public class AcrSwtImageManager extends AbstractSwtImageManager<Content> {
        }
 
        @Override
-       protected Image getSwtImage(Content node) {
-               throw new UnsupportedOperationException();
+       protected ImageData getSwtImageData(Content node) {
+               try (InputStream in = node.open(InputStream.class)) {
+                       ImageData imageData = new ImageData(in);
+                       return imageData;
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
        }
 
        @Override
@@ -45,4 +54,15 @@ public class AcrSwtImageManager extends AbstractSwtImageManager<Content> {
                buf.append(node.getPath());
                return buf.toString();
        }
+
+       @Override
+       public Cms2DSize getImageSize(Content node) {
+               // TODO cache it?
+               Optional<Integer> width = node.get(SvgAttrs.width, Integer.class);
+               Optional<Integer> height = node.get(SvgAttrs.height, Integer.class);
+               if (!width.isEmpty() && !height.isEmpty())
+                       return new Cms2DSize(width.get(), height.get());
+               return super.getImageSize(node);
+       }
+
 }
index a5d22bca1b2fe5dde04b5ed48adcd5c27b6323a4..578dac25142d919c8dccfbcecbe1329b014dc509 100644 (file)
@@ -6,7 +6,6 @@ import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.cms.ux.Cms2DSize;
 import org.argeo.api.cms.ux.CmsImageManager;
 import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.widgets.EditableImage;
 import org.argeo.cms.ux.acr.ContentPart;
 import org.argeo.eclipse.ui.specific.CmsFileUpload;
 import org.eclipse.swt.SWT;
@@ -14,38 +13,36 @@ import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
 
 /** An image within the Argeo Text framework */
-public class Img extends EditableImage implements SwtSectionPart, ContentPart {
+public class Img extends LinkedControl implements SwtSectionPart, ContentPart {
        private static final long serialVersionUID = 6233572783968188476L;
 
        private final SwtSection section;
 
        private final CmsImageManager<Control, Content> imageManager;
-//     private FileUploadHandler currentUploadHandler = null;
-//     private FileUploadListener fileUploadListener;
+
+       private Cms2DSize preferredImageSize;
 
        public Img(Composite parent, int swtStyle, Content imgNode, Cms2DSize preferredImageSize) {
                this(SwtSection.findSection(parent), parent, swtStyle, imgNode, preferredImageSize, null);
-//             setStyle(TextStyles.TEXT_IMAGE);
        }
 
        public Img(Composite parent, int swtStyle, Content imgNode) {
                this(SwtSection.findSection(parent), parent, swtStyle, imgNode, null, null);
-//             setStyle(TextStyles.TEXT_IMAGE);
        }
 
        public Img(Composite parent, int swtStyle, Content imgNode, CmsImageManager<Control, Content> imageManager) {
                this(SwtSection.findSection(parent), parent, swtStyle, imgNode, null, imageManager);
-//             setStyle(TextStyles.TEXT_IMAGE);
        }
 
        Img(SwtSection section, Composite parent, int swtStyle, Content imgNode, Cms2DSize preferredImageSize,
                        CmsImageManager<Control, Content> imageManager) {
-               super(parent, swtStyle, preferredImageSize);
+               super(parent, swtStyle);
+               this.preferredImageSize = preferredImageSize;
                this.section = section;
                this.imageManager = imageManager != null ? imageManager : CmsSwtUtils.getCmsView(section).getImageManager();
-//             CmsSwtUtils.style(this, TextStyles.TEXT_IMG);
                setData(imgNode);
        }
 
@@ -58,20 +55,23 @@ public class Img extends EditableImage implements SwtSectionPart, ContentPart {
                }
        }
 
-       @Override
-       public synchronized void stopEditing() {
-               super.stopEditing();
-//             fileUploadListener = null;
-       }
-
-       @Override
        protected synchronized Boolean load(Control lbl) {
                Content imgNode = getContent();
-               boolean loaded = imageManager.load(imgNode, lbl, getPreferredImageSize());
-               // getParent().layout();
+               boolean loaded = imageManager.load(imgNode, lbl, preferredImageSize, toUri());
                return loaded;
        }
 
+       protected Label createLabel(Composite box, String style) {
+               Label lbl = new Label(box, getStyle());
+               // lbl.setLayoutData(CmsUiUtils.fillWidth());
+               CmsSwtUtils.markup(lbl);
+               CmsSwtUtils.style(lbl, style);
+               if (mouseListener != null)
+                       lbl.addMouseListener(mouseListener);
+               load(lbl);
+               return lbl;
+       }
+
        protected Content getUploadFolder() {
                return getContent().getParent();
        }
@@ -140,4 +140,15 @@ public class Img extends EditableImage implements SwtSectionPart, ContentPart {
                return "Img #" + getPartId();
        }
 
+       public void setPreferredSize(Cms2DSize size) {
+               this.preferredImageSize = size;
+       }
+
+       public Cms2DSize getPreferredImageSize() {
+               return preferredImageSize;
+       }
+
+       public void setPreferredImageSize(Cms2DSize preferredImageSize) {
+               this.preferredImageSize = preferredImageSize;
+       }
 }
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/LinkedControl.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/LinkedControl.java
new file mode 100644 (file)
index 0000000..6a75dfb
--- /dev/null
@@ -0,0 +1,64 @@
+package org.argeo.cms.swt.acr;
+
+import java.net.URI;
+
+import org.argeo.api.acr.Content;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.widgets.StyledControl;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * A {@link StyledControl} which can link either to an internal {@link Content}
+ * or an external URI.
+ */
+public abstract class LinkedControl extends StyledControl {
+
+       private static final long serialVersionUID = -7603153425459801216L;
+
+       private Content linkedContent;
+       private URI plainUri;
+
+       public LinkedControl(Composite parent, int swtStyle) {
+               super(parent, swtStyle);
+       }
+
+       public void setLink(Content linkedContent) {
+               if (plainUri != null)
+                       throw new IllegalStateException("An URI is already set");
+               this.linkedContent = linkedContent;
+       }
+
+       public void setLink(URI uri) {
+               if (linkedContent != null)
+                       throw new IllegalStateException("A linked content is already set");
+               this.plainUri = uri;
+       }
+
+       public boolean isInternalLink() {
+               if (!hasLink())
+                       throw new IllegalStateException("No link has been set");
+               return linkedContent != null;
+       }
+
+       public boolean hasLink() {
+               return plainUri != null || linkedContent != null;
+       }
+
+       public Content getLinkedContent() {
+               return linkedContent;
+       }
+
+       public URI getPlainUri() {
+               return plainUri;
+       }
+
+       public URI toUri() {
+               if (plainUri != null)
+                       return plainUri;
+               if (linkedContent != null)
+                       return URI.create("#" + CmsSwtUtils.cleanPathForUrl(linkedContent.getPath()));
+               return null;
+
+       }
+
+}
index e712e2fe6dc2eeba001ccb11e8faa73bb01f0f7d..1800a712af86e8adb7e1104e12ea33e4ccfe7163 100644 (file)
@@ -12,6 +12,7 @@ import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Text;
 
 /** A stylable and editable image. */
+@Deprecated
 public abstract class EditableImage extends StyledControl {
        private static final long serialVersionUID = -5689145523114022890L;
        private final static CmsLog log = CmsLog.getLog(EditableImage.class);
@@ -73,9 +74,9 @@ public abstract class EditableImage extends StyledControl {
                        loaded = true;
                if (control != null) {
                        ((Label) control).setText(imgTag);
-                       control.setSize(preferredImageSize != null
-                                       ? new Point(preferredImageSize.getWidth(), preferredImageSize.getHeight())
-                                       : getSize());
+                       control.setSize(
+                                       preferredImageSize != null ? new Point(preferredImageSize.width(), preferredImageSize.height())
+                                                       : getSize());
                } else {
                        loaded = false;
                }