--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.entity.api</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+Require-Capability:\
+cms.datamodel;filter:="(name=jcrx)"
+
+Provide-Capability:\
+cms.datamodel; name=entity; cnd=/org/argeo/entity/entity.cnd
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.entity.api</artifactId>
+ <name>Entity API</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ <!-- Argeo Commons -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.enterprise</artifactId>
+ <version>${version.argeo-commons}</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package org.argeo.entity;
+
+/** Constant related to entities, typically used in an OSGi context. */
+public interface EntityConstants {
+ final static String TYPE = "entity.type";
+ final static String DEFAULT_EDITORY_ID = "entity.defaultEditorId";
+
+}
--- /dev/null
+package org.argeo.entity;
+
+import javax.jcr.Node;
+
+/** The definition of an entity, a composite configurable data structure. */
+public interface EntityDefinition {
+ String getEditorId(Node entity);
+
+ String getType();
+}
--- /dev/null
+package org.argeo.entity;
+
+import org.argeo.naming.LdapAttrs;
+
+/** Constants used to name entity structures. */
+public interface EntityNames {
+ @Deprecated
+ final String FORM_BASE = "form";
+ final String SUBMISSIONS_BASE = "submissions";
+ @Deprecated
+ final String TERM = "term";
+ final String NAME = "name";
+
+// final String ENTITY_DEFINITIONS_PATH = "/entity";
+ @Deprecated
+ final String TYPOLOGIES_PATH = "/" + TERM;
+ /** Administrative units. */
+ final String ADM = "adm";
+
+ final String ENTITY_TYPE = "entity:type";
+ // final String ENTITY_UID = "entity:uid";
+ // final String ENTITY_NAME = "entity:name";
+
+ // GENERIC CONCEPTS
+ /** The language which is relevant. */
+ final String XML_LANG = "xml:lang";
+ /** The date which is relevant. */
+ final String ENTITY_DATE = "entity:date";
+ @Deprecated
+ final String ENTITY_RELATED_TO = "entity:relatedTo";
+
+ // DEFAULT FOLDER NAMES
+ final String MEDIA = "media";
+ final String FILES = "files";
+
+ // LDAP-LIKE ENTITIES
+ @Deprecated
+ final String DISPLAY_NAME = LdapAttrs.displayName.property();
+ // Persons
+ @Deprecated
+ final String GIVEN_NAME = LdapAttrs.givenName.property();
+ @Deprecated
+ final String SURNAME = LdapAttrs.sn.property();
+ @Deprecated
+ final String EMAIL = LdapAttrs.mail.property();
+ @Deprecated
+ final String OU = LdapAttrs.ou.property();
+
+ // WGS84
+ final String GEO_LAT = "geo:lat";
+ final String GEO_LONG = "geo:long";
+ final String GEO_ALT = "geo:alt";
+
+ // SVG
+ final String SVG_WIDTH = "svg:width";
+ final String SVG_HEIGHT = "svg:height";
+ final String SVG_LENGTH = "svg:length";
+ final String SVG_UNIT = "svg:unit";
+ final String SVG_DUR = "svg:dur";
+ final String SVG_DIRECTION = "svg:direction";
+}
--- /dev/null
+package org.argeo.entity;
+
+/** Types related to entities. */
+public enum EntityType implements JcrName {
+ // entity
+ entity, local, relatedTo,
+ // typology
+ typologies, terms, term,
+ // form
+ form, formSet, formSubmission,
+ // graphics
+ box,
+ // geography
+ geopoint, bearing,
+ // ldap
+ person, user;
+
+ @Override
+ public String getPrefix() {
+ return prefix();
+ }
+
+ public static String prefix() {
+ return "entity";
+ }
+
+ public String basePath() {
+ return '/' + name();
+ }
+
+ @Override
+ public String getNamespace() {
+ return namespace();
+ }
+
+ public static String namespace() {
+ return "http://www.argeo.org/ns/entity";
+ }
+
+}
--- /dev/null
+package org.argeo.entity;
+
+/** Types related to entities. */
+@Deprecated
+public interface EntityTypes {
+ final static String ENTITY_ENTITY = "entity:entity";
+ final static String ENTITY_DEFINITION = "entity:definition";
+
+ final static String ENTITY_PERSON = "entity:person";
+}
--- /dev/null
+package org.argeo.entity;
+
+import java.util.function.Supplier;
+
+/** Can be applied to {@link Enum}s in order to generate prefixed names. */
+@FunctionalInterface
+public interface JcrName extends Supplier<String> {
+ String name();
+
+ default String getPrefix() {
+ return null;
+ }
+
+ default String getNamespace() {
+ return null;
+ }
+
+ @Override
+ default String get() {
+ String prefix = getPrefix();
+ return prefix != null ? prefix + ":" + name() : name();
+ }
+
+ default String withNamespace() {
+ String namespace = getNamespace();
+ if (namespace == null)
+ throw new UnsupportedOperationException("No namespace is specified for " + getClass());
+ return "{" + namespace + "}" + name();
+ }
+}
--- /dev/null
+package org.argeo.entity;
+
+import java.util.List;
+
+/** Provides optimised access and utilities around terms typologies. */
+public interface TermsManager {
+ List<String> listAllTerms(String typology);
+}
--- /dev/null
+// Standard namespaces
+<xsd = "http://www.w3.org/2001/XMLSchema">
+<h = "http://www.w3.org/1999/xhtml">
+// see https://www.w3.org/2003/01/geo/
+<geo = "http://www.w3.org/2003/01/geo/wgs84_pos#">
+<svg = "http://www.w3.org/2000/svg">
+
+<ldap = "http://www.argeo.org/ns/ldap">
+<entity = 'http://www.argeo.org/ns/entity'>
+
+[entity:entity] > mix:created, mix:referenceable
+mixin
+
+[entity:local] > entity:entity
+mixin
+- entity:type (String) m
+
+[entity:relatedTo]
+mixin
++ entity:relatedTo (nt:address) *
+
+//
+// ENTITY DEFINITION
+//
+//[entity:definition] > entity:composite, mix:created, mix:lastModified, mix:referenceable
+//- entity:type (String) multiple
+
+//[entity:part]
+
+//[entity:reference]
+
+//[entity:composite]
+//orderable
+//+ * (entity:part)
+//+ * (entity:reference)
+//+ * (entity:composite)
+
+//
+// TYPOLOGY
+//
+[entity:typologies]
++ * (entity:terms) = entity:terms
+
+[entity:term]
+orderable
+- name (NAME) m
+- * (*)
++ term (entity:term) = entity:term *
+
+[entity:terms] > mix:referenceable
+orderable
++ term (entity:term) = entity:term *
+
+//
+// FORM
+//
+[entity:form]
+mixin
+
+[entity:formSubmission]
+mixin
+
+[entity:formSet] > mix:title
+mixin
+
+//
+// GRAPHICS
+//
+[entity:box]
+mixin
+- svg:width (DOUBLE)
+- svg:height (DOUBLE)
+- svg:length (DOUBLE)
+- svg:unit (STRING)
+- svg:dur (DOUBLE)
+
+// LDAP-LIKE ENTITIES
+// A real person
+[entity:person] > entity:entity
+mixin
+- ldap:sn (String)
+- ldap:givenName (String)
+- ldap:mail (String) *
+
+[entity:user] > entity:person
+mixin
+- ldap:distinguishedName (String)
+- ldap:uid (String)
+
+// GEOGRAPHY
+[entity:geopoint]
+mixin
+- geo:long (DOUBLE)
+- geo:lat (DOUBLE)
+- geo:alt (DOUBLE)
+
+[entity:bearing]
+mixin
+- svg:direction (DOUBLE)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.entity.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.entity.core</artifactId>
+ <name>Entity Reference Implementation</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>org.argeo.entity.api</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ </dependency>
+
+ <!-- Argeo Commons -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms</artifactId>
+ <version>${version.argeo-commons}</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package org.argeo.entity.core;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.NodeUtils;
+import org.argeo.entity.EntityConstants;
+import org.argeo.entity.EntityDefinition;
+import org.argeo.jcr.Jcr;
+import org.osgi.framework.BundleContext;
+
+/** An entity definition based on a JCR data structure. */
+public class JcrEntityDefinition implements EntityDefinition {
+ private Repository repository;
+
+ private String type;
+ private String defaultEditoryId;
+
+ public void init(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
+ Session adminSession = NodeUtils.openDataAdminSession(repository, null);
+ try {
+ type = properties.get(EntityConstants.TYPE);
+ if (type == null)
+ throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set.");
+ defaultEditoryId = properties.get(EntityConstants.DEFAULT_EDITORY_ID);
+// String definitionPath = EntityNames.ENTITY_DEFINITIONS_PATH + '/' + type;
+// if (!adminSession.itemExists(definitionPath)) {
+// Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath, EntityTypes.ENTITY_DEFINITION);
+//// entityDefinition.addMixin(EntityTypes.ENTITY_DEFINITION);
+// adminSession.save();
+// }
+ initJcr(adminSession);
+ } finally {
+ Jcr.logout(adminSession);
+ }
+ }
+
+ /** To be overridden in order to perform additional initialisations. */
+ protected void initJcr(Session adminSession) throws RepositoryException {
+
+ }
+
+ public void destroy(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
+
+ }
+
+ @Override
+ public String getEditorId(Node entity) {
+ return defaultEditoryId;
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ protected Repository getRepository() {
+ return repository;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public String toString() {
+ return "Entity Definition " + getType();
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.entity.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+Import-Package:\
+org.eclipse.swt,\
+*
\ No newline at end of file
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.entity.ui</artifactId>
+ <name>Entity UI</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>org.argeo.entity.core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ </dependency>
+
+ <!-- Argeo Commons -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms.ui</artifactId>
+ <version>${version.argeo-commons}</version>
+ </dependency>
+
+ <!-- Specific -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.eclipse.ui.rap</artifactId>
+ <version>2.1.91-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Eclipse E4 -->
+ <dependency>
+ <groupId>org.argeo.tp</groupId>
+ <artifactId>argeo-tp-rap-e4</artifactId>
+ <version>${version.argeo-tp}</version>
+ <type>pom</type>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package org.argeo.entity.ui.forms;
+
+import javax.jcr.Item;
+
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.util.CmsIcon;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.entity.TermsManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** Common logic between single and mutliple terms editable part. */
+public abstract class AbstractTermsPart extends StyledControl implements EditablePart {
+ private static final long serialVersionUID = -5497097995341927710L;
+ protected final TermsManager termsManager;
+ protected final String typology;
+
+ protected final boolean editable;
+
+ private CmsIcon deleteIcon;
+ private CmsIcon addIcon;
+ private CmsIcon cancelIcon;
+
+ private Color highlightColor;
+ private Composite highlight;
+
+ protected final CmsTheme theme;
+
+ public AbstractTermsPart(Composite parent, int style, Item item, TermsManager termsManager,
+ String typology) {
+ super(parent, style, item);
+ this.termsManager = termsManager;
+ this.typology = typology;
+ this.theme = CmsTheme.getCmsTheme(parent);
+ editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
+ highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
+ }
+
+ protected void createHighlight(Composite block) {
+ highlight = new Composite(block, SWT.NONE);
+ highlight.setBackground(highlightColor);
+ GridData highlightGd = new GridData(SWT.FILL, SWT.FILL, false, false);
+ highlightGd.widthHint = 5;
+ highlightGd.heightHint = 3;
+ highlight.setLayoutData(highlightGd);
+
+ }
+
+ protected String getTermLabel(String name) {
+ return name;
+ }
+
+ protected abstract void refresh(ContextOverlay contextArea, String filter, Text txt);
+
+ protected boolean isTermSelectable(String term) {
+ return true;
+ }
+
+ protected void processTermListLabel(String term, Label label) {
+
+ }
+
+ //
+ // STYLING
+ //
+ public void setDeleteIcon(CmsIcon deleteIcon) {
+ this.deleteIcon = deleteIcon;
+ }
+
+ public void setAddIcon(CmsIcon addIcon) {
+ this.addIcon = addIcon;
+ }
+
+ public void setCancelIcon(CmsIcon cancelIcon) {
+ this.cancelIcon = cancelIcon;
+ }
+
+ protected TermsManager getTermsManager() {
+ return termsManager;
+ }
+
+ protected void styleDelete(ToolItem deleteItem) {
+ if (deleteIcon != null)
+ deleteItem.setImage(deleteIcon.getSmallIcon(theme));
+ else
+ deleteItem.setText("-");
+ }
+
+ protected void styleCancel(ToolItem cancelItem) {
+ if (cancelIcon != null)
+ cancelItem.setImage(cancelIcon.getSmallIcon(theme));
+ else
+ cancelItem.setText("X");
+ }
+
+ protected void styleAdd(ToolItem addItem) {
+ if (addIcon != null)
+ addItem.setImage(addIcon.getSmallIcon(theme));
+ else
+ addItem.setText("+");
+ }
+}
--- /dev/null
+package org.argeo.entity.ui.forms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Item;
+
+import org.argeo.cms.ui.forms.FormStyle;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+import org.argeo.eclipse.ui.MouseDoubleClick;
+import org.argeo.eclipse.ui.MouseDown;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.entity.TermsManager;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** {@link EditablePart} for multiple terms. */
+public class MultiTermsPart extends AbstractTermsPart {
+ private static final long serialVersionUID = -4961135649177920808L;
+
+ public MultiTermsPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
+ super(parent, style, item, termsManager, typology);
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ Composite placeholder = new Composite(box, SWT.NONE);
+ RowLayout rl = new RowLayout(SWT.HORIZONTAL | SWT.WRAP);
+ placeholder.setLayout(rl);
+ List<String> currentValue = Jcr.getMultiple(getNode(), typology);
+ if (currentValue != null && !currentValue.isEmpty())
+ for (String value : currentValue) {
+ Composite block = new Composite(placeholder, SWT.NONE);
+ block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
+ Label lbl = new Label(block, SWT.SINGLE);
+ String display = getTermLabel(value);
+ lbl.setText(display);
+ CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
+ if (editable)
+ lbl.addMouseListener((MouseDoubleClick) (e) -> {
+ startEditing();
+ });
+ if (isEditing()) {
+ ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+ ToolItem deleteItem = new ToolItem(toolBar, SWT.FLAT);
+ styleDelete(deleteItem);
+ deleteItem.addSelectionListener((Selected) (e) -> {
+ // we retrieve them again here because they may have changed
+ List<String> curr = Jcr.getMultiple(getNode(), typology);
+ List<String> newValue = new ArrayList<>();
+ for (String v : curr) {
+ if (!v.equals(value))
+ newValue.add(v);
+ }
+ Jcr.set(getNode(), typology, newValue);
+ Jcr.save(getNode());
+ block.dispose();
+ layout(true, true);
+ });
+
+ }
+ }
+ else {// empty
+ if (editable && !isEditing()) {
+ ToolBar toolBar = new ToolBar(placeholder, SWT.HORIZONTAL);
+ ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
+ styleAdd(addItem);
+ addItem.addSelectionListener((Selected) (e) -> {
+ startEditing();
+ });
+ }
+ }
+
+ if (isEditing()) {
+ Composite block = new Composite(placeholder, SWT.NONE);
+ block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
+
+ createHighlight(block);
+
+ Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
+ txt.setLayoutData(CmsUiUtils.fillWidth());
+// txt.setMessage("[new]");
+
+ CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
+
+ ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+ ToolItem cancelItem = new ToolItem(toolBar, SWT.FLAT);
+ styleCancel(cancelItem);
+ cancelItem.addSelectionListener((Selected) (e) -> {
+ stopEditing();
+ });
+
+ ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
+ private static final long serialVersionUID = -7980078594405384874L;
+
+ @Override
+ protected void onHide() {
+ stopEditing();
+ }
+ };
+ contextOverlay.setLayout(new GridLayout());
+ // filter
+ txt.addModifyListener((e) -> {
+ String filter = txt.getText().toLowerCase();
+ if ("".equals(filter.trim()))
+ filter = null;
+ refresh(contextOverlay, filter, txt);
+ });
+ txt.addFocusListener(new FocusListener() {
+ private static final long serialVersionUID = -6024501573409619949L;
+
+ @Override
+ public void focusLost(FocusEvent event) {
+// if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
+// getDisplay().asyncExec(() -> stopEditing());
+ }
+
+ @Override
+ public void focusGained(FocusEvent event) {
+ // txt.setText("");
+ if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
+ refresh(contextOverlay, null, txt);
+ }
+ });
+ layout(new Control[] { txt });
+ // getDisplay().asyncExec(() -> txt.setFocus());
+ }
+ return placeholder;
+ }
+
+ @Override
+ protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
+ CmsUiUtils.clear(contextArea);
+ List<String> terms = termsManager.listAllTerms(typology);
+ List<String> currentValue = Jcr.getMultiple(getNode(), typology);
+ terms: for (String term : terms) {
+ if (currentValue != null && currentValue.contains(term))
+ continue terms;
+ String display = getTermLabel(term);
+ if (filter != null && !display.toLowerCase().contains(filter))
+ continue terms;
+ Label termL = new Label(contextArea, SWT.WRAP);
+ termL.setText(display);
+ processTermListLabel(term, termL);
+ if (isTermSelectable(term))
+ termL.addMouseListener((MouseDown) (e) -> {
+ List<String> newValue = new ArrayList<>();
+ List<String> curr = Jcr.getMultiple(getNode(), typology);
+ if (currentValue != null)
+ newValue.addAll(curr);
+ newValue.add(term);
+ Jcr.set(getNode(), typology, newValue);
+ Jcr.save(getNode());
+ contextArea.hide();
+ stopEditing();
+ });
+ }
+ contextArea.show();
+ }
+
+}
--- /dev/null
+package org.argeo.entity.ui.forms;
+
+import java.util.List;
+
+import javax.jcr.Item;
+
+import org.argeo.cms.ui.forms.FormStyle;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+import org.argeo.eclipse.ui.MouseDoubleClick;
+import org.argeo.eclipse.ui.MouseDown;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.entity.TermsManager;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** {@link EditablePart} for terms. */
+public class SingleTermPart extends AbstractTermsPart {
+ private static final long serialVersionUID = -4961135649177920808L;
+
+ public SingleTermPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
+ super(parent, style, item, termsManager, typology);
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ if (isEditing()) {
+ Composite block = new Composite(box, SWT.NONE);
+ block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
+
+ createHighlight(block);
+
+ Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
+ CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
+
+ ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+ ToolItem deleteItem = new ToolItem(toolBar, SWT.PUSH);
+ styleDelete(deleteItem);
+ deleteItem.addSelectionListener((Selected) (e) -> {
+ Jcr.set(getNode(), typology, null);
+ Jcr.save(getNode());
+ stopEditing();
+ });
+ ToolItem cancelItem = new ToolItem(toolBar, SWT.PUSH);
+ styleCancel(cancelItem);
+ cancelItem.addSelectionListener((Selected) (e) -> {
+ stopEditing();
+ });
+
+ ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
+ private static final long serialVersionUID = -7980078594405384874L;
+
+ @Override
+ protected void onHide() {
+ stopEditing();
+ }
+ };
+ contextOverlay.setLayout(new GridLayout());
+ // filter
+ txt.addModifyListener((e) -> {
+ String filter = txt.getText().toLowerCase();
+ if ("".equals(filter.trim()))
+ filter = null;
+ refresh(contextOverlay, filter, txt);
+ });
+ txt.addFocusListener(new FocusListener() {
+ private static final long serialVersionUID = -6024501573409619949L;
+
+ @Override
+ public void focusLost(FocusEvent event) {
+// if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
+// getDisplay().asyncExec(() -> stopEditing());
+ }
+
+ @Override
+ public void focusGained(FocusEvent event) {
+ // txt.setText("");
+ if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
+ refresh(contextOverlay, null, txt);
+ }
+ });
+ layout(new Control[] { block });
+ getDisplay().asyncExec(() -> txt.setFocus());
+ return block;
+ } else {
+ Composite block = new Composite(box, SWT.NONE);
+ block.setLayout(CmsUiUtils.noSpaceGridLayout(2));
+ String currentValue = Jcr.get(getNode(), typology);
+ if (currentValue != null) {
+ Label lbl = new Label(block, SWT.SINGLE);
+ String display = getTermLabel(currentValue);
+ lbl.setText(display);
+ CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
+
+ lbl.addMouseListener((MouseDoubleClick) (e) -> {
+ startEditing();
+ });
+ } else {
+ ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+ ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
+ styleAdd(addItem);
+ addItem.addSelectionListener((Selected) (e) -> {
+ startEditing();
+ });
+ }
+ return block;
+ }
+ }
+
+ @Override
+ protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
+ CmsUiUtils.clear(contextArea);
+ List<String> terms = termsManager.listAllTerms(typology);
+ terms: for (String term : terms) {
+ String display = getTermLabel(term);
+ if (filter != null && !display.toLowerCase().contains(filter))
+ continue terms;
+ Label termL = new Label(contextArea, SWT.WRAP);
+ termL.setText(display);
+ processTermListLabel(term, termL);
+ if (isTermSelectable(term))
+ termL.addMouseListener((MouseDown) (e) -> {
+ Jcr.set(getNode(), typology, term);
+ Jcr.save(getNode());
+ contextArea.hide();
+ stopEditing();
+ });
+ }
+ contextArea.show();
+ // txt.setFocus();
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.suite.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Suite Maintenance Service">
+ <implementation class="org.argeo.suite.core.SuiteMaintenanceService"/>
+ <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
+ <reference bind="setUserTransaction" cardinality="1..1" interface="javax.transaction.UserTransaction" name="UserTransaction" policy="static"/>
+ <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Suite Terms Manager">
+ <implementation class="org.argeo.suite.core.SuiteTermsManager"/>
+ <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
+ <service>
+ <provide interface="org.argeo.entity.TermsManager"/>
+ </service>
+</scr:component>
--- /dev/null
+Bundle-ActivationPolicy: lazy
+
+Service-Component:\
+OSGI-INF/termsManager.xml,\
+OSGI-INF/maintenanceService.xml
+
+Import-Package:\
+javax.transaction,\
+org.osgi.service.useradmin,\
+javax.jcr.nodetype,\
+javax.jcr.security,\
+org.argeo.api,\
+org.argeo.entity,\
+*
\ No newline at end of file
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/
+source.. = src/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.suite.core</artifactId>
+ <name>Suite Core</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>org.argeo.entity.core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ </dependency>
+
+ <!-- Argeo Commons -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms</artifactId>
+ <version>${version.argeo-commons}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.maintenance</artifactId>
+ <version>${version.argeo-commons}</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package org.argeo.suite;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A container for an object whose relevance can be ranked. Typically used in an
+ * OSGi context with the service.ranking property.
+ */
+public class RankedObject<T> {
+ private final static Log log = LogFactory.getLog(RankedObject.class);
+
+ private final static String SERVICE_RANKING = "service.ranking";
+// private final static String SERVICE_ID = "service.id";
+
+ private T object;
+ private Map<String, Object> properties;
+ private final Long rank;
+
+ public RankedObject(T object, Map<String, Object> properties) {
+ this(object, properties, extractRanking(properties));
+ }
+
+ public RankedObject(T object, Map<String, Object> properties, Long rank) {
+ super();
+ this.object = object;
+ this.properties = properties;
+ this.rank = rank;
+ }
+
+ private static Long extractRanking(Map<String, Object> properties) {
+ if (properties == null)
+ return 0l;
+ if (properties.containsKey(SERVICE_RANKING))
+ return Long.valueOf(properties.get(SERVICE_RANKING).toString());
+// else if (properties.containsKey(SERVICE_ID))
+// return (Long) properties.get(SERVICE_ID);
+ else
+ return 0l;
+ }
+
+ public T get() {
+ return object;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ public Long getRank() {
+ return rank;
+ }
+
+ @Override
+ public int hashCode() {
+ return object.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof RankedObject))
+ return false;
+ RankedObject<?> other = (RankedObject<?>) obj;
+ return rank.equals(other.rank) && object.equals(other.object);
+ }
+
+ @Override
+ public String toString() {
+ return object.getClass().getName() + " with rank " + rank;
+ }
+
+ public static <K, T> RankedObject<T> putIfHigherRank(Map<K, RankedObject<T>> map, K key, T object,
+ Map<String, Object> properties) {
+ RankedObject<T> rankedObject = new RankedObject<>(object, properties);
+ if (!map.containsKey(key)) {
+ map.put(key, rankedObject);
+ if (log.isTraceEnabled())
+ log.trace(
+ "Added " + key + " as " + object.getClass().getName() + " with rank " + rankedObject.getRank());
+ return rankedObject;
+ } else {
+ RankedObject<T> current = map.get(key);
+ if (current.getRank() <= rankedObject.getRank()) {
+ map.put(key, rankedObject);
+ if (log.isTraceEnabled())
+ log.trace("Replaced " + key + " by " + object.getClass().getName() + " with rank "
+ + rankedObject.getRank());
+ return rankedObject;
+ } else {
+ return current;
+ }
+ }
+
+ }
+
+}
--- /dev/null
+package org.argeo.suite;
+
+import java.util.Map;
+
+/**
+ * Key used to classify and filter available components (typically provided by
+ * OSGi services).
+ */
+@Deprecated
+public class RankingKey implements Comparable<RankingKey> {
+ public final static String SERVICE_PID = "service.pid";
+ public final static String SERVICE_ID = "service.id";
+ public final static String SERVICE_RANKING = "service.ranking";
+ public final static String DATA_TYPE = "data.type";
+
+ private String pid;
+ private Integer ranking = 0;
+ private Long id = 0l;
+ private String dataType;
+ private String dataPath;
+
+ public RankingKey(String pid, Integer ranking, Long id, String dataType, String dataPath) {
+ super();
+ this.pid = pid;
+ this.ranking = ranking;
+ this.id = id;
+ this.dataType = dataType;
+ this.dataPath = dataPath;
+ }
+
+ public RankingKey(Map<String, Object> properties) {
+ this.pid = properties.containsKey(SERVICE_PID) ? properties.get(SERVICE_PID).toString() : null;
+ this.ranking = properties.containsKey(SERVICE_RANKING)
+ ? 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(DATA_TYPE) ? properties.get(DATA_TYPE).toString() : null;
+ }
+
+ @Override
+ public int hashCode() {
+ Integer result = 0;
+ if (pid != null)
+ result = +pid.hashCode();
+ if (ranking != null)
+ result = +ranking;
+ if (dataType != null)
+ result = +dataType.hashCode();
+ return result;
+ }
+
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return new RankingKey(pid, ranking, id, dataType, dataPath);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("");
+ if (pid != null)
+ sb.append(pid);
+ if (ranking != null && ranking != 0)
+ sb.append(' ').append(ranking);
+ if (dataType != null)
+ sb.append(' ').append(dataType);
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof RankingKey))
+ return false;
+ RankingKey other = (RankingKey) obj;
+ return equalsOrBothNull(pid, other.pid) && equalsOrBothNull(ranking, other.ranking)
+ && equalsOrBothNull(id, other.id) && equalsOrBothNull(dataType, other.dataType)
+ && equalsOrBothNull(dataPath, other.dataPath);
+ }
+
+ @Override
+ public int compareTo(RankingKey o) {
+ if (pid != null && o.pid != null) {
+ if (pid.equals(o.pid)) {
+ 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 pid.compareTo(o.pid);
+ }
+
+ } 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 -1;
+ }
+
+ public String getPid() {
+ return pid;
+ }
+
+ public Integer getRanking() {
+ return ranking;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getDataType() {
+ return dataType;
+ }
+
+ public String getDataPath() {
+ return dataPath;
+ }
+
+ public static RankingKey minPid(String pid) {
+ return new RankingKey(pid, Integer.MIN_VALUE, null, null, null);
+ }
+
+ public static RankingKey maxPid(String pid) {
+ 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;
+ if (o1 == null && o2 != null)
+ return false;
+ if (o1 != null && o2 == null)
+ return false;
+ return o2.equals(o1);
+ }
+}
--- /dev/null
+package org.argeo.suite;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.naming.Distinguished;
+import org.argeo.naming.LdapAttrs;
+
+/** Office specific roles used in the code */
+public enum SuiteRole implements Distinguished {
+ coworker, manager;
+
+ public String getRolePrefix() {
+ return "org.argeo.suite";
+ }
+
+ public String dn() {
+ return new StringBuilder(LdapAttrs.cn.name()).append("=").append(getRolePrefix()).append(".").append(name())
+ .append(",").append(NodeConstants.ROLES_BASEDN).toString();
+ }
+}
--- /dev/null
+package org.argeo.suite;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.Privilege;
+import javax.naming.ldap.LdapName;
+import javax.security.auth.x500.X500Principal;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.auth.CmsSession;
+import org.argeo.entity.EntityType;
+import org.argeo.jackrabbit.security.JackrabbitSecurityUtils;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.naming.LdapAttrs;
+
+/** Utilities around the Argeo Suite APIs. */
+public class SuiteUtils {
+
+ public static String getUserNodePath(LdapName userDn) {
+ String uid = userDn.getRdn(userDn.size() - 1).getValue().toString();
+ return EntityType.user.basePath() + '/' + uid;
+ }
+
+ public static Node getOrCreateUserNode(Session adminSession, LdapName userDn) {
+ try {
+ Node usersBase = adminSession.getNode(EntityType.user.basePath());
+ String uid = userDn.getRdn(userDn.size() - 1).getValue().toString();
+ Node userNode;
+ if (!usersBase.hasNode(uid)) {
+ userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
+ userNode.addMixin(EntityType.user.get());
+ userNode.addMixin(NodeType.MIX_CREATED);
+ userNode.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString());
+ userNode.setProperty(LdapAttrs.uid.property(), uid);
+ adminSession.save();
+ JackrabbitSecurityUtils.denyPrivilege(adminSession, userNode.getPath(), SuiteRole.coworker.dn(),
+ Privilege.JCR_READ);
+ JcrUtils.addPrivilege(adminSession, userNode.getPath(), new X500Principal(userDn.toString()).getName(),
+ Privilege.JCR_READ);
+ JcrUtils.addPrivilege(adminSession, userNode.getPath(), NodeConstants.ROLE_USER_ADMIN,
+ Privilege.JCR_ALL);
+ } else {
+ userNode = usersBase.getNode(uid);
+ }
+ return userNode;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot create user node for " + userDn, e);
+ }
+ }
+
+ public static Node getCmsSessionNode(Session session, CmsSession cmsSession) {
+ try {
+ return session.getNode(getUserNodePath(cmsSession.getUserDn()) + '/' + cmsSession.getUuid().toString());
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get session dir for " + cmsSession, e);
+ }
+ }
+
+ public static Node getOrCreateCmsSessionNode(Session adminSession, CmsSession cmsSession) {
+ try {
+ LdapName userDn = cmsSession.getUserDn();
+// String uid = userDn.get(userDn.size() - 1);
+ Node userNode = getOrCreateUserNode(adminSession, userDn);
+// if (!usersBase.hasNode(uid)) {
+// userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
+// userNode.addMixin(EntityType.user.get());
+// userNode.addMixin(NodeType.MIX_CREATED);
+// usersBase.setProperty(LdapAttrs.uid.property(), uid);
+// usersBase.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString());
+// adminSession.save();
+// } else {
+// userNode = usersBase.getNode(uid);
+// }
+ String cmsSessionUuid = cmsSession.getUuid().toString();
+ Node cmsSessionNode;
+ if (!userNode.hasNode(cmsSessionUuid)) {
+ cmsSessionNode = userNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED);
+ cmsSessionNode.addMixin(NodeType.MIX_CREATED);
+ adminSession.save();
+ JcrUtils.addPrivilege(adminSession, cmsSessionNode.getPath(), cmsSession.getUserRole(),
+ Privilege.JCR_ALL);
+ } else {
+ cmsSessionNode = userNode.getNode(cmsSessionUuid);
+ }
+ return cmsSessionNode;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot create session dir for " + cmsSession, e);
+ }
+ }
+
+ /** Singleton. */
+ private SuiteUtils() {
+
+ }
+
+}
--- /dev/null
+package org.argeo.suite.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.ItemExistsException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.maintenance.AbstractMaintenanceService;
+
+/** Base for custom initialisations. */
+public abstract class CustomMaintenanceService extends AbstractMaintenanceService {
+ private final static Log log = LogFactory.getLog(AbstractMaintenanceService.class);
+
+ protected List<String> getTypologies() {
+ return new ArrayList<>();
+ }
+
+ protected String getTypologiesLoadBase() {
+ return "/sys/terms";
+ }
+
+ protected void loadTypologies(Node customBaseNode) throws RepositoryException, IOException {
+ List<String> typologies = getTypologies();
+ if (!typologies.isEmpty()) {
+ Node termsBase = JcrUtils.getOrAdd(customBaseNode, EntityType.terms.name(), EntityType.typologies.get());
+ for (String terms : typologies) {
+ loadTerms(termsBase, terms);
+ }
+ termsBase.getSession().save();
+ }
+ }
+
+ protected void loadTerms(Node termsBase, String name) throws IOException, RepositoryException {
+ try {
+ if (termsBase.hasNode(name))
+ return;
+
+ String termsLoadPath = getTypologiesLoadBase() + '/' + name + ".xml";
+ URL termsUrl = getClass().getClassLoader().getResource(termsLoadPath);
+ if (termsUrl == null)
+ throw new IllegalArgumentException("Terms '" + name + "' not found.");
+ try (InputStream in = termsUrl.openStream()) {
+ termsBase.getSession().importXML(termsBase.getPath(), in,
+ ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+ } catch (ItemExistsException e) {
+ log.warn("Terms " + name + " exists with another UUID, removing it...");
+ termsBase.getNode(name).remove();
+ try (InputStream in = termsUrl.openStream()) {
+ termsBase.getSession().importXML(termsBase.getPath(), in,
+ ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+ }
+ }
+ if (log.isDebugEnabled())
+ log.debug("Terms '" + name + "' loaded.");
+ termsBase.getSession().save();
+ } catch (RepositoryException | IOException e) {
+ log.error("Cannot load terms '" + name + "': " + e.getMessage());
+ throw e;
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.suite.core;
+
+import java.io.IOException;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.Privilege;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.maintenance.AbstractMaintenanceService;
+
+/** Initialises an Argeo Suite backend. */
+public class SuiteMaintenanceService extends AbstractMaintenanceService {
+
+ @Override
+ public boolean prepareJcrTree(Session adminSession) throws RepositoryException, IOException {
+ boolean modified = false;
+ Node rootNode = adminSession.getRootNode();
+ if (!rootNode.hasNode(EntityType.user.name())) {
+ rootNode.addNode(EntityType.user.name(), NodeType.NT_UNSTRUCTURED);
+ modified = true;
+ }
+ if (modified)
+ adminSession.save();
+ return modified;
+ }
+
+ @Override
+ public void configurePrivileges(Session adminSession) throws RepositoryException {
+ JcrUtils.addPrivilege(adminSession, EntityType.user.basePath(), NodeConstants.ROLE_USER_ADMIN,
+ Privilege.JCR_ALL);
+ //JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), Privilege.JCR_READ);
+ }
+
+}
--- /dev/null
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
+ */
+class SuiteTerm {
+ private final String name;
+ private final String relativePath;
+ private final SuiteTypology typology;
+ private final String id;
+
+ private final SuiteTerm parentTerm;
+ private final List<SuiteTerm> subTerms = new ArrayList<>();
+
+ SuiteTerm(SuiteTypology typology, String relativePath, SuiteTerm parentTerm) {
+ this.typology = typology;
+ this.parentTerm = parentTerm;
+ this.relativePath = relativePath;
+ int index = relativePath.lastIndexOf('/');
+ if (index > 0) {
+ this.name = relativePath.substring(index);
+ } else {
+ this.name = relativePath;
+ }
+ id = typology.getName() + '/' + relativePath;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getRelativePath() {
+ return relativePath;
+ }
+
+ SuiteTypology getTypology() {
+ return typology;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ List<SuiteTerm> getSubTerms() {
+ return subTerms;
+ }
+
+ SuiteTerm getParentTerm() {
+ return parentTerm;
+ }
+
+}
--- /dev/null
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.entity.EntityNames;
+import org.argeo.entity.EntityType;
+import org.argeo.entity.TermsManager;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+
+/** Argeo Suite implementation of terms manager. */
+public class SuiteTermsManager implements TermsManager {
+ private final Map<String, SuiteTerm> terms = new HashMap<>();
+ private final Map<String, SuiteTypology> typologies = new HashMap<>();
+
+ // JCR
+ private Repository repository;
+ private Session adminSession;
+
+ public void init() {
+ adminSession = NodeUtils.openDataAdminSession(repository, NodeConstants.SYS_WORKSPACE);
+ }
+
+ @Override
+ public List<String> listAllTerms(String typology) {
+ List<String> res = new ArrayList<>();
+ SuiteTypology t = getTypology(typology);
+ for (SuiteTerm term : t.getAllTerms()) {
+ res.add(term.getId());
+ }
+ return res;
+ }
+
+ SuiteTypology getTypology(String typology) {
+ SuiteTypology t = typologies.get(typology);
+ if (t == null) {
+ Node termsNode = Jcr.getNode(adminSession, "SELECT * FROM [{0}] WHERE NAME()=\"{1}\"",
+ EntityType.terms.get(), typology);
+ if (termsNode == null)
+ throw new IllegalArgumentException("Typology " + typology + " not found.");
+ t = loadTypology(termsNode);
+ }
+ return t;
+ }
+
+ SuiteTypology loadTypology(Node termsNode) {
+ try {
+ SuiteTypology typology = new SuiteTypology(termsNode);
+ for (Node termNode : Jcr.iterate(termsNode.getNodes())) {
+ if (termNode.isNodeType(EntityType.term.get())) {
+ SuiteTerm term = loadTerm(typology, termNode, null);
+ if (!term.getSubTerms().isEmpty())
+ typology.markNotFlat();
+ typology.getSubTerms().add(term);
+ }
+ }
+ typologies.put(typology.getName(), typology);
+ return typology;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot load typology from " + termsNode, e);
+ }
+ }
+
+ SuiteTerm loadTerm(SuiteTypology typology, Node termNode, SuiteTerm parentTerm) throws RepositoryException {
+ String name = termNode.getProperty(EntityNames.NAME).getString();
+ String relativePath = parentTerm == null ? name : parentTerm.getRelativePath() + '/' + name;
+ SuiteTerm term = new SuiteTerm(typology, relativePath, parentTerm);
+ terms.put(term.getId(), term);
+ for (Node subTermNode : Jcr.iterate(termNode.getNodes())) {
+ if (termNode.isNodeType(EntityType.term.get())) {
+ SuiteTerm subTerm = loadTerm(typology, subTermNode, term);
+ term.getSubTerms().add(subTerm);
+ }
+ }
+ return term;
+ }
+
+ public void destroy() {
+ Jcr.logout(adminSession);
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+}
--- /dev/null
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.jcr.Jcr;
+
+/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
+class SuiteTypology {
+ private final String name;
+ private final Node node;
+ private boolean isFlat = true;
+
+ private final List<SuiteTerm> subTerms = new ArrayList<>();
+
+ public SuiteTypology(Node node) {
+ this.node = node;
+ this.name = Jcr.getName(this.node);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Node getNode() {
+ return node;
+ }
+
+ void markNotFlat() {
+ if (isFlat)
+ isFlat = false;
+ }
+
+ public boolean isFlat() {
+ return isFlat;
+ }
+
+ public List<SuiteTerm> getSubTerms() {
+ return subTerms;
+ }
+
+ public List<SuiteTerm> getAllTerms() {
+ if (isFlat)
+ return subTerms;
+ else {
+ List<SuiteTerm> terms = new ArrayList<>();
+ for (SuiteTerm subTerm : subTerms) {
+ terms.add(subTerm);
+ collectSubTerms(terms, subTerm);
+ }
+ return terms;
+ }
+ }
+
+ private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
+ for (SuiteTerm subTerm : term.getSubTerms()) {
+ terms.add(subTerm);
+ collectSubTerms(terms, subTerm);
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.suite.library;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.argeo.util.DigestUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/** Parses a .docx document, trying its best to extract text and table data. */
+public class DocxExtractor {
+ final static String T = "t";
+ final static String TC = "tc";
+ final static String TR = "tr";
+ final static String TBL = "tbl";
+ final static String P = "p";
+ static boolean debug = false;
+
+ final static String PROOF_ERR = "proofErr";
+ final static String TYPE = "type";
+ final static String SPELL_START = "spellStart";
+ final static String SPELL_END = "spellEnd";
+
+ protected List<Tbl> tables = new ArrayList<>();
+ protected List<String> text = new ArrayList<>();
+ protected Map<String, byte[]> media = new TreeMap<>();
+ private Set<String> mediaDigests = new HashSet<>();
+
+ protected void processTextItem(List<String> lines, String str) {
+ lines.add(str);
+ }
+
+ protected boolean skipMedia(String digest) {
+ return false;
+ }
+
+ class DocxHandler extends DefaultHandler {
+
+ private StringBuilder buffer = new StringBuilder();
+ private Tbl currentTbl = null;
+
+ boolean inSpellErr = false;
+ boolean inParagraph = false;
+
+ @Override
+ public void startElement(String uri, String name, String qName, Attributes attributes) throws SAXException {
+ // System.out.println(localName + " " + qName + " " + uri.hashCode());
+ if (P.equals(name)) {
+ if (debug && currentTbl == null)
+ System.out.println("# START PARA");
+ inParagraph = true;
+ } else if (PROOF_ERR.equals(name)) {
+ String type = attributes.getValue(uri, TYPE);
+ if (SPELL_START.equals(type))
+ inSpellErr = true;
+ else if (SPELL_END.equals(type))
+ inSpellErr = false;
+
+ } else if (TBL.equals(name)) {
+ if (currentTbl != null) {
+ Tbl childTbl = new Tbl();
+ childTbl.parentTbl = currentTbl;
+ currentTbl = childTbl;
+ // throw new IllegalStateException("Already an active table");
+ } else {
+ currentTbl = new Tbl();
+ }
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String name, String qName) throws SAXException {
+ if (name.equals(T)) {
+// if (inSpellErr) {
+// // do not reset the buffer
+// return;
+// }
+
+ if (currentTbl != null) {
+ currentTbl.appendText(buffer.toString());
+ } else {
+ String str = buffer.toString();
+ // replace NO-BREAK SPACE by regular space.
+ str = str.replace('\u00A0', ' ');
+ str = str.strip();
+ if (!"".equals(str)) {
+ processTextItem(text, str);
+ }
+ }
+ } else if (name.equals(P)) {
+ if (debug && currentTbl == null)
+ System.out.println("# END PARA");
+ if (currentTbl != null) {
+ currentTbl.currentRow.current.text.append('\n');
+ } else {
+
+ }
+ inParagraph = false;
+ } else if (name.equals(TC)) {
+ if (currentTbl != null)
+ currentTbl.closeColumn();
+ } else if (name.equals(TR)) {
+ if (currentTbl != null)
+ currentTbl.closeRow();
+ } else if (name.equals(TBL)) {
+ if (currentTbl != null) {
+ tables.add(currentTbl);
+ if (currentTbl.parentTbl != null)
+ currentTbl = currentTbl.parentTbl;
+ else
+ currentTbl = null;
+ } else {
+ throw new IllegalStateException("Closing a table while none was open.");
+ }
+ }
+ // reset the buffer
+ buffer.setLength(0);
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ buffer.append(ch, start, length);
+ }
+
+ }
+
+ public static class Tbl {
+ Tbl parentTbl = null;
+ Tr currentRow = new Tr();
+ List<Tr> rows = new ArrayList<>();
+
+ void appendText(String str) {
+ currentRow.current.text.append(str);
+ }
+
+ void closeColumn() {
+ currentRow.columns.add(currentRow.current);
+ currentRow.current = new Tc();
+ }
+
+ void closeRow() {
+ rows.add(currentRow);
+ currentRow = new Tr();
+ }
+
+ public List<Tr> getRows() {
+ return rows;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (Tr tr : rows) {
+ String txt = tr.toString();
+ sb.append(txt).append('\n');
+ }
+ return sb.toString();
+ }
+ }
+
+ public static class Tr {
+ Tc current = new Tc();
+ List<Tc> columns = new ArrayList<>();
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (Tc tc : columns) {
+ sb.append("\"").append(tc.toString()).append("\"").append(',');
+ }
+ return sb.toString();
+ }
+
+ public List<Tc> getColumns() {
+ return columns;
+ }
+
+ }
+
+ public static class Tc {
+ StringBuilder text = new StringBuilder();
+
+ @Override
+ public String toString() {
+ return text.toString().trim();
+ }
+
+ }
+
+ protected void parse(Reader in) {
+ try {
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ spf.setNamespaceAware(true);
+ SAXParser saxParser = spf.newSAXParser();
+ XMLReader xmlReader = saxParser.getXMLReader();
+ xmlReader.setContentHandler(new DocxHandler());
+ xmlReader.parse(new InputSource(in));
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ throw new RuntimeException("Cannot parse document", e);
+ }
+ }
+
+ public List<String> getText() {
+ return text;
+ }
+
+ public List<Tbl> getTables() {
+ return tables;
+ }
+
+ public Map<String, byte[]> getMedia() {
+ return media;
+ }
+
+ public void load(ZipInputStream zIn) {
+ try {
+ ZipEntry entry = null;
+ while ((entry = zIn.getNextEntry()) != null) {
+ if ("word/document.xml".equals(entry.getName())) {
+ try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ byte[] buffer = new byte[2048];
+ int len = 0;
+ while ((len = zIn.read(buffer)) > 0) {
+ out.write(buffer, 0, len);
+ }
+ try (Reader reader = new InputStreamReader(new ByteArrayInputStream(out.toByteArray()),
+ StandardCharsets.UTF_8)) {
+ parse(reader);
+ }
+ }
+ } else if (entry.getName().startsWith("word/media")) {
+ String fileName = entry.getName().substring(entry.getName().lastIndexOf('/') + 1);
+ int dotIndex = fileName.lastIndexOf('.');
+ String ext = fileName.substring(dotIndex + 1).toLowerCase();
+ // we ignore .jfif
+ if ("jpeg".equals(ext))
+ ext = "jpg";
+ fileName = fileName.substring(0, dotIndex) + "." + ext;
+ switch (ext) {
+ case "png":
+ case "jpg":
+ case "gif":
+ case "bmp":
+ case "tiff":
+ try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ byte[] buffer = new byte[2048];
+ int len = 0;
+ while ((len = zIn.read(buffer)) > 0) {
+ out.write(buffer, 0, len);
+ }
+ byte[] bytes = out.toByteArray();
+ String digest = DigestUtils.digest(DigestUtils.MD5, bytes);
+ if (skipMedia(digest))
+ break;
+ if (!mediaDigests.contains(digest)) {
+ media.put(fileName, bytes);
+ mediaDigests.add(digest);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ // System.out.println(entry.getName());
+ }
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ // throw new IllegalArgumentException("No document.xml found");
+
+ }
+
+// public static Reader extractDocumentXml(ZipInputStream zIn) throws IOException {
+// ZipEntry entry = null;
+// while ((entry = zIn.getNextEntry()) != null) {
+// if ("word/document.xml".equals(entry.getName())) {
+// try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+// byte[] buffer = new byte[2048];
+// int len = 0;
+// while ((len = zIn.read(buffer)) > 0) {
+// out.write(buffer, 0, len);
+// }
+// return new InputStreamReader(new ByteArrayInputStream(out.toByteArray()), StandardCharsets.UTF_8);
+// }
+// } else {
+// System.out.println(entry.getName());
+// }
+// }
+// throw new IllegalArgumentException("No document.xml found");
+// }
+
+// protected static ZipInputStream openAsZip(String file) throws IOException {
+// ZipInputStream zIn;
+// Path path = Paths.get(file);
+// zIn = new ZipInputStream(Files.newInputStream(path));
+// return zIn;
+// }
+
+ public static void main(String[] args) throws IOException {
+ if (args.length == 0)
+ throw new IllegalArgumentException("Provide a file path");
+ Path p = Paths.get(args[0]);
+
+ DocxExtractor importer = new DocxExtractor();
+ try (ZipInputStream zIn = new ZipInputStream(Files.newInputStream(p))) {
+ importer.load(zIn);
+ }
+ // display
+ System.out.println("## TEXT");
+ for (int i = 0; i < importer.text.size(); i++) {
+ String str = importer.text.get(i);
+ System.out.println(str);
+ }
+
+ System.out.println("\n");
+
+ for (int i = 0; i < importer.tables.size(); i++) {
+ Tbl tbl = importer.tables.get(i);
+ System.out.println("## TABLE " + i);
+ System.out.println(tbl);
+ }
+
+ System.out.println("## MEDIA");
+ for (String fileName : importer.media.keySet()) {
+ int sizeKb = importer.media.get(fileName).length / 1024;
+ System.out.println(fileName + " " + sizeKb + " kB");
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.suite.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.util.ISO9075;
+
+/** Ease XPath generation for JCR requests */
+public class XPathUtils {
+ private final static Log log = LogFactory.getLog(XPathUtils.class);
+
+ private final static String QUERY_XPATH = "xpath";
+
+ public static String descendantFrom(String parentPath) {
+ if (notEmpty(parentPath)) {
+ if ("/".equals(parentPath))
+ parentPath = "";
+ // Hardcoded dependency to Jackrabbit. Remove
+ String result = "/jcr:root" + ISO9075.encodePath(parentPath);
+ if (log.isTraceEnabled()) {
+ String result2 = "/jcr:root" + parentPath;
+ if (!result2.equals(result))
+ log.warn("Encoded Path " + result2 + " --> " + result);
+ }
+ return result;
+ } else
+ return "";
+ }
+
+ public static String localAnd(String... conditions) {
+ StringBuilder builder = new StringBuilder();
+ for (String condition : conditions) {
+ if (notEmpty(condition)) {
+ builder.append(" ").append(condition).append(" and ");
+ }
+ }
+ if (builder.length() > 3)
+ return builder.substring(0, builder.length() - 4);
+ else
+ return "";
+ }
+
+ public static String xPathNot(String condition) {
+ if (notEmpty(condition))
+ return "not(" + condition + ")";
+ else
+ return "";
+ }
+
+ public static String getFreeTextConstraint(String filter) throws RepositoryException {
+ StringBuilder builder = new StringBuilder();
+ if (notEmpty(filter)) {
+ String[] strs = filter.trim().split(" ");
+ for (String token : strs) {
+ builder.append("jcr:contains(.,'*" + encodeXPathStringValue(token) + "*') and ");
+ }
+ return builder.substring(0, builder.length() - 4);
+ }
+ return "";
+ }
+
+ public static String getPropertyContains(String propertyName, String filter) throws RepositoryException {
+ if (notEmpty(filter))
+ return "jcr:contains(@" + propertyName + ",'*" + encodeXPathStringValue(filter) + "*')";
+ return "";
+ }
+
+ private final static DateFormat jcrRefFormatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'+02:00'");
+
+ /**
+ * @param propertyName
+ * @param calendar the reference date
+ * @param lowerOrGreater "<", ">" TODO validate ">="
+ * @return
+ * @throws RepositoryException
+ */
+ public static String getPropertyDateComparaison(String propertyName, Calendar cal, String lowerOrGreater)
+ throws RepositoryException {
+ if (cal != null) {
+ String jcrDateStr = jcrRefFormatter.format(cal.getTime());
+
+ // jcrDateStr = "2015-08-03T05:00:03:000Z";
+ String result = "@" + propertyName + " " + lowerOrGreater + " xs:dateTime('" + jcrDateStr + "')";
+ return result;
+ }
+ return "";
+ }
+
+ public static String getPropertyEquals(String propertyName, String value) {
+ if (notEmpty(value))
+ return "@" + propertyName + "='" + encodeXPathStringValue(value) + "'";
+ return "";
+ }
+
+ public static String encodeXPathStringValue(String propertyValue) {
+ // TODO implement safer mechanism to escape invalid characters
+ // Also check why we have used this regex in ResourceSerrviceImpl l 474
+ // String cleanedKey = key.replaceAll("(?:')", "''");
+ String result = propertyValue.replaceAll("'", "''");
+ return result;
+ }
+
+ public static void andAppend(StringBuilder builder, String condition) {
+ if (notEmpty(condition)) {
+ builder.append(condition);
+ builder.append(" and ");
+ }
+ }
+
+ public static void appendOrderByProperties(StringBuilder builder, boolean ascending, String... propertyNames) {
+ if (propertyNames.length > 0) {
+ builder.append(" order by ");
+ for (String propName : propertyNames)
+ builder.append("@").append(propName).append(", ");
+ builder = builder.delete(builder.length() - 2, builder.length());
+ if (ascending)
+ builder.append(" ascending ");
+ else
+ builder.append(" descending ");
+ }
+ }
+
+ public static void appendAndPropStringCondition(StringBuilder builder, String propertyName, String filter)
+ throws RepositoryException {
+ if (notEmpty(filter)) {
+ andAppend(builder, getPropertyContains(propertyName, filter));
+ }
+ }
+
+ public static void appendAndNotPropStringCondition(StringBuilder builder, String propertyName, String filter)
+ throws RepositoryException {
+ if (notEmpty(filter)) {
+ String cond = getPropertyContains(propertyName, filter);
+ builder.append(xPathNot(cond));
+ builder.append(" and ");
+ }
+ }
+
+ public static Query createQuery(Session session, String queryString) throws RepositoryException {
+ QueryManager queryManager = session.getWorkspace().getQueryManager();
+ // Localise JCR properties for XPATH
+ queryString = localiseJcrItemNames(queryString);
+ return queryManager.createQuery(queryString, QUERY_XPATH);
+ }
+
+ private final static String NS_JCR = "\\{http://www.jcp.org/jcr/1.0\\}";
+ private final static String NS_NT = "\\{http://www.jcp.org/jcr/nt/1.0\\}";
+ private final static String NS_MIX = "\\{http://www.jcp.org/jcr/mix/1.0\\}";
+
+ /**
+ * Replace the generic namespace with the local "jcr:", "nt:", "mix:" values. It
+ * is a workaround that must be later cleaned
+ */
+ public static String localiseJcrItemNames(String name) {
+ name = name.replaceAll(NS_JCR, "jcr:");
+ name = name.replaceAll(NS_NT, "nt:");
+ name = name.replaceAll(NS_MIX, "mix:");
+ return name;
+ }
+
+ private static boolean notEmpty(String stringToTest) {
+ return !(stringToTest == null || "".equals(stringToTest.trim()));
+ }
+
+ /** Singleton. */
+ private XPathUtils() {
+
+ }
+}
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.suite.theme.default</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Argeo Suite Default Theme">
+ <implementation class="org.argeo.cms.ui.util.BundleCmsTheme"/>
+ <service>
+ <provide interface="org.argeo.cms.ui.CmsTheme"/>
+ </service>
+</scr:component>
--- /dev/null
+Service-Component:\
+OSGI-INF/cmsTheme.xml
+
+Import-Package:\
+org.argeo.cms.ui.util,\
+*
\ No newline at end of file
--- /dev/null
+bin.includes = META-INF/,\
+ icons/,\
+ OSGI-INF/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.suite.theme.default</artifactId>
+ <name>Suite Default Theme</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ </dependencies>
+</project>
--- /dev/null
+.argeo-suite-header {
+ color: white;
+ background-color: #00294b;
+}
+
+.argeo-suite-headerTitle {
+ font: bold 18px sans-serif;
+ color: white;
+ background-color: #00294b;
+}
+
+.argeo-suite-leadPane {
+ background-color: #eee;
+}
+
+Label.argeo-suite-leadPane {
+ font: 14px sans-serif;
+ color: #888;
+ background-color: #eee;
+}
+
+Button.argeo-suite-leadPane:hover {
+ cursor:pointer;
+}
+
+.argeo-suite-recentItems {
+ font: bold 14px sans-serif;
+ color: white;
+ background-color: #00294b;
+ padding: 8px 16px;
+}
+
+.argeo-suite-titleContainer {
+ background-color: #00294b;
+ padding: 6px 8px 4px 8px;
+}
+
+.argeo-suite-titleLabel {
+ font: bold 14px sans-serif;
+ color: white;
+ background-color: #00294b;
+}
+
+.argeo-suite-subTitleLabel {
+ font: italic 14px sans-serif;
+ color: #777;
+ padding: 4px 8px;
+}
+
+.argeo-suite-simpleLabel {
+ font: bold 14px sans-serif;
+ padding: 0px;
+}
+
+.argeo-suite-simpleText {
+ font: 14px sans-serif;
+ padding: 0px;
+}
+
+.argeo-suite-titleCell {
+ font: bold 14px sans-serif;
+ background-color: #ddd;
+}
+
+.argeo-suite-inlineButton {
+ padding: 0px 4px;
+ font: 12px sans-serif;
+ border: 1px solid white;
+ color: white;
+ background-image: none;
+ background-color: #00294b;
+}
+
+.argeo-suite-inlineButton:hover {
+ color: #00294b;
+ background-color: white;
+}
+
+Composite.argeo-suite-mainTabBody {
+ background-color: #eee;
+ border: 1px solid #bbb;
+}
+
+.argeo-suite-mainTab {
+ background-color: #eee;
+ border: 1px solid #888;
+}
+
+ToolItem.argeo-suite-mainTab {
+ border: none;
+ background-color: #eee;
+}
+
+ToolItem.argeo-suite-mainTab:hover {
+ background-color: #eee;
+}
+
+
+Button.argeo-suite-mainTab {
+ border: 1px solid #eee;
+ background-color: #eee;
+}
+
+.argeo-suite-mainTab:hover {
+ background-color: #eee;
+}
+
+Button.argeo-suite-mainTab:hover {
+ cursor: pointer;
+ background-color: #eee;
+}
+
+.argeo-suite-mainTabSelected {
+ font: bold 14px sans-serif;
+ color: white;
+ /*background-color: #00294b;*/
+ background-color: #5882b5;
+ border:1px solid #888;
+}
+
+ToolItem.argeo-suite-mainTabSelected {
+ border: none;
+}
+
+ToolItem.argeo-suite-mainTabSelected:hover {
+ background-color: #5882b5;
+}
+
+Button.argeo-suite-mainTabSelected {
+ border: none;
+}
+
+Sash {
+ border: 1px solid white;
+ background-image: none;
+ background-color: white;
+}
+
+Sash:hover {
+ border: 1px solid #5882b5;
+ background-color: #5882b5;
+}
+
+TreeItem{
+ background-color:#fff;
+}
+
+Tree-RowOverlay:selected {
+ color:#fff;
+ background-color:#5882b5;
+}
+
+TableItem{
+ background-color:#fff;
+}
+
+Table-RowOverlay:selected {
+ color:#fff;
+ background-color:#5882b5;
+}
+
+.argeo-suite-navigationBar{
+ background-color:#ddd;
+}
+
+.argeo-suite-navigationTitle{
+ background-color:#ddd;
+ font:bold 14px sans-serif;
+}
+
+.argeo-suite-navigationButton{
+ color:#777;
+ background-color:#ddd;
+ font:bold 14px sans-serif;
+}
+
+.argeo-suite-navigationButton:hover{
+ cursor:pointer;
+ color:#ddd;
+ background-color:#777;
+}
--- /dev/null
+.argeo-suite-header {
+ color: white;
+ background-color: #00294b;
+}
+
+.argeo-suite-headerTitle {
+ font: bold 14px sans-serif;
+ color: white;
+ background-color: #00294b;
+}
+
+.argeo-suite-leadPane {
+ background-color: #eee;
+}
+
+Label.argeo-suite-leadPane {
+ font: 11px sans-serif;
+ color: #888;
+ background-color: #eee;
+}
+
+Button.argeo-suite-leadPane:hover {
+ cursor: pointer;
+}
+
+.argeo-suite-recentItems {
+ font: bold 13px sans-serif;
+ color: white;
+ background-color: #00294b;
+ padding: 8px 16px;
+}
+
+.argeo-suite-titleContainer {
+ background-color: #00294b;
+}
+
+.argeo-suite-titleLabel {
+ font: bold 13px sans-serif;
+ margin: 6px 8px 4px 8px;
+ color: white;
+ background-color: #00294b;
+}
+
+.argeo-suite-subTitleLabel {
+ font: italic 14px sans-serif;
+ color: #777;
+ margin: 4px 8px;
+}
+
+.argeo-suite-formLine {
+ padding: 4px 8px 4px 16px;
+}
+
+.argeo-suite-simpleLabel {
+ font: normal 11px sans-serif;
+ border: 8px solid #eee;
+}
+
+.argeo-suite-simpleText {
+
+}
+
+.argeo-suite-simpleInput {
+ padding: 4px 8px 4px 8px;
+}
+
+.argeo-suite-titleCell {
+ font: bold 11px sans-serif;
+ background-color: #ddd;
+}
+
+.argeo-suite-inlineButton {
+ padding: 0px 4px;
+ font: 12px sans-serif;
+ border: 1px solid white;
+ color: white;
+ background-image: none;
+ background-color: #00294b;
+}
+
+.argeo-suite-inlineButton:hover {
+ color: #00294b;
+ background-color: white;
+}
+
+Composite.argeo-suite-mainTabBody {
+ background-color: #eee;
+ border: 1px solid #bbb;
+}
+
+.argeo-suite-mainTab {
+ background-color: #eee;
+ border: 1px solid #bbb;
+}
+
+ToolItem.argeo-suite-mainTab {
+ border: none;
+ background-color: #eee;
+}
+
+Button.argeo-suite-mainTab {
+ border: none;
+ background-color: #eee;
+}
+
+.argeo-suite-mainTab:hover {
+ background-color: #eee;
+}
+
+Button.argeo-suite-mainTab:hover {
+ cursor: pointer;
+ background-color: #eee;
+}
+
+.argeo-suite-mainTabSelected {
+ font: bold 14px sans-serif;
+ color: white;
+ /*background-color: #00294b;*/
+ background-color: #5882b5;
+ border: 1px solid #00294b;
+}
+
+ToolItem.argeo-suite-mainTabSelected {
+ border: none;
+}
+
+Button.argeo-suite-mainTabSelected {
+ border: none;
+}
\ No newline at end of file
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.suite.ui.rap</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Argeo Suite Web App">
+ <implementation class="org.argeo.cms.web.CmsWebApp"/>
+ <property name="contextName" type="String" value="argeo"/>
+ <reference bind="setCmsApp" cardinality="1..1" interface="org.argeo.cms.ui.CmsApp" name="CmsApp" policy="dynamic" target="(service.pid=argeo.suite.ui.app)" unbind="unsetCmsApp"/>
+ <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
+</scr:component>
--- /dev/null
+Service-Component: OSGI-INF/cmsWebApp.xml
+
+Import-Package:\
+org.argeo.cms.web,\
+org.eclipse.rap.rwt.application,\
+*
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/
+source.. = src/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.suite.ui.rap</artifactId>
+ <name>Suite UI RAP</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>org.argeo.suite.ui</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ </dependency>
+
+ <!-- Eclipse E4 -->
+ <dependency>
+ <groupId>org.argeo.tp</groupId>
+ <artifactId>argeo-tp-rap-e4</artifactId>
+ <version>${version.argeo-tp}</version>
+ <type>pom</type>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.suite.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Argeo Suite App">
+ <implementation class="org.argeo.suite.ui.SuiteApp"/>
+ <service>
+ <provide interface="org.argeo.cms.ui.CmsApp"/>
+ <provide interface="org.osgi.service.event.EventHandler"/>
+ </service>
+ <properties entry="config/cmsApp.properties"/>
+ <reference bind="addUiProvider" cardinality="0..n" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" unbind="removeUiProvider"/>
+ <reference bind="addTheme" cardinality="1..n" interface="org.argeo.cms.ui.CmsTheme" name="CmsTheme" policy="dynamic" unbind="removeTheme"/>
+ <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="dynamic" target="(cn=ego)"/>
+ <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
+ <reference bind="setCmsUserManager" cardinality="1..1" interface="org.argeo.cms.CmsUserManager" name="CmsUserManager" policy="static"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default Dashboard">
+ <implementation class="org.argeo.suite.ui.DefaultDashboard"/>
+ <service>
+ <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+ </service>
+ <properties entry="config/dashboard.properties"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Dashboard Layer">
+ <implementation class="org.argeo.suite.ui.DefaultEditionLayer"/>
+ <service>
+ <provide interface="org.argeo.suite.ui.SuiteLayer"/>
+ </service>
+ <properties entry="config/dashboardLayer.properties"/>
+ <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.suite.ui.recentItems)"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Work Header">
+ <implementation class="org.argeo.suite.ui.DefaultHeader"/>
+ <service>
+ <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+ <provide interface="org.osgi.service.cm.ManagedService"/>
+ </service>
+ <properties entry="config/header.properties"/>
+</scr:component>
--- /dev/null
+dashboard=dashboard
+people=contacts
+documents=documents
+locations=locations
+recentItems=recent items
+
+appTitle=Argeo Suite
+
+#
+# PEOPLE
+# org.argeo.people.ui.PeopleMsg
+#
+person=Person
+organisation=Organisation
+
+# NewPersonWizard
+firstName=First Name
+lastName=Last Name
+salutation=Salutation
+email=Email
+personWizardWindowTitle=New person
+personWizardPageTitle=Create a contact
+
+# NewOrgWizard
+legalName=Legal name
+legalForm=Legal form
+vatId=VAT ID
+orgWizardWindowTitle=New organisation
+orgWizardPageTitle=Create an organisation
+
+
+# ContextAddressComposite
+chooseAnOrganisation=Choose an organisation
+street=Street
+streetComplement=Street complement
+zipCode=Zip code
+city=City
+state=State
+country=Country
+geopoint=Geopoint
+
+# FilteredOrderableEntityTable
+filterHelp=Type filter criterion separated by a space
+
+# BankAccountComposite
+accountHolder=Account holder
+bankName=Bank name
+currency=Currency
+accountNumber=Account number
+bankNumber=Bank number
+BIC=BIC
+IBAN=IBAN
+
+# EditJobDialog
+position=Role
+chosenItem=Chose item
+department=Department
+isPrimary=Is primary
+searchAndChooseEntity=Search and choose a corresponding entity
+
+# ContactListCTab (e4)
+notes=Notes
+addAContact=Add a contact
+contactValue=Contact value
+linkedCompany=Linked company
+
+# OrgAdminInfoCTab (e4)
+paymentAccount=Payment account
+
+# OrgEditor (e4)
+orgDetails=Details
+orgActivityLog=Activity log
+team=Team
+orgAdmin=Admin.
+
+# PersonEditor (e4)
+personDetails=Contact details
+personActivityLog=Activity log
+personOrgs=Organisations
+personSecurity=Security
+
+# PersonSecurityCTab (e4)
+resetPassword=Reset password
+
+# Generic
+label=Label
+aCustomLabel=A custom label
+description=Description
+value=Value
+name=Name
+primary=Primary
+add=Add
+save=Save
+pickUp=Pick up
+
+# Tags
+confirmNewTag=Tag #{0} is not yet registered. Are you sure you want to create it?
+cannotCreateTag=Tag #{0} is not yet registered and you don't have enough rights to create it.
--- /dev/null
+dashboard=dashboard
+people=Kontakte
+documents=Dokumente
+locations=Orte
+recentItems=neulich
+
+appTitle=Argeo Suite
+
+#
+# PEOPLE
+# org.argeo.people.ui.PeopleMsg
+#
+person=Person
+organisation=Organisation
+
+# NewPersonWizard
+firstName=Vorname
+lastName=Nachname
+salutation=Salutation
+email=E-Mail
+personWizardWindowTitle=Neue Person
+personWizardPageTitle=Kontakt erstellen
+
+# NewOrgWizard
+legalName=Name
+legalForm=Geschäftsform
+vatId=Ust ID
+orgWizardWindowTitle=Neue Organisation
+orgWizardPageTitle=Organisation erstellen
+
+
+# ContextAddressComposite
+chooseAnOrganisation=Organisation wählen
+street=Strasse
+streetComplement=Strasse Zusatz
+zipCode=PLZ
+city=Stadt
+state=Bundesland
+country=Land
+geopoint=Geopoint
+
+# FilteredOrderableEntityTable
+filterHelp=Type filter criterion separated by a space
+
+# BankAccountComposite
+accountHolder=Kontoinhaber
+bankName=Name der Bank
+currency=Währung
+accountNumber=Kontonummer
+bankNumber=BLZ
+BIC=BIC
+IBAN=IBAN
+
+# EditJobDialog
+position=Rolle
+chosenItem=Auswahl
+department=Abteilung
+isPrimary=Ist Primär
+searchAndChooseEntity=Suche und wähle ein zugehöriges Objekt
+
+# ContactListCTab (e4)
+notes=Bemerkungen
+addAContact=Kontakt hinzufügen
+contactValue=Kontakt value
+linkedCompany=zugehörige Firma
+
+# OrgAdminInfoCTab (e4)
+paymentAccount=Geschäftskonto
+
+# OrgEditor (e4)
+orgDetails=Details
+orgActivityLog=Aktivitäten Log
+team=Team
+orgAdmin=Admin.
+
+# PersonEditor (e4)
+personDetails=Kontakt Daten
+personActivityLog=Aktivitäten Log
+personOrgs=Organisationen
+personSecurity=Sicherheit
+
+# PersonSecurityCTab (e4)
+resetPassword=Passwort zurücksetzen
+
+# Generic
+label=Beschriftung
+aCustomLabel=Eine spezifische Beschriftung
+description=Beschreibung
+value=Wert
+name=Name
+primary=Haupt-
+add=Hinzufügen
+save=Speichern
+pickUp=Aussuchen
+
+# Tags
+confirmNewTag=Das Hashtag '{0}' existiert noch nicht. WollenSie es hinzufügen?
+cannotCreateTag=Das Hashtag '{0}' existiert nicht uns Sie haben nicht die Rechte, um es hinzufügen.
--- /dev/null
+dashboard=dashboard
+people=contacts
+documents=documents
+locations=lieux
+recentItems=récent
+
+appTitle=Argeo Suite
+
+#
+# GENERIC
+#
+
+#
+# PEOPLE
+# org.argeo.people.ui.PeopleMsg
+#
+person=Personne
+organisation=Organisation
+
+# NewPersonWizard
+firstName=Prénom
+lastName=Nom
+salutation=Salutation
+email=Email
+personWizardWindowTitle=Nouvelle personne
+personWizardPageTitle=Créer un contact
+
+# NewOrgWizard
+legalName=Nom
+legalForm=Forme légale
+vatId=ID TVA
+orgWizardWindowTitle=Nouvelle organisation
+orgWizardPageTitle=Créer une organisation
+
+
+# ContextAddressComposite
+chooseAnOrganisation=Choisir une organisation
+street=Rue
+streetComplement=Complément rue
+zipCode=Code postal
+city=Ville
+state=État
+country=Pays
+geopoint=Géocoordonnées
+
+# FilteredOrderableEntityTable
+filterHelp=Sasir les critères de filtrage séparés par des espaces
+
+# BankAccountComposite
+accountHolder=Propriétaire du compte
+bankName=Nom de la banque
+currency=Devise
+accountNumber=Numéro de compte
+bankNumber=Numéro de banque
+BIC=BIC
+IBAN=IBAN
+
+# EditJobDialog
+position=Rôle
+chosenItem=Choisir une élément
+department=Service
+isPrimary=Principal
+searchAndChooseEntity=Cherhcer et choisir l'entitée correspondante
+
+# ContactListCTab (e4)
+notes=Notes
+addAContact=Ajouter un contact
+contactValue=Valeur
+linkedCompany=Entreprise liée
+
+# OrgAdminInfoCTab (e4)
+paymentAccount=Compte de paiement
+
+# OrgEditor (e4)
+orgDetails=Détails
+orgActivityLog=Activités
+team=Équipe
+orgAdmin=Admin.
+
+# PersonEditor (e4)
+personDetails=Détails du contact
+personActivityLog=Activités
+personOrgs=Organisations
+personSecurity=Accès
+
+# PersonSecurityCTab (e4)
+resetPassword=Force le mot de passe
+
+# Generic
+label=Étiquette
+aCustomLabel=Une étiquette spécifique
+description=Description
+value=Valeur
+name=Nom
+primary=Principal
+add=Ajouter
+save=Sauver
+pickUp=Choisir
+
+# Tags
+confirmNewTag=Le tag #{0} n'existe pas encore. Voulez-vous le créer?
+cannotCreateTag=Le tag #{0} n'existe pas encore et vous n'avez pas les droits pour le créer.
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Lead Pane">
+ <implementation class="org.argeo.suite.ui.DefaultLeadPane"/>
+ <service>
+ <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+ </service>
+ <properties entry="config/leadPane.properties"/>
+ <property name="defaultLayers" type="String">argeo.suite.ui.dashboardLayer
+argeo.documents.ui.documentsLayer
+ </property>
+ <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default Login Screen">
+ <implementation class="org.argeo.suite.ui.DefaultLoginScreen"/>
+ <properties entry="config/loginScreen.properties"/>
+ <service>
+ <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+ </service>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" name="Default Recent Items">
+ <implementation class="org.argeo.suite.ui.RecentItems"/>
+ <service>
+ <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+ </service>
+ <properties entry="config/recentItems.properties"/>
+</scr:component>
--- /dev/null
+Service-Component:\
+OSGI-INF/cmsApp.xml,\
+OSGI-INF/header.xml,\
+OSGI-INF/leadPane.xml,\
+OSGI-INF/loginScreen.xml,\
+OSGI-INF/recentItems.xml,\
+OSGI-INF/dashboard.xml,\
+OSGI-INF/dashboardLayer.xml
+
+Import-Package:\
+org.argeo.api,\
+org.eclipse.swt,\
+org.osgi.framework,\
+org.argeo.entity,\
+org.eclipse.core.commands.common,\
+org.eclipse.jface.window,\
+org.eclipse.jface.dialogs,\
+*
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/,\
+ config/,\
+ OSGI-INF/loginScreen.xml,\
+ OSGI-INF/dashboard.xml,\
+ OSGI-INF/recentItems.xml,\
+ OSGI-INF/dashboardLayer.xml
+source.. = src/
--- /dev/null
+service.pid=argeo.suite.ui.app
+
+event.topics=argeo/suite/*
\ No newline at end of file
--- /dev/null
+service.pid=argeo.suite.ui.dashboard
--- /dev/null
+service.pid=argeo.suite.ui.dashboardLayer
+
+title=Dashboard
+icon=dashboard
\ No newline at end of file
--- /dev/null
+service.pid=argeo.suite.ui.header
+argeo.suite.ui=true
+
+argeo.suite.ui.header.title=%appTitle
\ No newline at end of file
--- /dev/null
+service.pid=argeo.suite.ui.leadPane
--- /dev/null
+service.pid=argeo.suite.ui.loginScreen
--- /dev/null
+service.pid=argeo.suite.ui.recentItems
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.suite.ui</artifactId>
+ <name>Suite UI</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>org.argeo.suite.core</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>org.argeo.entity.ui</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ </dependency>
+
+ <!-- Argeo Commons -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.eclipse.ui</artifactId>
+ <version>${version.argeo-commons}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.eclipse.ui.rap</artifactId>
+ <version>${version.argeo-commons}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Eclipse E4 -->
+ <dependency>
+ <groupId>org.argeo.tp</groupId>
+ <artifactId>argeo-tp-rap-e4</artifactId>
+ <version>${version.argeo-tp}</version>
+ <type>pom</type>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package org.argeo.suite.ui;
+
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.dialogs.CmsWizardDialog;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.naming.LdapAttrs;
+import org.argeo.suite.SuiteRole;
+import org.argeo.suite.ui.dialogs.NewUserWizard;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.osgi.service.useradmin.User;
+
+/** Entry to the admin area. */
+public class AdminEntryArea implements CmsUiProvider {
+
+ private CmsUserManager cmsUserManager;
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ CmsTheme theme = CmsTheme.getCmsTheme(parent);
+ parent.setLayout(new GridLayout());
+ TableViewer usersViewer = new TableViewer(parent);
+ usersViewer.setContentProvider(new UsersContentProvider());
+
+ TableViewerColumn idCol = new TableViewerColumn(usersViewer, SWT.NONE);
+ idCol.getColumn().setWidth(70);
+ idCol.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+
+ return getUserProperty(element, LdapAttrs.uid.name());
+ }
+ });
+
+ TableViewerColumn givenNameCol = new TableViewerColumn(usersViewer, SWT.NONE);
+ givenNameCol.getColumn().setWidth(150);
+ givenNameCol.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+
+ return getUserProperty(element, LdapAttrs.givenName.name());
+ }
+ });
+
+ TableViewerColumn snCol = new TableViewerColumn(usersViewer, SWT.NONE);
+ snCol.getColumn().setWidth(150);
+ snCol.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+
+ return getUserProperty(element, LdapAttrs.sn.name());
+ }
+ });
+
+ TableViewerColumn mailCol = new TableViewerColumn(usersViewer, SWT.NONE);
+ mailCol.getColumn().setWidth(400);
+ mailCol.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+
+ return getUserProperty(element, LdapAttrs.mail.name());
+ }
+ });
+
+ Composite bottom = new Composite(parent, SWT.NONE);
+ bottom.setLayoutData(CmsUiUtils.fillWidth());
+ bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
+ ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
+ bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+ ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
+ deleteItem.setEnabled(false);
+// CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
+ deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
+ ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
+ addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+ usersViewer.addDoubleClickListener(new IDoubleClickListener() {
+
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ User user = (User) usersViewer.getStructuredSelection().getFirstElement();
+ if (user != null) {
+// Node userNode = getOrCreateUserNode(user, context);
+ CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
+ SuiteEvent.eventProperties(user));
+ }
+
+ }
+ });
+ usersViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ User user = (User) usersViewer.getStructuredSelection().getFirstElement();
+ if (user != null) {
+// Node userNode = getOrCreateUserNode(user, context);
+ CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
+ SuiteEvent.eventProperties(user));
+ deleteItem.setEnabled(true);
+ } else {
+ deleteItem.setEnabled(false);
+ }
+ }
+ });
+
+ addItem.addSelectionListener((Selected) (e) -> {
+ // SuiteUtils.getOrCreateUserNode(adminSession, userDn);
+ Wizard wizard = new NewUserWizard(null);
+ CmsWizardDialog dialog = new CmsWizardDialog(parent.getShell(), wizard);
+ // WizardDialog dialog = new WizardDialog(shell, wizard);
+ if (dialog.open() == Window.OK) {
+ // TODO create
+ }
+ });
+
+ usersViewer.getTable().setLayoutData(CmsUiUtils.fillAll());
+ usersViewer.setInput(cmsUserManager);
+
+ return usersViewer.getTable();
+ }
+
+// private Node getOrCreateUserNode(User user, Node context) {
+// return JcrUtils.mkdirs(Jcr.getSession(context),
+// "/" + EntityType.user.name() + "/" + getUserProperty(user, LdapAttrs.uid.name()),
+// EntityType.user.get());
+// }
+
+ private String getUserProperty(Object element, String key) {
+ Object value = ((User) element).getProperties().get(key);
+ return value != null ? value.toString() : null;
+ }
+
+ class UsersContentProvider implements IStructuredContentProvider {
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ CmsUserManager cum = (CmsUserManager) inputElement;
+ Set<User> users = cum.listUsersInGroup(SuiteRole.coworker.dn(), null);
+ return users.toArray();
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ }
+
+ public void setCmsUserManager(CmsUserManager cmsUserManager) {
+ this.cmsUserManager = cmsUserManager;
+ }
+
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Provides a dashboard. */
+public class DefaultDashboard implements CmsUiProvider {
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ parent.setLayout(new GridLayout());
+ CmsView cmsView = CmsView.getCmsView(parent);
+ if (cmsView.isAnonymous())
+ throw new IllegalStateException("No user is not logged in");
+
+ Label lbl = new Label(parent, SWT.NONE);
+ lbl.setText("Welcome " + CurrentUser.getDisplayName() + "!");
+
+ return lbl;
+ }
+
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.widgets.TabbedArea;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** An app layer based on an entry area and an editor area. */
+public class DefaultEditionLayer implements SuiteLayer {
+ private CmsUiProvider entryArea;
+ private CmsUiProvider workArea;
+ private List<String> weights = new ArrayList<>();
+ private boolean startMaximized = false;
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ if (entryArea != null) {
+ SashFormEditionArea sashFormEditionArea = new SashFormEditionArea(parent, parent.getStyle());
+ entryArea.createUi(sashFormEditionArea.getEntryArea(), context);
+ if (this.workArea != null) {
+ this.workArea.createUi(sashFormEditionArea.getEditorArea(), context);
+ }
+ return sashFormEditionArea;
+ } else {
+ if (this.workArea != null) {
+ Composite area = new Composite(parent, SWT.NONE);
+ this.workArea.createUi(area, context);
+ return area;
+ }
+ CmsTheme theme = CmsTheme.getCmsTheme(parent);
+ TabbedArea tabbedArea = createTabbedArea(parent, theme);
+ return tabbedArea;
+ }
+ }
+
+ @Override
+ public void view(CmsUiProvider uiProvider, Composite workArea, Node context) {
+ TabbedArea tabbedArea;
+ if (workArea instanceof SashFormEditionArea) {
+ tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
+ } else if (workArea instanceof TabbedArea) {
+ tabbedArea = (TabbedArea) workArea;
+ } else
+ throw new IllegalArgumentException("Unsupported work area " + workArea.getClass().getName());
+ tabbedArea.view(uiProvider, context);
+ }
+
+ @Override
+ public void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
+ TabbedArea tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
+ tabbedArea.open(uiProvider, context);
+ }
+
+ public void init(Map<String, Object> properties) {
+ weights = LangUtils.toStringList(properties.get(Property.weights.name()));
+ startMaximized = properties.containsKey(Property.startMaximized.name())
+ && "true".equals(properties.get(Property.startMaximized.name()));
+ }
+
+ public void setEntryArea(CmsUiProvider entryArea) {
+ this.entryArea = entryArea;
+ }
+
+ public void setWorkArea(CmsUiProvider workArea) {
+ this.workArea = workArea;
+ }
+
+ TabbedArea createTabbedArea(Composite parent, CmsTheme theme) {
+ TabbedArea tabbedArea = new TabbedArea(parent, SWT.NONE);
+ tabbedArea.setBodyStyle(SuiteStyle.mainTabBody.style());
+ tabbedArea.setTabStyle(SuiteStyle.mainTab.style());
+ tabbedArea.setTabSelectedStyle(SuiteStyle.mainTabSelected.style());
+ tabbedArea.setCloseIcon(SuiteIcon.close.getSmallIcon(theme));
+ tabbedArea.setLayoutData(CmsUiUtils.fillAll());
+ return tabbedArea;
+ }
+
+ /** A work area based on an entry area and and a tabbed area. */
+ class SashFormEditionArea extends SashForm {
+ private static final long serialVersionUID = 2219125778722702618L;
+ private CmsTheme theme;
+ private Composite entryArea;
+ private Composite editorArea;
+ private TabbedArea tabbedArea;
+
+ SashFormEditionArea(Composite parent, int style) {
+ super(parent, SWT.HORIZONTAL);
+ theme = CmsTheme.getCmsTheme(parent);
+
+ if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
+ editorArea = new Composite(this, SWT.BORDER);
+ entryArea = new Composite(this, SWT.BORDER);
+ } else {
+ entryArea = new Composite(this, SWT.NONE);
+ editorArea = new Composite(this, SWT.NONE);
+ }
+
+ if (weights.size() != 0) {
+ int[] actualWeight = new int[weights.size()];
+ for (int i = 0; i < weights.size(); i++) {
+ actualWeight[i] = Integer.parseInt(weights.get(i));
+ }
+ setWeights(actualWeight);
+ } else {
+ int[] actualWeights = new int[] { 3000, 7000 };
+ setWeights(actualWeights);
+ }
+ if (startMaximized)
+ setMaximizedControl(editorArea);
+ editorArea.setLayout(new GridLayout());
+
+ if (DefaultEditionLayer.this.workArea == null) {
+ tabbedArea = createTabbedArea(editorArea, theme);
+ }
+
+ }
+
+ Composite getEntryArea() {
+ return entryArea;
+ }
+
+ TabbedArea getTabbedArea() {
+ return tabbedArea;
+ }
+
+ Composite getEditorArea() {
+ return editorArea;
+ }
+
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.suite.ui;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+public class DefaultHeader implements CmsUiProvider, ManagedService {
+ public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title";
+ private Map<String, String> properties;
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ CmsView cmsView = CmsView.getCmsView(parent);
+ CmsTheme theme = CmsTheme.getCmsTheme(parent);
+
+ parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, true)));
+
+ // TODO right to left
+ Composite lead = new Composite(parent, SWT.NONE);
+ CmsUiUtils.style(lead, SuiteStyle.header);
+ lead.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false));
+ lead.setLayout(new GridLayout());
+ Label lbl = new Label(lead, SWT.NONE);
+ String title = properties.get(TITLE_PROPERTY);
+ lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString()
+ : title);
+ CmsUiUtils.style(lbl, SuiteStyle.headerTitle);
+ lbl.setLayoutData(CmsUiUtils.fillWidth());
+
+ Composite middle = new Composite(parent, SWT.NONE);
+ CmsUiUtils.style(middle, SuiteStyle.header);
+ middle.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
+ middle.setLayout(new GridLayout());
+
+ Composite end = new Composite(parent, SWT.NONE);
+ CmsUiUtils.style(end, SuiteStyle.header);
+ end.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, false));
+
+ if (!cmsView.isAnonymous()) {
+ end.setLayout(new GridLayout(2, false));
+ Label userL = new Label(end, SWT.NONE);
+ CmsUiUtils.style(userL, SuiteStyle.header);
+ userL.setText(CurrentUser.getDisplayName());
+ Button logoutB = new Button(end, SWT.FLAT);
+// CmsUiUtils.style(logoutB, SuiteStyle.header);
+ logoutB.setImage(SuiteIcon.logout.getSmallIcon(theme));
+ logoutB.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = 7116760083964201233L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ cmsView.logout();
+ }
+
+ });
+ } else {
+ end.setLayout(new GridLayout(1, false));
+ // required in order to avoid wrong height after logout
+ new Label(end, SWT.NONE).setText("");
+
+ }
+ return lbl;
+ }
+
+ public void init(Map<String, String> properties) {
+ this.properties = new TreeMap<>(properties);
+ }
+
+ @Override
+ public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+ if (properties != null)
+ this.properties.putAll(LangUtils.dictToStringMap(properties));
+ }
+
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.Localized;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.suite.RankedObject;
+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.osgi.framework.Constants;
+
+/** Side pane listing various perspectives. */
+public class DefaultLeadPane implements CmsUiProvider {
+ private final static Log log = LogFactory.getLog(DefaultLeadPane.class);
+
+ public static enum Property {
+ defaultLayers, adminLayers;
+ }
+
+ private Map<String, RankedObject<SuiteLayer>> layers = Collections.synchronizedSortedMap(new TreeMap<>());
+ private String[] defaultLayers;
+ private String[] adminLayers;
+
+ @Override
+ public Control createUi(Composite parent, Node node) throws RepositoryException {
+ CmsView cmsView = CmsView.getCmsView(parent);
+ GridLayout layout = new GridLayout();
+ layout.verticalSpacing = 10;
+ layout.marginTop = 10;
+ layout.marginLeft = 10;
+ layout.marginRight = 10;
+ parent.setLayout(layout);
+
+ Button first = null;
+ for (String layerId : defaultLayers) {
+ if (layers.containsKey(layerId)) {
+ RankedObject<SuiteLayer> layerObj = layers.get(layerId);
+
+ // TODO deal with i10n
+ String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
+ Localized title = null;
+ if (titleStr != null)
+ title = new Localized.Untranslated(titleStr);
+
+ String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
+ SuiteIcon icon = null;
+ if (iconName != null)
+ icon = SuiteIcon.valueOf(iconName);
+
+ Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon);
+ if (first == null)
+ first = b;
+ }
+ }
+
+ // TODO factorise
+ boolean isAdmin = cmsView.doAs(() -> CurrentUser.isInRole(NodeConstants.ROLE_USER_ADMIN));
+ if (isAdmin && adminLayers != null)
+ for (String layerId : adminLayers) {
+ if (layers.containsKey(layerId)) {
+ RankedObject<SuiteLayer> layerObj = layers.get(layerId);
+
+ // TODO deal with i10n
+ String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
+ Localized title = null;
+ if (titleStr != null)
+ title = new Localized.Untranslated(titleStr);
+
+ String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
+ SuiteIcon icon = null;
+ if (iconName != null)
+ icon = SuiteIcon.valueOf(iconName);
+
+ Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon);
+ if (first == null)
+ first = b;
+ }
+ }
+
+// Button dashboardB = createButton(parent, SuiteMsg.dashboard.name(), SuiteMsg.dashboard, SuiteIcon.dashboard);
+ if (!cmsView.isAnonymous()) {
+// createButton(parent, SuiteMsg.documents.name(), SuiteMsg.documents, SuiteIcon.documents);
+// createButton(parent, SuiteMsg.people.name(), SuiteMsg.people, SuiteIcon.people);
+// createButton(parent, SuiteMsg.locations.name(), SuiteMsg.locations, SuiteIcon.location);
+ }
+ return first;
+ }
+
+ public void init(Map<String, Object> properties) {
+ defaultLayers = (String[]) properties.get(Property.defaultLayers.toString());
+ if (defaultLayers == null)
+ throw new IllegalArgumentException("Default layers must be set.");
+ if (log.isDebugEnabled())
+ log.debug("Default layers: " + Arrays.asList(defaultLayers));
+ adminLayers = (String[]) properties.get(Property.adminLayers.toString());
+ if (log.isDebugEnabled() && adminLayers != null)
+ log.debug("Admin layers: " + Arrays.asList(adminLayers));
+ }
+
+ public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
+ if (properties.containsKey(Constants.SERVICE_PID)) {
+ String pid = (String) properties.get(Constants.SERVICE_PID);
+ RankedObject.putIfHigherRank(layers, pid, layer, properties);
+ }
+ }
+
+ public void removeLayer(SuiteLayer layer, Map<String, Object> properties) {
+ if (properties.containsKey(Constants.SERVICE_PID)) {
+ String pid = (String) properties.get(Constants.SERVICE_PID);
+ if (layers.containsKey(pid)) {
+ if (layers.get(pid).equals(new RankedObject<SuiteLayer>(layer, properties))) {
+ layers.remove(pid);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.widgets.auth.CmsLogin;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Provides a login screen. */
+public class DefaultLoginScreen implements CmsUiProvider {
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ CmsView cmsView = CmsView.getCmsView(parent);
+ if (!cmsView.isAnonymous())
+ throw new IllegalStateException(CurrentUser.getUsername() + " is already logged in");
+
+ parent.setLayout(new GridLayout());
+ Composite loginArea = new Composite(parent, SWT.NONE);
+ loginArea.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+
+ CmsLogin cmsLogin = new CmsLogin(cmsView);
+ cmsLogin.createUi(loginArea);
+ return cmsLogin.getCredentialsBlock();
+ }
+
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.suite.ui.widgets.DelayedText;
+import org.argeo.suite.util.XPathUtils;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** List recent items. */
+public class RecentItems implements CmsUiProvider {
+ private final static int SEARCH_TEXT_DELAY = 800;
+ private final static int SEARCH_DEFAULT_LIMIT = 100;
+
+ private CmsTheme theme;
+
+ private String entityType;
+
+ static enum Property {
+ entityTypes;
+ }
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ theme = CmsTheme.getCmsTheme(parent);
+ parent.setLayout(new GridLayout());
+// parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+ parent.setLayout(new GridLayout());
+
+// Composite top = new Composite(parent, SWT.BORDER);
+// CmsUiUtils.style(top, SuiteStyle.recentItems);
+// top.setLayoutData(CmsUiUtils.fillWidth());
+// top.setLayout(CmsUiUtils.noSpaceGridLayout(2));
+// Label lbl = new Label(top, SWT.FLAT);
+// lbl.setLayoutData(CmsUiUtils.fillWidth());
+// lbl.setText(SuiteMsg.recentItems.lead());
+// CmsUiUtils.style(lbl, SuiteStyle.recentItems);
+//
+// ToolBar topToolBar = new ToolBar(top, SWT.NONE);
+// ToolItem addItem = new ToolItem(topToolBar, SWT.FLAT);
+//// CmsUiUtils.style(addItem, SuiteStyle.recentItems);
+// addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+
+ if (context == null)
+ return null;
+ SingleEntityViewer entityViewer = new SingleEntityViewer(parent, SWT.NONE, context.getSession());
+ entityViewer.createUi();
+ entityViewer.getViewer().getTable().setLayoutData(CmsUiUtils.fillAll());
+
+ Composite bottom = new Composite(parent, SWT.NONE);
+ bottom.setLayoutData(CmsUiUtils.fillWidth());
+ bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
+ ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
+ bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+ ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
+ deleteItem.setEnabled(false);
+// CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
+ deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
+ ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
+ addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+ entityViewer.getViewer().addDoubleClickListener(new IDoubleClickListener() {
+
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
+ if (node != null)
+ CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
+ SuiteEvent.eventProperties(node));
+
+ }
+ });
+ entityViewer.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
+ if (node != null) {
+ CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
+ SuiteEvent.eventProperties(node));
+ deleteItem.setEnabled(true);
+ } else {
+ deleteItem.setEnabled(false);
+ }
+ }
+ });
+
+ return entityViewer.filterTxt;
+
+ }
+
+ public void init(Map<String, String> properties) {
+ // TODO manage multiple entities
+ entityType = properties.get(Property.entityTypes.name());
+ }
+
+ class SingleEntityViewer {
+ Composite parent;
+ Text filterTxt;
+ TableViewer viewer;
+ Session session;
+
+ public SingleEntityViewer(Composite parent, int style, Session session) {
+ this.parent = parent;
+ this.session = session;
+ }
+
+ public void createUi() {
+ // MainLayout
+ addFilterPanel(parent);
+ viewer = createListPart(parent, new SingleEntityLabelProvider());
+ refreshFilteredList();
+
+ try {
+ String[] nodeTypes = entityType != null && entityType.contains(":") ? new String[] { entityType }
+ : null;
+ session.getWorkspace().getObservationManager().addEventListener(new EventListener() {
+
+ @Override
+ public void onEvent(EventIterator events) {
+ parent.getDisplay().asyncExec(() -> refreshFilteredList());
+ }
+ }, Event.PROPERTY_CHANGED | Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED, "/", true,
+ null, nodeTypes, false);
+ } catch (RepositoryException e) {
+ throw new IllegalStateException("Cannot add JCR observer", e);
+ }
+
+ }
+
+ private void addFilterPanel(Composite parent) {
+ // Use a delayed text: the query won't be done until the user stop
+ // typing for 800ms
+ int style = SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL;
+ DelayedText delayedText = new DelayedText(parent, style, SEARCH_TEXT_DELAY);
+ filterTxt = delayedText.getText();
+ filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
+
+ // final ServerPushSession pushSession = new ServerPushSession();
+ delayedText.addDelayedModifyListener(null, new ModifyListener() {
+ private static final long serialVersionUID = 5003010530960334977L;
+
+ public void modifyText(ModifyEvent event) {
+ delayedText.getText().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ refreshFilteredList();
+ }
+ });
+ // pushSession.stop();
+ }
+ });
+
+ // Jump to the first item of the list using the down arrow
+ filterTxt.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -4523394262771183968L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
+ // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
+ if (e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.TAB) {
+// Object first = entityViewer.getElementAt(0);
+// if (first != null) {
+// entityViewer.getTable().setFocus();
+// entityViewer.setSelection(new StructuredSelection(first), true);
+// }
+ e.doit = false;
+ }
+ }
+ });
+
+ parent.addDisposeListener((e) -> {
+ delayedText.close();
+ });
+ }
+
+ protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) {
+// parent.setLayout(new GridLayout());
+// parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ Composite tableComposite = new Composite(parent, SWT.NONE);
+ GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL
+ | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
+ tableComposite.setLayoutData(gd);
+
+ TableViewer viewer = new TableViewer(tableComposite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+ viewer.setLabelProvider(labelProvider);
+
+ TableColumn singleColumn = new TableColumn(viewer.getTable(), SWT.V_SCROLL);
+ TableColumnLayout tableColumnLayout = new TableColumnLayout();
+ tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(85));
+ tableComposite.setLayout(tableColumnLayout);
+
+ // Corresponding table & style
+ Table table = viewer.getTable();
+// Listener[] mouseDownListeners = table.getListeners(SWT.MouseDown);
+// for (Listener listener : table.getListeners(SWT.MouseDown))
+// table.removeListener(SWT.MouseDown, listener);
+// for (Listener listener : table.getListeners(SWT.MouseUp))
+// table.removeListener(SWT.MouseUp, listener);
+// for (Listener listener : table.getListeners(SWT.MouseDoubleClick))
+// table.removeListener(SWT.MouseDoubleClick, listener);
+//
+// table.addMouseListener(new MouseListener() {
+//
+// @Override
+// public void mouseUp(MouseEvent e) {
+// System.out.println("Mouse up: "+e);
+// }
+//
+// @Override
+// public void mouseDown(MouseEvent e) {
+// System.out.println("Mouse down: "+e);
+// }
+//
+// @Override
+// public void mouseDoubleClick(MouseEvent e) {
+// System.out.println("Mouse double: "+e);
+//
+// }
+// });
+ table.setLinesVisible(true);
+ table.setHeaderVisible(false);
+ // CmsUiUtils.markup(table);
+ // CmsUiUtils.setItemHeight(table, 26);
+
+ viewer.setContentProvider(new BasicNodeListContentProvider());
+ return viewer;
+ }
+
+// public boolean setFocus() {
+// refreshFilteredList();
+// return parent.setFocus();
+// }
+
+ public void forceRefresh(Object object) {
+ refreshFilteredList();
+ }
+
+ protected void refreshFilteredList() {
+ try {
+ String filter = filterTxt.getText();
+ // Prevents the query on the full repository
+ // if (isEmpty(filter)) {
+ // entityViewer.setInput(null);
+ // return;
+ // }
+
+ // XPATH Query
+ String xpathQueryStr;
+ if (entityType != null) {
+ int indexColumn = entityType.indexOf(':');
+ if (indexColumn > 0) {// JCR node type
+ xpathQueryStr = "//element(*, " + entityType + ") order by @jcr:created descending";
+ } else {
+ xpathQueryStr = entityType.contains(":") ? "//element(*, " + entityType + ")"
+ : "//element(*, " + EntityType.entity.get() + ")[@entity:type='" + entityType + "']";
+ }
+ } else {
+ xpathQueryStr = "//element(*, " + EntityType.entity.get() + ")";
+ }
+// String xpathQueryStr = "//element(*, " + ConnectTypes.CONNECT_ENTITY + ")";
+ String xpathFilter = XPathUtils.getFreeTextConstraint(filter);
+ if (notEmpty(xpathFilter))
+ xpathQueryStr += "[" + xpathFilter + "]";
+
+// long begin = System.currentTimeMillis();
+ // session.refresh(false);
+ Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
+
+ xpathQuery.setLimit(SEARCH_DEFAULT_LIMIT);
+ QueryResult result = xpathQuery.execute();
+
+ NodeIterator nit = result.getNodes();
+ viewer.setInput(JcrUtils.nodeIteratorToList(nit));
+// if (log.isTraceEnabled()) {
+// long end = System.currentTimeMillis();
+// log.trace("Quick Search - Found: " + nit.getSize() + " in " + (end - begin)
+// + " ms by executing XPath query (" + xpathQueryStr + ").");
+// }
+ } catch (RepositoryException e) {
+ throw new IllegalStateException("Unable to list entities", e);
+ }
+ }
+
+ public TableViewer getViewer() {
+ return viewer;
+ }
+
+ class SingleEntityLabelProvider extends ColumnLabelProvider {
+ private static final long serialVersionUID = -2209337675781795677L;
+
+ @Override
+ public String getText(Object element) {
+ return Jcr.getTitle((Node) element);
+ }
+
+ }
+
+ class BasicNodeListContentProvider implements IStructuredContentProvider {
+ private static final long serialVersionUID = 1L;
+ // keep a cache of the Nodes in the content provider to be able to
+ // manage long request
+ private List<Node> nodes;
+
+ public void dispose() {
+ }
+
+ /** Expects a list of nodes as a new input */
+ @SuppressWarnings("unchecked")
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ nodes = (List<Node>) newInput;
+ }
+
+ public Object[] getElements(Object arg0) {
+ return nodes.toArray();
+ }
+ }
+ }
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import static org.argeo.cms.ui.CmsView.CMS_VIEW_UID_PROPERTY;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeUtils;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.auth.CmsSession;
+import org.argeo.cms.ui.AbstractCmsApp;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.dialogs.CmsFeedback;
+import org.argeo.cms.ui.util.CmsEvent;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.argeo.entity.EntityConstants;
+import org.argeo.entity.EntityNames;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.Jcr;
+import org.argeo.suite.RankedObject;
+import org.argeo.suite.SuiteUtils;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.Constants;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+import org.osgi.service.useradmin.User;
+
+/** The Argeo Suite App. */
+public class SuiteApp extends AbstractCmsApp implements EventHandler {
+ private final static Log log = LogFactory.getLog(SuiteApp.class);
+
+ public final static String PUBLIC_BASE_PATH_PROPERTY = "publicBasePath";
+ public final static String DEFAULT_UI_NAME_PROPERTY = "defaultUiName";
+ public final static String DEFAULT_THEME_ID_PROPERTY = "defaultThemeId";
+
+ private String publicBasePath = null;
+
+ private String pidPrefix;
+ private String headerPid;
+ private String leadPanePid;
+ private String loginScreenPid;
+// private String DASHBOARD_PID = pidPrefix + "dashboard";
+// private String RECENT_ITEMS_PID = pidPrefix + "recentItems";
+
+ private String defaultUiName = "app";
+ private String defaultThemeId = "org.argeo.suite.theme.default";
+
+ private Map<String, RankedObject<CmsUiProvider>> uiProvidersByPid = Collections.synchronizedMap(new HashMap<>());
+ private Map<String, RankedObject<CmsUiProvider>> uiProvidersByType = Collections.synchronizedMap(new HashMap<>());
+ private Map<String, RankedObject<SuiteLayer>> layersByPid = Collections.synchronizedSortedMap(new TreeMap<>());
+ private Map<String, RankedObject<SuiteLayer>> layersByType = Collections.synchronizedSortedMap(new TreeMap<>());
+
+ private CmsUserManager cmsUserManager;
+
+ // TODO make more optimal or via CmsSession/CmsView
+ private Map<String, SuiteUi> managedUis = new HashMap<>();
+
+// private CmsUiProvider headerPart = null;
+
+ public void init(Map<String, Object> properties) {
+ if (log.isDebugEnabled())
+ log.info("Argeo Suite App started");
+
+ if (properties.containsKey(DEFAULT_UI_NAME_PROPERTY))
+ defaultUiName = LangUtils.get(properties, DEFAULT_UI_NAME_PROPERTY);
+ if (properties.containsKey(DEFAULT_THEME_ID_PROPERTY))
+ defaultThemeId = LangUtils.get(properties, DEFAULT_THEME_ID_PROPERTY);
+ publicBasePath = LangUtils.get(properties, PUBLIC_BASE_PATH_PROPERTY);
+
+ if (properties.containsKey(Constants.SERVICE_PID)) {
+ String servicePid = properties.get(Constants.SERVICE_PID).toString();
+ if (servicePid.endsWith(".app")) {
+ pidPrefix = servicePid.substring(0, servicePid.length() - "app".length());
+ }
+ }
+
+ if (pidPrefix == null)
+ throw new IllegalArgumentException("PID prefix must be set.");
+
+ headerPid = pidPrefix + "header";
+ leadPanePid = pidPrefix + "leadPane";
+ loginScreenPid = pidPrefix + "loginScreen";
+ }
+
+ public void destroy(Map<String, Object> properties) {
+ for (SuiteUi ui : managedUis.values())
+ if (!ui.isDisposed())
+ ui.dispose();
+ if (log.isDebugEnabled())
+ log.info("Argeo Suite App stopped");
+
+ }
+
+ @Override
+ public Set<String> getUiNames() {
+ HashSet<String> uiNames = new HashSet<>();
+ uiNames.add(defaultUiName);
+ return uiNames;
+ }
+
+ @Override
+ public Composite initUi(Composite parent) {
+ String uiName = parent.getData(UI_NAME_PROPERTY) != null ? parent.getData(UI_NAME_PROPERTY).toString() : null;
+ CmsView cmsView = CmsView.getCmsView(parent);
+ if (cmsView == null)
+ throw new IllegalStateException("No CMS view is registered.");
+ CmsTheme theme = getTheme(uiName);
+ if (theme != null)
+ CmsTheme.registerCmsTheme(parent.getShell(), theme);
+ SuiteUi argeoSuiteUi = new SuiteUi(parent, SWT.INHERIT_DEFAULT);
+ String uid = cmsView.getUid();
+ managedUis.put(uid, argeoSuiteUi);
+ argeoSuiteUi.addDisposeListener((e) -> {
+ managedUis.remove(uid);
+ if (log.isDebugEnabled())
+ log.debug("Suite UI " + uid + " has been disposed.");
+ });
+ refreshUi(argeoSuiteUi, null);
+ return argeoSuiteUi;
+ }
+
+ @Override
+ public String getThemeId(String uiName) {
+ return defaultThemeId;
+ }
+
+ @Override
+ public void refreshUi(Composite parent, String state) {
+ try {
+ Node context = null;
+ SuiteUi ui = (SuiteUi) parent;
+ CmsView cmsView = CmsView.getCmsView(parent);
+ if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login
+ ui.logout();
+ refreshPart(findUiProvider(headerPid), ui.getHeader(), context);
+ ui.refreshBelowHeader(false);
+ refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context);
+ ui.layout(true, true);
+ } else {
+ CmsSession cmsSession = cmsView.getCmsSession();
+ if (ui.getUserDir() == null) {
+ if (cmsView.isAnonymous()) {
+ assert publicBasePath != null;
+ ui.initSessions(getRepository(), publicBasePath);
+ } else {
+ Session adminSession = null;
+ try {
+ adminSession = NodeUtils.openDataAdminSession(getRepository(), null);
+ Node userDir = SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
+ ui.initSessions(getRepository(), userDir.getPath());
+ } finally {
+ Jcr.logout(adminSession);
+ }
+ }
+ }
+ initLocale(cmsSession);
+ context = stateToNode(ui, state);
+ if (context == null)
+ context = ui.getUserDir();
+
+ refreshPart(findUiProvider(headerPid), ui.getHeader(), context);
+ ui.refreshBelowHeader(true);
+ for (String key : layersByPid.keySet()) {
+ SuiteLayer layer = layersByPid.get(key).get();
+ ui.addLayer(key, layer);
+ }
+ refreshPart(findUiProvider(leadPanePid), ui.getLeadPane(), context);
+ ui.layout(true, true);
+ setState(parent, state);
+ }
+ } catch (Exception e) {
+ CmsFeedback.show("Unexpected exception", e);
+ }
+ }
+
+ private void initLocale(CmsSession cmsSession) {
+ if (cmsSession == null)
+ return;
+ Locale locale = cmsSession.getLocale();
+ UiContext.setLocale(locale);
+ LocaleUtils.setThreadLocale(locale);
+
+ }
+
+ private void refreshPart(CmsUiProvider uiProvider, Composite part, Node context) {
+ CmsUiUtils.clear(part);
+ uiProvider.createUiPart(part, context);
+ }
+
+ private CmsUiProvider findUiProvider(String pid) {
+ if (!uiProvidersByPid.containsKey(pid))
+ throw new IllegalArgumentException("No UI provider registered as " + pid);
+ return uiProvidersByPid.get(pid).get();
+ }
+
+ private <T> T findByType(Map<String, RankedObject<T>> byType, Node context) {
+ if (context == null)
+ throw new IllegalArgumentException("A node should be provided");
+ try {
+ // mixins
+ Set<String> types = new TreeSet<>();
+ for (NodeType nodeType : context.getMixinNodeTypes()) {
+ String typeName = nodeType.getName();
+ if (byType.containsKey(typeName)) {
+ types.add(typeName);
+ }
+ }
+ // primary node type
+ {
+ NodeType nodeType = context.getPrimaryNodeType();
+ String typeName = nodeType.getName();
+ if (byType.containsKey(typeName)) {
+ types.add(typeName);
+ }
+ for (NodeType mixin : nodeType.getDeclaredSupertypes()) {
+ if (byType.containsKey(mixin.getName())) {
+ types.add(mixin.getName());
+ }
+ }
+ }
+ // entity type
+ if (context.isNodeType(EntityType.entity.get())) {
+ if (context.hasProperty(EntityNames.ENTITY_TYPE)) {
+ String typeName = context.getProperty(EntityNames.ENTITY_TYPE).getString();
+ if (byType.containsKey(typeName)) {
+ types.add(typeName);
+ }
+ }
+ }
+
+// if (context.getPath().equals("/")) {// root node
+// types.add("nt:folder");
+// }
+ if (NodeUtils.isUserHome(context) && byType.containsKey("nt:folder")) {// home node
+ types.add("nt:folder");
+ }
+
+ if (types.size() == 0)
+ throw new IllegalArgumentException("No type found for " + context);
+ String type = types.iterator().next();
+ if (!byType.containsKey(type))
+ throw new IllegalArgumentException("No component found for " + context + " with type " + type);
+ return byType.get(type).get();
+ } catch (RepositoryException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public void setState(Composite parent, String state) {
+ if (state == null || state.equals("~"))
+ return;
+ if (!state.startsWith("/") && !state.equals("~")) {
+ if (parent instanceof SuiteUi) {
+ SuiteUi ui = (SuiteUi) parent;
+ String currentLayerId = ui.getCurrentLayerId();
+ if (state.equals(currentLayerId))
+ return; // does nothing
+ else {
+ Map<String, Object> properties = new HashMap<>();
+ properties.put(SuiteEvent.LAYER, state);
+ ui.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), properties);
+ }
+ }
+ return;
+ }
+ SuiteUi suiteUi = (SuiteUi) parent;
+ Node node = stateToNode(suiteUi, state);
+ if (node == null) {
+ suiteUi.getCmsView().navigateTo("~");
+ } else {
+ suiteUi.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), SuiteEvent.eventProperties(node));
+ suiteUi.getCmsView().sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(node));
+ }
+ }
+
+ private String nodeToState(Node node) {
+ return '/' + Jcr.getWorkspaceName(node) + Jcr.getPath(node);
+ }
+
+ private Node stateToNode(SuiteUi suiteUi, String state) {
+ if (suiteUi == null)
+ return null;
+ if (state == null || !state.startsWith("/"))
+ return null;
+
+ String path = state.substring(1);
+ String workspace;
+ if (path.equals("")) {
+ workspace = null;
+ path = "/";
+ } else {
+ int index = path.indexOf('/');
+ if (index == 0) {
+ log.error("Cannot interpret " + state);
+// cmsView.navigateTo("~");
+ return null;
+ } else if (index > 0) {
+ workspace = path.substring(0, index);
+ path = path.substring(index);
+ } else {// index<0, assuming root node
+ workspace = path;
+ path = "/";
+ }
+ }
+ Session session = suiteUi.getSession(workspace);
+ if (session == null)
+ return null;
+ Node node = Jcr.getNode(session, path);
+ return node;
+ }
+
+ /*
+ * Events management
+ */
+
+ @Override
+ public void handleEvent(Event event) {
+
+ // Specific UI related events
+ SuiteUi ui = getRelatedUi(event);
+ if (ui == null)
+ return;
+ try {
+// String currentLayerId = ui.getCurrentLayerId();
+// SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null;
+ if (isTopic(event, SuiteEvent.refreshPart)) {
+ Node node = getNode(ui, event);
+ if (node == null)
+ return;
+ CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
+ SuiteLayer layer = findByType(layersByType, node);
+ ui.switchToLayer(layer, node);
+ ui.getCmsView().runAs(() -> layer.view(uiProvider, ui.getCurrentWorkArea(), node));
+ ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node));
+ } else if (isTopic(event, SuiteEvent.openNewPart)) {
+ Node node = getNode(ui, event);
+ if (node == null)
+ return;
+ CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
+ SuiteLayer layer = findByType(layersByType, node);
+ ui.switchToLayer(layer, node);
+ ui.getCmsView().runAs(() -> layer.open(uiProvider, ui.getCurrentWorkArea(), node));
+ ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node));
+ } else if (isTopic(event, SuiteEvent.switchLayer)) {
+ String layerId = get(event, SuiteEvent.LAYER);
+ if (layerId != null) {
+// ui.switchToLayer(layerId, ui.getUserDir());
+ ui.getCmsView().runAs(() -> ui.switchToLayer(layerId, ui.getUserDir()));
+ ui.getCmsView().navigateTo(layerId);
+ } else {
+ Node node = getNode(ui, event);
+ if (node != null) {
+ SuiteLayer layer = findByType(layersByType, node);
+ ui.getCmsView().runAs(() -> ui.switchToLayer(layer, node));
+ }
+ }
+ }
+ } catch (Exception e) {
+ log.error("Cannot handle event " + event, e);
+// CmsView.getCmsView(ui).exception(e);
+ }
+
+ }
+
+ private Node getNode(SuiteUi ui, Event event) {
+ String nodePath = get(event, SuiteEvent.NODE_PATH);
+ String workspaceName = get(event, SuiteEvent.WORKSPACE);
+ Session session = ui.getSession(workspaceName);
+ Node node;
+ if (nodePath == null) {
+ // look for a user
+ String username = get(event, SuiteEvent.USERNAME);
+ if (username == null)
+ return null;
+ User user = cmsUserManager.getUser(username);
+ if (user == null)
+ return null;
+ LdapName userDn;
+ try {
+ userDn = new LdapName(user.getName());
+ } catch (InvalidNameException e) {
+ throw new IllegalArgumentException("Badly formatted username", e);
+ }
+ String userNodePath = SuiteUtils.getUserNodePath(userDn);
+ if (Jcr.itemExists(session, userNodePath))
+ node = Jcr.getNode(session, userNodePath);
+ else {
+ Session adminSession = null;
+ try {
+ adminSession = NodeUtils.openDataAdminSession(getRepository(), workspaceName);
+ SuiteUtils.getOrCreateUserNode(adminSession, userDn);
+ } finally {
+ Jcr.logout(adminSession);
+ }
+ node = Jcr.getNode(session, userNodePath);
+ }
+ } else {
+ node = Jcr.getNode(session, nodePath);
+ }
+ return node;
+ }
+
+ private SuiteUi getRelatedUi(Event event) {
+ return managedUis.get(get(event, CMS_VIEW_UID_PROPERTY));
+ }
+
+ private static boolean isTopic(Event event, CmsEvent cmsEvent) {
+ return event.getTopic().equals(cmsEvent.topic());
+ }
+
+ private static String get(Event event, String key) {
+ Object value = event.getProperty(key);
+ if (value == null)
+ return null;
+// throw new IllegalArgumentException("Property " + key + " must be set");
+ return value.toString();
+
+ }
+
+ /*
+ * Dependency injection.
+ */
+
+ public void addUiProvider(CmsUiProvider uiProvider, Map<String, Object> properties) {
+ if (properties.containsKey(Constants.SERVICE_PID)) {
+ String pid = (String) properties.get(Constants.SERVICE_PID);
+ RankedObject.putIfHigherRank(uiProvidersByPid, pid, uiProvider, properties);
+ }
+ if (properties.containsKey(EntityConstants.TYPE)) {
+ List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
+ for (String type : types)
+ RankedObject.putIfHigherRank(uiProvidersByType, type, uiProvider, properties);
+ }
+ }
+
+ public void removeUiProvider(CmsUiProvider uiProvider, Map<String, Object> properties) {
+ if (properties.containsKey(Constants.SERVICE_PID)) {
+ String pid = (String) properties.get(Constants.SERVICE_PID);
+ if (uiProvidersByPid.containsKey(pid)) {
+ if (uiProvidersByPid.get(pid).equals(new RankedObject<CmsUiProvider>(uiProvider, properties))) {
+ uiProvidersByPid.remove(pid);
+ }
+ }
+ }
+ if (properties.containsKey(EntityConstants.TYPE)) {
+ List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
+ for (String type : types) {
+ if (uiProvidersByType.containsKey(type)) {
+ if (uiProvidersByType.get(type).equals(new RankedObject<CmsUiProvider>(uiProvider, properties))) {
+ uiProvidersByType.remove(type);
+ }
+ }
+ }
+ }
+ }
+
+ public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
+ if (properties.containsKey(Constants.SERVICE_PID)) {
+ String pid = (String) properties.get(Constants.SERVICE_PID);
+ RankedObject.putIfHigherRank(layersByPid, pid, layer, properties);
+ }
+ if (properties.containsKey(EntityConstants.TYPE)) {
+ List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
+ for (String type : types)
+ RankedObject.putIfHigherRank(layersByType, type, layer, properties);
+ }
+ }
+
+ public void removeLayer(SuiteLayer layer, Map<String, Object> properties) {
+ if (properties.containsKey(Constants.SERVICE_PID)) {
+ String pid = (String) properties.get(Constants.SERVICE_PID);
+ if (layersByPid.containsKey(pid)) {
+ if (layersByPid.get(pid).equals(new RankedObject<SuiteLayer>(layer, properties))) {
+ layersByPid.remove(pid);
+ }
+ }
+ }
+ if (properties.containsKey(EntityConstants.TYPE)) {
+ List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
+ for (String type : types) {
+ if (layersByType.containsKey(type)) {
+ if (layersByType.get(type).equals(new RankedObject<CmsUiProvider>(layer, properties))) {
+ layersByType.remove(type);
+ }
+ }
+ }
+ }
+ }
+
+ public void setCmsUserManager(CmsUserManager cmsUserManager) {
+ this.cmsUserManager = cmsUserManager;
+ }
+
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.util.CmsEvent;
+import org.argeo.jcr.Jcr;
+import org.osgi.service.useradmin.User;
+
+/** Events specific to Argeo Suite. */
+public enum SuiteEvent implements CmsEvent {
+ openNewPart, refreshPart, switchLayer;
+
+ public final static String LAYER = "layer";
+// public final static String NODE_ID = "nodeId";
+ public final static String NODE_PATH = "path";
+ public final static String USERNAME = "username";
+ public final static String WORKSPACE = "workspace";
+
+ public String getTopicBase() {
+ return "argeo/suite/ui";
+ }
+
+ public static Map<String, Object> eventProperties(Node node) {
+ Map<String, Object> properties = new HashMap<>();
+ properties.put(NODE_PATH, Jcr.getPath(node));
+ properties.put(WORKSPACE, Jcr.getWorkspaceName(node));
+ return properties;
+ }
+
+ public static Map<String, Object> eventProperties(User user) {
+ Map<String, Object> properties = new HashMap<>();
+ properties.put(USERNAME, user.getName());
+ return properties;
+ }
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import org.argeo.cms.ui.util.CmsIcon;
+
+/** Icon names used by Argeo Suite. */
+public enum SuiteIcon implements CmsIcon {
+ add, save, close, search, delete, logout, dashboard,
+ // people
+ people, person, organisation,
+ // library
+ documents, document, folder,
+ // admin and settings
+ settings, user,
+ // misc
+ task, tag, location, inbox, map;
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.widgets.Composite;
+
+/** An UI layer for the main work area. */
+public interface SuiteLayer extends CmsUiProvider {
+ static enum Property {
+ title, icon, weights, startMaximized;
+ }
+
+ void view(CmsUiProvider uiProvider, Composite workArea, Node context);
+
+ default void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
+ view(uiProvider, workArea, context);
+ }
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import org.argeo.cms.Localized;
+
+/** Localized messages. */
+public enum SuiteMsg implements Localized {
+ dashboard, people, documents, locations, recentItems,
+ // NewPersonWizard
+ firstName, lastName, salutation, email, personWizardWindowTitle, personWizardPageTitle,
+ // NewOrgWizard
+ orgWizardWindowTitle, orgWizardPageTitle, legalName, legalForm, vatId,
+ // ContextAddressComposite
+ chooseAnOrganisation, street, streetComplement, zipCode, city, state, country, geopoint,
+ // FilteredOrderableEntityTable
+ filterHelp,
+ // BankAccountComposite
+ accountHolder, bankName, currency, accountNumber, bankNumber, BIC, IBAN,
+ // EditJobDialog
+ position, chosenItem, department, isPrimary, searchAndChooseEntity,
+ // ContactListCTab (e4)
+ notes, addAContact, contactValue, linkedCompany,
+ // OrgAdminInfoCTab (e4)
+ paymentAccount,
+ // OrgEditor (e4)
+ orgDetails, orgActivityLog, team, orgAdmin,
+ // PersonEditor (e4)
+ personDetails, personActivityLog, personOrgs, personSecurity,
+ // PersonSecurityCTab (e4)
+ resetPassword,
+ // Generic
+ label, aCustomLabel, description, value, name, primary, add, save, pickup,
+ // Tag
+ confirmNewTag, cannotCreateTag;
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import org.argeo.cms.ui.util.CmsStyle;
+
+/** Styles used by Argeo Suite work UI. */
+public enum SuiteStyle implements CmsStyle {
+ // Header
+ header, headerTitle, headerMenu, headerMenuItem,
+ // Recent items
+ recentItems,
+ // Lead pane
+ leadPane, leadPaneItem, leadPaneSectionTitle, leadPaneSubSectionTitle,
+ // Group composite
+ titleContainer, titleLabel, subTitleLabel, formLine, formColumn, navigationBar, navigationTitle, navigationButton,
+ // Forms elements
+ simpleLabel, simpleText, simpleInput,
+ // table
+ titleCell,
+ // layers
+ workArea,
+ // tabbed area
+ mainTabBody, mainTabSelected, mainTab,
+ // Buttons
+ inlineButton;
+
+ @Override
+ public String getClassPrefix() {
+ return "argeo-suite";
+ }
+
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/** The view for the default ergonomics of Argeo Suite. */
+class SuiteUi extends Composite {
+ private static final long serialVersionUID = 6207018859086689108L;
+ private final static Log log = LogFactory.getLog(SuiteUi.class);
+ private Composite header;
+ private Composite belowHeader;
+ private Composite leadPane;
+ private Composite dynamicArea;
+
+ private Session sysSession;
+// private Session homeSession;
+ private Node userDir;
+
+ private Map<String, SuiteLayer> layers = new HashMap<>();
+ private Map<String, Composite> workAreas = new HashMap<>();
+ private String currentLayerId = null;
+
+ private CmsView cmsView;
+
+ public SuiteUi(Composite parent, int style) {
+ super(parent, style);
+ cmsView = CmsView.getCmsView(parent);
+ this.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ header = new Composite(this, SWT.NONE);
+ header.setLayout(CmsUiUtils.noSpaceGridLayout());
+ CmsUiUtils.style(header, SuiteStyle.header);
+ header.setLayoutData(CmsUiUtils.fillWidth());
+
+ belowHeader = new Composite(this, SWT.NONE);
+ belowHeader.setLayoutData(CmsUiUtils.fillAll());
+ }
+
+ public void refreshBelowHeader(boolean initApp) {
+ CmsUiUtils.clear(belowHeader);
+ int style = getStyle();
+ if (initApp) {
+ belowHeader.setLayout(CmsUiUtils.noSpaceGridLayout(2));
+
+ if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
+ dynamicArea = new Composite(belowHeader, SWT.NONE);
+ leadPane = new Composite(belowHeader, SWT.NONE);
+ } else {
+ leadPane = new Composite(belowHeader, SWT.NONE);
+ dynamicArea = new Composite(belowHeader, SWT.NONE);
+ }
+ leadPane.setLayoutData(CmsUiUtils.fillHeight());
+ leadPane.setLayout(CmsUiUtils.noSpaceGridLayout());
+ CmsUiUtils.style(leadPane, SuiteStyle.leadPane);
+
+ dynamicArea.setLayoutData(CmsUiUtils.fillAll());
+ dynamicArea.setLayout(new FormLayout());
+
+ } else {
+ belowHeader.setLayout(CmsUiUtils.noSpaceGridLayout());
+ }
+ }
+
+ /*
+ * LAYERS
+ */
+
+ Composite getCurrentWorkArea() {
+ if (currentLayerId == null)
+ throw new IllegalStateException("No current layer");
+ return workAreas.get(currentLayerId);
+ }
+
+ String getCurrentLayerId() {
+ return currentLayerId;
+ }
+
+ private Composite getLayer(String id, Node context) {
+ if (!layers.containsKey(id))
+ return null;
+ if (!workAreas.containsKey(id))
+ initLayer(id, layers.get(id), context);
+ return workAreas.get(id);
+ }
+
+ Composite switchToLayer(String layerId, Node context) {
+ Composite current = null;
+ if (currentLayerId != null) {
+ current = getCurrentWorkArea();
+ if (currentLayerId.equals(layerId))
+ return current;
+ }
+ if (context == null) {
+ if (!cmsView.isAnonymous())
+ context = userDir;
+ }
+ Composite toShow = getLayer(layerId, context);
+ if (toShow != null) {
+ currentLayerId = layerId;
+ if (!isDisposed()) {
+// getDisplay().syncExec(() -> {
+ if (!toShow.isDisposed()) {
+ toShow.moveAbove(null);
+ } else {
+ log.warn("Cannot show work area because it is disposed.");
+ toShow = initLayer(layerId, layers.get(layerId), context);
+ toShow.moveAbove(null);
+ }
+ dynamicArea.layout(true, true);
+// });
+ }
+ return toShow;
+ } else {
+ return current;
+ }
+ }
+
+ Composite switchToLayer(SuiteLayer layer, Node context) {
+ // TODO make it more robust
+ for (String layerId : layers.keySet()) {
+ SuiteLayer l = layers.get(layerId);
+ if (layer == l) {
+ return switchToLayer(layerId, context);
+ }
+ }
+ throw new IllegalArgumentException("Layer is not registered.");
+ }
+
+ void addLayer(String id, SuiteLayer layer) {
+ layers.put(id, layer);
+ }
+
+ void removeLayer(String id) {
+ layers.remove(id);
+ if (workAreas.containsKey(id)) {
+ Composite workArea = workAreas.remove(id);
+ if (!workArea.isDisposed())
+ workArea.dispose();
+ }
+ }
+
+ protected Composite initLayer(String id, SuiteLayer layer, Node context) {
+ Composite workArea = cmsView.doAs(() -> (Composite) layer.createUiPart(dynamicArea, context));
+ CmsUiUtils.style(workArea, SuiteStyle.workArea);
+ workArea.setLayoutData(CmsUiUtils.coverAll());
+ workAreas.put(id, workArea);
+ return workArea;
+ }
+
+ synchronized void logout() {
+ userDir = null;
+ Jcr.logout(sysSession);
+// Jcr.logout(homeSession);
+ currentLayerId = null;
+ workAreas.clear();
+ }
+
+ /*
+ * GETTERS / SETTERS
+ */
+
+ Composite getHeader() {
+ return header;
+ }
+
+ Composite getLeadPane() {
+ return leadPane;
+ }
+
+ Composite getBelowHeader() {
+ return belowHeader;
+ }
+
+// Session getSysSession() {
+// return sysSession;
+// }
+//
+ synchronized void initSessions(Repository repository, String userDirPath) throws RepositoryException {
+ this.sysSession = repository.login();
+// this.homeSession = repository.login(NodeConstants.HOME_WORKSPACE);
+ userDir = sysSession.getNode(userDirPath);
+ addDisposeListener((e) -> {
+ Jcr.logout(sysSession);
+// Jcr.logout(homeSession);
+ });
+ }
+
+ Node getUserDir() {
+ return userDir;
+ }
+
+ Session getSysSession() {
+ return sysSession;
+ }
+
+ Session getSession(String workspaceName) {
+ if (workspaceName == null)
+ return sysSession;
+ if (NodeConstants.SYS_WORKSPACE.equals(workspaceName))
+ return sysSession;
+// else if (NodeConstants.HOME_WORKSPACE.equals(workspaceName))
+// return homeSession;
+ else
+ throw new IllegalArgumentException("Unknown workspace " + workspaceName);
+ }
+
+ public CmsView getCmsView() {
+ return cmsView;
+ }
+
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.cms.Localized;
+import org.argeo.cms.ui.CmsEditable;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.dialogs.LightweightDialog;
+import org.argeo.cms.ui.util.CmsIcon;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.entity.EntityNames;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+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.Text;
+
+/** UI utilities related to the APAF project. */
+public class SuiteUiUtils {
+
+ /** Singleton. */
+ private SuiteUiUtils() {
+ }
+
+ /** creates a title bar composite with label and optional button */
+ public static void addTitleBar(Composite parent, String title, Boolean isEditable) {
+ Composite titleBar = new Composite(parent, SWT.NONE);
+ titleBar.setLayoutData(CmsUiUtils.fillWidth());
+ CmsUiUtils.style(titleBar, SuiteStyle.titleContainer);
+
+ titleBar.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(2, false)));
+ Label titleLbl = new Label(titleBar, SWT.NONE);
+ titleLbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
+ CmsUiUtils.style(titleLbl, SuiteStyle.titleLabel);
+ titleLbl.setText(title);
+
+ if (isEditable) {
+ Button editBtn = new Button(titleBar, SWT.PUSH);
+ editBtn.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+ CmsUiUtils.style(editBtn, SuiteStyle.inlineButton);
+ editBtn.setText("Edit");
+ }
+ }
+
+ public static Label addFormLabel(Composite parent, String label) {
+ Label lbl = new Label(parent, SWT.WRAP);
+ lbl.setText(label);
+ // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
+ CmsUiUtils.style(lbl, SuiteStyle.simpleLabel);
+ return lbl;
+ }
+
+ public static Text addFormTextField(Composite parent, String text, String message) {
+ return addFormTextField(parent, text, message, SWT.NONE);
+ }
+
+ public static Text addFormTextField(Composite parent, String text, String message, int style) {
+ Text txt = new Text(parent, style);
+ if (text != null)
+ txt.setText(text);
+ if (message != null)
+ txt.setMessage(message);
+ txt.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
+ CmsUiUtils.style(txt, SuiteStyle.simpleText);
+ return txt;
+ }
+
+ public static Text addFormInputField(Composite parent, String placeholder) {
+ Text txt = new Text(parent, SWT.BORDER);
+
+ GridData gridData = CmsUiUtils.fillWidth();
+ txt.setLayoutData(gridData);
+
+ if (placeholder != null)
+ txt.setText(placeholder);
+
+ CmsUiUtils.style(txt, SuiteStyle.simpleInput);
+ return txt;
+ }
+
+ /** creates a single horizontal-block composite for key:value display */
+ public static Text addFormLine(Composite parent, String label, String text) {
+ Composite lineComposite = new Composite(parent, SWT.NONE);
+ lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ lineComposite.setLayout(new GridLayout(2, false));
+ CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+ addFormLabel(lineComposite, label);
+ Text txt = addFormTextField(lineComposite, text, null);
+ txt.setEditable(false);
+ txt.setLayoutData(CmsUiUtils.fillWidth());
+ return txt;
+ }
+
+ public static Text addFormLine(Composite parent, String label, Node node, String property,
+ CmsEditable cmsEditable) {
+ Composite lineComposite = new Composite(parent, SWT.NONE);
+ lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ lineComposite.setLayout(new GridLayout(2, false));
+ CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+ addFormLabel(lineComposite, label);
+ String text = Jcr.get(node, property);
+// int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
+ Text txt = addFormTextField(lineComposite, text, null, SWT.WRAP);
+ if (cmsEditable != null && cmsEditable.isEditing()) {
+ txt.addModifyListener((e) -> {
+ Jcr.set(node, property, txt.getText());
+ Jcr.save(node);
+ });
+ } else {
+ txt.setEditable(false);
+ }
+ txt.setLayoutData(CmsUiUtils.fillWidth());
+ return txt;
+ }
+
+ public static Text addFormInput(Composite parent, String label, String placeholder) {
+ Composite lineComposite = new Composite(parent, SWT.NONE);
+ lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ lineComposite.setLayout(new GridLayout(2, false));
+ CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+ addFormLabel(lineComposite, label);
+ Text txt = addFormInputField(lineComposite, placeholder);
+ txt.setLayoutData(CmsUiUtils.fillWidth());
+ return txt;
+ }
+
+ /**
+ * creates a single horizontal-block composite for key:value display, with
+ * offset value
+ */
+ public static Text addFormLine(Composite parent, String label, String text, Integer offset) {
+ Composite lineComposite = new Composite(parent, SWT.NONE);
+ lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ lineComposite.setLayout(new GridLayout(3, false));
+ CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+ Label offsetLbl = new Label(lineComposite, SWT.NONE);
+ GridData gridData = new GridData();
+ gridData.widthHint = offset;
+ offsetLbl.setLayoutData(gridData);
+ addFormLabel(lineComposite, label);
+ Text txt = addFormTextField(lineComposite, text, null);
+ txt.setLayoutData(CmsUiUtils.fillWidth());
+ return txt;
+ }
+
+ /** creates a single vertical-block composite for key:value display */
+ public static Text addFormColumn(Composite parent, String label, String text) {
+// Composite columnComposite = new Composite(parent, SWT.NONE);
+// columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+// columnComposite.setLayout(new GridLayout(1, false));
+ addFormLabel(parent, label);
+ Text txt = addFormTextField(parent, text, null);
+ txt.setEditable(false);
+ txt.setLayoutData(CmsUiUtils.fillWidth());
+ return txt;
+ }
+
+ public static Text addFormColumn(Composite parent, String label, Node node, String property,
+ CmsEditable cmsEditable) {
+// Composite columnComposite = new Composite(parent, SWT.NONE);
+// columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+// columnComposite.setLayout(new GridLayout(1, false));
+ addFormLabel(parent, label);
+ String text = Jcr.get(node, property);
+// int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
+ Text txt = addFormTextField(parent, text, null, SWT.WRAP);
+ if (cmsEditable != null && cmsEditable.isEditing()) {
+ txt.addModifyListener((e) -> {
+ Jcr.set(node, property, txt.getText());
+ Jcr.save(node);
+ });
+ } else {
+ txt.setEditable(false);
+ }
+ txt.setLayoutData(CmsUiUtils.fillWidth());
+ return txt;
+ }
+
+ public static Label createBoldLabel(Composite parent, Localized localized) {
+ Label label = new Label(parent, SWT.LEAD);
+ label.setText(localized.lead());
+ label.setFont(EclipseUiUtils.getBoldFont(parent));
+ label.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+ return label;
+ }
+
+ public static Label addFormPicture(Composite parent, String label, Node fileNode) throws RepositoryException {
+ Composite lineComposite = new Composite(parent, SWT.NONE);
+ lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ lineComposite.setLayout(new GridLayout(2, true));
+ CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+ addFormLabel(lineComposite, label);
+
+ return addPicture(lineComposite, fileNode);
+ }
+
+ public static Label addPicture(Composite parent, Node fileNode) throws RepositoryException {
+ return addPicture(parent, fileNode, null);
+ }
+
+ public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth) throws RepositoryException {
+ Node content = fileNode.getNode(Node.JCR_CONTENT);
+ // TODO move it deeper in the middleware.
+ if (!content.isNodeType(EntityType.box.get())) {
+ if (content.getSession().hasPermission(content.getPath(), Session.ACTION_SET_PROPERTY)) {
+ try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
+ ImageData imageData = new ImageData(in);
+ content.addMixin(EntityType.box.get());
+ content.setProperty(EntityNames.SVG_WIDTH, imageData.width);
+ content.setProperty(EntityNames.SVG_HEIGHT, imageData.height);
+ content.getSession().save();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ // TODO optimise
+ Long width;
+ Long height;
+ if (content.isNodeType(EntityType.box.get())) {
+ width = content.getProperty(EntityNames.SVG_WIDTH).getLong();
+ height = content.getProperty(EntityNames.SVG_HEIGHT).getLong();
+ } else {
+ try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
+ ImageData imageData = new ImageData(in);
+ width = Long.valueOf(imageData.width);
+ height = Long.valueOf(imageData.height);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ if (maxWidth != null && width > maxWidth) {
+ Double ratio = maxWidth.doubleValue() / width.doubleValue();
+ width = maxWidth.longValue();
+ height = Math.round(ratio * height);
+ }
+ Label img = new Label(parent, SWT.NONE);
+ CmsUiUtils.markup(img);
+ img.setText(CmsUiUtils.img(fileNode, width.toString(), height.toString()));
+ if (parent.getLayout() instanceof GridLayout) {
+ GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+ gd.widthHint = width.intValue();
+ gd.heightHint = height.intValue();
+ img.setLayoutData(gd);
+ }
+ img.addMouseListener(new MouseListener() {
+ private static final long serialVersionUID = -1362242049325206168L;
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ LightweightDialog dialog = new LightweightDialog(img.getShell()) {
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ parent.setLayout(new GridLayout());
+ ScrolledComposite scroll = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
+ scroll.setLayoutData(CmsUiUtils.fillAll());
+ scroll.setLayout(CmsUiUtils.noSpaceGridLayout());
+ scroll.setExpandHorizontal(true);
+ scroll.setExpandVertical(true);
+ // scroll.setAlwaysShowScrollBars(true);
+
+ Composite c = new Composite(scroll, SWT.NONE);
+ scroll.setContent(c);
+ c.setLayout(new GridLayout());
+ c.setLayoutData(CmsUiUtils.fillAll());
+ Label bigImg = new Label(c, SWT.NONE);
+ CmsUiUtils.markup(bigImg);
+ bigImg.setText(CmsUiUtils.img(fileNode, Jcr.get(content, EntityNames.SVG_WIDTH),
+ Jcr.get(content, EntityNames.SVG_HEIGHT)));
+ bigImg.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+ return bigImg;
+ }
+
+ @Override
+ protected Point getInitialSize() {
+ Point shellSize = img.getShell().getSize();
+ return new Point(shellSize.x - 100, shellSize.y - 100);
+ }
+
+ };
+ dialog.open();
+ }
+ });
+ return img;
+ }
+
+ public static Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon) {
+ CmsTheme theme = CmsTheme.getCmsTheme(parent);
+ Button button = new Button(parent, SWT.PUSH);
+ CmsUiUtils.style(button, SuiteStyle.leadPane);
+ if (icon != null)
+ button.setImage(icon.getBigIcon(theme));
+ button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false));
+ // button.setToolTipText(msg.lead());
+ if (msg != null) {
+ Label lbl = new Label(parent, SWT.NONE);
+ CmsUiUtils.style(lbl, SuiteStyle.leadPane);
+ lbl.setText(msg.lead());
+ lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
+ }
+ CmsUiUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer);
+ return button;
+ }
+
+// public static String createAndConfigureEntity(Shell shell, Session referenceSession, String mainMixin,
+// String... additionnalProps) {
+//
+// Session tmpSession = null;
+// Session mainSession = null;
+// try {
+// // FIXME would not work if home is another physical workspace
+// tmpSession = referenceSession.getRepository().login(NodeConstants.HOME_WORKSPACE);
+// Node draftNode = null;
+// for (int i = 0; i < additionnalProps.length - 1; i += 2) {
+// draftNode.setProperty(additionnalProps[i], additionnalProps[i + 1]);
+// }
+// Wizard wizard = null;
+// CmsWizardDialog dialog = new CmsWizardDialog(shell, wizard);
+// // WizardDialog dialog = new WizardDialog(shell, wizard);
+// if (dialog.open() == Window.OK) {
+// String parentPath = null;// "/" + appService.getBaseRelPath(mainMixin);
+// // FIXME it should be possible to specify the workspace
+// mainSession = referenceSession.getRepository().login();
+// Node parent = mainSession.getNode(parentPath);
+// Node task = null;// appService.publishEntity(parent, mainMixin, draftNode);
+//// task = appService.saveEntity(task, false);
+// referenceSession.refresh(true);
+// return task.getPath();
+// }
+// return null;
+// } catch (RepositoryException e1) {
+// throw new JcrException(
+// "Unable to create " + mainMixin + " entity with session " + referenceSession.toString(), e1);
+// } finally {
+// JcrUtils.logoutQuietly(tmpSession);
+// JcrUtils.logoutQuietly(mainSession);
+// }
+// }
+
+}
--- /dev/null
+package org.argeo.suite.ui;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.naming.LdapAttrs;
+import org.eclipse.swt.SWT;
+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.Group;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.useradmin.User;
+
+/** Edit a suite user. */
+public class SuiteUserUiProvider implements CmsUiProvider {
+ private String[] availableRoles;
+ private CmsUserManager cmsUserManager;
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ Section main = new Section(parent, SWT.NONE, context);
+ main.setLayoutData(CmsUiUtils.fillAll());
+
+ String uid = context.getName();
+ User user = cmsUserManager.getUserFromLocalId(uid);
+
+// Text givenName = new Text(main, SWT.SINGLE);
+// givenName.setText(getUserProperty(user, LdapAttrs.givenName.name()));
+ Text givenName = SuiteUiUtils.addFormInput(main, SuiteMsg.firstName.lead(),
+ getUserProperty(user, LdapAttrs.givenName.name()));
+
+ Text sn = SuiteUiUtils.addFormInput(main, SuiteMsg.lastName.lead(), getUserProperty(user, LdapAttrs.sn.name()));
+ // sn.setText(getUserProperty(user, LdapAttrs.sn.name()));
+
+ Text email = SuiteUiUtils.addFormInput(main, SuiteMsg.email.lead(),
+ getUserProperty(user, LdapAttrs.mail.name()));
+ // email.setText(getUserProperty(user, LdapAttrs.mail.name()));
+
+ Text uidT = SuiteUiUtils.addFormLine(main, "uid", getUserProperty(user, LdapAttrs.uid.name()));
+ uidT.setText(uid);
+
+// Label dnL = new Label(main, SWT.NONE);
+// dnL.setText(user.getName());
+
+ // roles
+ // Section rolesSection = new Section(main, SWT.NONE, context);
+ Group rolesSection = new Group(main, SWT.NONE);
+ rolesSection.setText("Roles");
+ rolesSection.setLayoutData(CmsUiUtils.fillWidth());
+ rolesSection.setLayout(new GridLayout());
+ // new Label(rolesSection, SWT.NONE).setText("Roles:");
+ List<String> roles = Arrays.asList(cmsUserManager.getUserRoles(user.getName()));
+ for (String role : availableRoles) {
+ // new Label(rolesSection, SWT.NONE).setText(role);
+ Button radio = new Button(rolesSection, SWT.CHECK);
+ radio.setText(role);
+ if (roles.contains(role))
+ radio.setSelection(true);
+ }
+
+ return main;
+ }
+
+ public void setCmsUserManager(CmsUserManager cmsUserManager) {
+ this.cmsUserManager = cmsUserManager;
+ }
+
+ private String getUserProperty(Object element, String key) {
+ Object value = ((User) element).getProperties().get(key);
+ return value != null ? value.toString() : null;
+ }
+
+ public void init(Map<String, Object> properties) {
+ availableRoles = (String[]) properties.get("availableRoles");
+ }
+}
--- /dev/null
+package org.argeo.suite.ui.dialogs;
+
+import org.argeo.suite.ui.SuiteMsg;
+import org.argeo.suite.ui.SuiteUiUtils;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+public class NewPersonPage extends WizardPage {
+ private static final long serialVersionUID = -944349994177526468L;
+ protected Text lastNameTxt;
+ protected Text firstNameTxt;
+ protected Text emailTxt;
+
+ protected NewPersonPage(String pageName) {
+ super(pageName);
+ setTitle(SuiteMsg.personWizardPageTitle.lead());
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ parent.setLayout(new GridLayout(2, false));
+
+ // FirstName
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+ firstNameTxt = new Text(parent, SWT.BORDER);
+ firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ // LastName
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+ lastNameTxt = new Text(parent, SWT.BORDER);
+ lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.email);
+ emailTxt = new Text(parent, SWT.BORDER);
+ emailTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ ModifyListener ml = new ModifyListener() {
+ private static final long serialVersionUID = -1628130380128946886L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ getContainer().updateButtons();
+ }
+ };
+
+ firstNameTxt.addModifyListener(ml);
+ lastNameTxt.addModifyListener(ml);
+ emailTxt.addModifyListener(ml);
+
+ // Don't forget this.
+ setControl(firstNameTxt);
+ firstNameTxt.setFocus();
+
+ }
+
+// public void updateNode(Node node, PeopleService peopleService, ResourcesService resourcesService) {
+// ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_LAST_NAME, PropertyType.STRING, lastNameTxt.getText());
+// ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_FIRST_NAME, PropertyType.STRING,
+// firstNameTxt.getText());
+// ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_DISPLAY_NAME, PropertyType.STRING,
+// firstNameTxt.getText() + " " + lastNameTxt.getText());
+// String email = emailTxt.getText();
+// ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_PRIMARY_EMAIL, PropertyType.STRING, email);
+// PeopleJcrUtils.createEmail(resourcesService, peopleService, node, email, true, null, null);
+// }
+}
--- /dev/null
+package org.argeo.suite.ui.dialogs;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
+
+import javax.jcr.Node;
+
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.suite.ui.SuiteMsg;
+import org.argeo.suite.ui.SuiteUiUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/** Ask first & last name. Update the passed node on finish */
+public class NewPersonWizard extends Wizard {
+ // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
+
+ // Context
+ private Node person;
+
+ // This page widgets
+ protected Text lastNameTxt;
+ protected Text firstNameTxt;
+ // private Button useDistinctDisplayNameBtn;
+ // private Text displayNameTxt;
+
+ public NewPersonWizard(Node person) {
+ this.person = person;
+ }
+
+ @Override
+ public void addPages() {
+ try {
+ MainInfoPage page = new MainInfoPage("Main page");
+ addPage(page);
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot add page to wizard", e);
+ }
+ setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
+ }
+
+ /**
+ * Called when the user click on 'Finish' in the wizard. The task is then
+ * created and the corresponding session saved.
+ */
+ @Override
+ public boolean performFinish() {
+ String lastName = lastNameTxt.getText();
+ String firstName = firstNameTxt.getText();
+ // String displayName = displayNameTxt.getText();
+ // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
+ if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
+ MessageDialog.openError(getShell(), "Non-valid information",
+ "Please enter at least a name that is not empty.");
+ return false;
+ } else {
+// ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
+// ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
+// String fullName = firstName + " " + lastName;
+// ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
+ return true;
+ }
+ }
+
+ @Override
+ public boolean performCancel() {
+ return true;
+ }
+
+ @Override
+ public boolean canFinish() {
+ String lastName = lastNameTxt.getText();
+ String firstName = firstNameTxt.getText();
+ if (isEmpty(lastName) && isEmpty(firstName)) {
+ return false;
+ } else
+ return true;
+ }
+
+ protected class MainInfoPage extends WizardPage {
+ private static final long serialVersionUID = 1L;
+
+ public MainInfoPage(String pageName) {
+ super(pageName);
+ setTitle(SuiteMsg.personWizardPageTitle.lead());
+ // setMessage("Please enter a last name and/or a first name.");
+ }
+
+ public void createControl(Composite parent) {
+ parent.setLayout(new GridLayout(2, false));
+
+ // FirstName
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+ firstNameTxt = new Text(parent, SWT.BORDER);
+ // firstNameTxt.setMessage("a first name");
+ firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ // LastName
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+ lastNameTxt = new Text(parent, SWT.BORDER);
+ // lastNameTxt.setMessage("a last name");
+ lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ // Display Name
+ // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
+ // useDistinctDisplayNameBtn.setText("Define a disting display name");
+ // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
+ // true, false, 2, 1));
+ //
+ // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
+ // displayNameTxt = new Text(parent, SWT.BORDER);
+ // displayNameTxt.setMessage("an optional display name");
+ // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
+ // false));
+ // displayNameTxt.setEnabled(false);
+ //
+ // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
+ // private static final long serialVersionUID = 1L;
+ //
+ // @Override
+ // public void widgetSelected(SelectionEvent e) {
+ // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
+ // }
+ // });
+
+ ModifyListener ml = new ModifyListener() {
+ private static final long serialVersionUID = -1628130380128946886L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ getContainer().updateButtons();
+ }
+ };
+
+ firstNameTxt.addModifyListener(ml);
+ lastNameTxt.addModifyListener(ml);
+ // displayNameTxt.addModifyListener(ml);
+
+ // Don't forget this.
+ setControl(firstNameTxt);
+ firstNameTxt.setFocus();
+ }
+ }
+}
--- /dev/null
+package org.argeo.suite.ui.dialogs;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
+
+import javax.jcr.Node;
+
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.suite.ui.SuiteMsg;
+import org.argeo.suite.ui.SuiteUiUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/** Ask first & last name. Update the passed node on finish */
+public class NewUserWizard extends Wizard {
+ // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
+
+ // Context
+ private Node person;
+
+ // This page widgets
+ protected Text lastNameTxt;
+ protected Text firstNameTxt;
+ // private Button useDistinctDisplayNameBtn;
+ // private Text displayNameTxt;
+
+ public NewUserWizard(Node person) {
+ this.person = person;
+ }
+
+ @Override
+ public void addPages() {
+ try {
+ MainInfoPage page = new MainInfoPage("Main page");
+ addPage(page);
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot add page to wizard", e);
+ }
+ setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
+ }
+
+ /**
+ * Called when the user click on 'Finish' in the wizard. The task is then
+ * created and the corresponding session saved.
+ */
+ @Override
+ public boolean performFinish() {
+ String lastName = lastNameTxt.getText();
+ String firstName = firstNameTxt.getText();
+ // String displayName = displayNameTxt.getText();
+ // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
+ if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
+ MessageDialog.openError(getShell(), "Non-valid information",
+ "Please enter at least a name that is not empty.");
+ return false;
+ } else {
+// ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
+// ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
+// String fullName = firstName + " " + lastName;
+// ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
+ return true;
+ }
+ }
+
+ @Override
+ public boolean performCancel() {
+ return true;
+ }
+
+ @Override
+ public boolean canFinish() {
+ String lastName = lastNameTxt.getText();
+ String firstName = firstNameTxt.getText();
+ if (isEmpty(lastName) && isEmpty(firstName)) {
+ return false;
+ } else
+ return true;
+ }
+
+ protected class MainInfoPage extends WizardPage {
+ private static final long serialVersionUID = 1L;
+
+ public MainInfoPage(String pageName) {
+ super(pageName);
+ setTitle(SuiteMsg.personWizardPageTitle.lead());
+ // setMessage("Please enter a last name and/or a first name.");
+ }
+
+ public void createControl(Composite parent) {
+ parent.setLayout(new GridLayout(2, false));
+
+ // FirstName
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+ firstNameTxt = new Text(parent, SWT.BORDER);
+ // firstNameTxt.setMessage("a first name");
+ firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ // LastName
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+ lastNameTxt = new Text(parent, SWT.BORDER);
+ // lastNameTxt.setMessage("a last name");
+ lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ // Display Name
+ // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
+ // useDistinctDisplayNameBtn.setText("Define a disting display name");
+ // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
+ // true, false, 2, 1));
+ //
+ // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
+ // displayNameTxt = new Text(parent, SWT.BORDER);
+ // displayNameTxt.setMessage("an optional display name");
+ // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
+ // false));
+ // displayNameTxt.setEnabled(false);
+ //
+ // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
+ // private static final long serialVersionUID = 1L;
+ //
+ // @Override
+ // public void widgetSelected(SelectionEvent e) {
+ // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
+ // }
+ // });
+
+ ModifyListener ml = new ModifyListener() {
+ private static final long serialVersionUID = -1628130380128946886L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ getContainer().updateButtons();
+ }
+ };
+
+ firstNameTxt.addModifyListener(ml);
+ lastNameTxt.addModifyListener(ml);
+ // displayNameTxt.addModifyListener(ml);
+
+ // Don't forget this.
+ setControl(firstNameTxt);
+ firstNameTxt.setFocus();
+ }
+ }
+}
--- /dev/null
+package org.argeo.suite.ui.widgets;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+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;
+
+/**
+ * Generic popup context menu for TableViewer to enable single sourcing between
+ * CMS and Workbench
+ */
+public abstract class AbstractConnectContextMenu {
+
+ private Shell parentShell;
+ private Shell shell;
+ // Local context
+
+ private final static String KEY_ACTION_ID = "actionId";
+ private final String[] defaultActions;
+ private Map<String, Button> actionButtons = new HashMap<String, Button>();
+
+ public AbstractConnectContextMenu(Display display, String[] defaultActions) {
+ parentShell = display.getActiveShell();
+ shell = new Shell(parentShell, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+ this.defaultActions = defaultActions;
+ }
+
+ protected void createControl() {
+ shell.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ Composite boxCmp = new Composite(shell, SWT.NO_FOCUS | SWT.BORDER);
+ boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
+// CmsUiUtils.style(boxCmp, ConnectUiStyles.CONTEXT_MENU_BOX);
+ createContextMenu(boxCmp);
+ shell.addShellListener(new ActionsShellListener());
+ }
+
+ protected void createContextMenu(Composite boxCmp) {
+ ActionsSelListener asl = new ActionsSelListener();
+ for (String actionId : defaultActions) {
+ Button btn = new Button(boxCmp, SWT.FLAT | SWT.LEAD);
+ btn.setText(getLabel(actionId));
+ btn.setLayoutData(EclipseUiUtils.fillWidth());
+ CmsUiUtils.markup(btn);
+// CmsUiUtils.style(btn, actionId + ConnectUiStyles.BUTTON_SUFFIX);
+ btn.setData(KEY_ACTION_ID, actionId);
+ btn.addSelectionListener(asl);
+ actionButtons.put(actionId, btn);
+ }
+ }
+
+ protected void setVisible(boolean visible, String... buttonIds) {
+ for (String id : buttonIds) {
+ Button button = actionButtons.get(id);
+ button.setVisible(visible);
+ GridData gd = (GridData) button.getLayoutData();
+ gd.heightHint = visible ? SWT.DEFAULT : 0;
+ }
+ }
+
+ public void show(Control source, Point location, IStructuredSelection selection) {
+ if (shell.isDisposed()) {
+ shell = new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+ createControl();
+ }
+ if (shell.isVisible())
+ shell.setVisible(false);
+
+ if (aboutToShow(source, location, selection)) {
+ shell.pack();
+ shell.layout();
+ if (source instanceof Control)
+ shell.setLocation(((Control) source).toDisplay(location.x, location.y));
+ shell.open();
+ }
+ }
+
+ protected Shell getParentShell() {
+ return parentShell;
+ }
+
+ class StyleButton extends Label {
+ private static final long serialVersionUID = 7731102609123946115L;
+
+ public StyleButton(Composite parent, int swtStyle) {
+ super(parent, swtStyle);
+ }
+ }
+
+ class ActionsSelListener extends SelectionAdapter {
+ private static final long serialVersionUID = -1041871937815812149L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ Object eventSource = e.getSource();
+ if (eventSource instanceof Button) {
+ Button pressedBtn = (Button) eventSource;
+ performAction((String) pressedBtn.getData(KEY_ACTION_ID));
+ shell.close();
+ }
+ }
+ }
+
+ class ActionsShellListener extends org.eclipse.swt.events.ShellAdapter {
+ private static final long serialVersionUID = -5092341449523150827L;
+
+ @Override
+ public void shellDeactivated(ShellEvent e) {
+ setVisible(false);
+ shell.setVisible(false);
+ //shell.close();
+ }
+ }
+
+ protected abstract boolean performAction(String actionId);
+
+ protected abstract boolean aboutToShow(Control source, Point location, IStructuredSelection selection);
+
+ protected abstract String getLabel(String actionId);
+}
--- /dev/null
+package org.argeo.suite.ui.widgets;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.rap.rwt.widgets.DropDown;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * Enable easy addition of a {@code DropDown} widget to a text with listeners
+ * configured
+ */
+public abstract class ConnectAbstractDropDown {
+
+ private final Text text;
+ private final DropDown dropDown;
+ private boolean modifyFromList = false;
+
+ // Current displayed text
+ private String userText = "";
+ // Current displayed list items
+ private String[] values;
+
+ // Fine tuning
+ boolean readOnly;
+ boolean refreshOnFocus;
+
+ /** Implementing classes should call refreshValues() after initialisation */
+ public ConnectAbstractDropDown(Text text) {
+ this(text, SWT.NONE, false);
+ }
+
+ /**
+ * Implementing classes should call refreshValues() after initialisation
+ *
+ * @param text
+ * @param style
+ * only SWT.READ_ONLY is understood, check if the entered text is
+ * part of the legal choices.
+ */
+ public ConnectAbstractDropDown(Text text, int style) {
+ this(text, style, false);
+ }
+
+ /**
+ * Implementers should call refreshValues() once init has been done.
+ *
+ * @param text
+ * @param style
+ * only SWT.READ_ONLY is understood, check if the entered text is
+ * part of the legal choices.
+ * @param refreshOnFocus
+ * if true, the possible values are computed each time the focus is
+ * gained. It enables, among other to fine tune the getFilteredValues
+ * method depending on the current context
+ */
+ public ConnectAbstractDropDown(Text text, int style, boolean refreshOnFocus) {
+ this.text = text;
+ dropDown = new DropDown(text);
+ Object obj = dropDown;
+ if (obj instanceof Widget)
+ CmsUiUtils.markup((Widget) obj);
+ readOnly = (style & SWT.READ_ONLY) != 0;
+ this.refreshOnFocus = refreshOnFocus;
+ addListeners();
+ }
+
+ /**
+ * Overwrite to force the refresh of the possible values on focus gained event
+ */
+ protected boolean refreshOnFocus() {
+ return refreshOnFocus;
+ }
+
+ public String getText() {
+ return text.getText();
+ }
+
+ public void init() {
+ refreshValues();
+ }
+
+ public void reset(String value) {
+ modifyFromList = true;
+ if (EclipseUiUtils.notEmpty(value))
+ text.setText(value);
+ else
+ text.setText("");
+ refreshValues();
+ modifyFromList = false;
+ }
+
+ /** Overwrite to provide specific filtering */
+ protected abstract List<String> getFilteredValues(String filter);
+
+ protected void refreshValues() {
+ List<String> filteredValues = getFilteredValues(text.getText());
+ values = filteredValues.toArray(new String[filteredValues.size()]);
+ dropDown.setItems(values);
+ }
+
+ protected void addListeners() {
+ addModifyListener();
+ addSelectionListener();
+ addDefaultSelectionListener();
+ addFocusListener();
+ }
+
+ protected void addFocusListener() {
+ text.addFocusListener(new FocusListener() {
+ private static final long serialVersionUID = -7179112097626535946L;
+
+ public void focusGained(FocusEvent event) {
+ if (refreshOnFocus) {
+ modifyFromList = true;
+ refreshValues();
+ modifyFromList = false;
+ }
+ dropDown.setVisible(true);
+ }
+
+ public void focusLost(FocusEvent event) {
+ dropDown.setVisible(false);
+ if (readOnly && values != null && !Arrays.asList(values).contains(userText)) {
+ modifyFromList = true;
+ text.setText("");
+ refreshValues();
+ modifyFromList = false;
+ }
+ }
+ });
+ }
+
+ private void addSelectionListener() {
+ Object obj = dropDown;
+ if (obj instanceof Widget)
+ ((Widget) obj).addListener(SWT.Selection, new Listener() {
+ private static final long serialVersionUID = -2357157809365135142L;
+
+ public void handleEvent(Event event) {
+ if (event.index != -1) {
+ modifyFromList = true;
+ text.setText(values[event.index]);
+ modifyFromList = false;
+ text.selectAll();
+ } else {
+ text.setText(userText);
+ text.setSelection(userText.length(), userText.length());
+ text.setFocus();
+ }
+ }
+ });
+ }
+
+ private void addDefaultSelectionListener() {
+ Object obj = dropDown;
+ if (obj instanceof Widget)
+ ((Widget) obj).addListener(SWT.DefaultSelection, new Listener() {
+ private static final long serialVersionUID = -5958008322630466068L;
+
+ public void handleEvent(Event event) {
+ if (event.index != -1) {
+ text.setText(values[event.index]);
+ text.setSelection(event.text.length());
+ dropDown.setVisible(false);
+ }
+ }
+ });
+ }
+
+ private void addModifyListener() {
+ text.addListener(SWT.Modify, new Listener() {
+ private static final long serialVersionUID = -4373972835244263346L;
+
+ public void handleEvent(Event event) {
+ if (!modifyFromList) {
+ userText = text.getText();
+ refreshValues();
+ if (values.length == 1)
+ dropDown.setSelectionIndex(0);
+ dropDown.setVisible(true);
+ }
+ }
+ });
+ }
+}
--- /dev/null
+package org.argeo.suite.ui.widgets;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.rap.rwt.service.ServerPushSession;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Text that introduce a timer in the attached ModifyListener.
+ *
+ * Note that corresponding ModifyEvent will *NOT* be sent in the UI thread.
+ * Calling ModifierInstance must be implemented in consequence. Note also that
+ * this delayed text only manages one listener at a time.
+ *
+ */
+public class DelayedText {
+ final int delay;
+ private Object lock = new Object();
+ private MyTimer timer = new MyTimer(DelayedText.this.toString());
+ private ModifyListener delayedModifyListener;
+ private ServerPushSession pushSession;
+
+ private Text text;
+
+ private ModifyListener modifyListener = new ModifyListener() {
+ private static final long serialVersionUID = 1117506414462641980L;
+
+ public void modifyText(ModifyEvent e) {
+ ModifyEvent delayedEvent = null;
+ synchronized (lock) {
+ if (delayedModifyListener != null) {
+ Event tmpEvent = new Event();
+ tmpEvent.widget = text;
+ tmpEvent.display = e.display;
+ tmpEvent.data = e.data;
+ tmpEvent.time = e.time;
+ delayedEvent = new ModifyEvent(tmpEvent);
+ }
+ }
+ final ModifyEvent timerModifyEvent = delayedEvent;
+
+ synchronized (timer) {
+ if (timer.timerTask != null) {
+ timer.timerTask.cancel();
+ timer.timerTask = null;
+ }
+
+ if (delayedEvent != null) {
+ timer.timerTask = new TimerTask() {
+ public void run() {
+ synchronized (lock) {
+ delayedModifyListener.modifyText(timerModifyEvent);
+ // Bad approach: it is not a good idea to put a
+ // display.asyncExec in a lock...
+ // DelayedText.this.getDisplay().asyncExec(new
+ // Runnable() {
+ // @Override
+ // public void run() {
+ // delayedModifyListener.modifyText(timerModifyEvent);
+ // }
+ // }
+ // );
+ }
+ synchronized (timer) {
+ timer.timerTask = null;
+ }
+ }
+ };
+ timer.schedule(timer.timerTask, delay);
+ if (pushSession != null)
+ pushSession.start();
+ }
+ }
+ };
+ };
+
+ public DelayedText(Composite parent, int style, int delayInMs) {
+ // super(parent, style);
+ text = new Text(parent, style);
+ this.delay = delayInMs;
+ text.addModifyListener(modifyListener);
+ }
+
+ /**
+ * Adds a modify text listener that will be delayed. If another Modify event
+ * happens during the waiting delay, the older event will be canceled an a new
+ * one will be scheduled after another new delay.
+ */
+ public void addDelayedModifyListener(ServerPushSession pushSession, ModifyListener listener) {
+ synchronized (lock) {
+ delayedModifyListener = listener;
+ this.pushSession = pushSession;
+ }
+ }
+
+ public void removeDelayedModifyListener(ModifyListener listener) {
+ synchronized (lock) {
+ delayedModifyListener = null;
+ pushSession = null;
+ }
+ }
+
+ private class MyTimer extends Timer {
+ private TimerTask timerTask = null;
+
+ public MyTimer(String name) {
+ super(name);
+ }
+ }
+
+ public Text getText() {
+ return text;
+ }
+
+ public void close() {
+ if (pushSession != null)
+ pushSession.stop();
+ if (timer != null)
+ timer.cancel();
+ };
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.suite</groupId>
+ <artifactId>argeo-suite</artifactId>
+ <version>2.1.18-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>core</artifactId>
+ <name>Argeo Core Components</name>
+ <packaging>pom</packaging>
+ <modules>
+ <!-- Entity Framework -->
+ <module>org.argeo.entity.api</module>
+ <module>org.argeo.entity.core</module>
+ <module>org.argeo.entity.ui</module>
+
+ <!-- Argeo Suite -->
+ <module>org.argeo.suite.core</module>
+ <module>org.argeo.suite.ui</module>
+ <module>org.argeo.suite.ui.rap</module>
+ <module>org.argeo.suite.theme.default</module>
+ </modules>
+</project>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.entity.api</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-Require-Capability:\
-cms.datamodel;filter:="(name=jcrx)"
-
-Provide-Capability:\
-cms.datamodel; name=entity; cnd=/org/argeo/entity/entity.cnd
+++ /dev/null
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
- .
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.suite</groupId>
- <artifactId>argeo-suite</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.entity.api</artifactId>
- <name>Entity API</name>
- <packaging>jar</packaging>
- <dependencies>
- <!-- Argeo Commons -->
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.enterprise</artifactId>
- <version>${version.argeo-commons}</version>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-package org.argeo.entity;
-
-/** Constant related to entities, typically used in an OSGi context. */
-public interface EntityConstants {
- final static String TYPE = "entity.type";
- final static String DEFAULT_EDITORY_ID = "entity.defaultEditorId";
-
-}
+++ /dev/null
-package org.argeo.entity;
-
-import javax.jcr.Node;
-
-/** The definition of an entity, a composite configurable data structure. */
-public interface EntityDefinition {
- String getEditorId(Node entity);
-
- String getType();
-}
+++ /dev/null
-package org.argeo.entity;
-
-import org.argeo.naming.LdapAttrs;
-
-/** Constants used to name entity structures. */
-public interface EntityNames {
- @Deprecated
- final String FORM_BASE = "form";
- final String SUBMISSIONS_BASE = "submissions";
- @Deprecated
- final String TERM = "term";
- final String NAME = "name";
-
-// final String ENTITY_DEFINITIONS_PATH = "/entity";
- @Deprecated
- final String TYPOLOGIES_PATH = "/" + TERM;
- /** Administrative units. */
- final String ADM = "adm";
-
- final String ENTITY_TYPE = "entity:type";
- // final String ENTITY_UID = "entity:uid";
- // final String ENTITY_NAME = "entity:name";
-
- // GENERIC CONCEPTS
- /** The language which is relevant. */
- final String XML_LANG = "xml:lang";
- /** The date which is relevant. */
- final String ENTITY_DATE = "entity:date";
- @Deprecated
- final String ENTITY_RELATED_TO = "entity:relatedTo";
-
- // DEFAULT FOLDER NAMES
- final String MEDIA = "media";
- final String FILES = "files";
-
- // LDAP-LIKE ENTITIES
- @Deprecated
- final String DISPLAY_NAME = LdapAttrs.displayName.property();
- // Persons
- @Deprecated
- final String GIVEN_NAME = LdapAttrs.givenName.property();
- @Deprecated
- final String SURNAME = LdapAttrs.sn.property();
- @Deprecated
- final String EMAIL = LdapAttrs.mail.property();
- @Deprecated
- final String OU = LdapAttrs.ou.property();
-
- // WGS84
- final String GEO_LAT = "geo:lat";
- final String GEO_LONG = "geo:long";
- final String GEO_ALT = "geo:alt";
-
- // SVG
- final String SVG_WIDTH = "svg:width";
- final String SVG_HEIGHT = "svg:height";
- final String SVG_LENGTH = "svg:length";
- final String SVG_UNIT = "svg:unit";
- final String SVG_DUR = "svg:dur";
- final String SVG_DIRECTION = "svg:direction";
-}
+++ /dev/null
-package org.argeo.entity;
-
-/** Types related to entities. */
-public enum EntityType implements JcrName {
- // entity
- entity, local, relatedTo,
- // typology
- typologies, terms, term,
- // form
- form, formSet, formSubmission,
- // graphics
- box,
- // geography
- geopoint, bearing,
- // ldap
- person, user;
-
- @Override
- public String getPrefix() {
- return prefix();
- }
-
- public static String prefix() {
- return "entity";
- }
-
- public String basePath() {
- return '/' + name();
- }
-
- @Override
- public String getNamespace() {
- return namespace();
- }
-
- public static String namespace() {
- return "http://www.argeo.org/ns/entity";
- }
-
-}
+++ /dev/null
-package org.argeo.entity;
-
-/** Types related to entities. */
-@Deprecated
-public interface EntityTypes {
- final static String ENTITY_ENTITY = "entity:entity";
- final static String ENTITY_DEFINITION = "entity:definition";
-
- final static String ENTITY_PERSON = "entity:person";
-}
+++ /dev/null
-package org.argeo.entity;
-
-import java.util.function.Supplier;
-
-/** Can be applied to {@link Enum}s in order to generate prefixed names. */
-@FunctionalInterface
-public interface JcrName extends Supplier<String> {
- String name();
-
- default String getPrefix() {
- return null;
- }
-
- default String getNamespace() {
- return null;
- }
-
- @Override
- default String get() {
- String prefix = getPrefix();
- return prefix != null ? prefix + ":" + name() : name();
- }
-
- default String withNamespace() {
- String namespace = getNamespace();
- if (namespace == null)
- throw new UnsupportedOperationException("No namespace is specified for " + getClass());
- return "{" + namespace + "}" + name();
- }
-}
+++ /dev/null
-package org.argeo.entity;
-
-import java.util.List;
-
-/** Provides optimised access and utilities around terms typologies. */
-public interface TermsManager {
- List<String> listAllTerms(String typology);
-}
+++ /dev/null
-// Standard namespaces
-<xsd = "http://www.w3.org/2001/XMLSchema">
-<h = "http://www.w3.org/1999/xhtml">
-// see https://www.w3.org/2003/01/geo/
-<geo = "http://www.w3.org/2003/01/geo/wgs84_pos#">
-<svg = "http://www.w3.org/2000/svg">
-
-<ldap = "http://www.argeo.org/ns/ldap">
-<entity = 'http://www.argeo.org/ns/entity'>
-
-[entity:entity] > mix:created, mix:referenceable
-mixin
-
-[entity:local] > entity:entity
-mixin
-- entity:type (String) m
-
-[entity:relatedTo]
-mixin
-+ entity:relatedTo (nt:address) *
-
-//
-// ENTITY DEFINITION
-//
-//[entity:definition] > entity:composite, mix:created, mix:lastModified, mix:referenceable
-//- entity:type (String) multiple
-
-//[entity:part]
-
-//[entity:reference]
-
-//[entity:composite]
-//orderable
-//+ * (entity:part)
-//+ * (entity:reference)
-//+ * (entity:composite)
-
-//
-// TYPOLOGY
-//
-[entity:typologies]
-+ * (entity:terms) = entity:terms
-
-[entity:term]
-orderable
-- name (NAME) m
-- * (*)
-+ term (entity:term) = entity:term *
-
-[entity:terms] > mix:referenceable
-orderable
-+ term (entity:term) = entity:term *
-
-//
-// FORM
-//
-[entity:form]
-mixin
-
-[entity:formSubmission]
-mixin
-
-[entity:formSet] > mix:title
-mixin
-
-//
-// GRAPHICS
-//
-[entity:box]
-mixin
-- svg:width (DOUBLE)
-- svg:height (DOUBLE)
-- svg:length (DOUBLE)
-- svg:unit (STRING)
-- svg:dur (DOUBLE)
-
-// LDAP-LIKE ENTITIES
-// A real person
-[entity:person] > entity:entity
-mixin
-- ldap:sn (String)
-- ldap:givenName (String)
-- ldap:mail (String) *
-
-[entity:user] > entity:person
-mixin
-- ldap:distinguishedName (String)
-- ldap:uid (String)
-
-// GEOGRAPHY
-[entity:geopoint]
-mixin
-- geo:long (DOUBLE)
-- geo:lat (DOUBLE)
-- geo:alt (DOUBLE)
-
-[entity:bearing]
-mixin
-- svg:direction (DOUBLE)
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.entity.core</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
- .
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.suite</groupId>
- <artifactId>argeo-suite</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.entity.core</artifactId>
- <name>Entity Reference Implementation</name>
- <packaging>jar</packaging>
- <dependencies>
- <dependency>
- <groupId>org.argeo.suite</groupId>
- <artifactId>org.argeo.entity.api</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- </dependency>
-
- <!-- Argeo Commons -->
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.cms</artifactId>
- <version>${version.argeo-commons}</version>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-package org.argeo.entity.core;
-
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.NodeUtils;
-import org.argeo.entity.EntityConstants;
-import org.argeo.entity.EntityDefinition;
-import org.argeo.jcr.Jcr;
-import org.osgi.framework.BundleContext;
-
-/** An entity definition based on a JCR data structure. */
-public class JcrEntityDefinition implements EntityDefinition {
- private Repository repository;
-
- private String type;
- private String defaultEditoryId;
-
- public void init(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
- Session adminSession = NodeUtils.openDataAdminSession(repository, null);
- try {
- type = properties.get(EntityConstants.TYPE);
- if (type == null)
- throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set.");
- defaultEditoryId = properties.get(EntityConstants.DEFAULT_EDITORY_ID);
-// String definitionPath = EntityNames.ENTITY_DEFINITIONS_PATH + '/' + type;
-// if (!adminSession.itemExists(definitionPath)) {
-// Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath, EntityTypes.ENTITY_DEFINITION);
-//// entityDefinition.addMixin(EntityTypes.ENTITY_DEFINITION);
-// adminSession.save();
-// }
- initJcr(adminSession);
- } finally {
- Jcr.logout(adminSession);
- }
- }
-
- /** To be overridden in order to perform additional initialisations. */
- protected void initJcr(Session adminSession) throws RepositoryException {
-
- }
-
- public void destroy(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
-
- }
-
- @Override
- public String getEditorId(Node entity) {
- return defaultEditoryId;
- }
-
- @Override
- public String getType() {
- return type;
- }
-
- protected Repository getRepository() {
- return repository;
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public String toString() {
- return "Entity Definition " + getType();
- }
-
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.entity.ui</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-Import-Package:\
-org.eclipse.swt,\
-*
\ No newline at end of file
+++ /dev/null
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
- .
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.suite</groupId>
- <artifactId>argeo-suite</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.entity.ui</artifactId>
- <name>Entity UI</name>
- <packaging>jar</packaging>
- <dependencies>
- <dependency>
- <groupId>org.argeo.suite</groupId>
- <artifactId>org.argeo.entity.core</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- </dependency>
-
- <!-- Argeo Commons -->
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.cms.ui</artifactId>
- <version>${version.argeo-commons}</version>
- </dependency>
-
- <!-- Specific -->
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.eclipse.ui.rap</artifactId>
- <version>2.1.91-SNAPSHOT</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Eclipse E4 -->
- <dependency>
- <groupId>org.argeo.tp</groupId>
- <artifactId>argeo-tp-rap-e4</artifactId>
- <version>${version.argeo-tp}</version>
- <type>pom</type>
- <scope>provided</scope>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-package org.argeo.entity.ui.forms;
-
-import javax.jcr.Item;
-
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.util.CmsIcon;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.widgets.ContextOverlay;
-import org.argeo.cms.ui.widgets.StyledControl;
-import org.argeo.entity.TermsManager;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** Common logic between single and mutliple terms editable part. */
-public abstract class AbstractTermsPart extends StyledControl implements EditablePart {
- private static final long serialVersionUID = -5497097995341927710L;
- protected final TermsManager termsManager;
- protected final String typology;
-
- protected final boolean editable;
-
- private CmsIcon deleteIcon;
- private CmsIcon addIcon;
- private CmsIcon cancelIcon;
-
- private Color highlightColor;
- private Composite highlight;
-
- protected final CmsTheme theme;
-
- public AbstractTermsPart(Composite parent, int style, Item item, TermsManager termsManager,
- String typology) {
- super(parent, style, item);
- this.termsManager = termsManager;
- this.typology = typology;
- this.theme = CmsTheme.getCmsTheme(parent);
- editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
- highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
- }
-
- protected void createHighlight(Composite block) {
- highlight = new Composite(block, SWT.NONE);
- highlight.setBackground(highlightColor);
- GridData highlightGd = new GridData(SWT.FILL, SWT.FILL, false, false);
- highlightGd.widthHint = 5;
- highlightGd.heightHint = 3;
- highlight.setLayoutData(highlightGd);
-
- }
-
- protected String getTermLabel(String name) {
- return name;
- }
-
- protected abstract void refresh(ContextOverlay contextArea, String filter, Text txt);
-
- protected boolean isTermSelectable(String term) {
- return true;
- }
-
- protected void processTermListLabel(String term, Label label) {
-
- }
-
- //
- // STYLING
- //
- public void setDeleteIcon(CmsIcon deleteIcon) {
- this.deleteIcon = deleteIcon;
- }
-
- public void setAddIcon(CmsIcon addIcon) {
- this.addIcon = addIcon;
- }
-
- public void setCancelIcon(CmsIcon cancelIcon) {
- this.cancelIcon = cancelIcon;
- }
-
- protected TermsManager getTermsManager() {
- return termsManager;
- }
-
- protected void styleDelete(ToolItem deleteItem) {
- if (deleteIcon != null)
- deleteItem.setImage(deleteIcon.getSmallIcon(theme));
- else
- deleteItem.setText("-");
- }
-
- protected void styleCancel(ToolItem cancelItem) {
- if (cancelIcon != null)
- cancelItem.setImage(cancelIcon.getSmallIcon(theme));
- else
- cancelItem.setText("X");
- }
-
- protected void styleAdd(ToolItem addItem) {
- if (addIcon != null)
- addItem.setImage(addIcon.getSmallIcon(theme));
- else
- addItem.setText("+");
- }
-}
+++ /dev/null
-package org.argeo.entity.ui.forms;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Item;
-
-import org.argeo.cms.ui.forms.FormStyle;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.widgets.ContextOverlay;
-import org.argeo.eclipse.ui.MouseDoubleClick;
-import org.argeo.eclipse.ui.MouseDown;
-import org.argeo.eclipse.ui.Selected;
-import org.argeo.entity.TermsManager;
-import org.argeo.jcr.Jcr;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** {@link EditablePart} for multiple terms. */
-public class MultiTermsPart extends AbstractTermsPart {
- private static final long serialVersionUID = -4961135649177920808L;
-
- public MultiTermsPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
- super(parent, style, item, termsManager, typology);
- }
-
- @Override
- protected Control createControl(Composite box, String style) {
- Composite placeholder = new Composite(box, SWT.NONE);
- RowLayout rl = new RowLayout(SWT.HORIZONTAL | SWT.WRAP);
- placeholder.setLayout(rl);
- List<String> currentValue = Jcr.getMultiple(getNode(), typology);
- if (currentValue != null && !currentValue.isEmpty())
- for (String value : currentValue) {
- Composite block = new Composite(placeholder, SWT.NONE);
- block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
- Label lbl = new Label(block, SWT.SINGLE);
- String display = getTermLabel(value);
- lbl.setText(display);
- CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
- if (editable)
- lbl.addMouseListener((MouseDoubleClick) (e) -> {
- startEditing();
- });
- if (isEditing()) {
- ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
- ToolItem deleteItem = new ToolItem(toolBar, SWT.FLAT);
- styleDelete(deleteItem);
- deleteItem.addSelectionListener((Selected) (e) -> {
- // we retrieve them again here because they may have changed
- List<String> curr = Jcr.getMultiple(getNode(), typology);
- List<String> newValue = new ArrayList<>();
- for (String v : curr) {
- if (!v.equals(value))
- newValue.add(v);
- }
- Jcr.set(getNode(), typology, newValue);
- Jcr.save(getNode());
- block.dispose();
- layout(true, true);
- });
-
- }
- }
- else {// empty
- if (editable && !isEditing()) {
- ToolBar toolBar = new ToolBar(placeholder, SWT.HORIZONTAL);
- ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
- styleAdd(addItem);
- addItem.addSelectionListener((Selected) (e) -> {
- startEditing();
- });
- }
- }
-
- if (isEditing()) {
- Composite block = new Composite(placeholder, SWT.NONE);
- block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
-
- createHighlight(block);
-
- Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
- txt.setLayoutData(CmsUiUtils.fillWidth());
-// txt.setMessage("[new]");
-
- CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
-
- ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
- ToolItem cancelItem = new ToolItem(toolBar, SWT.FLAT);
- styleCancel(cancelItem);
- cancelItem.addSelectionListener((Selected) (e) -> {
- stopEditing();
- });
-
- ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
- private static final long serialVersionUID = -7980078594405384874L;
-
- @Override
- protected void onHide() {
- stopEditing();
- }
- };
- contextOverlay.setLayout(new GridLayout());
- // filter
- txt.addModifyListener((e) -> {
- String filter = txt.getText().toLowerCase();
- if ("".equals(filter.trim()))
- filter = null;
- refresh(contextOverlay, filter, txt);
- });
- txt.addFocusListener(new FocusListener() {
- private static final long serialVersionUID = -6024501573409619949L;
-
- @Override
- public void focusLost(FocusEvent event) {
-// if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
-// getDisplay().asyncExec(() -> stopEditing());
- }
-
- @Override
- public void focusGained(FocusEvent event) {
- // txt.setText("");
- if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
- refresh(contextOverlay, null, txt);
- }
- });
- layout(new Control[] { txt });
- // getDisplay().asyncExec(() -> txt.setFocus());
- }
- return placeholder;
- }
-
- @Override
- protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
- CmsUiUtils.clear(contextArea);
- List<String> terms = termsManager.listAllTerms(typology);
- List<String> currentValue = Jcr.getMultiple(getNode(), typology);
- terms: for (String term : terms) {
- if (currentValue != null && currentValue.contains(term))
- continue terms;
- String display = getTermLabel(term);
- if (filter != null && !display.toLowerCase().contains(filter))
- continue terms;
- Label termL = new Label(contextArea, SWT.WRAP);
- termL.setText(display);
- processTermListLabel(term, termL);
- if (isTermSelectable(term))
- termL.addMouseListener((MouseDown) (e) -> {
- List<String> newValue = new ArrayList<>();
- List<String> curr = Jcr.getMultiple(getNode(), typology);
- if (currentValue != null)
- newValue.addAll(curr);
- newValue.add(term);
- Jcr.set(getNode(), typology, newValue);
- Jcr.save(getNode());
- contextArea.hide();
- stopEditing();
- });
- }
- contextArea.show();
- }
-
-}
+++ /dev/null
-package org.argeo.entity.ui.forms;
-
-import java.util.List;
-
-import javax.jcr.Item;
-
-import org.argeo.cms.ui.forms.FormStyle;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.widgets.ContextOverlay;
-import org.argeo.eclipse.ui.MouseDoubleClick;
-import org.argeo.eclipse.ui.MouseDown;
-import org.argeo.eclipse.ui.Selected;
-import org.argeo.entity.TermsManager;
-import org.argeo.jcr.Jcr;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** {@link EditablePart} for terms. */
-public class SingleTermPart extends AbstractTermsPart {
- private static final long serialVersionUID = -4961135649177920808L;
-
- public SingleTermPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
- super(parent, style, item, termsManager, typology);
- }
-
- @Override
- protected Control createControl(Composite box, String style) {
- if (isEditing()) {
- Composite block = new Composite(box, SWT.NONE);
- block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
-
- createHighlight(block);
-
- Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
- CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
-
- ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
- ToolItem deleteItem = new ToolItem(toolBar, SWT.PUSH);
- styleDelete(deleteItem);
- deleteItem.addSelectionListener((Selected) (e) -> {
- Jcr.set(getNode(), typology, null);
- Jcr.save(getNode());
- stopEditing();
- });
- ToolItem cancelItem = new ToolItem(toolBar, SWT.PUSH);
- styleCancel(cancelItem);
- cancelItem.addSelectionListener((Selected) (e) -> {
- stopEditing();
- });
-
- ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
- private static final long serialVersionUID = -7980078594405384874L;
-
- @Override
- protected void onHide() {
- stopEditing();
- }
- };
- contextOverlay.setLayout(new GridLayout());
- // filter
- txt.addModifyListener((e) -> {
- String filter = txt.getText().toLowerCase();
- if ("".equals(filter.trim()))
- filter = null;
- refresh(contextOverlay, filter, txt);
- });
- txt.addFocusListener(new FocusListener() {
- private static final long serialVersionUID = -6024501573409619949L;
-
- @Override
- public void focusLost(FocusEvent event) {
-// if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
-// getDisplay().asyncExec(() -> stopEditing());
- }
-
- @Override
- public void focusGained(FocusEvent event) {
- // txt.setText("");
- if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
- refresh(contextOverlay, null, txt);
- }
- });
- layout(new Control[] { block });
- getDisplay().asyncExec(() -> txt.setFocus());
- return block;
- } else {
- Composite block = new Composite(box, SWT.NONE);
- block.setLayout(CmsUiUtils.noSpaceGridLayout(2));
- String currentValue = Jcr.get(getNode(), typology);
- if (currentValue != null) {
- Label lbl = new Label(block, SWT.SINGLE);
- String display = getTermLabel(currentValue);
- lbl.setText(display);
- CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
-
- lbl.addMouseListener((MouseDoubleClick) (e) -> {
- startEditing();
- });
- } else {
- ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
- ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
- styleAdd(addItem);
- addItem.addSelectionListener((Selected) (e) -> {
- startEditing();
- });
- }
- return block;
- }
- }
-
- @Override
- protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
- CmsUiUtils.clear(contextArea);
- List<String> terms = termsManager.listAllTerms(typology);
- terms: for (String term : terms) {
- String display = getTermLabel(term);
- if (filter != null && !display.toLowerCase().contains(filter))
- continue terms;
- Label termL = new Label(contextArea, SWT.WRAP);
- termL.setText(display);
- processTermListLabel(term, termL);
- if (isTermSelectable(term))
- termL.addMouseListener((MouseDown) (e) -> {
- Jcr.set(getNode(), typology, term);
- Jcr.save(getNode());
- contextArea.hide();
- stopEditing();
- });
- }
- contextArea.show();
- // txt.setFocus();
- }
-
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.suite.core</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Suite Maintenance Service">
- <implementation class="org.argeo.suite.core.SuiteMaintenanceService"/>
- <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
- <reference bind="setUserTransaction" cardinality="1..1" interface="javax.transaction.UserTransaction" name="UserTransaction" policy="static"/>
- <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Suite Terms Manager">
- <implementation class="org.argeo.suite.core.SuiteTermsManager"/>
- <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
- <service>
- <provide interface="org.argeo.entity.TermsManager"/>
- </service>
-</scr:component>
+++ /dev/null
-Bundle-ActivationPolicy: lazy
-
-Service-Component:\
-OSGI-INF/termsManager.xml,\
-OSGI-INF/maintenanceService.xml
-
-Import-Package:\
-javax.transaction,\
-org.osgi.service.useradmin,\
-javax.jcr.nodetype,\
-javax.jcr.security,\
-org.argeo.api,\
-org.argeo.entity,\
-*
\ No newline at end of file
+++ /dev/null
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- OSGI-INF/
-source.. = src/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.suite</groupId>
- <artifactId>argeo-suite</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.suite.core</artifactId>
- <name>Suite Core</name>
- <packaging>jar</packaging>
- <dependencies>
- <dependency>
- <groupId>org.argeo.suite</groupId>
- <artifactId>org.argeo.entity.core</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- </dependency>
-
- <!-- Argeo Commons -->
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.cms</artifactId>
- <version>${version.argeo-commons}</version>
- </dependency>
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.maintenance</artifactId>
- <version>${version.argeo-commons}</version>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-package org.argeo.suite;
-
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A container for an object whose relevance can be ranked. Typically used in an
- * OSGi context with the service.ranking property.
- */
-public class RankedObject<T> {
- private final static Log log = LogFactory.getLog(RankedObject.class);
-
- private final static String SERVICE_RANKING = "service.ranking";
-// private final static String SERVICE_ID = "service.id";
-
- private T object;
- private Map<String, Object> properties;
- private final Long rank;
-
- public RankedObject(T object, Map<String, Object> properties) {
- this(object, properties, extractRanking(properties));
- }
-
- public RankedObject(T object, Map<String, Object> properties, Long rank) {
- super();
- this.object = object;
- this.properties = properties;
- this.rank = rank;
- }
-
- private static Long extractRanking(Map<String, Object> properties) {
- if (properties == null)
- return 0l;
- if (properties.containsKey(SERVICE_RANKING))
- return Long.valueOf(properties.get(SERVICE_RANKING).toString());
-// else if (properties.containsKey(SERVICE_ID))
-// return (Long) properties.get(SERVICE_ID);
- else
- return 0l;
- }
-
- public T get() {
- return object;
- }
-
- public Map<String, Object> getProperties() {
- return properties;
- }
-
- public Long getRank() {
- return rank;
- }
-
- @Override
- public int hashCode() {
- return object.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof RankedObject))
- return false;
- RankedObject<?> other = (RankedObject<?>) obj;
- return rank.equals(other.rank) && object.equals(other.object);
- }
-
- @Override
- public String toString() {
- return object.getClass().getName() + " with rank " + rank;
- }
-
- public static <K, T> RankedObject<T> putIfHigherRank(Map<K, RankedObject<T>> map, K key, T object,
- Map<String, Object> properties) {
- RankedObject<T> rankedObject = new RankedObject<>(object, properties);
- if (!map.containsKey(key)) {
- map.put(key, rankedObject);
- if (log.isTraceEnabled())
- log.trace(
- "Added " + key + " as " + object.getClass().getName() + " with rank " + rankedObject.getRank());
- return rankedObject;
- } else {
- RankedObject<T> current = map.get(key);
- if (current.getRank() <= rankedObject.getRank()) {
- map.put(key, rankedObject);
- if (log.isTraceEnabled())
- log.trace("Replaced " + key + " by " + object.getClass().getName() + " with rank "
- + rankedObject.getRank());
- return rankedObject;
- } else {
- return current;
- }
- }
-
- }
-
-}
+++ /dev/null
-package org.argeo.suite;
-
-import java.util.Map;
-
-/**
- * Key used to classify and filter available components (typically provided by
- * OSGi services).
- */
-@Deprecated
-public class RankingKey implements Comparable<RankingKey> {
- public final static String SERVICE_PID = "service.pid";
- public final static String SERVICE_ID = "service.id";
- public final static String SERVICE_RANKING = "service.ranking";
- public final static String DATA_TYPE = "data.type";
-
- private String pid;
- private Integer ranking = 0;
- private Long id = 0l;
- private String dataType;
- private String dataPath;
-
- public RankingKey(String pid, Integer ranking, Long id, String dataType, String dataPath) {
- super();
- this.pid = pid;
- this.ranking = ranking;
- this.id = id;
- this.dataType = dataType;
- this.dataPath = dataPath;
- }
-
- public RankingKey(Map<String, Object> properties) {
- this.pid = properties.containsKey(SERVICE_PID) ? properties.get(SERVICE_PID).toString() : null;
- this.ranking = properties.containsKey(SERVICE_RANKING)
- ? 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(DATA_TYPE) ? properties.get(DATA_TYPE).toString() : null;
- }
-
- @Override
- public int hashCode() {
- Integer result = 0;
- if (pid != null)
- result = +pid.hashCode();
- if (ranking != null)
- result = +ranking;
- if (dataType != null)
- result = +dataType.hashCode();
- return result;
- }
-
- @Override
- protected Object clone() throws CloneNotSupportedException {
- return new RankingKey(pid, ranking, id, dataType, dataPath);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("");
- if (pid != null)
- sb.append(pid);
- if (ranking != null && ranking != 0)
- sb.append(' ').append(ranking);
- if (dataType != null)
- sb.append(' ').append(dataType);
- return sb.toString();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof RankingKey))
- return false;
- RankingKey other = (RankingKey) obj;
- return equalsOrBothNull(pid, other.pid) && equalsOrBothNull(ranking, other.ranking)
- && equalsOrBothNull(id, other.id) && equalsOrBothNull(dataType, other.dataType)
- && equalsOrBothNull(dataPath, other.dataPath);
- }
-
- @Override
- public int compareTo(RankingKey o) {
- if (pid != null && o.pid != null) {
- if (pid.equals(o.pid)) {
- 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 pid.compareTo(o.pid);
- }
-
- } 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 -1;
- }
-
- public String getPid() {
- return pid;
- }
-
- public Integer getRanking() {
- return ranking;
- }
-
- public Long getId() {
- return id;
- }
-
- public String getDataType() {
- return dataType;
- }
-
- public String getDataPath() {
- return dataPath;
- }
-
- public static RankingKey minPid(String pid) {
- return new RankingKey(pid, Integer.MIN_VALUE, null, null, null);
- }
-
- public static RankingKey maxPid(String pid) {
- 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;
- if (o1 == null && o2 != null)
- return false;
- if (o1 != null && o2 == null)
- return false;
- return o2.equals(o1);
- }
-}
+++ /dev/null
-package org.argeo.suite;
-
-import org.argeo.api.NodeConstants;
-import org.argeo.naming.Distinguished;
-import org.argeo.naming.LdapAttrs;
-
-/** Office specific roles used in the code */
-public enum SuiteRole implements Distinguished {
- coworker, manager;
-
- public String getRolePrefix() {
- return "org.argeo.suite";
- }
-
- public String dn() {
- return new StringBuilder(LdapAttrs.cn.name()).append("=").append(getRolePrefix()).append(".").append(name())
- .append(",").append(NodeConstants.ROLES_BASEDN).toString();
- }
-}
+++ /dev/null
-package org.argeo.suite;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.security.Privilege;
-import javax.naming.ldap.LdapName;
-import javax.security.auth.x500.X500Principal;
-
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.auth.CmsSession;
-import org.argeo.entity.EntityType;
-import org.argeo.jackrabbit.security.JackrabbitSecurityUtils;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.naming.LdapAttrs;
-
-/** Utilities around the Argeo Suite APIs. */
-public class SuiteUtils {
-
- public static String getUserNodePath(LdapName userDn) {
- String uid = userDn.getRdn(userDn.size() - 1).getValue().toString();
- return EntityType.user.basePath() + '/' + uid;
- }
-
- public static Node getOrCreateUserNode(Session adminSession, LdapName userDn) {
- try {
- Node usersBase = adminSession.getNode(EntityType.user.basePath());
- String uid = userDn.getRdn(userDn.size() - 1).getValue().toString();
- Node userNode;
- if (!usersBase.hasNode(uid)) {
- userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
- userNode.addMixin(EntityType.user.get());
- userNode.addMixin(NodeType.MIX_CREATED);
- userNode.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString());
- userNode.setProperty(LdapAttrs.uid.property(), uid);
- adminSession.save();
- JackrabbitSecurityUtils.denyPrivilege(adminSession, userNode.getPath(), SuiteRole.coworker.dn(),
- Privilege.JCR_READ);
- JcrUtils.addPrivilege(adminSession, userNode.getPath(), new X500Principal(userDn.toString()).getName(),
- Privilege.JCR_READ);
- JcrUtils.addPrivilege(adminSession, userNode.getPath(), NodeConstants.ROLE_USER_ADMIN,
- Privilege.JCR_ALL);
- } else {
- userNode = usersBase.getNode(uid);
- }
- return userNode;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot create user node for " + userDn, e);
- }
- }
-
- public static Node getCmsSessionNode(Session session, CmsSession cmsSession) {
- try {
- return session.getNode(getUserNodePath(cmsSession.getUserDn()) + '/' + cmsSession.getUuid().toString());
- } catch (RepositoryException e) {
- throw new JcrException("Cannot get session dir for " + cmsSession, e);
- }
- }
-
- public static Node getOrCreateCmsSessionNode(Session adminSession, CmsSession cmsSession) {
- try {
- LdapName userDn = cmsSession.getUserDn();
-// String uid = userDn.get(userDn.size() - 1);
- Node userNode = getOrCreateUserNode(adminSession, userDn);
-// if (!usersBase.hasNode(uid)) {
-// userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
-// userNode.addMixin(EntityType.user.get());
-// userNode.addMixin(NodeType.MIX_CREATED);
-// usersBase.setProperty(LdapAttrs.uid.property(), uid);
-// usersBase.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString());
-// adminSession.save();
-// } else {
-// userNode = usersBase.getNode(uid);
-// }
- String cmsSessionUuid = cmsSession.getUuid().toString();
- Node cmsSessionNode;
- if (!userNode.hasNode(cmsSessionUuid)) {
- cmsSessionNode = userNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED);
- cmsSessionNode.addMixin(NodeType.MIX_CREATED);
- adminSession.save();
- JcrUtils.addPrivilege(adminSession, cmsSessionNode.getPath(), cmsSession.getUserRole(),
- Privilege.JCR_ALL);
- } else {
- cmsSessionNode = userNode.getNode(cmsSessionUuid);
- }
- return cmsSessionNode;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot create session dir for " + cmsSession, e);
- }
- }
-
- /** Singleton. */
- private SuiteUtils() {
-
- }
-
-}
+++ /dev/null
-package org.argeo.suite.core;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.ItemExistsException;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.maintenance.AbstractMaintenanceService;
-
-/** Base for custom initialisations. */
-public abstract class CustomMaintenanceService extends AbstractMaintenanceService {
- private final static Log log = LogFactory.getLog(AbstractMaintenanceService.class);
-
- protected List<String> getTypologies() {
- return new ArrayList<>();
- }
-
- protected String getTypologiesLoadBase() {
- return "/sys/terms";
- }
-
- protected void loadTypologies(Node customBaseNode) throws RepositoryException, IOException {
- List<String> typologies = getTypologies();
- if (!typologies.isEmpty()) {
- Node termsBase = JcrUtils.getOrAdd(customBaseNode, EntityType.terms.name(), EntityType.typologies.get());
- for (String terms : typologies) {
- loadTerms(termsBase, terms);
- }
- termsBase.getSession().save();
- }
- }
-
- protected void loadTerms(Node termsBase, String name) throws IOException, RepositoryException {
- try {
- if (termsBase.hasNode(name))
- return;
-
- String termsLoadPath = getTypologiesLoadBase() + '/' + name + ".xml";
- URL termsUrl = getClass().getClassLoader().getResource(termsLoadPath);
- if (termsUrl == null)
- throw new IllegalArgumentException("Terms '" + name + "' not found.");
- try (InputStream in = termsUrl.openStream()) {
- termsBase.getSession().importXML(termsBase.getPath(), in,
- ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
- } catch (ItemExistsException e) {
- log.warn("Terms " + name + " exists with another UUID, removing it...");
- termsBase.getNode(name).remove();
- try (InputStream in = termsUrl.openStream()) {
- termsBase.getSession().importXML(termsBase.getPath(), in,
- ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
- }
- }
- if (log.isDebugEnabled())
- log.debug("Terms '" + name + "' loaded.");
- termsBase.getSession().save();
- } catch (RepositoryException | IOException e) {
- log.error("Cannot load terms '" + name + "': " + e.getMessage());
- throw e;
- }
- }
-
-}
+++ /dev/null
-package org.argeo.suite.core;
-
-import java.io.IOException;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.security.Privilege;
-
-import org.argeo.api.NodeConstants;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.maintenance.AbstractMaintenanceService;
-
-/** Initialises an Argeo Suite backend. */
-public class SuiteMaintenanceService extends AbstractMaintenanceService {
-
- @Override
- public boolean prepareJcrTree(Session adminSession) throws RepositoryException, IOException {
- boolean modified = false;
- Node rootNode = adminSession.getRootNode();
- if (!rootNode.hasNode(EntityType.user.name())) {
- rootNode.addNode(EntityType.user.name(), NodeType.NT_UNSTRUCTURED);
- modified = true;
- }
- if (modified)
- adminSession.save();
- return modified;
- }
-
- @Override
- public void configurePrivileges(Session adminSession) throws RepositoryException {
- JcrUtils.addPrivilege(adminSession, EntityType.user.basePath(), NodeConstants.ROLE_USER_ADMIN,
- Privilege.JCR_ALL);
- //JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), Privilege.JCR_READ);
- }
-
-}
+++ /dev/null
-package org.argeo.suite.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
- */
-class SuiteTerm {
- private final String name;
- private final String relativePath;
- private final SuiteTypology typology;
- private final String id;
-
- private final SuiteTerm parentTerm;
- private final List<SuiteTerm> subTerms = new ArrayList<>();
-
- SuiteTerm(SuiteTypology typology, String relativePath, SuiteTerm parentTerm) {
- this.typology = typology;
- this.parentTerm = parentTerm;
- this.relativePath = relativePath;
- int index = relativePath.lastIndexOf('/');
- if (index > 0) {
- this.name = relativePath.substring(index);
- } else {
- this.name = relativePath;
- }
- id = typology.getName() + '/' + relativePath;
- }
-
- public String getName() {
- return name;
- }
-
- public String getRelativePath() {
- return relativePath;
- }
-
- SuiteTypology getTypology() {
- return typology;
- }
-
- public String getId() {
- return id;
- }
-
- List<SuiteTerm> getSubTerms() {
- return subTerms;
- }
-
- SuiteTerm getParentTerm() {
- return parentTerm;
- }
-
-}
+++ /dev/null
-package org.argeo.suite.core;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.NodeConstants;
-import org.argeo.api.NodeUtils;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.entity.TermsManager;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-
-/** Argeo Suite implementation of terms manager. */
-public class SuiteTermsManager implements TermsManager {
- private final Map<String, SuiteTerm> terms = new HashMap<>();
- private final Map<String, SuiteTypology> typologies = new HashMap<>();
-
- // JCR
- private Repository repository;
- private Session adminSession;
-
- public void init() {
- adminSession = NodeUtils.openDataAdminSession(repository, NodeConstants.SYS_WORKSPACE);
- }
-
- @Override
- public List<String> listAllTerms(String typology) {
- List<String> res = new ArrayList<>();
- SuiteTypology t = getTypology(typology);
- for (SuiteTerm term : t.getAllTerms()) {
- res.add(term.getId());
- }
- return res;
- }
-
- SuiteTypology getTypology(String typology) {
- SuiteTypology t = typologies.get(typology);
- if (t == null) {
- Node termsNode = Jcr.getNode(adminSession, "SELECT * FROM [{0}] WHERE NAME()=\"{1}\"",
- EntityType.terms.get(), typology);
- if (termsNode == null)
- throw new IllegalArgumentException("Typology " + typology + " not found.");
- t = loadTypology(termsNode);
- }
- return t;
- }
-
- SuiteTypology loadTypology(Node termsNode) {
- try {
- SuiteTypology typology = new SuiteTypology(termsNode);
- for (Node termNode : Jcr.iterate(termsNode.getNodes())) {
- if (termNode.isNodeType(EntityType.term.get())) {
- SuiteTerm term = loadTerm(typology, termNode, null);
- if (!term.getSubTerms().isEmpty())
- typology.markNotFlat();
- typology.getSubTerms().add(term);
- }
- }
- typologies.put(typology.getName(), typology);
- return typology;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot load typology from " + termsNode, e);
- }
- }
-
- SuiteTerm loadTerm(SuiteTypology typology, Node termNode, SuiteTerm parentTerm) throws RepositoryException {
- String name = termNode.getProperty(EntityNames.NAME).getString();
- String relativePath = parentTerm == null ? name : parentTerm.getRelativePath() + '/' + name;
- SuiteTerm term = new SuiteTerm(typology, relativePath, parentTerm);
- terms.put(term.getId(), term);
- for (Node subTermNode : Jcr.iterate(termNode.getNodes())) {
- if (termNode.isNodeType(EntityType.term.get())) {
- SuiteTerm subTerm = loadTerm(typology, subTermNode, term);
- term.getSubTerms().add(subTerm);
- }
- }
- return term;
- }
-
- public void destroy() {
- Jcr.logout(adminSession);
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
-}
+++ /dev/null
-package org.argeo.suite.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-
-import org.argeo.jcr.Jcr;
-
-/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
-class SuiteTypology {
- private final String name;
- private final Node node;
- private boolean isFlat = true;
-
- private final List<SuiteTerm> subTerms = new ArrayList<>();
-
- public SuiteTypology(Node node) {
- this.node = node;
- this.name = Jcr.getName(this.node);
- }
-
- public String getName() {
- return name;
- }
-
- public Node getNode() {
- return node;
- }
-
- void markNotFlat() {
- if (isFlat)
- isFlat = false;
- }
-
- public boolean isFlat() {
- return isFlat;
- }
-
- public List<SuiteTerm> getSubTerms() {
- return subTerms;
- }
-
- public List<SuiteTerm> getAllTerms() {
- if (isFlat)
- return subTerms;
- else {
- List<SuiteTerm> terms = new ArrayList<>();
- for (SuiteTerm subTerm : subTerms) {
- terms.add(subTerm);
- collectSubTerms(terms, subTerm);
- }
- return terms;
- }
- }
-
- private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
- for (SuiteTerm subTerm : term.getSubTerms()) {
- terms.add(subTerm);
- collectSubTerms(terms, subTerm);
- }
- }
-
-}
+++ /dev/null
-package org.argeo.suite.library;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.argeo.util.DigestUtils;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-
-/** Parses a .docx document, trying its best to extract text and table data. */
-public class DocxExtractor {
- final static String T = "t";
- final static String TC = "tc";
- final static String TR = "tr";
- final static String TBL = "tbl";
- final static String P = "p";
- static boolean debug = false;
-
- final static String PROOF_ERR = "proofErr";
- final static String TYPE = "type";
- final static String SPELL_START = "spellStart";
- final static String SPELL_END = "spellEnd";
-
- protected List<Tbl> tables = new ArrayList<>();
- protected List<String> text = new ArrayList<>();
- protected Map<String, byte[]> media = new TreeMap<>();
- private Set<String> mediaDigests = new HashSet<>();
-
- protected void processTextItem(List<String> lines, String str) {
- lines.add(str);
- }
-
- protected boolean skipMedia(String digest) {
- return false;
- }
-
- class DocxHandler extends DefaultHandler {
-
- private StringBuilder buffer = new StringBuilder();
- private Tbl currentTbl = null;
-
- boolean inSpellErr = false;
- boolean inParagraph = false;
-
- @Override
- public void startElement(String uri, String name, String qName, Attributes attributes) throws SAXException {
- // System.out.println(localName + " " + qName + " " + uri.hashCode());
- if (P.equals(name)) {
- if (debug && currentTbl == null)
- System.out.println("# START PARA");
- inParagraph = true;
- } else if (PROOF_ERR.equals(name)) {
- String type = attributes.getValue(uri, TYPE);
- if (SPELL_START.equals(type))
- inSpellErr = true;
- else if (SPELL_END.equals(type))
- inSpellErr = false;
-
- } else if (TBL.equals(name)) {
- if (currentTbl != null) {
- Tbl childTbl = new Tbl();
- childTbl.parentTbl = currentTbl;
- currentTbl = childTbl;
- // throw new IllegalStateException("Already an active table");
- } else {
- currentTbl = new Tbl();
- }
- }
- }
-
- @Override
- public void endElement(String uri, String name, String qName) throws SAXException {
- if (name.equals(T)) {
-// if (inSpellErr) {
-// // do not reset the buffer
-// return;
-// }
-
- if (currentTbl != null) {
- currentTbl.appendText(buffer.toString());
- } else {
- String str = buffer.toString();
- // replace NO-BREAK SPACE by regular space.
- str = str.replace('\u00A0', ' ');
- str = str.strip();
- if (!"".equals(str)) {
- processTextItem(text, str);
- }
- }
- } else if (name.equals(P)) {
- if (debug && currentTbl == null)
- System.out.println("# END PARA");
- if (currentTbl != null) {
- currentTbl.currentRow.current.text.append('\n');
- } else {
-
- }
- inParagraph = false;
- } else if (name.equals(TC)) {
- if (currentTbl != null)
- currentTbl.closeColumn();
- } else if (name.equals(TR)) {
- if (currentTbl != null)
- currentTbl.closeRow();
- } else if (name.equals(TBL)) {
- if (currentTbl != null) {
- tables.add(currentTbl);
- if (currentTbl.parentTbl != null)
- currentTbl = currentTbl.parentTbl;
- else
- currentTbl = null;
- } else {
- throw new IllegalStateException("Closing a table while none was open.");
- }
- }
- // reset the buffer
- buffer.setLength(0);
- }
-
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- buffer.append(ch, start, length);
- }
-
- }
-
- public static class Tbl {
- Tbl parentTbl = null;
- Tr currentRow = new Tr();
- List<Tr> rows = new ArrayList<>();
-
- void appendText(String str) {
- currentRow.current.text.append(str);
- }
-
- void closeColumn() {
- currentRow.columns.add(currentRow.current);
- currentRow.current = new Tc();
- }
-
- void closeRow() {
- rows.add(currentRow);
- currentRow = new Tr();
- }
-
- public List<Tr> getRows() {
- return rows;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- for (Tr tr : rows) {
- String txt = tr.toString();
- sb.append(txt).append('\n');
- }
- return sb.toString();
- }
- }
-
- public static class Tr {
- Tc current = new Tc();
- List<Tc> columns = new ArrayList<>();
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- for (Tc tc : columns) {
- sb.append("\"").append(tc.toString()).append("\"").append(',');
- }
- return sb.toString();
- }
-
- public List<Tc> getColumns() {
- return columns;
- }
-
- }
-
- public static class Tc {
- StringBuilder text = new StringBuilder();
-
- @Override
- public String toString() {
- return text.toString().trim();
- }
-
- }
-
- protected void parse(Reader in) {
- try {
- SAXParserFactory spf = SAXParserFactory.newInstance();
- spf.setNamespaceAware(true);
- SAXParser saxParser = spf.newSAXParser();
- XMLReader xmlReader = saxParser.getXMLReader();
- xmlReader.setContentHandler(new DocxHandler());
- xmlReader.parse(new InputSource(in));
- } catch (ParserConfigurationException | SAXException | IOException e) {
- throw new RuntimeException("Cannot parse document", e);
- }
- }
-
- public List<String> getText() {
- return text;
- }
-
- public List<Tbl> getTables() {
- return tables;
- }
-
- public Map<String, byte[]> getMedia() {
- return media;
- }
-
- public void load(ZipInputStream zIn) {
- try {
- ZipEntry entry = null;
- while ((entry = zIn.getNextEntry()) != null) {
- if ("word/document.xml".equals(entry.getName())) {
- try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
- byte[] buffer = new byte[2048];
- int len = 0;
- while ((len = zIn.read(buffer)) > 0) {
- out.write(buffer, 0, len);
- }
- try (Reader reader = new InputStreamReader(new ByteArrayInputStream(out.toByteArray()),
- StandardCharsets.UTF_8)) {
- parse(reader);
- }
- }
- } else if (entry.getName().startsWith("word/media")) {
- String fileName = entry.getName().substring(entry.getName().lastIndexOf('/') + 1);
- int dotIndex = fileName.lastIndexOf('.');
- String ext = fileName.substring(dotIndex + 1).toLowerCase();
- // we ignore .jfif
- if ("jpeg".equals(ext))
- ext = "jpg";
- fileName = fileName.substring(0, dotIndex) + "." + ext;
- switch (ext) {
- case "png":
- case "jpg":
- case "gif":
- case "bmp":
- case "tiff":
- try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
- byte[] buffer = new byte[2048];
- int len = 0;
- while ((len = zIn.read(buffer)) > 0) {
- out.write(buffer, 0, len);
- }
- byte[] bytes = out.toByteArray();
- String digest = DigestUtils.digest(DigestUtils.MD5, bytes);
- if (skipMedia(digest))
- break;
- if (!mediaDigests.contains(digest)) {
- media.put(fileName, bytes);
- mediaDigests.add(digest);
- }
- }
- break;
- default:
- break;
- }
- } else {
- // System.out.println(entry.getName());
- }
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- // throw new IllegalArgumentException("No document.xml found");
-
- }
-
-// public static Reader extractDocumentXml(ZipInputStream zIn) throws IOException {
-// ZipEntry entry = null;
-// while ((entry = zIn.getNextEntry()) != null) {
-// if ("word/document.xml".equals(entry.getName())) {
-// try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-// byte[] buffer = new byte[2048];
-// int len = 0;
-// while ((len = zIn.read(buffer)) > 0) {
-// out.write(buffer, 0, len);
-// }
-// return new InputStreamReader(new ByteArrayInputStream(out.toByteArray()), StandardCharsets.UTF_8);
-// }
-// } else {
-// System.out.println(entry.getName());
-// }
-// }
-// throw new IllegalArgumentException("No document.xml found");
-// }
-
-// protected static ZipInputStream openAsZip(String file) throws IOException {
-// ZipInputStream zIn;
-// Path path = Paths.get(file);
-// zIn = new ZipInputStream(Files.newInputStream(path));
-// return zIn;
-// }
-
- public static void main(String[] args) throws IOException {
- if (args.length == 0)
- throw new IllegalArgumentException("Provide a file path");
- Path p = Paths.get(args[0]);
-
- DocxExtractor importer = new DocxExtractor();
- try (ZipInputStream zIn = new ZipInputStream(Files.newInputStream(p))) {
- importer.load(zIn);
- }
- // display
- System.out.println("## TEXT");
- for (int i = 0; i < importer.text.size(); i++) {
- String str = importer.text.get(i);
- System.out.println(str);
- }
-
- System.out.println("\n");
-
- for (int i = 0; i < importer.tables.size(); i++) {
- Tbl tbl = importer.tables.get(i);
- System.out.println("## TABLE " + i);
- System.out.println(tbl);
- }
-
- System.out.println("## MEDIA");
- for (String fileName : importer.media.keySet()) {
- int sizeKb = importer.media.get(fileName).length / 1024;
- System.out.println(fileName + " " + sizeKb + " kB");
- }
- }
-
-}
+++ /dev/null
-package org.argeo.suite.util;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.jackrabbit.util.ISO9075;
-
-/** Ease XPath generation for JCR requests */
-public class XPathUtils {
- private final static Log log = LogFactory.getLog(XPathUtils.class);
-
- private final static String QUERY_XPATH = "xpath";
-
- public static String descendantFrom(String parentPath) {
- if (notEmpty(parentPath)) {
- if ("/".equals(parentPath))
- parentPath = "";
- // Hardcoded dependency to Jackrabbit. Remove
- String result = "/jcr:root" + ISO9075.encodePath(parentPath);
- if (log.isTraceEnabled()) {
- String result2 = "/jcr:root" + parentPath;
- if (!result2.equals(result))
- log.warn("Encoded Path " + result2 + " --> " + result);
- }
- return result;
- } else
- return "";
- }
-
- public static String localAnd(String... conditions) {
- StringBuilder builder = new StringBuilder();
- for (String condition : conditions) {
- if (notEmpty(condition)) {
- builder.append(" ").append(condition).append(" and ");
- }
- }
- if (builder.length() > 3)
- return builder.substring(0, builder.length() - 4);
- else
- return "";
- }
-
- public static String xPathNot(String condition) {
- if (notEmpty(condition))
- return "not(" + condition + ")";
- else
- return "";
- }
-
- public static String getFreeTextConstraint(String filter) throws RepositoryException {
- StringBuilder builder = new StringBuilder();
- if (notEmpty(filter)) {
- String[] strs = filter.trim().split(" ");
- for (String token : strs) {
- builder.append("jcr:contains(.,'*" + encodeXPathStringValue(token) + "*') and ");
- }
- return builder.substring(0, builder.length() - 4);
- }
- return "";
- }
-
- public static String getPropertyContains(String propertyName, String filter) throws RepositoryException {
- if (notEmpty(filter))
- return "jcr:contains(@" + propertyName + ",'*" + encodeXPathStringValue(filter) + "*')";
- return "";
- }
-
- private final static DateFormat jcrRefFormatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'+02:00'");
-
- /**
- * @param propertyName
- * @param calendar the reference date
- * @param lowerOrGreater "<", ">" TODO validate ">="
- * @return
- * @throws RepositoryException
- */
- public static String getPropertyDateComparaison(String propertyName, Calendar cal, String lowerOrGreater)
- throws RepositoryException {
- if (cal != null) {
- String jcrDateStr = jcrRefFormatter.format(cal.getTime());
-
- // jcrDateStr = "2015-08-03T05:00:03:000Z";
- String result = "@" + propertyName + " " + lowerOrGreater + " xs:dateTime('" + jcrDateStr + "')";
- return result;
- }
- return "";
- }
-
- public static String getPropertyEquals(String propertyName, String value) {
- if (notEmpty(value))
- return "@" + propertyName + "='" + encodeXPathStringValue(value) + "'";
- return "";
- }
-
- public static String encodeXPathStringValue(String propertyValue) {
- // TODO implement safer mechanism to escape invalid characters
- // Also check why we have used this regex in ResourceSerrviceImpl l 474
- // String cleanedKey = key.replaceAll("(?:')", "''");
- String result = propertyValue.replaceAll("'", "''");
- return result;
- }
-
- public static void andAppend(StringBuilder builder, String condition) {
- if (notEmpty(condition)) {
- builder.append(condition);
- builder.append(" and ");
- }
- }
-
- public static void appendOrderByProperties(StringBuilder builder, boolean ascending, String... propertyNames) {
- if (propertyNames.length > 0) {
- builder.append(" order by ");
- for (String propName : propertyNames)
- builder.append("@").append(propName).append(", ");
- builder = builder.delete(builder.length() - 2, builder.length());
- if (ascending)
- builder.append(" ascending ");
- else
- builder.append(" descending ");
- }
- }
-
- public static void appendAndPropStringCondition(StringBuilder builder, String propertyName, String filter)
- throws RepositoryException {
- if (notEmpty(filter)) {
- andAppend(builder, getPropertyContains(propertyName, filter));
- }
- }
-
- public static void appendAndNotPropStringCondition(StringBuilder builder, String propertyName, String filter)
- throws RepositoryException {
- if (notEmpty(filter)) {
- String cond = getPropertyContains(propertyName, filter);
- builder.append(xPathNot(cond));
- builder.append(" and ");
- }
- }
-
- public static Query createQuery(Session session, String queryString) throws RepositoryException {
- QueryManager queryManager = session.getWorkspace().getQueryManager();
- // Localise JCR properties for XPATH
- queryString = localiseJcrItemNames(queryString);
- return queryManager.createQuery(queryString, QUERY_XPATH);
- }
-
- private final static String NS_JCR = "\\{http://www.jcp.org/jcr/1.0\\}";
- private final static String NS_NT = "\\{http://www.jcp.org/jcr/nt/1.0\\}";
- private final static String NS_MIX = "\\{http://www.jcp.org/jcr/mix/1.0\\}";
-
- /**
- * Replace the generic namespace with the local "jcr:", "nt:", "mix:" values. It
- * is a workaround that must be later cleaned
- */
- public static String localiseJcrItemNames(String name) {
- name = name.replaceAll(NS_JCR, "jcr:");
- name = name.replaceAll(NS_NT, "nt:");
- name = name.replaceAll(NS_MIX, "mix:");
- return name;
- }
-
- private static boolean notEmpty(String stringToTest) {
- return !(stringToTest == null || "".equals(stringToTest.trim()));
- }
-
- /** Singleton. */
- private XPathUtils() {
-
- }
-}
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.suite.theme.default</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Argeo Suite Default Theme">
- <implementation class="org.argeo.cms.ui.util.BundleCmsTheme"/>
- <service>
- <provide interface="org.argeo.cms.ui.CmsTheme"/>
- </service>
-</scr:component>
+++ /dev/null
-Service-Component:\
-OSGI-INF/cmsTheme.xml
-
-Import-Package:\
-org.argeo.cms.ui.util,\
-*
\ No newline at end of file
+++ /dev/null
-bin.includes = META-INF/,\
- icons/,\
- OSGI-INF/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.suite</groupId>
- <artifactId>argeo-suite</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.suite.theme.default</artifactId>
- <name>Suite Default Theme</name>
- <packaging>jar</packaging>
- <dependencies>
- </dependencies>
-</project>
+++ /dev/null
-.argeo-suite-header {
- color: white;
- background-color: #00294b;
-}
-
-.argeo-suite-headerTitle {
- font: bold 18px sans-serif;
- color: white;
- background-color: #00294b;
-}
-
-.argeo-suite-leadPane {
- background-color: #eee;
-}
-
-Label.argeo-suite-leadPane {
- font: 14px sans-serif;
- color: #888;
- background-color: #eee;
-}
-
-Button.argeo-suite-leadPane:hover {
- cursor:pointer;
-}
-
-.argeo-suite-recentItems {
- font: bold 14px sans-serif;
- color: white;
- background-color: #00294b;
- padding: 8px 16px;
-}
-
-.argeo-suite-titleContainer {
- background-color: #00294b;
- padding: 6px 8px 4px 8px;
-}
-
-.argeo-suite-titleLabel {
- font: bold 14px sans-serif;
- color: white;
- background-color: #00294b;
-}
-
-.argeo-suite-subTitleLabel {
- font: italic 14px sans-serif;
- color: #777;
- padding: 4px 8px;
-}
-
-.argeo-suite-simpleLabel {
- font: bold 14px sans-serif;
- padding: 0px;
-}
-
-.argeo-suite-simpleText {
- font: 14px sans-serif;
- padding: 0px;
-}
-
-.argeo-suite-titleCell {
- font: bold 14px sans-serif;
- background-color: #ddd;
-}
-
-.argeo-suite-inlineButton {
- padding: 0px 4px;
- font: 12px sans-serif;
- border: 1px solid white;
- color: white;
- background-image: none;
- background-color: #00294b;
-}
-
-.argeo-suite-inlineButton:hover {
- color: #00294b;
- background-color: white;
-}
-
-Composite.argeo-suite-mainTabBody {
- background-color: #eee;
- border: 1px solid #bbb;
-}
-
-.argeo-suite-mainTab {
- background-color: #eee;
- border: 1px solid #888;
-}
-
-ToolItem.argeo-suite-mainTab {
- border: none;
- background-color: #eee;
-}
-
-ToolItem.argeo-suite-mainTab:hover {
- background-color: #eee;
-}
-
-
-Button.argeo-suite-mainTab {
- border: 1px solid #eee;
- background-color: #eee;
-}
-
-.argeo-suite-mainTab:hover {
- background-color: #eee;
-}
-
-Button.argeo-suite-mainTab:hover {
- cursor: pointer;
- background-color: #eee;
-}
-
-.argeo-suite-mainTabSelected {
- font: bold 14px sans-serif;
- color: white;
- /*background-color: #00294b;*/
- background-color: #5882b5;
- border:1px solid #888;
-}
-
-ToolItem.argeo-suite-mainTabSelected {
- border: none;
-}
-
-ToolItem.argeo-suite-mainTabSelected:hover {
- background-color: #5882b5;
-}
-
-Button.argeo-suite-mainTabSelected {
- border: none;
-}
-
-Sash {
- border: 1px solid white;
- background-image: none;
- background-color: white;
-}
-
-Sash:hover {
- border: 1px solid #5882b5;
- background-color: #5882b5;
-}
-
-TreeItem{
- background-color:#fff;
-}
-
-Tree-RowOverlay:selected {
- color:#fff;
- background-color:#5882b5;
-}
-
-TableItem{
- background-color:#fff;
-}
-
-Table-RowOverlay:selected {
- color:#fff;
- background-color:#5882b5;
-}
-
-.argeo-suite-navigationBar{
- background-color:#ddd;
-}
-
-.argeo-suite-navigationTitle{
- background-color:#ddd;
- font:bold 14px sans-serif;
-}
-
-.argeo-suite-navigationButton{
- color:#777;
- background-color:#ddd;
- font:bold 14px sans-serif;
-}
-
-.argeo-suite-navigationButton:hover{
- cursor:pointer;
- color:#ddd;
- background-color:#777;
-}
+++ /dev/null
-.argeo-suite-header {
- color: white;
- background-color: #00294b;
-}
-
-.argeo-suite-headerTitle {
- font: bold 14px sans-serif;
- color: white;
- background-color: #00294b;
-}
-
-.argeo-suite-leadPane {
- background-color: #eee;
-}
-
-Label.argeo-suite-leadPane {
- font: 11px sans-serif;
- color: #888;
- background-color: #eee;
-}
-
-Button.argeo-suite-leadPane:hover {
- cursor: pointer;
-}
-
-.argeo-suite-recentItems {
- font: bold 13px sans-serif;
- color: white;
- background-color: #00294b;
- padding: 8px 16px;
-}
-
-.argeo-suite-titleContainer {
- background-color: #00294b;
-}
-
-.argeo-suite-titleLabel {
- font: bold 13px sans-serif;
- margin: 6px 8px 4px 8px;
- color: white;
- background-color: #00294b;
-}
-
-.argeo-suite-subTitleLabel {
- font: italic 14px sans-serif;
- color: #777;
- margin: 4px 8px;
-}
-
-.argeo-suite-formLine {
- padding: 4px 8px 4px 16px;
-}
-
-.argeo-suite-simpleLabel {
- font: normal 11px sans-serif;
- border: 8px solid #eee;
-}
-
-.argeo-suite-simpleText {
-
-}
-
-.argeo-suite-simpleInput {
- padding: 4px 8px 4px 8px;
-}
-
-.argeo-suite-titleCell {
- font: bold 11px sans-serif;
- background-color: #ddd;
-}
-
-.argeo-suite-inlineButton {
- padding: 0px 4px;
- font: 12px sans-serif;
- border: 1px solid white;
- color: white;
- background-image: none;
- background-color: #00294b;
-}
-
-.argeo-suite-inlineButton:hover {
- color: #00294b;
- background-color: white;
-}
-
-Composite.argeo-suite-mainTabBody {
- background-color: #eee;
- border: 1px solid #bbb;
-}
-
-.argeo-suite-mainTab {
- background-color: #eee;
- border: 1px solid #bbb;
-}
-
-ToolItem.argeo-suite-mainTab {
- border: none;
- background-color: #eee;
-}
-
-Button.argeo-suite-mainTab {
- border: none;
- background-color: #eee;
-}
-
-.argeo-suite-mainTab:hover {
- background-color: #eee;
-}
-
-Button.argeo-suite-mainTab:hover {
- cursor: pointer;
- background-color: #eee;
-}
-
-.argeo-suite-mainTabSelected {
- font: bold 14px sans-serif;
- color: white;
- /*background-color: #00294b;*/
- background-color: #5882b5;
- border: 1px solid #00294b;
-}
-
-ToolItem.argeo-suite-mainTabSelected {
- border: none;
-}
-
-Button.argeo-suite-mainTabSelected {
- border: none;
-}
\ No newline at end of file
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.suite.ui.rap</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Argeo Suite Web App">
- <implementation class="org.argeo.cms.web.CmsWebApp"/>
- <property name="contextName" type="String" value="argeo"/>
- <reference bind="setCmsApp" cardinality="1..1" interface="org.argeo.cms.ui.CmsApp" name="CmsApp" policy="dynamic" target="(service.pid=argeo.suite.ui.app)" unbind="unsetCmsApp"/>
- <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
-</scr:component>
+++ /dev/null
-Service-Component: OSGI-INF/cmsWebApp.xml
-
-Import-Package:\
-org.argeo.cms.web,\
-org.eclipse.rap.rwt.application,\
-*
+++ /dev/null
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- OSGI-INF/
-source.. = src/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.suite</groupId>
- <artifactId>argeo-suite</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.suite.ui.rap</artifactId>
- <name>Suite UI RAP</name>
- <packaging>jar</packaging>
- <dependencies>
- <dependency>
- <groupId>org.argeo.suite</groupId>
- <artifactId>org.argeo.suite.ui</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- </dependency>
-
- <!-- Eclipse E4 -->
- <dependency>
- <groupId>org.argeo.tp</groupId>
- <artifactId>argeo-tp-rap-e4</artifactId>
- <version>${version.argeo-tp}</version>
- <type>pom</type>
- <scope>provided</scope>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.suite.ui</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Argeo Suite App">
- <implementation class="org.argeo.suite.ui.SuiteApp"/>
- <service>
- <provide interface="org.argeo.cms.ui.CmsApp"/>
- <provide interface="org.osgi.service.event.EventHandler"/>
- </service>
- <properties entry="config/cmsApp.properties"/>
- <reference bind="addUiProvider" cardinality="0..n" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" unbind="removeUiProvider"/>
- <reference bind="addTheme" cardinality="1..n" interface="org.argeo.cms.ui.CmsTheme" name="CmsTheme" policy="dynamic" unbind="removeTheme"/>
- <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="dynamic" target="(cn=ego)"/>
- <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
- <reference bind="setCmsUserManager" cardinality="1..1" interface="org.argeo.cms.CmsUserManager" name="CmsUserManager" policy="static"/>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default Dashboard">
- <implementation class="org.argeo.suite.ui.DefaultDashboard"/>
- <service>
- <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
- </service>
- <properties entry="config/dashboard.properties"/>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Dashboard Layer">
- <implementation class="org.argeo.suite.ui.DefaultEditionLayer"/>
- <service>
- <provide interface="org.argeo.suite.ui.SuiteLayer"/>
- </service>
- <properties entry="config/dashboardLayer.properties"/>
- <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.suite.ui.recentItems)"/>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Work Header">
- <implementation class="org.argeo.suite.ui.DefaultHeader"/>
- <service>
- <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
- <provide interface="org.osgi.service.cm.ManagedService"/>
- </service>
- <properties entry="config/header.properties"/>
-</scr:component>
+++ /dev/null
-dashboard=dashboard
-people=contacts
-documents=documents
-locations=locations
-recentItems=recent items
-
-appTitle=Argeo Suite
-
-#
-# PEOPLE
-# org.argeo.people.ui.PeopleMsg
-#
-person=Person
-organisation=Organisation
-
-# NewPersonWizard
-firstName=First Name
-lastName=Last Name
-salutation=Salutation
-email=Email
-personWizardWindowTitle=New person
-personWizardPageTitle=Create a contact
-
-# NewOrgWizard
-legalName=Legal name
-legalForm=Legal form
-vatId=VAT ID
-orgWizardWindowTitle=New organisation
-orgWizardPageTitle=Create an organisation
-
-
-# ContextAddressComposite
-chooseAnOrganisation=Choose an organisation
-street=Street
-streetComplement=Street complement
-zipCode=Zip code
-city=City
-state=State
-country=Country
-geopoint=Geopoint
-
-# FilteredOrderableEntityTable
-filterHelp=Type filter criterion separated by a space
-
-# BankAccountComposite
-accountHolder=Account holder
-bankName=Bank name
-currency=Currency
-accountNumber=Account number
-bankNumber=Bank number
-BIC=BIC
-IBAN=IBAN
-
-# EditJobDialog
-position=Role
-chosenItem=Chose item
-department=Department
-isPrimary=Is primary
-searchAndChooseEntity=Search and choose a corresponding entity
-
-# ContactListCTab (e4)
-notes=Notes
-addAContact=Add a contact
-contactValue=Contact value
-linkedCompany=Linked company
-
-# OrgAdminInfoCTab (e4)
-paymentAccount=Payment account
-
-# OrgEditor (e4)
-orgDetails=Details
-orgActivityLog=Activity log
-team=Team
-orgAdmin=Admin.
-
-# PersonEditor (e4)
-personDetails=Contact details
-personActivityLog=Activity log
-personOrgs=Organisations
-personSecurity=Security
-
-# PersonSecurityCTab (e4)
-resetPassword=Reset password
-
-# Generic
-label=Label
-aCustomLabel=A custom label
-description=Description
-value=Value
-name=Name
-primary=Primary
-add=Add
-save=Save
-pickUp=Pick up
-
-# Tags
-confirmNewTag=Tag #{0} is not yet registered. Are you sure you want to create it?
-cannotCreateTag=Tag #{0} is not yet registered and you don't have enough rights to create it.
+++ /dev/null
-dashboard=dashboard
-people=Kontakte
-documents=Dokumente
-locations=Orte
-recentItems=neulich
-
-appTitle=Argeo Suite
-
-#
-# PEOPLE
-# org.argeo.people.ui.PeopleMsg
-#
-person=Person
-organisation=Organisation
-
-# NewPersonWizard
-firstName=Vorname
-lastName=Nachname
-salutation=Salutation
-email=E-Mail
-personWizardWindowTitle=Neue Person
-personWizardPageTitle=Kontakt erstellen
-
-# NewOrgWizard
-legalName=Name
-legalForm=Geschäftsform
-vatId=Ust ID
-orgWizardWindowTitle=Neue Organisation
-orgWizardPageTitle=Organisation erstellen
-
-
-# ContextAddressComposite
-chooseAnOrganisation=Organisation wählen
-street=Strasse
-streetComplement=Strasse Zusatz
-zipCode=PLZ
-city=Stadt
-state=Bundesland
-country=Land
-geopoint=Geopoint
-
-# FilteredOrderableEntityTable
-filterHelp=Type filter criterion separated by a space
-
-# BankAccountComposite
-accountHolder=Kontoinhaber
-bankName=Name der Bank
-currency=Währung
-accountNumber=Kontonummer
-bankNumber=BLZ
-BIC=BIC
-IBAN=IBAN
-
-# EditJobDialog
-position=Rolle
-chosenItem=Auswahl
-department=Abteilung
-isPrimary=Ist Primär
-searchAndChooseEntity=Suche und wähle ein zugehöriges Objekt
-
-# ContactListCTab (e4)
-notes=Bemerkungen
-addAContact=Kontakt hinzufügen
-contactValue=Kontakt value
-linkedCompany=zugehörige Firma
-
-# OrgAdminInfoCTab (e4)
-paymentAccount=Geschäftskonto
-
-# OrgEditor (e4)
-orgDetails=Details
-orgActivityLog=Aktivitäten Log
-team=Team
-orgAdmin=Admin.
-
-# PersonEditor (e4)
-personDetails=Kontakt Daten
-personActivityLog=Aktivitäten Log
-personOrgs=Organisationen
-personSecurity=Sicherheit
-
-# PersonSecurityCTab (e4)
-resetPassword=Passwort zurücksetzen
-
-# Generic
-label=Beschriftung
-aCustomLabel=Eine spezifische Beschriftung
-description=Beschreibung
-value=Wert
-name=Name
-primary=Haupt-
-add=Hinzufügen
-save=Speichern
-pickUp=Aussuchen
-
-# Tags
-confirmNewTag=Das Hashtag '{0}' existiert noch nicht. WollenSie es hinzufügen?
-cannotCreateTag=Das Hashtag '{0}' existiert nicht uns Sie haben nicht die Rechte, um es hinzufügen.
+++ /dev/null
-dashboard=dashboard
-people=contacts
-documents=documents
-locations=lieux
-recentItems=récent
-
-appTitle=Argeo Suite
-
-#
-# GENERIC
-#
-
-#
-# PEOPLE
-# org.argeo.people.ui.PeopleMsg
-#
-person=Personne
-organisation=Organisation
-
-# NewPersonWizard
-firstName=Prénom
-lastName=Nom
-salutation=Salutation
-email=Email
-personWizardWindowTitle=Nouvelle personne
-personWizardPageTitle=Créer un contact
-
-# NewOrgWizard
-legalName=Nom
-legalForm=Forme légale
-vatId=ID TVA
-orgWizardWindowTitle=Nouvelle organisation
-orgWizardPageTitle=Créer une organisation
-
-
-# ContextAddressComposite
-chooseAnOrganisation=Choisir une organisation
-street=Rue
-streetComplement=Complément rue
-zipCode=Code postal
-city=Ville
-state=État
-country=Pays
-geopoint=Géocoordonnées
-
-# FilteredOrderableEntityTable
-filterHelp=Sasir les critères de filtrage séparés par des espaces
-
-# BankAccountComposite
-accountHolder=Propriétaire du compte
-bankName=Nom de la banque
-currency=Devise
-accountNumber=Numéro de compte
-bankNumber=Numéro de banque
-BIC=BIC
-IBAN=IBAN
-
-# EditJobDialog
-position=Rôle
-chosenItem=Choisir une élément
-department=Service
-isPrimary=Principal
-searchAndChooseEntity=Cherhcer et choisir l'entitée correspondante
-
-# ContactListCTab (e4)
-notes=Notes
-addAContact=Ajouter un contact
-contactValue=Valeur
-linkedCompany=Entreprise liée
-
-# OrgAdminInfoCTab (e4)
-paymentAccount=Compte de paiement
-
-# OrgEditor (e4)
-orgDetails=Détails
-orgActivityLog=Activités
-team=Équipe
-orgAdmin=Admin.
-
-# PersonEditor (e4)
-personDetails=Détails du contact
-personActivityLog=Activités
-personOrgs=Organisations
-personSecurity=Accès
-
-# PersonSecurityCTab (e4)
-resetPassword=Force le mot de passe
-
-# Generic
-label=Étiquette
-aCustomLabel=Une étiquette spécifique
-description=Description
-value=Valeur
-name=Nom
-primary=Principal
-add=Ajouter
-save=Sauver
-pickUp=Choisir
-
-# Tags
-confirmNewTag=Le tag #{0} n'existe pas encore. Voulez-vous le créer?
-cannotCreateTag=Le tag #{0} n'existe pas encore et vous n'avez pas les droits pour le créer.
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Lead Pane">
- <implementation class="org.argeo.suite.ui.DefaultLeadPane"/>
- <service>
- <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
- </service>
- <properties entry="config/leadPane.properties"/>
- <property name="defaultLayers" type="String">argeo.suite.ui.dashboardLayer
-argeo.documents.ui.documentsLayer
- </property>
- <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default Login Screen">
- <implementation class="org.argeo.suite.ui.DefaultLoginScreen"/>
- <properties entry="config/loginScreen.properties"/>
- <service>
- <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
- </service>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" name="Default Recent Items">
- <implementation class="org.argeo.suite.ui.RecentItems"/>
- <service>
- <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
- </service>
- <properties entry="config/recentItems.properties"/>
-</scr:component>
+++ /dev/null
-Service-Component:\
-OSGI-INF/cmsApp.xml,\
-OSGI-INF/header.xml,\
-OSGI-INF/leadPane.xml,\
-OSGI-INF/loginScreen.xml,\
-OSGI-INF/recentItems.xml,\
-OSGI-INF/dashboard.xml,\
-OSGI-INF/dashboardLayer.xml
-
-Import-Package:\
-org.argeo.api,\
-org.eclipse.swt,\
-org.osgi.framework,\
-org.argeo.entity,\
-org.eclipse.core.commands.common,\
-org.eclipse.jface.window,\
-org.eclipse.jface.dialogs,\
-*
+++ /dev/null
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- OSGI-INF/,\
- config/,\
- OSGI-INF/loginScreen.xml,\
- OSGI-INF/dashboard.xml,\
- OSGI-INF/recentItems.xml,\
- OSGI-INF/dashboardLayer.xml
-source.. = src/
+++ /dev/null
-service.pid=argeo.suite.ui.app
-
-event.topics=argeo/suite/*
\ No newline at end of file
+++ /dev/null
-service.pid=argeo.suite.ui.dashboard
+++ /dev/null
-service.pid=argeo.suite.ui.dashboardLayer
-
-title=Dashboard
-icon=dashboard
\ No newline at end of file
+++ /dev/null
-service.pid=argeo.suite.ui.header
-argeo.suite.ui=true
-
-argeo.suite.ui.header.title=%appTitle
\ No newline at end of file
+++ /dev/null
-service.pid=argeo.suite.ui.leadPane
+++ /dev/null
-service.pid=argeo.suite.ui.loginScreen
+++ /dev/null
-service.pid=argeo.suite.ui.recentItems
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.suite</groupId>
- <artifactId>argeo-suite</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.suite.ui</artifactId>
- <name>Suite UI</name>
- <packaging>jar</packaging>
- <dependencies>
- <dependency>
- <groupId>org.argeo.suite</groupId>
- <artifactId>org.argeo.suite.core</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.argeo.suite</groupId>
- <artifactId>org.argeo.entity.ui</artifactId>
- <version>2.1.18-SNAPSHOT</version>
- </dependency>
-
- <!-- Argeo Commons -->
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.eclipse.ui</artifactId>
- <version>${version.argeo-commons}</version>
- </dependency>
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.eclipse.ui.rap</artifactId>
- <version>${version.argeo-commons}</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Eclipse E4 -->
- <dependency>
- <groupId>org.argeo.tp</groupId>
- <artifactId>argeo-tp-rap-e4</artifactId>
- <version>${version.argeo-tp}</version>
- <type>pom</type>
- <scope>provided</scope>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-package org.argeo.suite.ui;
-
-import java.util.Set;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.dialogs.CmsWizardDialog;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.Selected;
-import org.argeo.naming.LdapAttrs;
-import org.argeo.suite.SuiteRole;
-import org.argeo.suite.ui.dialogs.NewUserWizard;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.window.Window;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-import org.osgi.service.useradmin.User;
-
-/** Entry to the admin area. */
-public class AdminEntryArea implements CmsUiProvider {
-
- private CmsUserManager cmsUserManager;
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- CmsTheme theme = CmsTheme.getCmsTheme(parent);
- parent.setLayout(new GridLayout());
- TableViewer usersViewer = new TableViewer(parent);
- usersViewer.setContentProvider(new UsersContentProvider());
-
- TableViewerColumn idCol = new TableViewerColumn(usersViewer, SWT.NONE);
- idCol.getColumn().setWidth(70);
- idCol.setLabelProvider(new ColumnLabelProvider() {
-
- @Override
- public String getText(Object element) {
-
- return getUserProperty(element, LdapAttrs.uid.name());
- }
- });
-
- TableViewerColumn givenNameCol = new TableViewerColumn(usersViewer, SWT.NONE);
- givenNameCol.getColumn().setWidth(150);
- givenNameCol.setLabelProvider(new ColumnLabelProvider() {
-
- @Override
- public String getText(Object element) {
-
- return getUserProperty(element, LdapAttrs.givenName.name());
- }
- });
-
- TableViewerColumn snCol = new TableViewerColumn(usersViewer, SWT.NONE);
- snCol.getColumn().setWidth(150);
- snCol.setLabelProvider(new ColumnLabelProvider() {
-
- @Override
- public String getText(Object element) {
-
- return getUserProperty(element, LdapAttrs.sn.name());
- }
- });
-
- TableViewerColumn mailCol = new TableViewerColumn(usersViewer, SWT.NONE);
- mailCol.getColumn().setWidth(400);
- mailCol.setLabelProvider(new ColumnLabelProvider() {
-
- @Override
- public String getText(Object element) {
-
- return getUserProperty(element, LdapAttrs.mail.name());
- }
- });
-
- Composite bottom = new Composite(parent, SWT.NONE);
- bottom.setLayoutData(CmsUiUtils.fillWidth());
- bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
- ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
- bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
- ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
- deleteItem.setEnabled(false);
-// CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
- deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
- ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
- addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
- usersViewer.addDoubleClickListener(new IDoubleClickListener() {
-
- @Override
- public void doubleClick(DoubleClickEvent event) {
- User user = (User) usersViewer.getStructuredSelection().getFirstElement();
- if (user != null) {
-// Node userNode = getOrCreateUserNode(user, context);
- CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
- SuiteEvent.eventProperties(user));
- }
-
- }
- });
- usersViewer.addSelectionChangedListener(new ISelectionChangedListener() {
- public void selectionChanged(SelectionChangedEvent event) {
- User user = (User) usersViewer.getStructuredSelection().getFirstElement();
- if (user != null) {
-// Node userNode = getOrCreateUserNode(user, context);
- CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
- SuiteEvent.eventProperties(user));
- deleteItem.setEnabled(true);
- } else {
- deleteItem.setEnabled(false);
- }
- }
- });
-
- addItem.addSelectionListener((Selected) (e) -> {
- // SuiteUtils.getOrCreateUserNode(adminSession, userDn);
- Wizard wizard = new NewUserWizard(null);
- CmsWizardDialog dialog = new CmsWizardDialog(parent.getShell(), wizard);
- // WizardDialog dialog = new WizardDialog(shell, wizard);
- if (dialog.open() == Window.OK) {
- // TODO create
- }
- });
-
- usersViewer.getTable().setLayoutData(CmsUiUtils.fillAll());
- usersViewer.setInput(cmsUserManager);
-
- return usersViewer.getTable();
- }
-
-// private Node getOrCreateUserNode(User user, Node context) {
-// return JcrUtils.mkdirs(Jcr.getSession(context),
-// "/" + EntityType.user.name() + "/" + getUserProperty(user, LdapAttrs.uid.name()),
-// EntityType.user.get());
-// }
-
- private String getUserProperty(Object element, String key) {
- Object value = ((User) element).getProperties().get(key);
- return value != null ? value.toString() : null;
- }
-
- class UsersContentProvider implements IStructuredContentProvider {
-
- @Override
- public Object[] getElements(Object inputElement) {
- CmsUserManager cum = (CmsUserManager) inputElement;
- Set<User> users = cum.listUsersInGroup(SuiteRole.coworker.dn(), null);
- return users.toArray();
- }
-
- @Override
- public void dispose() {
- }
-
- @Override
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
-
- }
-
- public void setCmsUserManager(CmsUserManager cmsUserManager) {
- this.cmsUserManager = cmsUserManager;
- }
-
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** Provides a dashboard. */
-public class DefaultDashboard implements CmsUiProvider {
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- parent.setLayout(new GridLayout());
- CmsView cmsView = CmsView.getCmsView(parent);
- if (cmsView.isAnonymous())
- throw new IllegalStateException("No user is not logged in");
-
- Label lbl = new Label(parent, SWT.NONE);
- lbl.setText("Welcome " + CurrentUser.getDisplayName() + "!");
-
- return lbl;
- }
-
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.widgets.TabbedArea;
-import org.argeo.util.LangUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** An app layer based on an entry area and an editor area. */
-public class DefaultEditionLayer implements SuiteLayer {
- private CmsUiProvider entryArea;
- private CmsUiProvider workArea;
- private List<String> weights = new ArrayList<>();
- private boolean startMaximized = false;
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- if (entryArea != null) {
- SashFormEditionArea sashFormEditionArea = new SashFormEditionArea(parent, parent.getStyle());
- entryArea.createUi(sashFormEditionArea.getEntryArea(), context);
- if (this.workArea != null) {
- this.workArea.createUi(sashFormEditionArea.getEditorArea(), context);
- }
- return sashFormEditionArea;
- } else {
- if (this.workArea != null) {
- Composite area = new Composite(parent, SWT.NONE);
- this.workArea.createUi(area, context);
- return area;
- }
- CmsTheme theme = CmsTheme.getCmsTheme(parent);
- TabbedArea tabbedArea = createTabbedArea(parent, theme);
- return tabbedArea;
- }
- }
-
- @Override
- public void view(CmsUiProvider uiProvider, Composite workArea, Node context) {
- TabbedArea tabbedArea;
- if (workArea instanceof SashFormEditionArea) {
- tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
- } else if (workArea instanceof TabbedArea) {
- tabbedArea = (TabbedArea) workArea;
- } else
- throw new IllegalArgumentException("Unsupported work area " + workArea.getClass().getName());
- tabbedArea.view(uiProvider, context);
- }
-
- @Override
- public void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
- TabbedArea tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
- tabbedArea.open(uiProvider, context);
- }
-
- public void init(Map<String, Object> properties) {
- weights = LangUtils.toStringList(properties.get(Property.weights.name()));
- startMaximized = properties.containsKey(Property.startMaximized.name())
- && "true".equals(properties.get(Property.startMaximized.name()));
- }
-
- public void setEntryArea(CmsUiProvider entryArea) {
- this.entryArea = entryArea;
- }
-
- public void setWorkArea(CmsUiProvider workArea) {
- this.workArea = workArea;
- }
-
- TabbedArea createTabbedArea(Composite parent, CmsTheme theme) {
- TabbedArea tabbedArea = new TabbedArea(parent, SWT.NONE);
- tabbedArea.setBodyStyle(SuiteStyle.mainTabBody.style());
- tabbedArea.setTabStyle(SuiteStyle.mainTab.style());
- tabbedArea.setTabSelectedStyle(SuiteStyle.mainTabSelected.style());
- tabbedArea.setCloseIcon(SuiteIcon.close.getSmallIcon(theme));
- tabbedArea.setLayoutData(CmsUiUtils.fillAll());
- return tabbedArea;
- }
-
- /** A work area based on an entry area and and a tabbed area. */
- class SashFormEditionArea extends SashForm {
- private static final long serialVersionUID = 2219125778722702618L;
- private CmsTheme theme;
- private Composite entryArea;
- private Composite editorArea;
- private TabbedArea tabbedArea;
-
- SashFormEditionArea(Composite parent, int style) {
- super(parent, SWT.HORIZONTAL);
- theme = CmsTheme.getCmsTheme(parent);
-
- if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
- editorArea = new Composite(this, SWT.BORDER);
- entryArea = new Composite(this, SWT.BORDER);
- } else {
- entryArea = new Composite(this, SWT.NONE);
- editorArea = new Composite(this, SWT.NONE);
- }
-
- if (weights.size() != 0) {
- int[] actualWeight = new int[weights.size()];
- for (int i = 0; i < weights.size(); i++) {
- actualWeight[i] = Integer.parseInt(weights.get(i));
- }
- setWeights(actualWeight);
- } else {
- int[] actualWeights = new int[] { 3000, 7000 };
- setWeights(actualWeights);
- }
- if (startMaximized)
- setMaximizedControl(editorArea);
- editorArea.setLayout(new GridLayout());
-
- if (DefaultEditionLayer.this.workArea == null) {
- tabbedArea = createTabbedArea(editorArea, theme);
- }
-
- }
-
- Composite getEntryArea() {
- return entryArea;
- }
-
- TabbedArea getTabbedArea() {
- return tabbedArea;
- }
-
- Composite getEditorArea() {
- return editorArea;
- }
-
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.suite.ui;
-
-import java.util.Dictionary;
-import java.util.Map;
-import java.util.TreeMap;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.util.LangUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-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.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
-
-public class DefaultHeader implements CmsUiProvider, ManagedService {
- public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title";
- private Map<String, String> properties;
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- CmsView cmsView = CmsView.getCmsView(parent);
- CmsTheme theme = CmsTheme.getCmsTheme(parent);
-
- parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, true)));
-
- // TODO right to left
- Composite lead = new Composite(parent, SWT.NONE);
- CmsUiUtils.style(lead, SuiteStyle.header);
- lead.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false));
- lead.setLayout(new GridLayout());
- Label lbl = new Label(lead, SWT.NONE);
- String title = properties.get(TITLE_PROPERTY);
- lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString()
- : title);
- CmsUiUtils.style(lbl, SuiteStyle.headerTitle);
- lbl.setLayoutData(CmsUiUtils.fillWidth());
-
- Composite middle = new Composite(parent, SWT.NONE);
- CmsUiUtils.style(middle, SuiteStyle.header);
- middle.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
- middle.setLayout(new GridLayout());
-
- Composite end = new Composite(parent, SWT.NONE);
- CmsUiUtils.style(end, SuiteStyle.header);
- end.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, false));
-
- if (!cmsView.isAnonymous()) {
- end.setLayout(new GridLayout(2, false));
- Label userL = new Label(end, SWT.NONE);
- CmsUiUtils.style(userL, SuiteStyle.header);
- userL.setText(CurrentUser.getDisplayName());
- Button logoutB = new Button(end, SWT.FLAT);
-// CmsUiUtils.style(logoutB, SuiteStyle.header);
- logoutB.setImage(SuiteIcon.logout.getSmallIcon(theme));
- logoutB.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = 7116760083964201233L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- cmsView.logout();
- }
-
- });
- } else {
- end.setLayout(new GridLayout(1, false));
- // required in order to avoid wrong height after logout
- new Label(end, SWT.NONE).setText("");
-
- }
- return lbl;
- }
-
- public void init(Map<String, String> properties) {
- this.properties = new TreeMap<>(properties);
- }
-
- @Override
- public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
- if (properties != null)
- this.properties.putAll(LangUtils.dictToStringMap(properties));
- }
-
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-import java.util.TreeMap;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.Localized;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.suite.RankedObject;
-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.osgi.framework.Constants;
-
-/** Side pane listing various perspectives. */
-public class DefaultLeadPane implements CmsUiProvider {
- private final static Log log = LogFactory.getLog(DefaultLeadPane.class);
-
- public static enum Property {
- defaultLayers, adminLayers;
- }
-
- private Map<String, RankedObject<SuiteLayer>> layers = Collections.synchronizedSortedMap(new TreeMap<>());
- private String[] defaultLayers;
- private String[] adminLayers;
-
- @Override
- public Control createUi(Composite parent, Node node) throws RepositoryException {
- CmsView cmsView = CmsView.getCmsView(parent);
- GridLayout layout = new GridLayout();
- layout.verticalSpacing = 10;
- layout.marginTop = 10;
- layout.marginLeft = 10;
- layout.marginRight = 10;
- parent.setLayout(layout);
-
- Button first = null;
- for (String layerId : defaultLayers) {
- if (layers.containsKey(layerId)) {
- RankedObject<SuiteLayer> layerObj = layers.get(layerId);
-
- // TODO deal with i10n
- String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
- Localized title = null;
- if (titleStr != null)
- title = new Localized.Untranslated(titleStr);
-
- String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
- SuiteIcon icon = null;
- if (iconName != null)
- icon = SuiteIcon.valueOf(iconName);
-
- Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon);
- if (first == null)
- first = b;
- }
- }
-
- // TODO factorise
- boolean isAdmin = cmsView.doAs(() -> CurrentUser.isInRole(NodeConstants.ROLE_USER_ADMIN));
- if (isAdmin && adminLayers != null)
- for (String layerId : adminLayers) {
- if (layers.containsKey(layerId)) {
- RankedObject<SuiteLayer> layerObj = layers.get(layerId);
-
- // TODO deal with i10n
- String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
- Localized title = null;
- if (titleStr != null)
- title = new Localized.Untranslated(titleStr);
-
- String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
- SuiteIcon icon = null;
- if (iconName != null)
- icon = SuiteIcon.valueOf(iconName);
-
- Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon);
- if (first == null)
- first = b;
- }
- }
-
-// Button dashboardB = createButton(parent, SuiteMsg.dashboard.name(), SuiteMsg.dashboard, SuiteIcon.dashboard);
- if (!cmsView.isAnonymous()) {
-// createButton(parent, SuiteMsg.documents.name(), SuiteMsg.documents, SuiteIcon.documents);
-// createButton(parent, SuiteMsg.people.name(), SuiteMsg.people, SuiteIcon.people);
-// createButton(parent, SuiteMsg.locations.name(), SuiteMsg.locations, SuiteIcon.location);
- }
- return first;
- }
-
- public void init(Map<String, Object> properties) {
- defaultLayers = (String[]) properties.get(Property.defaultLayers.toString());
- if (defaultLayers == null)
- throw new IllegalArgumentException("Default layers must be set.");
- if (log.isDebugEnabled())
- log.debug("Default layers: " + Arrays.asList(defaultLayers));
- adminLayers = (String[]) properties.get(Property.adminLayers.toString());
- if (log.isDebugEnabled() && adminLayers != null)
- log.debug("Admin layers: " + Arrays.asList(adminLayers));
- }
-
- public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
- if (properties.containsKey(Constants.SERVICE_PID)) {
- String pid = (String) properties.get(Constants.SERVICE_PID);
- RankedObject.putIfHigherRank(layers, pid, layer, properties);
- }
- }
-
- public void removeLayer(SuiteLayer layer, Map<String, Object> properties) {
- if (properties.containsKey(Constants.SERVICE_PID)) {
- String pid = (String) properties.get(Constants.SERVICE_PID);
- if (layers.containsKey(pid)) {
- if (layers.get(pid).equals(new RankedObject<SuiteLayer>(layer, properties))) {
- layers.remove(pid);
- }
- }
- }
- }
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.widgets.auth.CmsLogin;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Provides a login screen. */
-public class DefaultLoginScreen implements CmsUiProvider {
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- CmsView cmsView = CmsView.getCmsView(parent);
- if (!cmsView.isAnonymous())
- throw new IllegalStateException(CurrentUser.getUsername() + " is already logged in");
-
- parent.setLayout(new GridLayout());
- Composite loginArea = new Composite(parent, SWT.NONE);
- loginArea.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
-
- CmsLogin cmsLogin = new CmsLogin(cmsView);
- cmsLogin.createUi(loginArea);
- return cmsLogin.getCredentialsBlock();
- }
-
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.EventListener;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.suite.ui.widgets.DelayedText;
-import org.argeo.suite.util.XPathUtils;
-import org.eclipse.jface.layout.TableColumnLayout;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ColumnWeightData;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** List recent items. */
-public class RecentItems implements CmsUiProvider {
- private final static int SEARCH_TEXT_DELAY = 800;
- private final static int SEARCH_DEFAULT_LIMIT = 100;
-
- private CmsTheme theme;
-
- private String entityType;
-
- static enum Property {
- entityTypes;
- }
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- theme = CmsTheme.getCmsTheme(parent);
- parent.setLayout(new GridLayout());
-// parent.setLayout(CmsUiUtils.noSpaceGridLayout());
- parent.setLayout(new GridLayout());
-
-// Composite top = new Composite(parent, SWT.BORDER);
-// CmsUiUtils.style(top, SuiteStyle.recentItems);
-// top.setLayoutData(CmsUiUtils.fillWidth());
-// top.setLayout(CmsUiUtils.noSpaceGridLayout(2));
-// Label lbl = new Label(top, SWT.FLAT);
-// lbl.setLayoutData(CmsUiUtils.fillWidth());
-// lbl.setText(SuiteMsg.recentItems.lead());
-// CmsUiUtils.style(lbl, SuiteStyle.recentItems);
-//
-// ToolBar topToolBar = new ToolBar(top, SWT.NONE);
-// ToolItem addItem = new ToolItem(topToolBar, SWT.FLAT);
-//// CmsUiUtils.style(addItem, SuiteStyle.recentItems);
-// addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
-
- if (context == null)
- return null;
- SingleEntityViewer entityViewer = new SingleEntityViewer(parent, SWT.NONE, context.getSession());
- entityViewer.createUi();
- entityViewer.getViewer().getTable().setLayoutData(CmsUiUtils.fillAll());
-
- Composite bottom = new Composite(parent, SWT.NONE);
- bottom.setLayoutData(CmsUiUtils.fillWidth());
- bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
- ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
- bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
- ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
- deleteItem.setEnabled(false);
-// CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
- deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
- ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
- addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
- entityViewer.getViewer().addDoubleClickListener(new IDoubleClickListener() {
-
- @Override
- public void doubleClick(DoubleClickEvent event) {
- Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
- if (node != null)
- CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
- SuiteEvent.eventProperties(node));
-
- }
- });
- entityViewer.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
- public void selectionChanged(SelectionChangedEvent event) {
- Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
- if (node != null) {
- CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
- SuiteEvent.eventProperties(node));
- deleteItem.setEnabled(true);
- } else {
- deleteItem.setEnabled(false);
- }
- }
- });
-
- return entityViewer.filterTxt;
-
- }
-
- public void init(Map<String, String> properties) {
- // TODO manage multiple entities
- entityType = properties.get(Property.entityTypes.name());
- }
-
- class SingleEntityViewer {
- Composite parent;
- Text filterTxt;
- TableViewer viewer;
- Session session;
-
- public SingleEntityViewer(Composite parent, int style, Session session) {
- this.parent = parent;
- this.session = session;
- }
-
- public void createUi() {
- // MainLayout
- addFilterPanel(parent);
- viewer = createListPart(parent, new SingleEntityLabelProvider());
- refreshFilteredList();
-
- try {
- String[] nodeTypes = entityType != null && entityType.contains(":") ? new String[] { entityType }
- : null;
- session.getWorkspace().getObservationManager().addEventListener(new EventListener() {
-
- @Override
- public void onEvent(EventIterator events) {
- parent.getDisplay().asyncExec(() -> refreshFilteredList());
- }
- }, Event.PROPERTY_CHANGED | Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED, "/", true,
- null, nodeTypes, false);
- } catch (RepositoryException e) {
- throw new IllegalStateException("Cannot add JCR observer", e);
- }
-
- }
-
- private void addFilterPanel(Composite parent) {
- // Use a delayed text: the query won't be done until the user stop
- // typing for 800ms
- int style = SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL;
- DelayedText delayedText = new DelayedText(parent, style, SEARCH_TEXT_DELAY);
- filterTxt = delayedText.getText();
- filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
-
- // final ServerPushSession pushSession = new ServerPushSession();
- delayedText.addDelayedModifyListener(null, new ModifyListener() {
- private static final long serialVersionUID = 5003010530960334977L;
-
- public void modifyText(ModifyEvent event) {
- delayedText.getText().getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- refreshFilteredList();
- }
- });
- // pushSession.stop();
- }
- });
-
- // Jump to the first item of the list using the down arrow
- filterTxt.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -4523394262771183968L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
- // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
- if (e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.TAB) {
-// Object first = entityViewer.getElementAt(0);
-// if (first != null) {
-// entityViewer.getTable().setFocus();
-// entityViewer.setSelection(new StructuredSelection(first), true);
-// }
- e.doit = false;
- }
- }
- });
-
- parent.addDisposeListener((e) -> {
- delayedText.close();
- });
- }
-
- protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) {
-// parent.setLayout(new GridLayout());
-// parent.setLayout(CmsUiUtils.noSpaceGridLayout());
-
- Composite tableComposite = new Composite(parent, SWT.NONE);
- GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL
- | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
- tableComposite.setLayoutData(gd);
-
- TableViewer viewer = new TableViewer(tableComposite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
- viewer.setLabelProvider(labelProvider);
-
- TableColumn singleColumn = new TableColumn(viewer.getTable(), SWT.V_SCROLL);
- TableColumnLayout tableColumnLayout = new TableColumnLayout();
- tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(85));
- tableComposite.setLayout(tableColumnLayout);
-
- // Corresponding table & style
- Table table = viewer.getTable();
-// Listener[] mouseDownListeners = table.getListeners(SWT.MouseDown);
-// for (Listener listener : table.getListeners(SWT.MouseDown))
-// table.removeListener(SWT.MouseDown, listener);
-// for (Listener listener : table.getListeners(SWT.MouseUp))
-// table.removeListener(SWT.MouseUp, listener);
-// for (Listener listener : table.getListeners(SWT.MouseDoubleClick))
-// table.removeListener(SWT.MouseDoubleClick, listener);
-//
-// table.addMouseListener(new MouseListener() {
-//
-// @Override
-// public void mouseUp(MouseEvent e) {
-// System.out.println("Mouse up: "+e);
-// }
-//
-// @Override
-// public void mouseDown(MouseEvent e) {
-// System.out.println("Mouse down: "+e);
-// }
-//
-// @Override
-// public void mouseDoubleClick(MouseEvent e) {
-// System.out.println("Mouse double: "+e);
-//
-// }
-// });
- table.setLinesVisible(true);
- table.setHeaderVisible(false);
- // CmsUiUtils.markup(table);
- // CmsUiUtils.setItemHeight(table, 26);
-
- viewer.setContentProvider(new BasicNodeListContentProvider());
- return viewer;
- }
-
-// public boolean setFocus() {
-// refreshFilteredList();
-// return parent.setFocus();
-// }
-
- public void forceRefresh(Object object) {
- refreshFilteredList();
- }
-
- protected void refreshFilteredList() {
- try {
- String filter = filterTxt.getText();
- // Prevents the query on the full repository
- // if (isEmpty(filter)) {
- // entityViewer.setInput(null);
- // return;
- // }
-
- // XPATH Query
- String xpathQueryStr;
- if (entityType != null) {
- int indexColumn = entityType.indexOf(':');
- if (indexColumn > 0) {// JCR node type
- xpathQueryStr = "//element(*, " + entityType + ") order by @jcr:created descending";
- } else {
- xpathQueryStr = entityType.contains(":") ? "//element(*, " + entityType + ")"
- : "//element(*, " + EntityType.entity.get() + ")[@entity:type='" + entityType + "']";
- }
- } else {
- xpathQueryStr = "//element(*, " + EntityType.entity.get() + ")";
- }
-// String xpathQueryStr = "//element(*, " + ConnectTypes.CONNECT_ENTITY + ")";
- String xpathFilter = XPathUtils.getFreeTextConstraint(filter);
- if (notEmpty(xpathFilter))
- xpathQueryStr += "[" + xpathFilter + "]";
-
-// long begin = System.currentTimeMillis();
- // session.refresh(false);
- Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
-
- xpathQuery.setLimit(SEARCH_DEFAULT_LIMIT);
- QueryResult result = xpathQuery.execute();
-
- NodeIterator nit = result.getNodes();
- viewer.setInput(JcrUtils.nodeIteratorToList(nit));
-// if (log.isTraceEnabled()) {
-// long end = System.currentTimeMillis();
-// log.trace("Quick Search - Found: " + nit.getSize() + " in " + (end - begin)
-// + " ms by executing XPath query (" + xpathQueryStr + ").");
-// }
- } catch (RepositoryException e) {
- throw new IllegalStateException("Unable to list entities", e);
- }
- }
-
- public TableViewer getViewer() {
- return viewer;
- }
-
- class SingleEntityLabelProvider extends ColumnLabelProvider {
- private static final long serialVersionUID = -2209337675781795677L;
-
- @Override
- public String getText(Object element) {
- return Jcr.getTitle((Node) element);
- }
-
- }
-
- class BasicNodeListContentProvider implements IStructuredContentProvider {
- private static final long serialVersionUID = 1L;
- // keep a cache of the Nodes in the content provider to be able to
- // manage long request
- private List<Node> nodes;
-
- public void dispose() {
- }
-
- /** Expects a list of nodes as a new input */
- @SuppressWarnings("unchecked")
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- nodes = (List<Node>) newInput;
- }
-
- public Object[] getElements(Object arg0) {
- return nodes.toArray();
- }
- }
- }
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import static org.argeo.cms.ui.CmsView.CMS_VIEW_UID_PROPERTY;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeUtils;
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.auth.CmsSession;
-import org.argeo.cms.ui.AbstractCmsApp;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.dialogs.CmsFeedback;
-import org.argeo.cms.ui.util.CmsEvent;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.entity.EntityConstants;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.suite.RankedObject;
-import org.argeo.suite.SuiteUtils;
-import org.argeo.util.LangUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Constants;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
-import org.osgi.service.useradmin.User;
-
-/** The Argeo Suite App. */
-public class SuiteApp extends AbstractCmsApp implements EventHandler {
- private final static Log log = LogFactory.getLog(SuiteApp.class);
-
- public final static String PUBLIC_BASE_PATH_PROPERTY = "publicBasePath";
- public final static String DEFAULT_UI_NAME_PROPERTY = "defaultUiName";
- public final static String DEFAULT_THEME_ID_PROPERTY = "defaultThemeId";
-
- private String publicBasePath = null;
-
- private String pidPrefix;
- private String headerPid;
- private String leadPanePid;
- private String loginScreenPid;
-// private String DASHBOARD_PID = pidPrefix + "dashboard";
-// private String RECENT_ITEMS_PID = pidPrefix + "recentItems";
-
- private String defaultUiName = "app";
- private String defaultThemeId = "org.argeo.suite.theme.default";
-
- private Map<String, RankedObject<CmsUiProvider>> uiProvidersByPid = Collections.synchronizedMap(new HashMap<>());
- private Map<String, RankedObject<CmsUiProvider>> uiProvidersByType = Collections.synchronizedMap(new HashMap<>());
- private Map<String, RankedObject<SuiteLayer>> layersByPid = Collections.synchronizedSortedMap(new TreeMap<>());
- private Map<String, RankedObject<SuiteLayer>> layersByType = Collections.synchronizedSortedMap(new TreeMap<>());
-
- private CmsUserManager cmsUserManager;
-
- // TODO make more optimal or via CmsSession/CmsView
- private Map<String, SuiteUi> managedUis = new HashMap<>();
-
-// private CmsUiProvider headerPart = null;
-
- public void init(Map<String, Object> properties) {
- if (log.isDebugEnabled())
- log.info("Argeo Suite App started");
-
- if (properties.containsKey(DEFAULT_UI_NAME_PROPERTY))
- defaultUiName = LangUtils.get(properties, DEFAULT_UI_NAME_PROPERTY);
- if (properties.containsKey(DEFAULT_THEME_ID_PROPERTY))
- defaultThemeId = LangUtils.get(properties, DEFAULT_THEME_ID_PROPERTY);
- publicBasePath = LangUtils.get(properties, PUBLIC_BASE_PATH_PROPERTY);
-
- if (properties.containsKey(Constants.SERVICE_PID)) {
- String servicePid = properties.get(Constants.SERVICE_PID).toString();
- if (servicePid.endsWith(".app")) {
- pidPrefix = servicePid.substring(0, servicePid.length() - "app".length());
- }
- }
-
- if (pidPrefix == null)
- throw new IllegalArgumentException("PID prefix must be set.");
-
- headerPid = pidPrefix + "header";
- leadPanePid = pidPrefix + "leadPane";
- loginScreenPid = pidPrefix + "loginScreen";
- }
-
- public void destroy(Map<String, Object> properties) {
- for (SuiteUi ui : managedUis.values())
- if (!ui.isDisposed())
- ui.dispose();
- if (log.isDebugEnabled())
- log.info("Argeo Suite App stopped");
-
- }
-
- @Override
- public Set<String> getUiNames() {
- HashSet<String> uiNames = new HashSet<>();
- uiNames.add(defaultUiName);
- return uiNames;
- }
-
- @Override
- public Composite initUi(Composite parent) {
- String uiName = parent.getData(UI_NAME_PROPERTY) != null ? parent.getData(UI_NAME_PROPERTY).toString() : null;
- CmsView cmsView = CmsView.getCmsView(parent);
- if (cmsView == null)
- throw new IllegalStateException("No CMS view is registered.");
- CmsTheme theme = getTheme(uiName);
- if (theme != null)
- CmsTheme.registerCmsTheme(parent.getShell(), theme);
- SuiteUi argeoSuiteUi = new SuiteUi(parent, SWT.INHERIT_DEFAULT);
- String uid = cmsView.getUid();
- managedUis.put(uid, argeoSuiteUi);
- argeoSuiteUi.addDisposeListener((e) -> {
- managedUis.remove(uid);
- if (log.isDebugEnabled())
- log.debug("Suite UI " + uid + " has been disposed.");
- });
- refreshUi(argeoSuiteUi, null);
- return argeoSuiteUi;
- }
-
- @Override
- public String getThemeId(String uiName) {
- return defaultThemeId;
- }
-
- @Override
- public void refreshUi(Composite parent, String state) {
- try {
- Node context = null;
- SuiteUi ui = (SuiteUi) parent;
- CmsView cmsView = CmsView.getCmsView(parent);
- if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login
- ui.logout();
- refreshPart(findUiProvider(headerPid), ui.getHeader(), context);
- ui.refreshBelowHeader(false);
- refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context);
- ui.layout(true, true);
- } else {
- CmsSession cmsSession = cmsView.getCmsSession();
- if (ui.getUserDir() == null) {
- if (cmsView.isAnonymous()) {
- assert publicBasePath != null;
- ui.initSessions(getRepository(), publicBasePath);
- } else {
- Session adminSession = null;
- try {
- adminSession = NodeUtils.openDataAdminSession(getRepository(), null);
- Node userDir = SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
- ui.initSessions(getRepository(), userDir.getPath());
- } finally {
- Jcr.logout(adminSession);
- }
- }
- }
- initLocale(cmsSession);
- context = stateToNode(ui, state);
- if (context == null)
- context = ui.getUserDir();
-
- refreshPart(findUiProvider(headerPid), ui.getHeader(), context);
- ui.refreshBelowHeader(true);
- for (String key : layersByPid.keySet()) {
- SuiteLayer layer = layersByPid.get(key).get();
- ui.addLayer(key, layer);
- }
- refreshPart(findUiProvider(leadPanePid), ui.getLeadPane(), context);
- ui.layout(true, true);
- setState(parent, state);
- }
- } catch (Exception e) {
- CmsFeedback.show("Unexpected exception", e);
- }
- }
-
- private void initLocale(CmsSession cmsSession) {
- if (cmsSession == null)
- return;
- Locale locale = cmsSession.getLocale();
- UiContext.setLocale(locale);
- LocaleUtils.setThreadLocale(locale);
-
- }
-
- private void refreshPart(CmsUiProvider uiProvider, Composite part, Node context) {
- CmsUiUtils.clear(part);
- uiProvider.createUiPart(part, context);
- }
-
- private CmsUiProvider findUiProvider(String pid) {
- if (!uiProvidersByPid.containsKey(pid))
- throw new IllegalArgumentException("No UI provider registered as " + pid);
- return uiProvidersByPid.get(pid).get();
- }
-
- private <T> T findByType(Map<String, RankedObject<T>> byType, Node context) {
- if (context == null)
- throw new IllegalArgumentException("A node should be provided");
- try {
- // mixins
- Set<String> types = new TreeSet<>();
- for (NodeType nodeType : context.getMixinNodeTypes()) {
- String typeName = nodeType.getName();
- if (byType.containsKey(typeName)) {
- types.add(typeName);
- }
- }
- // primary node type
- {
- NodeType nodeType = context.getPrimaryNodeType();
- String typeName = nodeType.getName();
- if (byType.containsKey(typeName)) {
- types.add(typeName);
- }
- for (NodeType mixin : nodeType.getDeclaredSupertypes()) {
- if (byType.containsKey(mixin.getName())) {
- types.add(mixin.getName());
- }
- }
- }
- // entity type
- if (context.isNodeType(EntityType.entity.get())) {
- if (context.hasProperty(EntityNames.ENTITY_TYPE)) {
- String typeName = context.getProperty(EntityNames.ENTITY_TYPE).getString();
- if (byType.containsKey(typeName)) {
- types.add(typeName);
- }
- }
- }
-
-// if (context.getPath().equals("/")) {// root node
-// types.add("nt:folder");
-// }
- if (NodeUtils.isUserHome(context) && byType.containsKey("nt:folder")) {// home node
- types.add("nt:folder");
- }
-
- if (types.size() == 0)
- throw new IllegalArgumentException("No type found for " + context);
- String type = types.iterator().next();
- if (!byType.containsKey(type))
- throw new IllegalArgumentException("No component found for " + context + " with type " + type);
- return byType.get(type).get();
- } catch (RepositoryException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void setState(Composite parent, String state) {
- if (state == null || state.equals("~"))
- return;
- if (!state.startsWith("/") && !state.equals("~")) {
- if (parent instanceof SuiteUi) {
- SuiteUi ui = (SuiteUi) parent;
- String currentLayerId = ui.getCurrentLayerId();
- if (state.equals(currentLayerId))
- return; // does nothing
- else {
- Map<String, Object> properties = new HashMap<>();
- properties.put(SuiteEvent.LAYER, state);
- ui.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), properties);
- }
- }
- return;
- }
- SuiteUi suiteUi = (SuiteUi) parent;
- Node node = stateToNode(suiteUi, state);
- if (node == null) {
- suiteUi.getCmsView().navigateTo("~");
- } else {
- suiteUi.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), SuiteEvent.eventProperties(node));
- suiteUi.getCmsView().sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(node));
- }
- }
-
- private String nodeToState(Node node) {
- return '/' + Jcr.getWorkspaceName(node) + Jcr.getPath(node);
- }
-
- private Node stateToNode(SuiteUi suiteUi, String state) {
- if (suiteUi == null)
- return null;
- if (state == null || !state.startsWith("/"))
- return null;
-
- String path = state.substring(1);
- String workspace;
- if (path.equals("")) {
- workspace = null;
- path = "/";
- } else {
- int index = path.indexOf('/');
- if (index == 0) {
- log.error("Cannot interpret " + state);
-// cmsView.navigateTo("~");
- return null;
- } else if (index > 0) {
- workspace = path.substring(0, index);
- path = path.substring(index);
- } else {// index<0, assuming root node
- workspace = path;
- path = "/";
- }
- }
- Session session = suiteUi.getSession(workspace);
- if (session == null)
- return null;
- Node node = Jcr.getNode(session, path);
- return node;
- }
-
- /*
- * Events management
- */
-
- @Override
- public void handleEvent(Event event) {
-
- // Specific UI related events
- SuiteUi ui = getRelatedUi(event);
- if (ui == null)
- return;
- try {
-// String currentLayerId = ui.getCurrentLayerId();
-// SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null;
- if (isTopic(event, SuiteEvent.refreshPart)) {
- Node node = getNode(ui, event);
- if (node == null)
- return;
- CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
- SuiteLayer layer = findByType(layersByType, node);
- ui.switchToLayer(layer, node);
- ui.getCmsView().runAs(() -> layer.view(uiProvider, ui.getCurrentWorkArea(), node));
- ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node));
- } else if (isTopic(event, SuiteEvent.openNewPart)) {
- Node node = getNode(ui, event);
- if (node == null)
- return;
- CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
- SuiteLayer layer = findByType(layersByType, node);
- ui.switchToLayer(layer, node);
- ui.getCmsView().runAs(() -> layer.open(uiProvider, ui.getCurrentWorkArea(), node));
- ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node));
- } else if (isTopic(event, SuiteEvent.switchLayer)) {
- String layerId = get(event, SuiteEvent.LAYER);
- if (layerId != null) {
-// ui.switchToLayer(layerId, ui.getUserDir());
- ui.getCmsView().runAs(() -> ui.switchToLayer(layerId, ui.getUserDir()));
- ui.getCmsView().navigateTo(layerId);
- } else {
- Node node = getNode(ui, event);
- if (node != null) {
- SuiteLayer layer = findByType(layersByType, node);
- ui.getCmsView().runAs(() -> ui.switchToLayer(layer, node));
- }
- }
- }
- } catch (Exception e) {
- log.error("Cannot handle event " + event, e);
-// CmsView.getCmsView(ui).exception(e);
- }
-
- }
-
- private Node getNode(SuiteUi ui, Event event) {
- String nodePath = get(event, SuiteEvent.NODE_PATH);
- String workspaceName = get(event, SuiteEvent.WORKSPACE);
- Session session = ui.getSession(workspaceName);
- Node node;
- if (nodePath == null) {
- // look for a user
- String username = get(event, SuiteEvent.USERNAME);
- if (username == null)
- return null;
- User user = cmsUserManager.getUser(username);
- if (user == null)
- return null;
- LdapName userDn;
- try {
- userDn = new LdapName(user.getName());
- } catch (InvalidNameException e) {
- throw new IllegalArgumentException("Badly formatted username", e);
- }
- String userNodePath = SuiteUtils.getUserNodePath(userDn);
- if (Jcr.itemExists(session, userNodePath))
- node = Jcr.getNode(session, userNodePath);
- else {
- Session adminSession = null;
- try {
- adminSession = NodeUtils.openDataAdminSession(getRepository(), workspaceName);
- SuiteUtils.getOrCreateUserNode(adminSession, userDn);
- } finally {
- Jcr.logout(adminSession);
- }
- node = Jcr.getNode(session, userNodePath);
- }
- } else {
- node = Jcr.getNode(session, nodePath);
- }
- return node;
- }
-
- private SuiteUi getRelatedUi(Event event) {
- return managedUis.get(get(event, CMS_VIEW_UID_PROPERTY));
- }
-
- private static boolean isTopic(Event event, CmsEvent cmsEvent) {
- return event.getTopic().equals(cmsEvent.topic());
- }
-
- private static String get(Event event, String key) {
- Object value = event.getProperty(key);
- if (value == null)
- return null;
-// throw new IllegalArgumentException("Property " + key + " must be set");
- return value.toString();
-
- }
-
- /*
- * Dependency injection.
- */
-
- public void addUiProvider(CmsUiProvider uiProvider, Map<String, Object> properties) {
- if (properties.containsKey(Constants.SERVICE_PID)) {
- String pid = (String) properties.get(Constants.SERVICE_PID);
- RankedObject.putIfHigherRank(uiProvidersByPid, pid, uiProvider, properties);
- }
- if (properties.containsKey(EntityConstants.TYPE)) {
- List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
- for (String type : types)
- RankedObject.putIfHigherRank(uiProvidersByType, type, uiProvider, properties);
- }
- }
-
- public void removeUiProvider(CmsUiProvider uiProvider, Map<String, Object> properties) {
- if (properties.containsKey(Constants.SERVICE_PID)) {
- String pid = (String) properties.get(Constants.SERVICE_PID);
- if (uiProvidersByPid.containsKey(pid)) {
- if (uiProvidersByPid.get(pid).equals(new RankedObject<CmsUiProvider>(uiProvider, properties))) {
- uiProvidersByPid.remove(pid);
- }
- }
- }
- if (properties.containsKey(EntityConstants.TYPE)) {
- List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
- for (String type : types) {
- if (uiProvidersByType.containsKey(type)) {
- if (uiProvidersByType.get(type).equals(new RankedObject<CmsUiProvider>(uiProvider, properties))) {
- uiProvidersByType.remove(type);
- }
- }
- }
- }
- }
-
- public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
- if (properties.containsKey(Constants.SERVICE_PID)) {
- String pid = (String) properties.get(Constants.SERVICE_PID);
- RankedObject.putIfHigherRank(layersByPid, pid, layer, properties);
- }
- if (properties.containsKey(EntityConstants.TYPE)) {
- List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
- for (String type : types)
- RankedObject.putIfHigherRank(layersByType, type, layer, properties);
- }
- }
-
- public void removeLayer(SuiteLayer layer, Map<String, Object> properties) {
- if (properties.containsKey(Constants.SERVICE_PID)) {
- String pid = (String) properties.get(Constants.SERVICE_PID);
- if (layersByPid.containsKey(pid)) {
- if (layersByPid.get(pid).equals(new RankedObject<SuiteLayer>(layer, properties))) {
- layersByPid.remove(pid);
- }
- }
- }
- if (properties.containsKey(EntityConstants.TYPE)) {
- List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
- for (String type : types) {
- if (layersByType.containsKey(type)) {
- if (layersByType.get(type).equals(new RankedObject<CmsUiProvider>(layer, properties))) {
- layersByType.remove(type);
- }
- }
- }
- }
- }
-
- public void setCmsUserManager(CmsUserManager cmsUserManager) {
- this.cmsUserManager = cmsUserManager;
- }
-
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.ui.util.CmsEvent;
-import org.argeo.jcr.Jcr;
-import org.osgi.service.useradmin.User;
-
-/** Events specific to Argeo Suite. */
-public enum SuiteEvent implements CmsEvent {
- openNewPart, refreshPart, switchLayer;
-
- public final static String LAYER = "layer";
-// public final static String NODE_ID = "nodeId";
- public final static String NODE_PATH = "path";
- public final static String USERNAME = "username";
- public final static String WORKSPACE = "workspace";
-
- public String getTopicBase() {
- return "argeo/suite/ui";
- }
-
- public static Map<String, Object> eventProperties(Node node) {
- Map<String, Object> properties = new HashMap<>();
- properties.put(NODE_PATH, Jcr.getPath(node));
- properties.put(WORKSPACE, Jcr.getWorkspaceName(node));
- return properties;
- }
-
- public static Map<String, Object> eventProperties(User user) {
- Map<String, Object> properties = new HashMap<>();
- properties.put(USERNAME, user.getName());
- return properties;
- }
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import org.argeo.cms.ui.util.CmsIcon;
-
-/** Icon names used by Argeo Suite. */
-public enum SuiteIcon implements CmsIcon {
- add, save, close, search, delete, logout, dashboard,
- // people
- people, person, organisation,
- // library
- documents, document, folder,
- // admin and settings
- settings, user,
- // misc
- task, tag, location, inbox, map;
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.widgets.Composite;
-
-/** An UI layer for the main work area. */
-public interface SuiteLayer extends CmsUiProvider {
- static enum Property {
- title, icon, weights, startMaximized;
- }
-
- void view(CmsUiProvider uiProvider, Composite workArea, Node context);
-
- default void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
- view(uiProvider, workArea, context);
- }
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import org.argeo.cms.Localized;
-
-/** Localized messages. */
-public enum SuiteMsg implements Localized {
- dashboard, people, documents, locations, recentItems,
- // NewPersonWizard
- firstName, lastName, salutation, email, personWizardWindowTitle, personWizardPageTitle,
- // NewOrgWizard
- orgWizardWindowTitle, orgWizardPageTitle, legalName, legalForm, vatId,
- // ContextAddressComposite
- chooseAnOrganisation, street, streetComplement, zipCode, city, state, country, geopoint,
- // FilteredOrderableEntityTable
- filterHelp,
- // BankAccountComposite
- accountHolder, bankName, currency, accountNumber, bankNumber, BIC, IBAN,
- // EditJobDialog
- position, chosenItem, department, isPrimary, searchAndChooseEntity,
- // ContactListCTab (e4)
- notes, addAContact, contactValue, linkedCompany,
- // OrgAdminInfoCTab (e4)
- paymentAccount,
- // OrgEditor (e4)
- orgDetails, orgActivityLog, team, orgAdmin,
- // PersonEditor (e4)
- personDetails, personActivityLog, personOrgs, personSecurity,
- // PersonSecurityCTab (e4)
- resetPassword,
- // Generic
- label, aCustomLabel, description, value, name, primary, add, save, pickup,
- // Tag
- confirmNewTag, cannotCreateTag;
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import org.argeo.cms.ui.util.CmsStyle;
-
-/** Styles used by Argeo Suite work UI. */
-public enum SuiteStyle implements CmsStyle {
- // Header
- header, headerTitle, headerMenu, headerMenuItem,
- // Recent items
- recentItems,
- // Lead pane
- leadPane, leadPaneItem, leadPaneSectionTitle, leadPaneSubSectionTitle,
- // Group composite
- titleContainer, titleLabel, subTitleLabel, formLine, formColumn, navigationBar, navigationTitle, navigationButton,
- // Forms elements
- simpleLabel, simpleText, simpleInput,
- // table
- titleCell,
- // layers
- workArea,
- // tabbed area
- mainTabBody, mainTabSelected, mainTab,
- // Buttons
- inlineButton;
-
- @Override
- public String getClassPrefix() {
- return "argeo-suite";
- }
-
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.jcr.Jcr;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FormLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** The view for the default ergonomics of Argeo Suite. */
-class SuiteUi extends Composite {
- private static final long serialVersionUID = 6207018859086689108L;
- private final static Log log = LogFactory.getLog(SuiteUi.class);
- private Composite header;
- private Composite belowHeader;
- private Composite leadPane;
- private Composite dynamicArea;
-
- private Session sysSession;
-// private Session homeSession;
- private Node userDir;
-
- private Map<String, SuiteLayer> layers = new HashMap<>();
- private Map<String, Composite> workAreas = new HashMap<>();
- private String currentLayerId = null;
-
- private CmsView cmsView;
-
- public SuiteUi(Composite parent, int style) {
- super(parent, style);
- cmsView = CmsView.getCmsView(parent);
- this.setLayout(CmsUiUtils.noSpaceGridLayout());
-
- header = new Composite(this, SWT.NONE);
- header.setLayout(CmsUiUtils.noSpaceGridLayout());
- CmsUiUtils.style(header, SuiteStyle.header);
- header.setLayoutData(CmsUiUtils.fillWidth());
-
- belowHeader = new Composite(this, SWT.NONE);
- belowHeader.setLayoutData(CmsUiUtils.fillAll());
- }
-
- public void refreshBelowHeader(boolean initApp) {
- CmsUiUtils.clear(belowHeader);
- int style = getStyle();
- if (initApp) {
- belowHeader.setLayout(CmsUiUtils.noSpaceGridLayout(2));
-
- if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
- dynamicArea = new Composite(belowHeader, SWT.NONE);
- leadPane = new Composite(belowHeader, SWT.NONE);
- } else {
- leadPane = new Composite(belowHeader, SWT.NONE);
- dynamicArea = new Composite(belowHeader, SWT.NONE);
- }
- leadPane.setLayoutData(CmsUiUtils.fillHeight());
- leadPane.setLayout(CmsUiUtils.noSpaceGridLayout());
- CmsUiUtils.style(leadPane, SuiteStyle.leadPane);
-
- dynamicArea.setLayoutData(CmsUiUtils.fillAll());
- dynamicArea.setLayout(new FormLayout());
-
- } else {
- belowHeader.setLayout(CmsUiUtils.noSpaceGridLayout());
- }
- }
-
- /*
- * LAYERS
- */
-
- Composite getCurrentWorkArea() {
- if (currentLayerId == null)
- throw new IllegalStateException("No current layer");
- return workAreas.get(currentLayerId);
- }
-
- String getCurrentLayerId() {
- return currentLayerId;
- }
-
- private Composite getLayer(String id, Node context) {
- if (!layers.containsKey(id))
- return null;
- if (!workAreas.containsKey(id))
- initLayer(id, layers.get(id), context);
- return workAreas.get(id);
- }
-
- Composite switchToLayer(String layerId, Node context) {
- Composite current = null;
- if (currentLayerId != null) {
- current = getCurrentWorkArea();
- if (currentLayerId.equals(layerId))
- return current;
- }
- if (context == null) {
- if (!cmsView.isAnonymous())
- context = userDir;
- }
- Composite toShow = getLayer(layerId, context);
- if (toShow != null) {
- currentLayerId = layerId;
- if (!isDisposed()) {
-// getDisplay().syncExec(() -> {
- if (!toShow.isDisposed()) {
- toShow.moveAbove(null);
- } else {
- log.warn("Cannot show work area because it is disposed.");
- toShow = initLayer(layerId, layers.get(layerId), context);
- toShow.moveAbove(null);
- }
- dynamicArea.layout(true, true);
-// });
- }
- return toShow;
- } else {
- return current;
- }
- }
-
- Composite switchToLayer(SuiteLayer layer, Node context) {
- // TODO make it more robust
- for (String layerId : layers.keySet()) {
- SuiteLayer l = layers.get(layerId);
- if (layer == l) {
- return switchToLayer(layerId, context);
- }
- }
- throw new IllegalArgumentException("Layer is not registered.");
- }
-
- void addLayer(String id, SuiteLayer layer) {
- layers.put(id, layer);
- }
-
- void removeLayer(String id) {
- layers.remove(id);
- if (workAreas.containsKey(id)) {
- Composite workArea = workAreas.remove(id);
- if (!workArea.isDisposed())
- workArea.dispose();
- }
- }
-
- protected Composite initLayer(String id, SuiteLayer layer, Node context) {
- Composite workArea = cmsView.doAs(() -> (Composite) layer.createUiPart(dynamicArea, context));
- CmsUiUtils.style(workArea, SuiteStyle.workArea);
- workArea.setLayoutData(CmsUiUtils.coverAll());
- workAreas.put(id, workArea);
- return workArea;
- }
-
- synchronized void logout() {
- userDir = null;
- Jcr.logout(sysSession);
-// Jcr.logout(homeSession);
- currentLayerId = null;
- workAreas.clear();
- }
-
- /*
- * GETTERS / SETTERS
- */
-
- Composite getHeader() {
- return header;
- }
-
- Composite getLeadPane() {
- return leadPane;
- }
-
- Composite getBelowHeader() {
- return belowHeader;
- }
-
-// Session getSysSession() {
-// return sysSession;
-// }
-//
- synchronized void initSessions(Repository repository, String userDirPath) throws RepositoryException {
- this.sysSession = repository.login();
-// this.homeSession = repository.login(NodeConstants.HOME_WORKSPACE);
- userDir = sysSession.getNode(userDirPath);
- addDisposeListener((e) -> {
- Jcr.logout(sysSession);
-// Jcr.logout(homeSession);
- });
- }
-
- Node getUserDir() {
- return userDir;
- }
-
- Session getSysSession() {
- return sysSession;
- }
-
- Session getSession(String workspaceName) {
- if (workspaceName == null)
- return sysSession;
- if (NodeConstants.SYS_WORKSPACE.equals(workspaceName))
- return sysSession;
-// else if (NodeConstants.HOME_WORKSPACE.equals(workspaceName))
-// return homeSession;
- else
- throw new IllegalArgumentException("Unknown workspace " + workspaceName);
- }
-
- public CmsView getCmsView() {
- return cmsView;
- }
-
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.cms.Localized;
-import org.argeo.cms.ui.CmsEditable;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.dialogs.LightweightDialog;
-import org.argeo.cms.ui.util.CmsIcon;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.Point;
-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.Text;
-
-/** UI utilities related to the APAF project. */
-public class SuiteUiUtils {
-
- /** Singleton. */
- private SuiteUiUtils() {
- }
-
- /** creates a title bar composite with label and optional button */
- public static void addTitleBar(Composite parent, String title, Boolean isEditable) {
- Composite titleBar = new Composite(parent, SWT.NONE);
- titleBar.setLayoutData(CmsUiUtils.fillWidth());
- CmsUiUtils.style(titleBar, SuiteStyle.titleContainer);
-
- titleBar.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(2, false)));
- Label titleLbl = new Label(titleBar, SWT.NONE);
- titleLbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
- CmsUiUtils.style(titleLbl, SuiteStyle.titleLabel);
- titleLbl.setText(title);
-
- if (isEditable) {
- Button editBtn = new Button(titleBar, SWT.PUSH);
- editBtn.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
- CmsUiUtils.style(editBtn, SuiteStyle.inlineButton);
- editBtn.setText("Edit");
- }
- }
-
- public static Label addFormLabel(Composite parent, String label) {
- Label lbl = new Label(parent, SWT.WRAP);
- lbl.setText(label);
- // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
- CmsUiUtils.style(lbl, SuiteStyle.simpleLabel);
- return lbl;
- }
-
- public static Text addFormTextField(Composite parent, String text, String message) {
- return addFormTextField(parent, text, message, SWT.NONE);
- }
-
- public static Text addFormTextField(Composite parent, String text, String message, int style) {
- Text txt = new Text(parent, style);
- if (text != null)
- txt.setText(text);
- if (message != null)
- txt.setMessage(message);
- txt.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
- CmsUiUtils.style(txt, SuiteStyle.simpleText);
- return txt;
- }
-
- public static Text addFormInputField(Composite parent, String placeholder) {
- Text txt = new Text(parent, SWT.BORDER);
-
- GridData gridData = CmsUiUtils.fillWidth();
- txt.setLayoutData(gridData);
-
- if (placeholder != null)
- txt.setText(placeholder);
-
- CmsUiUtils.style(txt, SuiteStyle.simpleInput);
- return txt;
- }
-
- /** creates a single horizontal-block composite for key:value display */
- public static Text addFormLine(Composite parent, String label, String text) {
- Composite lineComposite = new Composite(parent, SWT.NONE);
- lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- lineComposite.setLayout(new GridLayout(2, false));
- CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
- addFormLabel(lineComposite, label);
- Text txt = addFormTextField(lineComposite, text, null);
- txt.setEditable(false);
- txt.setLayoutData(CmsUiUtils.fillWidth());
- return txt;
- }
-
- public static Text addFormLine(Composite parent, String label, Node node, String property,
- CmsEditable cmsEditable) {
- Composite lineComposite = new Composite(parent, SWT.NONE);
- lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- lineComposite.setLayout(new GridLayout(2, false));
- CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
- addFormLabel(lineComposite, label);
- String text = Jcr.get(node, property);
-// int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
- Text txt = addFormTextField(lineComposite, text, null, SWT.WRAP);
- if (cmsEditable != null && cmsEditable.isEditing()) {
- txt.addModifyListener((e) -> {
- Jcr.set(node, property, txt.getText());
- Jcr.save(node);
- });
- } else {
- txt.setEditable(false);
- }
- txt.setLayoutData(CmsUiUtils.fillWidth());
- return txt;
- }
-
- public static Text addFormInput(Composite parent, String label, String placeholder) {
- Composite lineComposite = new Composite(parent, SWT.NONE);
- lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- lineComposite.setLayout(new GridLayout(2, false));
- CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
- addFormLabel(lineComposite, label);
- Text txt = addFormInputField(lineComposite, placeholder);
- txt.setLayoutData(CmsUiUtils.fillWidth());
- return txt;
- }
-
- /**
- * creates a single horizontal-block composite for key:value display, with
- * offset value
- */
- public static Text addFormLine(Composite parent, String label, String text, Integer offset) {
- Composite lineComposite = new Composite(parent, SWT.NONE);
- lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- lineComposite.setLayout(new GridLayout(3, false));
- CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
- Label offsetLbl = new Label(lineComposite, SWT.NONE);
- GridData gridData = new GridData();
- gridData.widthHint = offset;
- offsetLbl.setLayoutData(gridData);
- addFormLabel(lineComposite, label);
- Text txt = addFormTextField(lineComposite, text, null);
- txt.setLayoutData(CmsUiUtils.fillWidth());
- return txt;
- }
-
- /** creates a single vertical-block composite for key:value display */
- public static Text addFormColumn(Composite parent, String label, String text) {
-// Composite columnComposite = new Composite(parent, SWT.NONE);
-// columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-// columnComposite.setLayout(new GridLayout(1, false));
- addFormLabel(parent, label);
- Text txt = addFormTextField(parent, text, null);
- txt.setEditable(false);
- txt.setLayoutData(CmsUiUtils.fillWidth());
- return txt;
- }
-
- public static Text addFormColumn(Composite parent, String label, Node node, String property,
- CmsEditable cmsEditable) {
-// Composite columnComposite = new Composite(parent, SWT.NONE);
-// columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-// columnComposite.setLayout(new GridLayout(1, false));
- addFormLabel(parent, label);
- String text = Jcr.get(node, property);
-// int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
- Text txt = addFormTextField(parent, text, null, SWT.WRAP);
- if (cmsEditable != null && cmsEditable.isEditing()) {
- txt.addModifyListener((e) -> {
- Jcr.set(node, property, txt.getText());
- Jcr.save(node);
- });
- } else {
- txt.setEditable(false);
- }
- txt.setLayoutData(CmsUiUtils.fillWidth());
- return txt;
- }
-
- public static Label createBoldLabel(Composite parent, Localized localized) {
- Label label = new Label(parent, SWT.LEAD);
- label.setText(localized.lead());
- label.setFont(EclipseUiUtils.getBoldFont(parent));
- label.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
- return label;
- }
-
- public static Label addFormPicture(Composite parent, String label, Node fileNode) throws RepositoryException {
- Composite lineComposite = new Composite(parent, SWT.NONE);
- lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- lineComposite.setLayout(new GridLayout(2, true));
- CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
- addFormLabel(lineComposite, label);
-
- return addPicture(lineComposite, fileNode);
- }
-
- public static Label addPicture(Composite parent, Node fileNode) throws RepositoryException {
- return addPicture(parent, fileNode, null);
- }
-
- public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth) throws RepositoryException {
- Node content = fileNode.getNode(Node.JCR_CONTENT);
- // TODO move it deeper in the middleware.
- if (!content.isNodeType(EntityType.box.get())) {
- if (content.getSession().hasPermission(content.getPath(), Session.ACTION_SET_PROPERTY)) {
- try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
- ImageData imageData = new ImageData(in);
- content.addMixin(EntityType.box.get());
- content.setProperty(EntityNames.SVG_WIDTH, imageData.width);
- content.setProperty(EntityNames.SVG_HEIGHT, imageData.height);
- content.getSession().save();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- // TODO optimise
- Long width;
- Long height;
- if (content.isNodeType(EntityType.box.get())) {
- width = content.getProperty(EntityNames.SVG_WIDTH).getLong();
- height = content.getProperty(EntityNames.SVG_HEIGHT).getLong();
- } else {
- try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
- ImageData imageData = new ImageData(in);
- width = Long.valueOf(imageData.width);
- height = Long.valueOf(imageData.height);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- if (maxWidth != null && width > maxWidth) {
- Double ratio = maxWidth.doubleValue() / width.doubleValue();
- width = maxWidth.longValue();
- height = Math.round(ratio * height);
- }
- Label img = new Label(parent, SWT.NONE);
- CmsUiUtils.markup(img);
- img.setText(CmsUiUtils.img(fileNode, width.toString(), height.toString()));
- if (parent.getLayout() instanceof GridLayout) {
- GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
- gd.widthHint = width.intValue();
- gd.heightHint = height.intValue();
- img.setLayoutData(gd);
- }
- img.addMouseListener(new MouseListener() {
- private static final long serialVersionUID = -1362242049325206168L;
-
- @Override
- public void mouseUp(MouseEvent e) {
- }
-
- @Override
- public void mouseDown(MouseEvent e) {
- }
-
- @Override
- public void mouseDoubleClick(MouseEvent e) {
- LightweightDialog dialog = new LightweightDialog(img.getShell()) {
-
- @Override
- protected Control createDialogArea(Composite parent) {
- parent.setLayout(new GridLayout());
- ScrolledComposite scroll = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
- scroll.setLayoutData(CmsUiUtils.fillAll());
- scroll.setLayout(CmsUiUtils.noSpaceGridLayout());
- scroll.setExpandHorizontal(true);
- scroll.setExpandVertical(true);
- // scroll.setAlwaysShowScrollBars(true);
-
- Composite c = new Composite(scroll, SWT.NONE);
- scroll.setContent(c);
- c.setLayout(new GridLayout());
- c.setLayoutData(CmsUiUtils.fillAll());
- Label bigImg = new Label(c, SWT.NONE);
- CmsUiUtils.markup(bigImg);
- bigImg.setText(CmsUiUtils.img(fileNode, Jcr.get(content, EntityNames.SVG_WIDTH),
- Jcr.get(content, EntityNames.SVG_HEIGHT)));
- bigImg.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
- return bigImg;
- }
-
- @Override
- protected Point getInitialSize() {
- Point shellSize = img.getShell().getSize();
- return new Point(shellSize.x - 100, shellSize.y - 100);
- }
-
- };
- dialog.open();
- }
- });
- return img;
- }
-
- public static Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon) {
- CmsTheme theme = CmsTheme.getCmsTheme(parent);
- Button button = new Button(parent, SWT.PUSH);
- CmsUiUtils.style(button, SuiteStyle.leadPane);
- if (icon != null)
- button.setImage(icon.getBigIcon(theme));
- button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false));
- // button.setToolTipText(msg.lead());
- if (msg != null) {
- Label lbl = new Label(parent, SWT.NONE);
- CmsUiUtils.style(lbl, SuiteStyle.leadPane);
- lbl.setText(msg.lead());
- lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
- }
- CmsUiUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer);
- return button;
- }
-
-// public static String createAndConfigureEntity(Shell shell, Session referenceSession, String mainMixin,
-// String... additionnalProps) {
-//
-// Session tmpSession = null;
-// Session mainSession = null;
-// try {
-// // FIXME would not work if home is another physical workspace
-// tmpSession = referenceSession.getRepository().login(NodeConstants.HOME_WORKSPACE);
-// Node draftNode = null;
-// for (int i = 0; i < additionnalProps.length - 1; i += 2) {
-// draftNode.setProperty(additionnalProps[i], additionnalProps[i + 1]);
-// }
-// Wizard wizard = null;
-// CmsWizardDialog dialog = new CmsWizardDialog(shell, wizard);
-// // WizardDialog dialog = new WizardDialog(shell, wizard);
-// if (dialog.open() == Window.OK) {
-// String parentPath = null;// "/" + appService.getBaseRelPath(mainMixin);
-// // FIXME it should be possible to specify the workspace
-// mainSession = referenceSession.getRepository().login();
-// Node parent = mainSession.getNode(parentPath);
-// Node task = null;// appService.publishEntity(parent, mainMixin, draftNode);
-//// task = appService.saveEntity(task, false);
-// referenceSession.refresh(true);
-// return task.getPath();
-// }
-// return null;
-// } catch (RepositoryException e1) {
-// throw new JcrException(
-// "Unable to create " + mainMixin + " entity with session " + referenceSession.toString(), e1);
-// } finally {
-// JcrUtils.logoutQuietly(tmpSession);
-// JcrUtils.logoutQuietly(mainSession);
-// }
-// }
-
-}
+++ /dev/null
-package org.argeo.suite.ui;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.naming.LdapAttrs;
-import org.eclipse.swt.SWT;
-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.Group;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.useradmin.User;
-
-/** Edit a suite user. */
-public class SuiteUserUiProvider implements CmsUiProvider {
- private String[] availableRoles;
- private CmsUserManager cmsUserManager;
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- Section main = new Section(parent, SWT.NONE, context);
- main.setLayoutData(CmsUiUtils.fillAll());
-
- String uid = context.getName();
- User user = cmsUserManager.getUserFromLocalId(uid);
-
-// Text givenName = new Text(main, SWT.SINGLE);
-// givenName.setText(getUserProperty(user, LdapAttrs.givenName.name()));
- Text givenName = SuiteUiUtils.addFormInput(main, SuiteMsg.firstName.lead(),
- getUserProperty(user, LdapAttrs.givenName.name()));
-
- Text sn = SuiteUiUtils.addFormInput(main, SuiteMsg.lastName.lead(), getUserProperty(user, LdapAttrs.sn.name()));
- // sn.setText(getUserProperty(user, LdapAttrs.sn.name()));
-
- Text email = SuiteUiUtils.addFormInput(main, SuiteMsg.email.lead(),
- getUserProperty(user, LdapAttrs.mail.name()));
- // email.setText(getUserProperty(user, LdapAttrs.mail.name()));
-
- Text uidT = SuiteUiUtils.addFormLine(main, "uid", getUserProperty(user, LdapAttrs.uid.name()));
- uidT.setText(uid);
-
-// Label dnL = new Label(main, SWT.NONE);
-// dnL.setText(user.getName());
-
- // roles
- // Section rolesSection = new Section(main, SWT.NONE, context);
- Group rolesSection = new Group(main, SWT.NONE);
- rolesSection.setText("Roles");
- rolesSection.setLayoutData(CmsUiUtils.fillWidth());
- rolesSection.setLayout(new GridLayout());
- // new Label(rolesSection, SWT.NONE).setText("Roles:");
- List<String> roles = Arrays.asList(cmsUserManager.getUserRoles(user.getName()));
- for (String role : availableRoles) {
- // new Label(rolesSection, SWT.NONE).setText(role);
- Button radio = new Button(rolesSection, SWT.CHECK);
- radio.setText(role);
- if (roles.contains(role))
- radio.setSelection(true);
- }
-
- return main;
- }
-
- public void setCmsUserManager(CmsUserManager cmsUserManager) {
- this.cmsUserManager = cmsUserManager;
- }
-
- private String getUserProperty(Object element, String key) {
- Object value = ((User) element).getProperties().get(key);
- return value != null ? value.toString() : null;
- }
-
- public void init(Map<String, Object> properties) {
- availableRoles = (String[]) properties.get("availableRoles");
- }
-}
+++ /dev/null
-package org.argeo.suite.ui.dialogs;
-
-import org.argeo.suite.ui.SuiteMsg;
-import org.argeo.suite.ui.SuiteUiUtils;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-public class NewPersonPage extends WizardPage {
- private static final long serialVersionUID = -944349994177526468L;
- protected Text lastNameTxt;
- protected Text firstNameTxt;
- protected Text emailTxt;
-
- protected NewPersonPage(String pageName) {
- super(pageName);
- setTitle(SuiteMsg.personWizardPageTitle.lead());
- }
-
- @Override
- public void createControl(Composite parent) {
- parent.setLayout(new GridLayout(2, false));
-
- // FirstName
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
- firstNameTxt = new Text(parent, SWT.BORDER);
- firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- // LastName
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
- lastNameTxt = new Text(parent, SWT.BORDER);
- lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.email);
- emailTxt = new Text(parent, SWT.BORDER);
- emailTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- ModifyListener ml = new ModifyListener() {
- private static final long serialVersionUID = -1628130380128946886L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- getContainer().updateButtons();
- }
- };
-
- firstNameTxt.addModifyListener(ml);
- lastNameTxt.addModifyListener(ml);
- emailTxt.addModifyListener(ml);
-
- // Don't forget this.
- setControl(firstNameTxt);
- firstNameTxt.setFocus();
-
- }
-
-// public void updateNode(Node node, PeopleService peopleService, ResourcesService resourcesService) {
-// ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_LAST_NAME, PropertyType.STRING, lastNameTxt.getText());
-// ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_FIRST_NAME, PropertyType.STRING,
-// firstNameTxt.getText());
-// ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_DISPLAY_NAME, PropertyType.STRING,
-// firstNameTxt.getText() + " " + lastNameTxt.getText());
-// String email = emailTxt.getText();
-// ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_PRIMARY_EMAIL, PropertyType.STRING, email);
-// PeopleJcrUtils.createEmail(resourcesService, peopleService, node, email, true, null, null);
-// }
-}
+++ /dev/null
-package org.argeo.suite.ui.dialogs;
-
-import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
-
-import javax.jcr.Node;
-
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.suite.ui.SuiteMsg;
-import org.argeo.suite.ui.SuiteUiUtils;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-/** Ask first & last name. Update the passed node on finish */
-public class NewPersonWizard extends Wizard {
- // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
-
- // Context
- private Node person;
-
- // This page widgets
- protected Text lastNameTxt;
- protected Text firstNameTxt;
- // private Button useDistinctDisplayNameBtn;
- // private Text displayNameTxt;
-
- public NewPersonWizard(Node person) {
- this.person = person;
- }
-
- @Override
- public void addPages() {
- try {
- MainInfoPage page = new MainInfoPage("Main page");
- addPage(page);
- } catch (Exception e) {
- throw new RuntimeException("Cannot add page to wizard", e);
- }
- setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
- }
-
- /**
- * Called when the user click on 'Finish' in the wizard. The task is then
- * created and the corresponding session saved.
- */
- @Override
- public boolean performFinish() {
- String lastName = lastNameTxt.getText();
- String firstName = firstNameTxt.getText();
- // String displayName = displayNameTxt.getText();
- // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
- if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
- MessageDialog.openError(getShell(), "Non-valid information",
- "Please enter at least a name that is not empty.");
- return false;
- } else {
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
-// String fullName = firstName + " " + lastName;
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
- return true;
- }
- }
-
- @Override
- public boolean performCancel() {
- return true;
- }
-
- @Override
- public boolean canFinish() {
- String lastName = lastNameTxt.getText();
- String firstName = firstNameTxt.getText();
- if (isEmpty(lastName) && isEmpty(firstName)) {
- return false;
- } else
- return true;
- }
-
- protected class MainInfoPage extends WizardPage {
- private static final long serialVersionUID = 1L;
-
- public MainInfoPage(String pageName) {
- super(pageName);
- setTitle(SuiteMsg.personWizardPageTitle.lead());
- // setMessage("Please enter a last name and/or a first name.");
- }
-
- public void createControl(Composite parent) {
- parent.setLayout(new GridLayout(2, false));
-
- // FirstName
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
- firstNameTxt = new Text(parent, SWT.BORDER);
- // firstNameTxt.setMessage("a first name");
- firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- // LastName
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
- lastNameTxt = new Text(parent, SWT.BORDER);
- // lastNameTxt.setMessage("a last name");
- lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- // Display Name
- // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
- // useDistinctDisplayNameBtn.setText("Define a disting display name");
- // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
- // true, false, 2, 1));
- //
- // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
- // displayNameTxt = new Text(parent, SWT.BORDER);
- // displayNameTxt.setMessage("an optional display name");
- // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
- // false));
- // displayNameTxt.setEnabled(false);
- //
- // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
- // private static final long serialVersionUID = 1L;
- //
- // @Override
- // public void widgetSelected(SelectionEvent e) {
- // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
- // }
- // });
-
- ModifyListener ml = new ModifyListener() {
- private static final long serialVersionUID = -1628130380128946886L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- getContainer().updateButtons();
- }
- };
-
- firstNameTxt.addModifyListener(ml);
- lastNameTxt.addModifyListener(ml);
- // displayNameTxt.addModifyListener(ml);
-
- // Don't forget this.
- setControl(firstNameTxt);
- firstNameTxt.setFocus();
- }
- }
-}
+++ /dev/null
-package org.argeo.suite.ui.dialogs;
-
-import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
-
-import javax.jcr.Node;
-
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.suite.ui.SuiteMsg;
-import org.argeo.suite.ui.SuiteUiUtils;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-/** Ask first & last name. Update the passed node on finish */
-public class NewUserWizard extends Wizard {
- // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
-
- // Context
- private Node person;
-
- // This page widgets
- protected Text lastNameTxt;
- protected Text firstNameTxt;
- // private Button useDistinctDisplayNameBtn;
- // private Text displayNameTxt;
-
- public NewUserWizard(Node person) {
- this.person = person;
- }
-
- @Override
- public void addPages() {
- try {
- MainInfoPage page = new MainInfoPage("Main page");
- addPage(page);
- } catch (Exception e) {
- throw new RuntimeException("Cannot add page to wizard", e);
- }
- setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
- }
-
- /**
- * Called when the user click on 'Finish' in the wizard. The task is then
- * created and the corresponding session saved.
- */
- @Override
- public boolean performFinish() {
- String lastName = lastNameTxt.getText();
- String firstName = firstNameTxt.getText();
- // String displayName = displayNameTxt.getText();
- // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
- if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
- MessageDialog.openError(getShell(), "Non-valid information",
- "Please enter at least a name that is not empty.");
- return false;
- } else {
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
-// String fullName = firstName + " " + lastName;
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
- return true;
- }
- }
-
- @Override
- public boolean performCancel() {
- return true;
- }
-
- @Override
- public boolean canFinish() {
- String lastName = lastNameTxt.getText();
- String firstName = firstNameTxt.getText();
- if (isEmpty(lastName) && isEmpty(firstName)) {
- return false;
- } else
- return true;
- }
-
- protected class MainInfoPage extends WizardPage {
- private static final long serialVersionUID = 1L;
-
- public MainInfoPage(String pageName) {
- super(pageName);
- setTitle(SuiteMsg.personWizardPageTitle.lead());
- // setMessage("Please enter a last name and/or a first name.");
- }
-
- public void createControl(Composite parent) {
- parent.setLayout(new GridLayout(2, false));
-
- // FirstName
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
- firstNameTxt = new Text(parent, SWT.BORDER);
- // firstNameTxt.setMessage("a first name");
- firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- // LastName
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
- lastNameTxt = new Text(parent, SWT.BORDER);
- // lastNameTxt.setMessage("a last name");
- lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- // Display Name
- // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
- // useDistinctDisplayNameBtn.setText("Define a disting display name");
- // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
- // true, false, 2, 1));
- //
- // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
- // displayNameTxt = new Text(parent, SWT.BORDER);
- // displayNameTxt.setMessage("an optional display name");
- // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
- // false));
- // displayNameTxt.setEnabled(false);
- //
- // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
- // private static final long serialVersionUID = 1L;
- //
- // @Override
- // public void widgetSelected(SelectionEvent e) {
- // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
- // }
- // });
-
- ModifyListener ml = new ModifyListener() {
- private static final long serialVersionUID = -1628130380128946886L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- getContainer().updateButtons();
- }
- };
-
- firstNameTxt.addModifyListener(ml);
- lastNameTxt.addModifyListener(ml);
- // displayNameTxt.addModifyListener(ml);
-
- // Don't forget this.
- setControl(firstNameTxt);
- firstNameTxt.setFocus();
- }
- }
-}
+++ /dev/null
-package org.argeo.suite.ui.widgets;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Button;
-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;
-
-/**
- * Generic popup context menu for TableViewer to enable single sourcing between
- * CMS and Workbench
- */
-public abstract class AbstractConnectContextMenu {
-
- private Shell parentShell;
- private Shell shell;
- // Local context
-
- private final static String KEY_ACTION_ID = "actionId";
- private final String[] defaultActions;
- private Map<String, Button> actionButtons = new HashMap<String, Button>();
-
- public AbstractConnectContextMenu(Display display, String[] defaultActions) {
- parentShell = display.getActiveShell();
- shell = new Shell(parentShell, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
- this.defaultActions = defaultActions;
- }
-
- protected void createControl() {
- shell.setLayout(EclipseUiUtils.noSpaceGridLayout());
- Composite boxCmp = new Composite(shell, SWT.NO_FOCUS | SWT.BORDER);
- boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
-// CmsUiUtils.style(boxCmp, ConnectUiStyles.CONTEXT_MENU_BOX);
- createContextMenu(boxCmp);
- shell.addShellListener(new ActionsShellListener());
- }
-
- protected void createContextMenu(Composite boxCmp) {
- ActionsSelListener asl = new ActionsSelListener();
- for (String actionId : defaultActions) {
- Button btn = new Button(boxCmp, SWT.FLAT | SWT.LEAD);
- btn.setText(getLabel(actionId));
- btn.setLayoutData(EclipseUiUtils.fillWidth());
- CmsUiUtils.markup(btn);
-// CmsUiUtils.style(btn, actionId + ConnectUiStyles.BUTTON_SUFFIX);
- btn.setData(KEY_ACTION_ID, actionId);
- btn.addSelectionListener(asl);
- actionButtons.put(actionId, btn);
- }
- }
-
- protected void setVisible(boolean visible, String... buttonIds) {
- for (String id : buttonIds) {
- Button button = actionButtons.get(id);
- button.setVisible(visible);
- GridData gd = (GridData) button.getLayoutData();
- gd.heightHint = visible ? SWT.DEFAULT : 0;
- }
- }
-
- public void show(Control source, Point location, IStructuredSelection selection) {
- if (shell.isDisposed()) {
- shell = new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
- createControl();
- }
- if (shell.isVisible())
- shell.setVisible(false);
-
- if (aboutToShow(source, location, selection)) {
- shell.pack();
- shell.layout();
- if (source instanceof Control)
- shell.setLocation(((Control) source).toDisplay(location.x, location.y));
- shell.open();
- }
- }
-
- protected Shell getParentShell() {
- return parentShell;
- }
-
- class StyleButton extends Label {
- private static final long serialVersionUID = 7731102609123946115L;
-
- public StyleButton(Composite parent, int swtStyle) {
- super(parent, swtStyle);
- }
- }
-
- class ActionsSelListener extends SelectionAdapter {
- private static final long serialVersionUID = -1041871937815812149L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- Object eventSource = e.getSource();
- if (eventSource instanceof Button) {
- Button pressedBtn = (Button) eventSource;
- performAction((String) pressedBtn.getData(KEY_ACTION_ID));
- shell.close();
- }
- }
- }
-
- class ActionsShellListener extends org.eclipse.swt.events.ShellAdapter {
- private static final long serialVersionUID = -5092341449523150827L;
-
- @Override
- public void shellDeactivated(ShellEvent e) {
- setVisible(false);
- shell.setVisible(false);
- //shell.close();
- }
- }
-
- protected abstract boolean performAction(String actionId);
-
- protected abstract boolean aboutToShow(Control source, Point location, IStructuredSelection selection);
-
- protected abstract String getLabel(String actionId);
-}
+++ /dev/null
-package org.argeo.suite.ui.widgets;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.rap.rwt.widgets.DropDown;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.Widget;
-
-/**
- * Enable easy addition of a {@code DropDown} widget to a text with listeners
- * configured
- */
-public abstract class ConnectAbstractDropDown {
-
- private final Text text;
- private final DropDown dropDown;
- private boolean modifyFromList = false;
-
- // Current displayed text
- private String userText = "";
- // Current displayed list items
- private String[] values;
-
- // Fine tuning
- boolean readOnly;
- boolean refreshOnFocus;
-
- /** Implementing classes should call refreshValues() after initialisation */
- public ConnectAbstractDropDown(Text text) {
- this(text, SWT.NONE, false);
- }
-
- /**
- * Implementing classes should call refreshValues() after initialisation
- *
- * @param text
- * @param style
- * only SWT.READ_ONLY is understood, check if the entered text is
- * part of the legal choices.
- */
- public ConnectAbstractDropDown(Text text, int style) {
- this(text, style, false);
- }
-
- /**
- * Implementers should call refreshValues() once init has been done.
- *
- * @param text
- * @param style
- * only SWT.READ_ONLY is understood, check if the entered text is
- * part of the legal choices.
- * @param refreshOnFocus
- * if true, the possible values are computed each time the focus is
- * gained. It enables, among other to fine tune the getFilteredValues
- * method depending on the current context
- */
- public ConnectAbstractDropDown(Text text, int style, boolean refreshOnFocus) {
- this.text = text;
- dropDown = new DropDown(text);
- Object obj = dropDown;
- if (obj instanceof Widget)
- CmsUiUtils.markup((Widget) obj);
- readOnly = (style & SWT.READ_ONLY) != 0;
- this.refreshOnFocus = refreshOnFocus;
- addListeners();
- }
-
- /**
- * Overwrite to force the refresh of the possible values on focus gained event
- */
- protected boolean refreshOnFocus() {
- return refreshOnFocus;
- }
-
- public String getText() {
- return text.getText();
- }
-
- public void init() {
- refreshValues();
- }
-
- public void reset(String value) {
- modifyFromList = true;
- if (EclipseUiUtils.notEmpty(value))
- text.setText(value);
- else
- text.setText("");
- refreshValues();
- modifyFromList = false;
- }
-
- /** Overwrite to provide specific filtering */
- protected abstract List<String> getFilteredValues(String filter);
-
- protected void refreshValues() {
- List<String> filteredValues = getFilteredValues(text.getText());
- values = filteredValues.toArray(new String[filteredValues.size()]);
- dropDown.setItems(values);
- }
-
- protected void addListeners() {
- addModifyListener();
- addSelectionListener();
- addDefaultSelectionListener();
- addFocusListener();
- }
-
- protected void addFocusListener() {
- text.addFocusListener(new FocusListener() {
- private static final long serialVersionUID = -7179112097626535946L;
-
- public void focusGained(FocusEvent event) {
- if (refreshOnFocus) {
- modifyFromList = true;
- refreshValues();
- modifyFromList = false;
- }
- dropDown.setVisible(true);
- }
-
- public void focusLost(FocusEvent event) {
- dropDown.setVisible(false);
- if (readOnly && values != null && !Arrays.asList(values).contains(userText)) {
- modifyFromList = true;
- text.setText("");
- refreshValues();
- modifyFromList = false;
- }
- }
- });
- }
-
- private void addSelectionListener() {
- Object obj = dropDown;
- if (obj instanceof Widget)
- ((Widget) obj).addListener(SWT.Selection, new Listener() {
- private static final long serialVersionUID = -2357157809365135142L;
-
- public void handleEvent(Event event) {
- if (event.index != -1) {
- modifyFromList = true;
- text.setText(values[event.index]);
- modifyFromList = false;
- text.selectAll();
- } else {
- text.setText(userText);
- text.setSelection(userText.length(), userText.length());
- text.setFocus();
- }
- }
- });
- }
-
- private void addDefaultSelectionListener() {
- Object obj = dropDown;
- if (obj instanceof Widget)
- ((Widget) obj).addListener(SWT.DefaultSelection, new Listener() {
- private static final long serialVersionUID = -5958008322630466068L;
-
- public void handleEvent(Event event) {
- if (event.index != -1) {
- text.setText(values[event.index]);
- text.setSelection(event.text.length());
- dropDown.setVisible(false);
- }
- }
- });
- }
-
- private void addModifyListener() {
- text.addListener(SWT.Modify, new Listener() {
- private static final long serialVersionUID = -4373972835244263346L;
-
- public void handleEvent(Event event) {
- if (!modifyFromList) {
- userText = text.getText();
- refreshValues();
- if (values.length == 1)
- dropDown.setSelectionIndex(0);
- dropDown.setVisible(true);
- }
- }
- });
- }
-}
+++ /dev/null
-package org.argeo.suite.ui.widgets;
-
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.eclipse.rap.rwt.service.ServerPushSession;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Text that introduce a timer in the attached ModifyListener.
- *
- * Note that corresponding ModifyEvent will *NOT* be sent in the UI thread.
- * Calling ModifierInstance must be implemented in consequence. Note also that
- * this delayed text only manages one listener at a time.
- *
- */
-public class DelayedText {
- final int delay;
- private Object lock = new Object();
- private MyTimer timer = new MyTimer(DelayedText.this.toString());
- private ModifyListener delayedModifyListener;
- private ServerPushSession pushSession;
-
- private Text text;
-
- private ModifyListener modifyListener = new ModifyListener() {
- private static final long serialVersionUID = 1117506414462641980L;
-
- public void modifyText(ModifyEvent e) {
- ModifyEvent delayedEvent = null;
- synchronized (lock) {
- if (delayedModifyListener != null) {
- Event tmpEvent = new Event();
- tmpEvent.widget = text;
- tmpEvent.display = e.display;
- tmpEvent.data = e.data;
- tmpEvent.time = e.time;
- delayedEvent = new ModifyEvent(tmpEvent);
- }
- }
- final ModifyEvent timerModifyEvent = delayedEvent;
-
- synchronized (timer) {
- if (timer.timerTask != null) {
- timer.timerTask.cancel();
- timer.timerTask = null;
- }
-
- if (delayedEvent != null) {
- timer.timerTask = new TimerTask() {
- public void run() {
- synchronized (lock) {
- delayedModifyListener.modifyText(timerModifyEvent);
- // Bad approach: it is not a good idea to put a
- // display.asyncExec in a lock...
- // DelayedText.this.getDisplay().asyncExec(new
- // Runnable() {
- // @Override
- // public void run() {
- // delayedModifyListener.modifyText(timerModifyEvent);
- // }
- // }
- // );
- }
- synchronized (timer) {
- timer.timerTask = null;
- }
- }
- };
- timer.schedule(timer.timerTask, delay);
- if (pushSession != null)
- pushSession.start();
- }
- }
- };
- };
-
- public DelayedText(Composite parent, int style, int delayInMs) {
- // super(parent, style);
- text = new Text(parent, style);
- this.delay = delayInMs;
- text.addModifyListener(modifyListener);
- }
-
- /**
- * Adds a modify text listener that will be delayed. If another Modify event
- * happens during the waiting delay, the older event will be canceled an a new
- * one will be scheduled after another new delay.
- */
- public void addDelayedModifyListener(ServerPushSession pushSession, ModifyListener listener) {
- synchronized (lock) {
- delayedModifyListener = listener;
- this.pushSession = pushSession;
- }
- }
-
- public void removeDelayedModifyListener(ModifyListener listener) {
- synchronized (lock) {
- delayedModifyListener = null;
- pushSession = null;
- }
- }
-
- private class MyTimer extends Timer {
- private TimerTask timerTask = null;
-
- public MyTimer(String name) {
- super(name);
- }
- }
-
- public Text getText() {
- return text;
- }
-
- public void close() {
- if (pushSession != null)
- pushSession.stop();
- if (timer != null)
- timer.cancel();
- };
-
-}
<git.rw />
</properties>
<modules>
- <!-- Entity Framework -->
- <module>org.argeo.entity.api</module>
- <module>org.argeo.entity.core</module>
- <module>org.argeo.entity.ui</module>
-
- <!-- Argeo Suite -->
- <module>org.argeo.suite.core</module>
- <module>org.argeo.suite.ui</module>
- <module>org.argeo.suite.ui.rap</module>
- <module>org.argeo.suite.theme.default</module>
-
+ <module>core</module>
<!-- Functional areas -->
<module>library</module>
<module>publishing</module>