* 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();
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())
/**
* 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
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();
}
@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();
}
/*
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 + "]";
}
-
}
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);
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);
}
/** @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 */
}
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()));
}
}
@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();
@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();
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 = "";
/**
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;
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,
// 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 {
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);
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);
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);
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);
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;
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);
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 {
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);
}
}
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) {
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);
}
}
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
}
@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
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);
+ }
+
}
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;
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);
}
}
}
- @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();
}
return "Img #" + getPartId();
}
+ public void setPreferredSize(Cms2DSize size) {
+ this.preferredImageSize = size;
+ }
+
+ public Cms2DSize getPreferredImageSize() {
+ return preferredImageSize;
+ }
+
+ public void setPreferredImageSize(Cms2DSize preferredImageSize) {
+ this.preferredImageSize = preferredImageSize;
+ }
}
--- /dev/null
+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;
+
+ }
+
+}
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);
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;
}