From a55bb0dc7e9fbcefb645d34ce24b326d1506a623 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 12 Oct 2020 10:20:59 +0200 Subject: [PATCH] Introduce Entity framework. --- dep/org.argeo.suite.dep.e4.rap/pom.xml | 50 ++- org.argeo.entity.api/.classpath | 7 + org.argeo.entity.api/.gitignore | 2 + org.argeo.entity.api/.project | 28 ++ org.argeo.entity.api/META-INF/.gitignore | 1 + org.argeo.entity.api/bnd.bnd | 3 + org.argeo.entity.api/build.properties | 4 + org.argeo.entity.api/pom.xml | 21 ++ .../src/org/argeo/entity/EntityConstants.java | 8 + .../org/argeo/entity/EntityDefinition.java | 10 + .../src/org/argeo/entity/EntityNames.java | 24 ++ .../src/org/argeo/entity/EntityTypes.java | 9 + .../src/org/argeo/entity/entity.cnd | 28 ++ org.argeo.entity.core/.classpath | 7 + org.argeo.entity.core/.gitignore | 2 + org.argeo.entity.core/.project | 28 ++ org.argeo.entity.core/META-INF/.gitignore | 1 + org.argeo.entity.core/bnd.bnd | 0 org.argeo.entity.core/build.properties | 4 + org.argeo.entity.core/pom.xml | 29 ++ .../entity/core/JcrEntityDefinition.java | 76 ++++ org.argeo.entity.ui/.classpath | 7 + org.argeo.entity.ui/.gitignore | 2 + org.argeo.entity.ui/.project | 28 ++ org.argeo.entity.ui/META-INF/.gitignore | 1 + org.argeo.entity.ui/bnd.bnd | 0 org.argeo.entity.ui/build.properties | 4 + org.argeo.entity.ui/pom.xml | 38 ++ org.argeo.suite.core/.classpath | 7 + org.argeo.suite.core/.gitignore | 2 + org.argeo.suite.core/.project | 28 ++ org.argeo.suite.core/META-INF/.gitignore | 1 + org.argeo.suite.core/bnd.bnd | 4 + org.argeo.suite.core/build.properties | 4 + org.argeo.suite.core/pom.xml | 29 ++ .../src/org/argeo/suite/RankingKey.java | 161 ++++++++ .../src/org/argeo/suite/SuiteRole.java | 19 + .../argeo/suite/library/DocxExtractor.java | 355 ++++++++++++++++++ .../suite/e4/parts/EntitySearchView.java | 280 -------------- .../e4/parts/SingleEntitySearchView.java | 265 ------------- org.argeo.suite.ui/OSGI-INF/recentItems.xml | 2 +- org.argeo.suite.ui/pom.xml | 11 +- .../src/org/argeo/suite/ui/ArgeoSuiteApp.java | 2 +- .../org/argeo/suite/ui/DefaultLeadPane.java | 8 +- .../src/org/argeo/suite/ui/RecentItems.java | 5 +- pom.xml | 10 +- 46 files changed, 1043 insertions(+), 572 deletions(-) create mode 100644 org.argeo.entity.api/.classpath create mode 100644 org.argeo.entity.api/.gitignore create mode 100644 org.argeo.entity.api/.project create mode 100644 org.argeo.entity.api/META-INF/.gitignore create mode 100644 org.argeo.entity.api/bnd.bnd create mode 100644 org.argeo.entity.api/build.properties create mode 100644 org.argeo.entity.api/pom.xml create mode 100644 org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java create mode 100644 org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java create mode 100644 org.argeo.entity.api/src/org/argeo/entity/EntityNames.java create mode 100644 org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java create mode 100644 org.argeo.entity.api/src/org/argeo/entity/entity.cnd create mode 100644 org.argeo.entity.core/.classpath create mode 100644 org.argeo.entity.core/.gitignore create mode 100644 org.argeo.entity.core/.project create mode 100644 org.argeo.entity.core/META-INF/.gitignore create mode 100644 org.argeo.entity.core/bnd.bnd create mode 100644 org.argeo.entity.core/build.properties create mode 100644 org.argeo.entity.core/pom.xml create mode 100644 org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java create mode 100644 org.argeo.entity.ui/.classpath create mode 100644 org.argeo.entity.ui/.gitignore create mode 100644 org.argeo.entity.ui/.project create mode 100644 org.argeo.entity.ui/META-INF/.gitignore create mode 100644 org.argeo.entity.ui/bnd.bnd create mode 100644 org.argeo.entity.ui/build.properties create mode 100644 org.argeo.entity.ui/pom.xml create mode 100644 org.argeo.suite.core/.classpath create mode 100644 org.argeo.suite.core/.gitignore create mode 100644 org.argeo.suite.core/.project create mode 100644 org.argeo.suite.core/META-INF/.gitignore create mode 100644 org.argeo.suite.core/bnd.bnd create mode 100644 org.argeo.suite.core/build.properties create mode 100644 org.argeo.suite.core/pom.xml create mode 100644 org.argeo.suite.core/src/org/argeo/suite/RankingKey.java create mode 100644 org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java create mode 100644 org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java delete mode 100644 org.argeo.suite.e4/src/org/argeo/suite/e4/parts/EntitySearchView.java delete mode 100644 org.argeo.suite.e4/src/org/argeo/suite/e4/parts/SingleEntitySearchView.java diff --git a/dep/org.argeo.suite.dep.e4.rap/pom.xml b/dep/org.argeo.suite.dep.e4.rap/pom.xml index 76a59c5..c6508a9 100644 --- a/dep/org.argeo.suite.dep.e4.rap/pom.xml +++ b/dep/org.argeo.suite.dep.e4.rap/pom.xml @@ -13,10 +13,27 @@ Suite E4 Platform RAP jar - + org.argeo.suite - org.argeo.suite.cms + org.argeo.entity.api + 2.1.16-SNAPSHOT + + + org.argeo.suite + org.argeo.entity.core + 2.1.16-SNAPSHOT + + + org.argeo.suite + org.argeo.entity.ui + 2.1.16-SNAPSHOT + + + + + org.argeo.suite + org.argeo.suite.core 2.1.16-SNAPSHOT @@ -29,23 +46,30 @@ org.argeo.suite.ui.rap 2.1.16-SNAPSHOT + + + + org.argeo.suite + org.argeo.suite.cms + 2.1.16-SNAPSHOT + - + - - - - - - - - - - + + + + + + + + + + diff --git a/org.argeo.entity.api/.classpath b/org.argeo.entity.api/.classpath new file mode 100644 index 0000000..e801ebf --- /dev/null +++ b/org.argeo.entity.api/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.entity.api/.gitignore b/org.argeo.entity.api/.gitignore new file mode 100644 index 0000000..09e3bc9 --- /dev/null +++ b/org.argeo.entity.api/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.argeo.entity.api/.project b/org.argeo.entity.api/.project new file mode 100644 index 0000000..1269cce --- /dev/null +++ b/org.argeo.entity.api/.project @@ -0,0 +1,28 @@ + + + org.argeo.entity.api + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.entity.api/META-INF/.gitignore b/org.argeo.entity.api/META-INF/.gitignore new file mode 100644 index 0000000..4854a41 --- /dev/null +++ b/org.argeo.entity.api/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/org.argeo.entity.api/bnd.bnd b/org.argeo.entity.api/bnd.bnd new file mode 100644 index 0000000..a7d5dd1 --- /dev/null +++ b/org.argeo.entity.api/bnd.bnd @@ -0,0 +1,3 @@ + +Provide-Capability:\ +cms.datamodel; name=entity; cnd=/org/argeo/entity/entity.cnd diff --git a/org.argeo.entity.api/build.properties b/org.argeo.entity.api/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/org.argeo.entity.api/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.argeo.entity.api/pom.xml b/org.argeo.entity.api/pom.xml new file mode 100644 index 0000000..444274c --- /dev/null +++ b/org.argeo.entity.api/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + org.argeo.suite + argeo-suite + 2.1.16-SNAPSHOT + .. + + org.argeo.entity.api + Entity API + jar + + + + org.argeo.commons + org.argeo.enterprise + ${version.argeo-commons} + + + diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java b/org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java new file mode 100644 index 0000000..f7a2de8 --- /dev/null +++ b/org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java @@ -0,0 +1,8 @@ +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"; + +} diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java b/org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java new file mode 100644 index 0000000..08aff61 --- /dev/null +++ b/org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java @@ -0,0 +1,10 @@ +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(); +} diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java b/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java new file mode 100644 index 0000000..9739471 --- /dev/null +++ b/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java @@ -0,0 +1,24 @@ +package org.argeo.entity; + +import org.argeo.naming.LdapAttrs; + +/** Constants used to name entity structures. */ +public interface EntityNames { + final String ENTITY_DEFINITIONS_PATH = "/entity:entityDefinitions"; + + final String ENTITY_TYPE = "entity:type"; + final String ENTITY_UID = "entity:uid"; + + // GENERIC CONCEPTS + /** The date which is clearly relevant for this entity. */ + final String ENTITY_DATE = "entity:date"; + final String ENTITY_RELATED_TO = "entity:relatedTo"; + + // LDAP-LIKE ENTITIES + final String DISPLAY_NAME = LdapAttrs.displayName.property(); + // Persons + final String GIVEN_NAME = LdapAttrs.givenName.property(); + final String SURNAME = LdapAttrs.sn.property(); + final String EMAIL = LdapAttrs.mail.property(); + +} diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java b/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java new file mode 100644 index 0000000..f4b3e5e --- /dev/null +++ b/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java @@ -0,0 +1,9 @@ +package org.argeo.entity; + +/** Types related to entities. */ +public interface EntityTypes { + final static String ENTITY_ENTITY = "entity:entity"; + final static String ENTITY_DEFINITION = "entity:definition"; + + final static String ENTITY_PERSON = "entity:person"; +} diff --git a/org.argeo.entity.api/src/org/argeo/entity/entity.cnd b/org.argeo.entity.api/src/org/argeo/entity/entity.cnd new file mode 100644 index 0000000..67116cd --- /dev/null +++ b/org.argeo.entity.api/src/org/argeo/entity/entity.cnd @@ -0,0 +1,28 @@ + + + +[entity:entity] > mix:title, mix:created, mix:lastModified, mix:referenceable +mixin +//- entity:uid (String) m // an implementation dependent UID for each entity +//- entity:type (String) // the type of this entity + +[entity:definition] > entity:composite, mix:title, mix:created, mix:lastModified, mix:referenceable +mixin + +[entity:part] +mixin + +[entity:reference] +mixin + +[entity:composite] +mixin +orderable ++ * (entity:part) ++ * (entity:reference) ++ * (entity:composite) + +// LDAP-LIKE ENTITIES +// A real person +[entity:person] > entity:entity +mixin diff --git a/org.argeo.entity.core/.classpath b/org.argeo.entity.core/.classpath new file mode 100644 index 0000000..e801ebf --- /dev/null +++ b/org.argeo.entity.core/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.entity.core/.gitignore b/org.argeo.entity.core/.gitignore new file mode 100644 index 0000000..09e3bc9 --- /dev/null +++ b/org.argeo.entity.core/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.argeo.entity.core/.project b/org.argeo.entity.core/.project new file mode 100644 index 0000000..1acff84 --- /dev/null +++ b/org.argeo.entity.core/.project @@ -0,0 +1,28 @@ + + + org.argeo.entity.core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.entity.core/META-INF/.gitignore b/org.argeo.entity.core/META-INF/.gitignore new file mode 100644 index 0000000..4854a41 --- /dev/null +++ b/org.argeo.entity.core/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/org.argeo.entity.core/bnd.bnd b/org.argeo.entity.core/bnd.bnd new file mode 100644 index 0000000..e69de29 diff --git a/org.argeo.entity.core/build.properties b/org.argeo.entity.core/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/org.argeo.entity.core/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.argeo.entity.core/pom.xml b/org.argeo.entity.core/pom.xml new file mode 100644 index 0000000..1349b7e --- /dev/null +++ b/org.argeo.entity.core/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + org.argeo.suite + argeo-suite + 2.1.16-SNAPSHOT + .. + + org.argeo.entity.core + Entity Reference Implementation + jar + + + org.argeo.suite + org.argeo.entity.api + 2.1.16-SNAPSHOT + + + + + org.argeo.commons + org.argeo.cms + ${version.argeo-commons} + + + diff --git a/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java b/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java new file mode 100644 index 0000000..15fb812 --- /dev/null +++ b/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java @@ -0,0 +1,76 @@ +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.entity.EntityNames; +import org.argeo.entity.EntityTypes; +import org.argeo.jcr.Jcr; +import org.argeo.jcr.JcrUtils; +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 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); + 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 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(); + } + +} diff --git a/org.argeo.entity.ui/.classpath b/org.argeo.entity.ui/.classpath new file mode 100644 index 0000000..e801ebf --- /dev/null +++ b/org.argeo.entity.ui/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.entity.ui/.gitignore b/org.argeo.entity.ui/.gitignore new file mode 100644 index 0000000..09e3bc9 --- /dev/null +++ b/org.argeo.entity.ui/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.argeo.entity.ui/.project b/org.argeo.entity.ui/.project new file mode 100644 index 0000000..a1f7177 --- /dev/null +++ b/org.argeo.entity.ui/.project @@ -0,0 +1,28 @@ + + + org.argeo.entity.ui + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.entity.ui/META-INF/.gitignore b/org.argeo.entity.ui/META-INF/.gitignore new file mode 100644 index 0000000..4854a41 --- /dev/null +++ b/org.argeo.entity.ui/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/org.argeo.entity.ui/bnd.bnd b/org.argeo.entity.ui/bnd.bnd new file mode 100644 index 0000000..e69de29 diff --git a/org.argeo.entity.ui/build.properties b/org.argeo.entity.ui/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/org.argeo.entity.ui/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.argeo.entity.ui/pom.xml b/org.argeo.entity.ui/pom.xml new file mode 100644 index 0000000..5cf1892 --- /dev/null +++ b/org.argeo.entity.ui/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + org.argeo.suite + argeo-suite + 2.1.16-SNAPSHOT + .. + + org.argeo.entity.ui + Entity UI + jar + + + org.argeo.suite + org.argeo.entity.core + 2.1.16-SNAPSHOT + + + + + org.argeo.commons + org.argeo.cms.ui + ${version.argeo-commons} + + + + + org.argeo.tp + argeo-tp-rap-e4 + ${version.argeo-tp} + pom + provided + + + diff --git a/org.argeo.suite.core/.classpath b/org.argeo.suite.core/.classpath new file mode 100644 index 0000000..e801ebf --- /dev/null +++ b/org.argeo.suite.core/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.suite.core/.gitignore b/org.argeo.suite.core/.gitignore new file mode 100644 index 0000000..09e3bc9 --- /dev/null +++ b/org.argeo.suite.core/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.argeo.suite.core/.project b/org.argeo.suite.core/.project new file mode 100644 index 0000000..f47b00e --- /dev/null +++ b/org.argeo.suite.core/.project @@ -0,0 +1,28 @@ + + + org.argeo.suite.core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.suite.core/META-INF/.gitignore b/org.argeo.suite.core/META-INF/.gitignore new file mode 100644 index 0000000..4854a41 --- /dev/null +++ b/org.argeo.suite.core/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/org.argeo.suite.core/bnd.bnd b/org.argeo.suite.core/bnd.bnd new file mode 100644 index 0000000..d70ca8c --- /dev/null +++ b/org.argeo.suite.core/bnd.bnd @@ -0,0 +1,4 @@ + +Import-Package:\ +org.argeo.api,\ +* \ No newline at end of file diff --git a/org.argeo.suite.core/build.properties b/org.argeo.suite.core/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/org.argeo.suite.core/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.argeo.suite.core/pom.xml b/org.argeo.suite.core/pom.xml new file mode 100644 index 0000000..c6a7d4f --- /dev/null +++ b/org.argeo.suite.core/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + org.argeo.suite + argeo-suite + 2.1.16-SNAPSHOT + .. + + org.argeo.suite.core + Suite Core + jar + + + org.argeo.suite + org.argeo.entity.core + 2.1.16-SNAPSHOT + + + + + org.argeo.commons + org.argeo.cms + ${version.argeo-commons} + + + diff --git a/org.argeo.suite.core/src/org/argeo/suite/RankingKey.java b/org.argeo.suite.core/src/org/argeo/suite/RankingKey.java new file mode 100644 index 0000000..d7a2670 --- /dev/null +++ b/org.argeo.suite.core/src/org/argeo/suite/RankingKey.java @@ -0,0 +1,161 @@ +package org.argeo.suite; + +import java.util.Map; + +import org.argeo.api.NodeConstants; + +/** + * Key used to classify and filter available components (typically provided by + * OSGi services). + */ +public class RankingKey implements Comparable { + 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 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); + } +} diff --git a/org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java b/org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java new file mode 100644 index 0000000..382f50c --- /dev/null +++ b/org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java @@ -0,0 +1,19 @@ +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(); + } +} diff --git a/org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java b/org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java new file mode 100644 index 0000000..53e73f3 --- /dev/null +++ b/org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java @@ -0,0 +1,355 @@ +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 tables = new ArrayList<>(); + protected List text = new ArrayList<>(); + protected Map media = new TreeMap<>(); + private Set mediaDigests = new HashSet<>(); + + protected void processTextItem(List 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 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 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 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 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 getText() { + return text; + } + + public List getTables() { + return tables; + } + + public Map 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"); + } + } + +} diff --git a/org.argeo.suite.e4/src/org/argeo/suite/e4/parts/EntitySearchView.java b/org.argeo.suite.e4/src/org/argeo/suite/e4/parts/EntitySearchView.java deleted file mode 100644 index e2a66b9..0000000 --- a/org.argeo.suite.e4/src/org/argeo/suite/e4/parts/EntitySearchView.java +++ /dev/null @@ -1,280 +0,0 @@ -package org.argeo.suite.e4.parts; - -import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty; - -import java.util.List; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.inject.Inject; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -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.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.activities.ActivitiesService; -import org.argeo.cms.ui.util.CmsUiUtils; -import org.argeo.connect.ConnectException; -import org.argeo.connect.resources.ResourcesService; -import org.argeo.connect.ui.ConnectUiConstants; -import org.argeo.connect.ui.Refreshable; -import org.argeo.connect.ui.SystemWorkbenchService; -import org.argeo.connect.ui.util.BasicNodeListContentProvider; -import org.argeo.connect.ui.util.JcrViewerDClickListener; -import org.argeo.connect.ui.widgets.DelayedText; -import org.argeo.connect.util.ConnectJcrUtils; -import org.argeo.connect.util.XPathUtils; -import org.argeo.eclipse.ui.EclipseUiUtils; -import org.argeo.entity.EntityTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.people.PeopleService; -import org.eclipse.e4.ui.di.Focus; -import org.eclipse.e4.ui.workbench.modeling.ESelectionService; -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -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.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; - -/** A table with a quick search field. */ -public class EntitySearchView implements Refreshable { - private final static Log log = LogFactory.getLog(EntitySearchView.class); - // public static final String ID = AsUiPlugin.PLUGIN_ID + ".quickSearchView"; - - /* DEPENDENCY INJECTION */ - @Inject - private Repository repository; - @Inject - private ResourcesService resourcesService; - @Inject - private ActivitiesService activitiesService; - @Inject - private PeopleService peopleService; - @Inject - private SystemWorkbenchService systemWorkbenchService; - - @Inject - private ESelectionService selectionService; - - // This page widgets - private TableViewer entityViewer; - private Text filterTxt; - - private Session session; - - // @Override - // public void init(IViewSite site) throws PartInitException { - // super.init(site); - // } - - @PostConstruct - public void createPartControl(Composite parent) { - session = ConnectJcrUtils.login(repository); - // MainLayout - parent.setLayout(new GridLayout()); - addFilterPanel(parent); - entityViewer = createListPart(parent, new EntitySingleColumnLabelProvider(resourcesService, activitiesService, - peopleService, systemWorkbenchService)); - refreshFilteredList(); - - try { - // new String[] { ConnectTypes.CONNECT_ENTITY } - 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, - null, false); - } catch (RepositoryException e) { - throw new ConnectException("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, ConnectUiConstants.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; - } - } - }); - } - - protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) { - parent.setLayout(new GridLayout()); - - 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 v = new TableViewer(tableComposite); - v.setLabelProvider(labelProvider); - - TableColumn singleColumn = new TableColumn(v.getTable(), SWT.V_SCROLL); - TableColumnLayout tableColumnLayout = new TableColumnLayout(); - tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(85)); - tableComposite.setLayout(tableColumnLayout); - - // Corresponding table & style - Table table = v.getTable(); - table.setLinesVisible(true); - table.setHeaderVisible(false); - CmsUiUtils.markup(table); - CmsUiUtils.setItemHeight(table, 26); - - v.setContentProvider(new BasicNodeListContentProvider()); - v.addDoubleClickListener(new JcrViewerDClickListener(systemWorkbenchService)); - v.addSelectionChangedListener(new ISelectionChangedListener() { - public void selectionChanged(SelectionChangedEvent event) { - IStructuredSelection selection = (IStructuredSelection) event.getSelection(); - List lst = selection.toList(); - if (lst != null && !lst.isEmpty()) - selectionService.setSelection(selection.toList()); - else - selectionService.setSelection(null); - } - }); - return v; - } - - @PreDestroy - public void dispose() { - JcrUtils.logoutQuietly(session); - } - - @Focus - public void setFocus() { - refreshFilteredList(); - filterTxt.setFocus(); - } - - @Override - 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 = "//element(*, " + EntityTypes.ENTITY_ENTITY + ")"; -// String xpathQueryStr = "//element(*, " + ConnectTypes.CONNECT_ENTITY + ")"; - String xpathFilter = XPathUtils.getFreeTextConstraint(filter); - if (notEmpty(xpathFilter)) - xpathQueryStr += "[" + xpathFilter + "]"; - - // boolean doOrder = orderResultsBtn != null - // && !(orderResultsBtn.isDisposed()) - // && orderResultsBtn.getSelection(); - // if (doOrder) { - // xpathQueryStr += " order by jcr:title"; - // } - - long begin = System.currentTimeMillis(); - // session.refresh(false); - Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr); - - xpathQuery.setLimit(ConnectUiConstants.SEARCH_DEFAULT_LIMIT); - QueryResult result = xpathQuery.execute(); - - NodeIterator nit = result.getNodes(); - entityViewer.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 ConnectException("Unable to list entities", e); - } - } - - // public void setRepository(Repository repository) { - // this.repository = repository; - // } - // - // public void setResourcesService(ResourcesService resourcesService) { - // this.resourcesService = resourcesService; - // } - // - // public void setActivitiesService(ActivitiesService activitiesService) { - // this.activitiesService = activitiesService; - // } - // - // public void setPeopleService(PeopleService peopleService) { - // this.peopleService = peopleService; - // } - // - // public void setSystemWorkbenchService(SystemWorkbenchService - // systemWorkbenchService) { - // this.systemWorkbenchService = systemWorkbenchService; - // } -} diff --git a/org.argeo.suite.e4/src/org/argeo/suite/e4/parts/SingleEntitySearchView.java b/org.argeo.suite.e4/src/org/argeo/suite/e4/parts/SingleEntitySearchView.java deleted file mode 100644 index 159dd2d..0000000 --- a/org.argeo.suite.e4/src/org/argeo/suite/e4/parts/SingleEntitySearchView.java +++ /dev/null @@ -1,265 +0,0 @@ -package org.argeo.suite.e4.parts; - -import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty; - -import java.util.List; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.inject.Inject; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -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.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.activities.ActivitiesService; -import org.argeo.cms.ui.util.CmsUiUtils; -import org.argeo.connect.ConnectException; -import org.argeo.connect.resources.ResourcesService; -import org.argeo.connect.ui.ConnectUiConstants; -import org.argeo.connect.ui.Refreshable; -import org.argeo.connect.ui.SystemWorkbenchService; -import org.argeo.connect.ui.util.BasicNodeListContentProvider; -import org.argeo.connect.ui.util.JcrViewerDClickListener; -import org.argeo.connect.ui.widgets.DelayedText; -import org.argeo.connect.util.ConnectJcrUtils; -import org.argeo.connect.util.XPathUtils; -import org.argeo.eclipse.ui.EclipseUiUtils; -import org.argeo.entity.EntityTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.people.PeopleService; -import org.eclipse.e4.ui.di.Focus; -import org.eclipse.e4.ui.model.application.ui.basic.MPart; -import org.eclipse.e4.ui.workbench.modeling.ESelectionService; -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -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.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; - -/** A table with a quick search field. */ -public class SingleEntitySearchView implements Refreshable { - public final static String ENTITY_TYPE = "entity:type"; - - private final static Log log = LogFactory.getLog(SingleEntitySearchView.class); - // public static final String ID = AsUiPlugin.PLUGIN_ID + ".quickSearchView"; - - /* DEPENDENCY INJECTION */ - @Inject - private Repository repository; - @Inject - private ResourcesService resourcesService; - @Inject - private ActivitiesService activitiesService; - @Inject - private PeopleService peopleService; - @Inject - private SystemWorkbenchService systemWorkbenchService; - - @Inject - private ESelectionService selectionService; - - @Inject - private MPart mPart; - - // This page widgets - private TableViewer entityViewer; - private Text filterTxt; - - private Session session; - - private String entityType; - - // @Override - // public void init(IViewSite site) throws PartInitException { - // super.init(site); - // } - - @PostConstruct - public void createPartControl(Composite parent) { - entityType = mPart.getProperties().get(ENTITY_TYPE); - if (entityType == null) - throw new IllegalArgumentException("Property " + ENTITY_TYPE + " must be set."); - - session = ConnectJcrUtils.login(repository); - // MainLayout - parent.setLayout(new GridLayout()); - addFilterPanel(parent); - entityViewer = createListPart(parent, new EntitySingleColumnLabelProvider(resourcesService, activitiesService, - peopleService, systemWorkbenchService)); - refreshFilteredList(); - - try { - String[] nodeTypes = 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 ConnectException("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, ConnectUiConstants.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; - } - } - }); - } - - protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) { - parent.setLayout(new GridLayout()); - - 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 v = new TableViewer(tableComposite); - v.setLabelProvider(labelProvider); - - TableColumn singleColumn = new TableColumn(v.getTable(), SWT.V_SCROLL); - TableColumnLayout tableColumnLayout = new TableColumnLayout(); - tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(85)); - tableComposite.setLayout(tableColumnLayout); - - // Corresponding table & style - Table table = v.getTable(); - table.setLinesVisible(true); - table.setHeaderVisible(false); - CmsUiUtils.markup(table); - CmsUiUtils.setItemHeight(table, 26); - - v.setContentProvider(new BasicNodeListContentProvider()); - v.addDoubleClickListener(new JcrViewerDClickListener(systemWorkbenchService)); - v.addSelectionChangedListener(new ISelectionChangedListener() { - public void selectionChanged(SelectionChangedEvent event) { - IStructuredSelection selection = (IStructuredSelection) event.getSelection(); - List lst = selection.toList(); - if (lst != null && !lst.isEmpty()) - selectionService.setSelection(selection.toList()); - else - selectionService.setSelection(null); - } - }); - return v; - } - - @PreDestroy - public void dispose() { - JcrUtils.logoutQuietly(session); - } - - @Focus - public void setFocus() { - refreshFilteredList(); - filterTxt.setFocus(); - } - - @Override - 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 = entityType.contains(":") ? "//element(*, " + entityType + ")" - : "//element(*, " + EntityTypes.ENTITY_ENTITY + ")[@entity:type='" + entityType + "']"; -// 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(ConnectUiConstants.SEARCH_DEFAULT_LIMIT); - QueryResult result = xpathQuery.execute(); - - NodeIterator nit = result.getNodes(); - entityViewer.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 ConnectException("Unable to list entities", e); - } - } -} diff --git a/org.argeo.suite.ui/OSGI-INF/recentItems.xml b/org.argeo.suite.ui/OSGI-INF/recentItems.xml index 3f1baff..8aaee16 100644 --- a/org.argeo.suite.ui/OSGI-INF/recentItems.xml +++ b/org.argeo.suite.ui/OSGI-INF/recentItems.xml @@ -1,5 +1,5 @@ - + diff --git a/org.argeo.suite.ui/pom.xml b/org.argeo.suite.ui/pom.xml index 321ddea..310ce62 100644 --- a/org.argeo.suite.ui/pom.xml +++ b/org.argeo.suite.ui/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.suite @@ -11,12 +13,17 @@ Suite UI jar + + org.argeo.suite + org.argeo.entity.ui + 2.1.16-SNAPSHOT + org.argeo.connect org.argeo.connect.ui ${version.argeo-connect} - + org.argeo.tp diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/ArgeoSuiteApp.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/ArgeoSuiteApp.java index 436b0da..29ba598 100644 --- a/org.argeo.suite.ui/src/org/argeo/suite/ui/ArgeoSuiteApp.java +++ b/org.argeo.suite.ui/src/org/argeo/suite/ui/ArgeoSuiteApp.java @@ -16,7 +16,6 @@ import javax.jcr.Session; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.api.RankingKey; import org.argeo.cms.ui.AbstractCmsApp; import org.argeo.cms.ui.CmsTheme; import org.argeo.cms.ui.CmsUiProvider; @@ -28,6 +27,7 @@ import org.argeo.entity.EntityNames; import org.argeo.entity.EntityTypes; import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrUtils; +import org.argeo.suite.RankingKey; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java index 6c60474..dd435b8 100644 --- a/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java +++ b/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java @@ -5,8 +5,6 @@ import java.util.Map; import javax.jcr.Node; import javax.jcr.RepositoryException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.argeo.cms.Localized; import org.argeo.cms.ui.CmsTheme; import org.argeo.cms.ui.CmsUiProvider; @@ -23,7 +21,7 @@ import org.eclipse.swt.widgets.Label; /** Side pane listing various perspectives. */ public class DefaultLeadPane implements CmsUiProvider { - private final static Log log = LogFactory.getLog(DefaultLeadPane.class); + // private final static Log log = LogFactory.getLog(DefaultLeadPane.class); @Override public Control createUi(Composite parent, Node node) throws RepositoryException { @@ -50,8 +48,8 @@ public class DefaultLeadPane implements CmsUiProvider { CmsUiUtils.style(button, SuiteStyle.leadPane); button.setImage(icon.getBigIcon(theme)); button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false)); - //button.setToolTipText(msg.lead()); - Label lbl = new Label(parent,SWT.NONE); + // button.setToolTipText(msg.lead()); + 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)); diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java index 0c08d2d..0ab37c5 100644 --- a/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java +++ b/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java @@ -14,7 +14,6 @@ import javax.jcr.observation.EventListener; import javax.jcr.query.Query; import javax.jcr.query.QueryResult; -import org.argeo.api.NodeConstants; import org.argeo.cms.ui.CmsTheme; import org.argeo.cms.ui.CmsUiProvider; import org.argeo.cms.ui.CmsView; @@ -24,6 +23,7 @@ import org.argeo.connect.ui.util.BasicNodeListContentProvider; import org.argeo.connect.ui.widgets.DelayedText; import org.argeo.connect.util.XPathUtils; import org.argeo.eclipse.ui.EclipseUiUtils; +import org.argeo.entity.EntityConstants; import org.argeo.entity.EntityTypes; import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrUtils; @@ -45,7 +45,6 @@ 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.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; @@ -126,7 +125,7 @@ public class RecentItems implements CmsUiProvider { } public void init(Map properties) { - entityType = properties.get(NodeConstants.DATA_TYPE); + entityType = properties.get(EntityConstants.TYPE); } class SingleEntityViewer { diff --git a/pom.xml b/pom.xml index 2f0a80c..eafe5a4 100644 --- a/pom.xml +++ b/pom.xml @@ -26,13 +26,19 @@ - - org.argeo.suite.cms + + org.argeo.entity.api + org.argeo.entity.core + org.argeo.entity.ui + + + org.argeo.suite.core org.argeo.suite.ui org.argeo.suite.ui.rap org.argeo.suite.theme.default + org.argeo.suite.cms org.argeo.suite.e4 org.argeo.suite.e4.rap org.argeo.suite.standard -- 2.30.2