*/
String NODE_REPOS_FACTORY_PID = "org.argeo.api.repos";
String NODE_USER_ADMIN_PID = "org.argeo.api.userAdmin";
+
+ /*
+ * ENTITIES
+ */
+ String DATA_TYPE = "argeo.data.type";
}
private String pid;
private Integer ranking = 0;
- private Long id;
+ private Long id = 0l;
private String dataType;
private String dataPath;
? Integer.parseInt(properties.get(SERVICE_RANKING).toString())
: 0;
this.id = properties.containsKey(SERVICE_ID) ? (Long) properties.get(SERVICE_ID) : null;
+
+ // Argeo specific
+ this.dataType = properties.containsKey(NodeConstants.DATA_TYPE)
+ ? properties.get(NodeConstants.DATA_TYPE).toString()
+ : null;
}
@Override
result = +pid.hashCode();
if (ranking != null)
result = +ranking;
+ if (dataType != null)
+ result = +dataType.hashCode();
return result;
}
sb.append(pid);
if (ranking != null && ranking != 0)
sb.append(' ').append(ranking);
+ if (dataType != null)
+ sb.append(' ').append(dataType);
return sb.toString();
}
}
} else {
-
+ if (dataType != null && o.dataType != null) {
+ if (dataType.equals(o.dataType)) {
+ // TODO factorise
+ if (ranking.equals(o.ranking))
+ if (id != null && o.id != null)
+ return id.compareTo(o.id);
+ else
+ return 0;
+ else
+ return ranking.compareTo(o.ranking);
+ } else {
+ return dataPath.compareTo(o.dataType);
+ }
+ }
}
- return 0;
+ return -1;
}
public String getPid() {
return new RankingKey(pid, Integer.MAX_VALUE, null, null, null);
}
+ public static RankingKey minDataType(String dataType) {
+ return new RankingKey(null, Integer.MIN_VALUE, null, dataType, null);
+ }
+
+ public static RankingKey maxDataType(String dataType) {
+ return new RankingKey(null, Integer.MAX_VALUE, null, dataType, null);
+ }
+
private static boolean equalsOrBothNull(Object o1, Object o2) {
if (o1 == null && o2 == null)
return true;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
-import org.argeo.api.MvcProvider;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
package org.argeo.cms.ui;
+import java.util.HashMap;
import java.util.Map;
import javax.security.auth.login.LoginContext;
}
+ /**
+ * Convenience methods for when {@link #sendEvent(String, Map)} only requires
+ * one single parameter.
+ */
+ default void sendEvent(String topic, String param, Object value) {
+ Map<String, Object> properties = new HashMap<>();
+ properties.put(param, value);
+ sendEvent(topic, properties);
+ }
+
static CmsView getCmsView(Composite parent) {
// find parent shell
Shell topShell = parent.getShell();
-package org.argeo.api;
+package org.argeo.cms.ui;
import java.util.function.BiFunction;
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import org.argeo.cms.ui.CmsView;
+
+/**
+ * Can be applied to {@link Enum}s in order to define events used by
+ * {@link CmsView#sendEvent(String, java.util.Map)}.
+ */
+public interface CmsEvent {
+ String name();
+
+ default String topic() {
+ return getTopicBase() + "/" + name();
+ }
+
+ default String getTopicBase() {
+ return "argeo/cms";
+ }
+
+
+}
/** Style widget */
public static <T extends Widget> T style(T widget, String style) {
+ if (style == null)
+ return widget;// does nothing
widget.setData(CmsConstants.STYLE, style);
return widget;
}
import javax.jcr.Node;
import javax.jcr.RepositoryException;
-import org.argeo.cms.CmsException;
import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.cms.ui.widgets.JcrComposite;
import org.eclipse.swt.SWT;
private Composite sectionHeader;
private final Integer relativeDepth;
- public Section(Composite parent, int style, Node node) throws RepositoryException {
+ public Section(Composite parent, int style, Node node) {
this(parent, findSection(parent), style, node);
}
- public Section(Section section, int style, Node node) throws RepositoryException {
+ public Section(Section section, int style, Node node) {
this(section, section, style, node);
}
- protected Section(Composite parent, Section parentSection, int style, Node node) throws RepositoryException {
+ protected Section(Composite parent, Section parentSection, int style, Node node) {
super(parent, style, node);
- this.parentSection = parentSection;
- if (parentSection != null) {
- relativeDepth = getNode().getDepth() - parentSection.getNode().getDepth();
- } else {
- relativeDepth = 0;
+ try {
+ this.parentSection = parentSection;
+ if (parentSection != null) {
+ relativeDepth = getNode().getDepth() - parentSection.getNode().getDepth();
+ } else {
+ relativeDepth = 0;
+ }
+ setLayout(CmsUiUtils.noSpaceGridLayout());
+ } catch (RepositoryException e) {
+ throw new IllegalStateException("Cannot create section from " + node, e);
}
- setLayout(CmsUiUtils.noSpaceGridLayout());
}
public Map<String, Section> getSubSections() throws RepositoryException {
collectDirectSubSections((Composite) child, subSections);
}
- public void createHeader() {
+ public Composite createHeader() {
+ return createHeader(this);
+ }
+
+ public Composite createHeader(Composite parent) {
if (sectionHeader != null)
- throw new CmsException("Section header was already created");
+ sectionHeader.dispose();
- sectionHeader = new Composite(this, SWT.NONE);
+ sectionHeader = new Composite(parent, SWT.NONE);
sectionHeader.setLayoutData(CmsUiUtils.fillWidth());
sectionHeader.setLayout(CmsUiUtils.noSpaceGridLayout());
// sectionHeader.moveAbove(null);
// layout();
+ return sectionHeader;
}
public Composite getHeader() {
public class JcrComposite extends Composite {
private static final long serialVersionUID = -1447009015451153367L;
- private final Session session;
+ private Session session;
private String nodeId;
private String property = null;
nodeId = null;
}
- public JcrComposite(Composite parent, int style, Item item)
- throws RepositoryException {
+ public JcrComposite(Composite parent, int style, Item item) {
this(parent, style, item, false);
}
- public JcrComposite(Composite parent, int style, Item item,
- boolean cacheImmediately) throws RepositoryException {
+ public JcrComposite(Composite parent, int style, Item item, boolean cacheImmediately) {
super(parent, style);
- this.session = item.getSession();
- if (!cacheImmediately && (SWT.READ_ONLY == (style & SWT.READ_ONLY))) {
- // (useless?) optimization: we only save a pointer to the session,
- // not even a reference to the item
- this.nodeId = null;
- } else {
- Node node;
- Property property = null;
- if (item instanceof Node) {
- node = (Node) item;
- } else {// Property
- property = (Property) item;
- if (property.isMultiple())// TODO manage property index
- throw new CmsException(
- "Multiple properties not supported yet.");
- this.property = property.getName();
- node = property.getParent();
+ if (item != null)
+ try {
+ this.session = item.getSession();
+ if (!cacheImmediately && (SWT.READ_ONLY == (style & SWT.READ_ONLY))) {
+ // (useless?) optimization: we only save a pointer to the session,
+ // not even a reference to the item
+ this.nodeId = null;
+ } else {
+ Node node;
+ Property property = null;
+ if (item instanceof Node) {
+ node = (Node) item;
+ } else {// Property
+ property = (Property) item;
+ if (property.isMultiple())// TODO manage property index
+ throw new CmsException("Multiple properties not supported yet.");
+ this.property = property.getName();
+ node = property.getParent();
+ }
+ this.nodeId = node.getIdentifier();
+ if (cacheImmediately)
+ this.cache = node;
+ }
+ setLayout(CmsUiUtils.noSpaceGridLayout());
+ } catch (RepositoryException e) {
+ throw new IllegalStateException("Cannot create composite from " + item, e);
}
- this.nodeId = node.getIdentifier();
- if (cacheImmediately)
- this.cache = node;
- }
- setLayout(CmsUiUtils.noSpaceGridLayout());
}
public synchronized Node getNode() {
throw new CmsException("Item is not a Property");
Node node = getNodeInternal();
if (!node.hasProperty(property))
- throw new CmsException("Property " + property
- + " is not set on " + node);
+ throw new CmsException("Property " + property + " is not set on " + node);
return node.getProperty(property);
} catch (RepositoryException e) {
- throw new CmsException("Cannot get property " + property
- + " from node " + nodeId, e);
+ throw new CmsException("Cannot get property " + property + " from node " + nodeId, e);
}
}
}
/** Set/update the cache or change the node */
- public synchronized void setNode(Node node) throws RepositoryException {
+ public synchronized void setNode(Node node) {
if (!itemIsNode())
throw new CmsException("Cannot set a Node on a Property");
return;
}
- if (session == null || session != node.getSession())// check session
- throw new CmsException("Uncompatible session");
-
- if (nodeId == null || !nodeId.equals(node.getIdentifier())) {
- nodeId = node.getIdentifier();
- cache = node;
- itemUpdated();
- } else {
- cache = node;// set/update cache
+ try {
+// if (session != null || session != node.getSession())// check session
+// throw new IllegalArgumentException("Uncompatible session");
+// if (session == null)
+ session = node.getSession();
+ if (nodeId == null || !nodeId.equals(node.getIdentifier())) {
+ nodeId = node.getIdentifier();
+ cache = node;
+ itemUpdated();
+ } else {
+ cache = node;// set/update cache
+ }
+ } catch (RepositoryException e) {
+ throw new IllegalStateException(e);
}
}
/** Set/update the cache or change the property */
- public synchronized void setProperty(Property prop)
- throws RepositoryException {
+ public synchronized void setProperty(Property prop) {
if (itemIsNode())
throw new CmsException("Cannot set a Property on a Node");
return;
}
- if (session == null || session != prop.getSession())// check session
- throw new CmsException("Uncompatible session");
-
- Node node = prop.getNode();
- if (nodeId == null || !nodeId.equals(node.getIdentifier())
- || !property.equals(prop.getName())) {
- nodeId = node.getIdentifier();
- property = prop.getName();
- cache = node;
- itemUpdated();
- } else {
- cache = node;// set/update cache
+ try {
+ if (session == null || session != prop.getSession())// check session
+ throw new IllegalArgumentException("Uncompatible session");
+
+ Node node = prop.getNode();
+ if (nodeId == null || !nodeId.equals(node.getIdentifier()) || !property.equals(prop.getName())) {
+ nodeId = node.getIdentifier();
+ property = prop.getName();
+ cache = node;
+ itemUpdated();
+ } else {
+ cache = node;// set/update cache
+ }
+ } catch (RepositoryException e) {
+ throw new IllegalStateException(e);
}
}
}
/** Change the node, does nothing if same. */
- public synchronized void setNodeId(String nodeId)
- throws RepositoryException {
+ public synchronized void setNodeId(String nodeId) throws RepositoryException {
if (this.nodeId != null && this.nodeId.equals(nodeId))
return;
this.nodeId = nodeId;
setLayout(CmsUiUtils.noSpaceGridLayout());
}
- public StyledControl(Composite parent, int style, Item item) throws RepositoryException {
+ public StyledControl(Composite parent, int style, Item item) {
super(parent, style, item);
}
- public StyledControl(Composite parent, int style, Item item, boolean cacheImmediately) throws RepositoryException {
+ public StyledControl(Composite parent, int style, Item item, boolean cacheImmediately) {
super(parent, style, item, cacheImmediately);
}
--- /dev/null
+package org.argeo.cms.ui.widgets;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+public class TabbedArea extends Composite {
+ private static final long serialVersionUID = 8659669229482033444L;
+
+ private Composite headers;
+ private Composite body;
+
+ private List<Section> sections = new ArrayList<>();
+
+ private Node previousNode;
+ private CmsUiProvider previousUiProvider;
+ private CmsUiProvider currentUiProvider;
+
+ private String tabStyle;
+ private String tabSelectedStyle;
+ private Image closeIcon;
+
+ private long openingTimer = 500;
+
+ public TabbedArea(Composite parent, int style) {
+ super(parent, style);
+
+ setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ // TODO manage tabs at bottom or sides
+ headers = new Composite(this, SWT.NONE);
+ headers.setLayoutData(CmsUiUtils.fillWidth());
+ body = new Composite(this, SWT.NONE);
+ body.setLayoutData(CmsUiUtils.fillAll());
+
+ body.setLayout(new FormLayout());
+ emptyState();
+ }
+
+ protected void refreshTabHeaders() {
+ int tabCount = sections.size() > 0 ? sections.size() : 1;
+ for (Control tab : headers.getChildren())
+ tab.dispose();
+ headers.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(tabCount, true)));
+
+ if (sections.size() == 0) {
+ Composite emptyHeader = new Composite(headers, SWT.NONE);
+ emptyHeader.setLayoutData(CmsUiUtils.fillAll());
+ emptyHeader.setLayout(new GridLayout());
+ Label lbl = new Label(emptyHeader, SWT.NONE);
+ lbl.setText("-");
+ lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
+
+ }
+
+ Section currentSection = getCurrentSection();
+ for (Section section : sections) {
+ boolean selected = section == currentSection;
+ Composite sectionHeader = section.createHeader(headers);
+ CmsUiUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle);
+ int headerColumns = 2;
+ sectionHeader.setLayout(new GridLayout(headerColumns, false));
+ Button title = new Button(sectionHeader, SWT.FLAT);
+ CmsUiUtils.style(title, selected ? tabSelectedStyle : tabStyle);
+ title.setLayoutData(CmsUiUtils.fillWidth());
+ title.addSelectionListener((Selected) (e) -> section.moveAbove(null));
+ Node node = section.getNode();
+ title.setText(Jcr.getTitle(node));
+ ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
+ CmsUiUtils.style(toolBar, selected ? tabSelectedStyle : tabStyle);
+ ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT);
+ if (closeIcon != null)
+ closeItem.setImage(closeIcon);
+ else
+ closeItem.setText("X");
+ closeItem.addSelectionListener((Selected) (e) -> closeTab(section));
+ }
+ }
+
+ public void view(CmsUiProvider uiProvider, Node context) {
+ int index = tabIndex(context);
+ if (index >= 0) {
+ showTab(index);
+ previousNode = context;
+ previousUiProvider = uiProvider;
+ return;
+ }
+ Section section = (Section) body.getChildren()[0];
+ previousNode = section.getNode();
+ if (previousNode == null) {// empty state
+ previousNode = context;
+ previousUiProvider = uiProvider;
+ } else {
+ previousUiProvider = currentUiProvider;
+ }
+ currentUiProvider = uiProvider;
+ section.setNode(context);
+ section.setLayoutData(CmsUiUtils.coversAll());
+ for (Control child : section.getChildren())
+ child.dispose();
+ uiProvider.createUiPart(section, context);
+ if (sections.size() == 0)
+ sections.add(section);
+ refreshTabHeaders();
+ layout(true, true);
+ }
+
+ public void open(CmsUiProvider uiProvider, Node context) {
+ try {
+ if (openingTimer > 0)
+ Thread.sleep(openingTimer);
+ } catch (InterruptedException e) {
+ // silent
+ }
+
+ // int index = tabIndex(context);
+ if (previousNode != null && Jcr.getIdentifier(previousNode).equals(Jcr.getIdentifier(context))) {
+ // does nothing
+ return;
+ }
+ if (sections.size() == 0)
+ CmsUiUtils.clear(body);
+ Section currentSection = getCurrentSection();
+ int currentIndex = sections.indexOf(currentSection);
+ Section nextCurrentSection = new Section(body, SWT.NONE, context);
+ nextCurrentSection.setLayoutData(CmsUiUtils.coversAll());
+ sections.remove(currentSection);
+ sections.add(currentIndex, nextCurrentSection);
+ sections.add(currentSection);
+ nextCurrentSection.moveAbove(null);
+ if (previousNode != null) {
+ view(previousUiProvider, previousNode);
+ }
+ refreshTabHeaders();
+ layout(true, true);
+ }
+
+ public void showTab(int index) {
+ Section sectionToShow = sections.get(index);
+ sectionToShow.moveAbove(null);
+ layout(true, true);
+ }
+
+ private int tabIndex(Node node) {
+ for (int i = 0; i < sections.size(); i++) {
+ Section section = sections.get(i);
+ if (Jcr.getIdentifier(section.getNode()).equals(Jcr.getIdentifier(node)))
+ return i;
+ }
+ return -1;
+ }
+
+ public void closeTab(Section section) {
+ int currentIndex = sections.indexOf(section);
+ int nextIndex = currentIndex == 0 ? 0 : currentIndex - 1;
+ sections.remove(section);
+ section.dispose();
+ if (sections.size() == 0) {
+ emptyState();
+ refreshTabHeaders();
+ layout(true, true);
+ return;
+ }
+ refreshTabHeaders();
+ showTab(nextIndex);
+ }
+
+ protected void emptyState() {
+ new Section(body, SWT.NONE, null);
+ refreshTabHeaders();
+ }
+
+ public Composite getCurrent() {
+ return getCurrentSection();
+ }
+
+ protected Section getCurrentSection() {
+ return (Section) body.getChildren()[0];
+ }
+
+ public void setTabStyle(String tabStyle) {
+ this.tabStyle = tabStyle;
+ }
+
+ public void setTabSelectedStyle(String tabSelectedStyle) {
+ this.tabSelectedStyle = tabSelectedStyle;
+ }
+
+ public void setCloseIcon(Image closeIcon) {
+ this.closeIcon = closeIcon;
+ }
+
+ public void setOpeningTimer(long openingTimer) {
+ this.openingTimer = openingTimer;
+ }
+
+}
import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
import java.security.PrivilegedAction;
+import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Override
public void sendEvent(String topic, Map<String, Object> properties) {
+ if (properties == null)
+ properties = new HashMap<>();
if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
+ properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
}
}
+ /**
+ * If node has mixin {@link NodeType#MIX_TITLE}, return
+ * {@link Property#JCR_TITLE}, otherwise return {@link #getName(Node)}.
+ */
+ public static String getTitle(Node node) {
+ if (Jcr.isNodeType(node, NodeType.MIX_TITLE))
+ return get(node, Property.JCR_TITLE);
+ else
+ return Jcr.getName(node);
+ }
+
/** Accesses a {@link NodeIterator} as an {@link Iterable}. */
@SuppressWarnings("unchecked")
public static Iterable<Node> iterate(NodeIterator nodeIterator) {