return noImg(AbstractImageManager.NO_IMAGE_SIZE);
}
- public static Image noImage(Cms2DSize size) {
- ResourceManager rm = RWT.getResourceManager();
- InputStream in = null;
- try {
- in = rm.getRegisteredContent(AbstractImageManager.NO_IMAGE);
- ImageData id = new ImageData(in);
- ImageData scaled = id.scaledTo(size.getWidth(), size.getHeight());
- Image image = new Image(Display.getCurrent(), scaled);
- return image;
- } finally {
- try {
- in.close();
- } catch (IOException e) {
- // silent
- }
- }
- }
+// public static Image noImage(Cms2DSize size) {
+// ResourceManager rm = RWT.getResourceManager();
+// InputStream in = null;
+// try {
+// in = rm.getRegisteredContent(AbstractImageManager.NO_IMAGE);
+// ImageData id = new ImageData(in);
+// ImageData scaled = id.scaledTo(size.getWidth(), size.getHeight());
+// Image image = new Image(Display.getCurrent(), scaled);
+// return image;
+// } finally {
+// try {
+// in.close();
+// } catch (IOException e) {
+// // silent
+// }
+// }
+// }
/** Lorem ipsum text to be used during development. */
public final static String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
package org.argeo.api.acr;
+import static org.argeo.api.acr.NamespaceUtils.unqualified;
+
import java.io.Closeable;
import java.io.IOException;
-import java.util.Collection;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
-import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
/**
<A> Optional<A> get(QName key, Class<A> clss);
- default Object get(String key) {
- if (key.indexOf(':') >= 0)
- throw new IllegalArgumentException("Name " + key + " has a prefix");
- return get(new QName(XMLConstants.NULL_NS_URI, key, XMLConstants.DEFAULT_NS_PREFIX));
+ Class<?> getType(QName key);
+
+ boolean isMultiple(QName key);
+
+ <A> List<A> getMultiple(QName key, Class<A> clss);
+
+ /*
+ * ATTRIBUTES OPERATION HELPERS
+ */
+ default boolean containsKey(QNamed key) {
+ return containsKey(key.qName());
}
- default Object put(String key, Object value) {
- if (key.indexOf(':') >= 0)
- throw new IllegalArgumentException("Name " + key + " has a prefix");
- return put(new QName(XMLConstants.NULL_NS_URI, key, XMLConstants.DEFAULT_NS_PREFIX), value);
+ default <A> Optional<A> get(QNamed key, Class<A> clss) {
+ return get(key.qName(), clss);
}
- default Object remove(String key) {
- if (key.indexOf(':') >= 0)
- throw new IllegalArgumentException("Name " + key + " has a prefix");
- return remove(new QName(XMLConstants.NULL_NS_URI, key, XMLConstants.DEFAULT_NS_PREFIX));
+ default Object get(QNamed key) {
+ return get(key.qName());
}
- Class<?> getType(QName key);
+ default Object put(QNamed key, Object value) {
+ return put(key.qName(), value);
+ }
- boolean isMultiple(QName key);
+ default Object remove(QNamed key) {
+ return remove(key.qName());
+ }
+
+ // TODO do we really need the helpers below?
- <A> Optional<List<A>> getMultiple(QName key, Class<A> clss);
+ default Object get(String key) {
+ return get(unqualified(key));
+ }
+
+ default Object put(String key, Object value) {
+ return put(unqualified(key), value);
+ }
+
+ default Object remove(String key) {
+ return remove(unqualified(key));
+ }
@SuppressWarnings("unchecked")
default <A> List<A> getMultiple(QName key) {
} catch (ClassCastException e) {
throw new IllegalArgumentException("Requested type is not the default type");
}
- Optional<List<A>> res = getMultiple(key, type);
- if (res == null)
- return null;
- else {
- if (res.isEmpty())
- throw new IllegalStateException("Metadata " + key + " is not availabel as list of type " + type);
- return res.get();
- }
+ List<A> res = getMultiple(key, type);
+ return res;
+// if (res == null)
+// return null;
+// else {
+// if (res.isEmpty())
+// throw new IllegalStateException("Metadata " + key + " is not availabel as list of type " + type);
+// return res.get();
+// }
}
/*
Content add(QName name, QName... classes);
default Content add(String name, QName... classes) {
- if (name.indexOf(':') >= 0)
- throw new IllegalArgumentException("Name " + name + " has a prefix");
- return add(new QName(XMLConstants.NULL_NS_URI, name, XMLConstants.DEFAULT_NS_PREFIX), classes);
+ return add(unqualified(name), classes);
}
void remove();
return false;
}
+ default boolean hasContentClass(QNamed contentClass) {
+ return hasContentClass(contentClass.qName());
+ }
+
/*
* SIBLINGS
*/
return false;
}
+ default boolean hasChild(QNamed name) {
+ return hasChild(name.qName());
+ }
+
default Content anyOrAddChild(QName name, QName... classes) {
Content child = anyChild(name);
if (child != null)
return this.add(name, classes);
}
+ default Content anyOrAddChild(String name, QName... classes) {
+ return anyOrAddChild(unqualified(name), classes);
+ }
+
/** Any child with this name, or null if there is none */
default Content anyChild(QName name) {
for (Content child : this) {
return null;
}
- /*
- * CONVENIENCE METHODS
- */
- default String attr(String key) {
- Object obj = get(key);
- if (obj == null)
- return null;
- return obj.toString();
+ default List<Content> children(QName name) {
+ List<Content> res = new ArrayList<>();
+ for (Content child : this) {
+ if (child.getName().equals(name))
+ res.add(child);
+ }
+ return res;
+ }
+
+ default Optional<Content> soleChild(QName name) {
+ List<Content> res = children(name);
+ if (res.isEmpty())
+ return Optional.empty();
+ if (res.size() > 1)
+ throw new IllegalStateException(this + " has multiple children with name " + name);
+ return Optional.of(res.get(0));
+ }
+
+ default Content child(QName name) {
+ return soleChild(name).orElseThrow();
+ }
+ default Content child(QNamed name) {
+ return child(name.qName());
}
+ /*
+ * ATTR AS STRING
+ */
default String attr(QName key) {
+ // TODO check String type?
Object obj = get(key);
if (obj == null)
return null;
return obj.toString();
+ }
+ default String attr(QNamed key) {
+ return attr(key.qName());
+ }
+
+ default String attr(String key) {
+ return attr(unqualified(key));
}
//
// default String attr(Object key) {
return !qName.getNamespaceURI().equals(XMLConstants.NULL_NS_URI);
}
+ public static void checkNoPrefix(String unqualified) {
+ if (unqualified.indexOf(':') >= 0)
+ throw new IllegalArgumentException("Name " + unqualified + " has a prefix");
+ }
+
+ public static QName unqualified(String name) {
+ checkNoPrefix(name);
+ return new ContentName(XMLConstants.NULL_NS_URI, name, XMLConstants.DEFAULT_NS_PREFIX);
+
+ }
+
/*
* DEFAULT NAMESPACE CONTEXT OPERATIONS as specified in NamespaceContext
*/
--- /dev/null
+package org.argeo.api.acr;
+
+import java.util.function.Supplier;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+
+/** An optionally qualified name. Primarily meant to be used in enums. */
+public interface QNamed extends Supplier<String> {
+ String name();
+
+ /** To be overridden when XML naming is not compatible with Java naming. */
+ default String localName() {
+ return name();
+ }
+
+ default QName qName() {
+ return new ContentName(getNamespace(), localName(), getDefaultPrefix());
+ }
+
+ default String get(NamespaceContext namespaceContext) {
+ return namespaceContext.getPrefix(getNamespace()) + ":" + localName();
+ }
+
+ default String get() {
+ return getDefaultPrefix() + ":" + localName();
+ }
+
+ String getNamespace();
+
+ String getDefaultPrefix();
+
+ /** To be used by enums without namespace (typically XML attributes). */
+ static interface Unqualified extends QNamed {
+ @Override
+ default String getNamespace() {
+ return XMLConstants.NULL_NS_URI;
+ }
+
+ @Override
+ default String getDefaultPrefix() {
+ return XMLConstants.DEFAULT_NS_PREFIX;
+ }
+
+ }
+}
/** A {@link Content} implementation. */
public interface ProvidedContent extends Content {
+ final static String ROOT_PATH = "/";
+
ProvidedSession getSession();
ContentProvider getProvider();
default ProvidedContent getMountPoint(String relativePath) {
throw new UnsupportedOperationException("This content doe not support mount");
}
+
+ default ProvidedContent getContent(String path) {
+ Content fileNode;
+ if (path.startsWith(ROOT_PATH)) {// absolute
+ fileNode = getSession().get(path);
+ } else {// relative
+ String absolutePath = getPath() + '/' + path;
+ fileNode = getSession().get(absolutePath);
+ }
+ return (ProvidedContent) fileNode;
+ }
}
private Integer height;
public Cms2DSize() {
-
}
public Cms2DSize(Integer width, Integer height) {
this.height = height;
}
+ @Override
+ public String toString() {
+ return Cms2DSize.class.getSimpleName() + "[" + width + "," + height + "]";
+ }
+
}
@SuppressWarnings("unchecked")
@Override
- public <A> Optional<List<A>> getMultiple(QName key, Class<A> clss) {
+ public <A> List<A> getMultiple(QName key, Class<A> clss) {
Object value = get(key);
if (value == null)
- return Optional.empty();
+ return new ArrayList<>();
if (value instanceof List) {
- try {
- List<A> res = (List<A>) value;
- return Optional.of(res);
- } catch (ClassCastException e) {
- List<A> res = new ArrayList<>();
- List<?> lst = (List<?>) value;
- try {
- for (Object o : lst) {
- A item = (A) o;
- res.add(item);
- }
- return Optional.of(res);
- } catch (ClassCastException e1) {
- return Optional.empty();
- }
+ if (isDefaultAttrTypeRequested(clss))
+ return (List<A>) value;
+ List<A> res = new ArrayList<>();
+ List<?> lst = (List<?>) value;
+ for (Object o : lst) {
+ A item = clss.isAssignableFrom(String.class) ? (A) o.toString() : (A) o;
+ res.add(item);
}
+ return res;
} else {// singleton
- try {
- A res = (A) value;
- return Optional.of(Collections.singletonList(res));
- } catch (ClassCastException e) {
- return Optional.empty();
- }
+// try {
+ A res = (A) value;
+ return Collections.singletonList(res);
+// } catch (ClassCastException e) {
+// return Optional.empty();
+// }
}
}
--- /dev/null
+package org.argeo.cms.acr;
+
+import org.argeo.api.acr.QNamed;
+
+public enum SvgAttrs implements QNamed {
+ /** */
+ width,
+ /** */
+ height,
+ /** */
+ length,
+ /** */
+ unit,
+ /** */
+ dur,
+ /** */
+ direction,
+ //
+ ;
+
+ @Override
+ public String getNamespace() {
+ return CmsContentTypes.SVG_1_1.getNamespace();
+ }
+
+ @Override
+ public String getDefaultPrefix() {
+ return CmsContentTypes.SVG_1_1.getDefaultPrefix();
+ }
+
+}
import org.argeo.api.acr.Content;
import org.argeo.api.acr.ContentName;
import org.argeo.api.acr.ContentResourceException;
+import org.argeo.api.acr.CrAttributeType;
import org.argeo.api.acr.CrName;
import org.argeo.api.acr.NamespaceUtils;
import org.argeo.api.acr.spi.ContentProvider;
import org.argeo.api.acr.spi.ProvidedContent;
import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.api.cms.CmsLog;
import org.argeo.cms.acr.AbstractContent;
import org.argeo.cms.acr.ContentUtils;
import org.argeo.util.FsUtils;
/** Content persisted as a filesystem {@link Path}. */
public class FsContent extends AbstractContent implements ProvidedContent {
+ private CmsLog log = CmsLog.getLog(FsContent.class);
+
final static String USER_ = "user:";
private static final Map<QName, String> BASIC_KEYS;
}
// TODO perform trivial file conversion to other formats
}
+
+ // TODO better deal with multiple types
if (value instanceof byte[]) {
String str = new String((byte[]) value, StandardCharsets.UTF_8);
String[] arr = str.split("\n");
+
if (arr.length == 1) {
- res = (A) arr[0];
+ if (clss.isAssignableFrom(String.class)) {
+ res = (A) arr[0];
+ } else {
+ res = (A) CrAttributeType.parse(arr[0]);
+ }
} else {
- List<String> lst = new ArrayList<>();
+ List<Object> lst = new ArrayList<>();
for (String s : arr) {
- lst.add(s);
+ lst.add(CrAttributeType.parse(s));
}
res = (A) lst;
}
}
- if (res == null)
- try {
- res = (A) value;
- } catch (ClassCastException e) {
- return Optional.empty();
- }
+ if (res == null) {
+ if (isDefaultAttrTypeRequested(clss))
+ return Optional.of((A) CrAttributeType.parse(value.toString()));
+ if (clss.isAssignableFrom(value.getClass()))
+ return Optional.of((A) value);
+ if (clss.isAssignableFrom(String.class))
+ return Optional.of((A) value.toString());
+ log.warn("Cannot interpret " + key + " in " + this);
+ return Optional.empty();
+// try {
+// res = (A) value;
+// } catch (ClassCastException e) {
+// return Optional.empty();
+// }
+ }
return Optional.of(res);
}
@Override
public List<QName> getContentClasses() {
List<QName> res = new ArrayList<>();
- Optional<List<String>> value = getMultiple(CrName.cc.qName(), String.class);
- if (!value.isEmpty()) {
- for (String s : value.get()) {
- QName name = NamespaceUtils.parsePrefixedName(provider, s);
- res.add(name);
- }
+ List<String> value = getMultiple(CrName.cc.qName(), String.class);
+ for (String s : value) {
+ QName name = NamespaceUtils.parsePrefixedName(provider, s);
+ res.add(name);
}
if (Files.isDirectory(path))
res.add(CrName.collection.qName());
import javax.xml.namespace.QName;
/** A (possibly) qualified name. To be used in enums. */
+@Deprecated
public interface QNamed {
String name();
import java.io.InputStream;
import org.argeo.api.acr.Content;
+import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.ux.Cms2DSize;
import org.argeo.cms.swt.AbstractSwtImageManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ux.CmsUxUtils;
import org.eclipse.swt.graphics.Image;
public class AcrSwtImageManager extends AbstractSwtImageManager<Content> {
@Override
public String getImageUrl(Content node) {
- // TODO Auto-generated method stub
- return null;
+ return getDataPathForUrl(node);
}
@Override
public String uploadImage(Content context, Content uploadFolder, String fileName, InputStream in,
String contentType) {
- // TODO Auto-generated method stub
- return null;
+ throw new UnsupportedOperationException();
}
@Override
protected Image getSwtImage(Content node) {
- // TODO Auto-generated method stub
- return null;
+ throw new UnsupportedOperationException();
}
@Override
protected String noImg(Cms2DSize size) {
- // TODO Auto-generated method stub
- return null;
+ String dataPath = "";
+ return CmsUxUtils.img(dataPath, size);
}
+ protected String getDataPathForUrl(Content content) {
+ return CmsSwtUtils.cleanPathForUrl(getDataPath(content));
+ }
+
+ /** A path in the node repository */
+ protected String getDataPath(Content node) {
+ // TODO make it more configurable?
+ StringBuilder buf = new StringBuilder(CmsConstants.PATH_DATA);
+ buf.append(node.getPath());
+ return buf.toString();
+ }
}
--- /dev/null
+package org.argeo.cms.swt.acr;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.NamespaceUtils;
+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;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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 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;
+
+ 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);
+ this.section = section;
+ this.imageManager = imageManager != null ? imageManager
+ : (CmsImageManager<Control, Content>) CmsSwtUtils.getCmsView(section).getImageManager();
+// CmsSwtUtils.style(this, TextStyles.TEXT_IMG);
+ setData(imgNode);
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ if (isEditing()) {
+ return createImageChooser(box, style);
+ } else {
+ return createLabel(box, style);
+ }
+ }
+
+ @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();
+ return loaded;
+ }
+
+ protected Content getUploadFolder() {
+ return getContent().getParent();
+ }
+
+ protected String getUploadName() {
+ Content node = getContent();
+ // TODO centralise pattern?
+ return NamespaceUtils.toPrefixedName(node.getName()) + '[' + node.getSiblingIndex() + ']';
+ }
+
+ protected CmsImageManager<Control, Content> getImageManager() {
+ return imageManager;
+ }
+
+ protected Control createImageChooser(Composite box, String style) {
+// JcrFileUploadReceiver receiver = new JcrFileUploadReceiver(this, getUploadFolder(), getUploadName(),
+// imageManager);
+// if (currentUploadHandler != null)
+// currentUploadHandler.dispose();
+// currentUploadHandler = prepareUpload(receiver);
+// final ServerPushSession pushSession = new ServerPushSession();
+ final CmsFileUpload fileUpload = new CmsFileUpload(box, SWT.NONE);
+ CmsSwtUtils.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 SwtSection getSection() {
+ return section;
+ }
+
+// public void setFileUploadListener(FileUploadListener fileUploadListener) {
+// this.fileUploadListener = fileUploadListener;
+// if (currentUploadHandler != null)
+// currentUploadHandler.addUploadListener(fileUploadListener);
+// }
+
+ @Override
+ public Content getContent() {
+ return (Content) getData();
+ }
+
+ @Override
+ public String getPartId() {
+ return ((ProvidedContent) getContent()).getSessionLocalId();
+ }
+
+ @Override
+ public String toString() {
+ return "Img #" + getPartId();
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.widgets;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ux.AbstractImageManager;
+import org.argeo.cms.ux.CmsUxUtils;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** A stylable and editable image. */
+public abstract class EditableImage extends StyledControl {
+ private static final long serialVersionUID = -5689145523114022890L;
+ private final static CmsLog log = CmsLog.getLog(EditableImage.class);
+
+ private Cms2DSize preferredImageSize;
+ private Boolean loaded = false;
+
+ public EditableImage(Composite parent, int swtStyle) {
+ super(parent, swtStyle);
+ }
+
+ public EditableImage(Composite parent, int swtStyle, Cms2DSize preferredImageSize) {
+ super(parent, swtStyle);
+ this.preferredImageSize = preferredImageSize;
+ }
+
+ @Override
+ protected void setContainerLayoutData(Composite composite) {
+ // composite.setLayoutData(fillWidth());
+ }
+
+ @Override
+ protected void setControlLayoutData(Control control) {
+ // control.setLayoutData(fillWidth());
+ }
+
+ /** To be overriden. */
+ protected String createImgTag() {
+ return noImg(preferredImageSize != null ? preferredImageSize : new Cms2DSize(getSize().x, getSize().y));
+ }
+
+ 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;
+ }
+
+ /** To be overriden. */
+ protected synchronized Boolean load(Control control) {
+ String imgTag;
+ try {
+ imgTag = createImgTag();
+ } catch (Exception e) {
+ // throw new CmsException("Cannot retrieve image", e);
+ log.error("Cannot retrieve image", e);
+ imgTag = noImg(preferredImageSize);
+ loaded = false;
+ }
+
+ if (imgTag == null) {
+ loaded = false;
+ imgTag = noImg(preferredImageSize);
+ } else
+ loaded = true;
+ if (control != null) {
+ ((Label) control).setText(imgTag);
+ control.setSize(preferredImageSize != null
+ ? new Point(preferredImageSize.getWidth(), preferredImageSize.getHeight())
+ : getSize());
+ } else {
+ loaded = false;
+ }
+ getParent().layout();
+ return loaded;
+ }
+
+ public void setPreferredSize(Cms2DSize size) {
+ this.preferredImageSize = size;
+ if (!loaded) {
+ load((Label) getControl());
+ }
+ }
+
+ protected Text createText(Composite box, String style) {
+ Text text = new Text(box, getStyle());
+ CmsSwtUtils.style(text, style);
+ return text;
+ }
+
+ public Cms2DSize getPreferredImageSize() {
+ return preferredImageSize;
+ }
+
+ public static String noImg(Cms2DSize size) {
+// ResourceManager rm = RWT.getResourceManager();
+// String noImgPath=rm.getLocation(AbstractImageManager.NO_IMAGE);
+ // FIXME load it via package service
+ String noImgPath = "";
+ return CmsUxUtils.img(noImgPath, size);
+ }
+
+ public static String noImg() {
+ return noImg(AbstractImageManager.NO_IMAGE_SIZE);
+ }
+
+}