From: Mathieu Date: Tue, 6 Dec 2022 05:47:51 +0000 (+0100) Subject: Merge remote-tracking branch 'origin/merge-to-testing' into testing X-Git-Tag: v2.1.26~1 X-Git-Url: https://git.argeo.org/?p=gpl%2Fargeo-suite.git;a=commitdiff_plain;h=615c2201dc78d0c103b25f0f273ff2e023eb87a1;hp=7dbe300240a6003d238c697d5d4150e3d95b41c1 Merge remote-tracking branch 'origin/merge-to-testing' into testing --- diff --git a/.project b/.project index ff41893..4106bf4 100644 --- a/.project +++ b/.project @@ -5,6 +5,11 @@ + + org.eclipse.pde.ds.core.builder + + + diff --git a/Makefile b/Makefile index c1803c9..1a573a5 100644 --- a/Makefile +++ b/Makefile @@ -10,24 +10,30 @@ org.argeo.app.api \ org.argeo.app.core \ org.argeo.app.servlet.odk \ org.argeo.app.servlet.publish \ -org.argeo.app.ui \ org.argeo.app.theme.default \ -org.argeo.app.ui.rap \ +org.argeo.app.profile.acr.fs \ +org.argeo.app.profile.acr.jcr \ +swt/org.argeo.app.swt \ +swt/org.argeo.app.ui \ A2_OUTPUT = $(SDK_BUILD_BASE)/a2 A2_BASE = $(A2_OUTPUT) DEP_CATEGORIES = \ org.argeo.tp \ -org.argeo.tp.apache \ org.argeo.tp.jetty \ -org.argeo.tp.eclipse.equinox \ -org.argeo.tp.eclipse.rap \ org.argeo.tp.jcr \ -org.argeo.tp.formats \ +org.argeo.tp.utils \ org.argeo.tp.gis \ +osgi/api/org.argeo.tp.osgi \ +osgi/equinox/org.argeo.tp.eclipse \ +swt/rap/org.argeo.tp.swt \ +swt/rap/org.argeo.tp.swt.workbench \ org.argeo.cms \ -org.argeo.cms.eclipse.rap \ +org.argeo.cms.jcr \ +swt/org.argeo.cms \ +swt/org.argeo.cms.jcr \ +swt/rap/org.argeo.cms \ clean: rm -rf $(BUILD_BASE) diff --git a/branch.mk b/branch.mk index 936a675..dbecaaa 100644 --- a/branch.mk +++ b/branch.mk @@ -1 +1 @@ -include $(SDK_SRC_BASE)/cnf/testing.bnd +BRANCH=testing \ No newline at end of file diff --git a/cnf/build.bnd b/cnf/build.bnd deleted file mode 100644 index a464edc..0000000 --- a/cnf/build.bnd +++ /dev/null @@ -1,3 +0,0 @@ --include: \ -${workspace}/cnf/testing.bnd, \ -${workspace}/sdk/argeo-build/argeo.bnd, \ diff --git a/cnf/testing.bnd b/cnf/testing.bnd deleted file mode 100644 index cae4d91..0000000 --- a/cnf/testing.bnd +++ /dev/null @@ -1,10 +0,0 @@ -MAJOR=2 -MINOR=1 -MICRO=25 -qualifier=.next - -category=org.argeo.suite -Bundle-RequiredExecutionEnvironment=JavaSE-11 - -argeo.rpm.stagingRepository=/srv/rpmfactory/testing/argeo-osgi-2/argeo -argeo.rpm.suffix= diff --git a/cnf/unstable.bnd b/cnf/unstable.bnd deleted file mode 100644 index 1f15381..0000000 --- a/cnf/unstable.bnd +++ /dev/null @@ -1,10 +0,0 @@ -MAJOR=2 -MINOR=3 -MICRO=5 -qualifier=.next - -category=org.argeo.suite -Bundle-RequiredExecutionEnvironment=JavaSE-11 - -argeo.rpm.stagingRepository=/srv/rpmfactory/unstable/argeo-osgi-2/argeo -argeo.rpm.suffix=-unstable diff --git a/configure b/configure old mode 100644 new mode 100755 index 9b3e980..9f49215 --- a/configure +++ b/configure @@ -1,55 +1,7 @@ #!/bin/sh -# We build where we are -SDK_BUILD_BASE=$(pwd -P)/output - # Source are located where this script is SDK_SRC_BASE="$(cd "$(dirname "$0")"; pwd -P)" -SDK_MK=$SDK_SRC_BASE/sdk.mk - -#echo SDK_BUILD_BASE=$SDK_BUILD_BASE -#echo SDK_SRC_BASE=$SDK_SRC_BASE -#echo SDK_MK=$SDK_MK - -if [ -f "$SDK_MK" ]; -then - -echo "File $SDK_MK already exists. Remove it in order to configure a new build location:" -echo "rm $SDK_MK" -exit 1 - -else - -if [ -z "$JAVA_HOME" ] -then -echo "Environment variable JAVA_HOME must be set" -exit 1 -fi - -# Create build directory, so that it can be used right away -# and we check whether we have the rights -mkdir -p $SDK_BUILD_BASE -if [ -f "$SDK_MK" ]; -then -echo "Cannot create $SDK_BUILD_BASE, SDK configuration has failed." -exit 2 -fi - -# Generate sdk.mk -cat > "$SDK_MK" < - + diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java b/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java index 7776056..b60a436 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java +++ b/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java @@ -1,6 +1,6 @@ package org.argeo.app.api; -import org.argeo.util.naming.LdapAttrs; +import org.argeo.api.acr.ldap.LdapAttr; /** Constants used to name entity structures. */ public interface EntityNames { @@ -35,16 +35,16 @@ public interface EntityNames { // LDAP-LIKE ENTITIES @Deprecated - final String DISPLAY_NAME = LdapAttrs.displayName.property(); + final String DISPLAY_NAME = LdapAttr.displayName.property(); // Persons @Deprecated - final String GIVEN_NAME = LdapAttrs.givenName.property(); + final String GIVEN_NAME = LdapAttr.givenName.property(); @Deprecated - final String SURNAME = LdapAttrs.sn.property(); + final String SURNAME = LdapAttr.sn.property(); @Deprecated - final String EMAIL = LdapAttrs.mail.property(); + final String EMAIL = LdapAttr.mail.property(); @Deprecated - final String OU = LdapAttrs.ou.property(); + final String OU = LdapAttr.ou.property(); // WGS84 final String GEO_LAT = "geo:lat"; diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityType.java b/org.argeo.app.api/src/org/argeo/app/api/EntityType.java index 48b1266..8b9164a 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/EntityType.java +++ b/org.argeo.app.api/src/org/argeo/app/api/EntityType.java @@ -1,7 +1,9 @@ package org.argeo.app.api; +import org.argeo.api.acr.QNamed; + /** Types related to entities. */ -public enum EntityType implements JcrName { +public enum EntityType implements QNamed { // entity entity, local, relatedTo, // structure @@ -18,25 +20,30 @@ public enum EntityType implements JcrName { person, user; @Override - public String getPrefix() { - return prefix(); - } - - public static String prefix() { + public String getDefaultPrefix() { return "entity"; } +// @Override +// public String getPrefix() { +// return getDefaultPrefix(); +// } +// +// 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"; } +// public static String namespace() { +// return "http://www.argeo.org/ns/entity"; +// } + } diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityTypes.java b/org.argeo.app.api/src/org/argeo/app/api/EntityTypes.java deleted file mode 100644 index f320794..0000000 --- a/org.argeo.app.api/src/org/argeo/app/api/EntityTypes.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.argeo.app.api; - -/** 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"; -} diff --git a/org.argeo.app.api/src/org/argeo/app/api/IdRange.java b/org.argeo.app.api/src/org/argeo/app/api/IdRange.java new file mode 100644 index 0000000..e47eb5e --- /dev/null +++ b/org.argeo.app.api/src/org/argeo/app/api/IdRange.java @@ -0,0 +1,133 @@ +package org.argeo.app.api; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +/** A range of numerical IDs (typically numerical uid or gid). */ +public class IdRange { + // see https://systemd.io/UIDS-GIDS/#special-distribution-uid-ranges + final static long MIN_INCLUDED = Long.parseUnsignedLong("66000"); + final static long MAX_EXCLUDED = Long.parseUnsignedLong("4294967294"); + + // We use long as a de facto unsigned int + + /** included */ + private final long min; + /** included */ + private final long max; + + public IdRange(long min, long max) { + this.min = min; + this.max = max; + } + + public IdRange(long minPow10) { + this(minPow10, maxFromMinPow10(minPow10)); + } + + public long getMin() { + return min; + } + + public long getMax() { + return max; + } + + @Override + public int hashCode() { + return (int) min; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof IdRange idRange) { + return min == idRange.min && max == idRange.max; + } else + return false; + } + + @Override + public String toString() { + return "[" + Long.toUnsignedString(min) + "," + Long.toUnsignedString(max) + "]"; + } + + /* + * RANGE GENERATION + */ + public static synchronized Set randomRanges10000(int count, Set forbiddenRanges) { + Set res = new HashSet<>(); + + for (int i = 0; i < count; i++) { + IdRange newRange = null; + do { + newRange = randomRange10000(); + } while (overlap(newRange, res) || overlap(newRange, forbiddenRanges)); + res.add(newRange); + } + return res; + } + + public static synchronized IdRange randomRange10000() { + // TODO make it more generic + long minPred = 7l; + long maxPred = 429496l; + + long rand = ThreadLocalRandom.current().nextLong(minPred, maxPred); + long min = rand * 10000l; + return new IdRange(min); + } + + public static boolean overlap(IdRange idRange, Set idRanges) { + for (IdRange other : idRanges) { + if (overlap(idRange, other)) + return true; + } + return false; + } + + public static boolean overlap(IdRange idRange, IdRange other) { + // see + // https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap + return idRange.min <= other.max && other.min <= idRange.max; + } + + /* + * UTILITIES + */ + + private static long maxFromMinPow10(long minPow10) { + if ((minPow10 % 100) != 0) { + throw new IllegalArgumentException(minPow10 + " must at least ends with two zeroes"); + } + int exp = 2; + exp: for (int i = exp + 1; i < 10; i++) { + if ((minPow10 % pow10(i)) != 0) + break exp; + exp++; + } +// System.out.println(exp); + + long max = minPow10 + pow10(exp) - 1; + return max; + } + + /** Power of 10. */ + private static long pow10(int exp) { + if (exp == 0) + return 1; + else + return 10 * pow10(exp - 1); + } + + public static void main(String... args) { + System.out.println(maxFromMinPow10(100)); + System.out.println(maxFromMinPow10(78500)); + System.out.println(maxFromMinPow10(716850000)); + +// System.out.println(pow10(6)); +// System.out.println(maxFromMinPow10(12)); +// System.out.println(maxFromMinPow10(124)); +// System.out.println(maxFromMinPow10(99814565)); + } +} diff --git a/org.argeo.app.api/src/org/argeo/app/api/JcrName.java b/org.argeo.app.api/src/org/argeo/app/api/JcrName.java deleted file mode 100644 index 182494a..0000000 --- a/org.argeo.app.api/src/org/argeo/app/api/JcrName.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.argeo.app.api; - -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 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(); - } -} diff --git a/org.argeo.app.api/src/org/argeo/app/api/RankedObject.java b/org.argeo.app.api/src/org/argeo/app/api/RankedObject.java index 31c43a7..fab42d7 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/RankedObject.java +++ b/org.argeo.app.api/src/org/argeo/app/api/RankedObject.java @@ -16,28 +16,28 @@ public class RankedObject { private T object; private Map properties; - private final Long rank; + private final int rank; public RankedObject(T object, Map properties) { this(object, properties, extractRanking(properties)); } - public RankedObject(T object, Map properties, Long rank) { + public RankedObject(T object, Map properties, int rank) { super(); this.object = object; this.properties = properties; this.rank = rank; } - private static Long extractRanking(Map properties) { + private static int extractRanking(Map properties) { if (properties == null) - return 0l; + return 0; if (properties.containsKey(SERVICE_RANKING)) - return Long.valueOf(properties.get(SERVICE_RANKING).toString()); + return (Integer) properties.get(SERVICE_RANKING); // else if (properties.containsKey(SERVICE_ID)) // return (Long) properties.get(SERVICE_ID); else - return 0l; + return 0; } public T get() { @@ -48,7 +48,7 @@ public class RankedObject { return properties; } - public Long getRank() { + public int getRank() { return rank; } @@ -62,7 +62,7 @@ public class RankedObject { if (!(obj instanceof RankedObject)) return false; RankedObject other = (RankedObject) obj; - return rank.equals(other.rank) && object.equals(other.object); + return rank == other.rank && object.equals(other.object); } @Override @@ -70,6 +70,18 @@ public class RankedObject { return object.getClass().getName() + " with rank " + rank; } + public static boolean hasHigherRank(Map> map, K key, Map properties) { + if (!map.containsKey(key)) + return true; + RankedObject rankedObject = new RankedObject<>(null, properties); + RankedObject current = map.get(key); + return current.getRank() < rankedObject.getRank(); + } + + /** + * @return the {@link RankedObject}, or null if the current one was + * kept + */ public static RankedObject putIfHigherRank(Map> map, K key, T object, Map properties) { RankedObject rankedObject = new RankedObject<>(object, properties); @@ -81,14 +93,18 @@ public class RankedObject { return rankedObject; } else { RankedObject current = map.get(key); - if (current.getRank() <= rankedObject.getRank()) { + if (current.getRank() < rankedObject.getRank()) { map.put(key, rankedObject); - if (log.isTraceEnabled()) - log.trace("Replaced " + key + " by " + object.getClass().getName() + " with rank " + if (log.isDebugEnabled()) + log.debug("Replaced " + key + " by " + object.getClass().getName() + " with rank " + rankedObject.getRank()); return rankedObject; + } else if (current.getRank() == rankedObject.getRank()) { + log.error("Already " + key + " by " + current.get().getClass().getName() + " with rank " + + rankedObject.getRank() + ", ignoring " + rankedObject.get().getClass().getName()); + return null; } else { - return current; + return null; } } diff --git a/org.argeo.app.api/src/org/argeo/app/api/RankingKey.java b/org.argeo.app.api/src/org/argeo/app/api/RankingKey.java deleted file mode 100644 index 691570c..0000000 --- a/org.argeo.app.api/src/org/argeo/app/api/RankingKey.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.argeo.app.api; - -import java.util.Map; - -/** - * Key used to classify and filter available components (typically provided by - * OSGi services). - */ -@Deprecated -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.app.api/src/org/argeo/app/api/SuiteRole.java b/org.argeo.app.api/src/org/argeo/app/api/SuiteRole.java index 38ce11f..5a2fc6b 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/SuiteRole.java +++ b/org.argeo.app.api/src/org/argeo/app/api/SuiteRole.java @@ -1,19 +1,47 @@ package org.argeo.app.api; +import javax.xml.namespace.QName; + +import org.argeo.api.acr.ArgeoNamespace; +import org.argeo.api.acr.ContentName; +import org.argeo.api.acr.ldap.LdapAttr; import org.argeo.api.cms.CmsConstants; -import org.argeo.util.naming.Distinguished; -import org.argeo.util.naming.LdapAttrs; +import org.argeo.cms.SystemRole; + +/** Standard suite system roles. */ +public enum SuiteRole implements SystemRole { + /** An external person who has read access to part of the information. */ + observer, + /** An active coworker. */ + coworker, + /** Someone who is allowed validate and publish information. */ + publisher, + /** Someone with manager status within an organisation. Does not necessarily give more rights. */ + manager, + // + ; + + private final static String QUALIFIER = "app."; + + private final ContentName name; -/** Office specific roles used in the code */ -public enum SuiteRole implements Distinguished { - coworker, manager; + SuiteRole() { + name = new ContentName(ArgeoNamespace.ROLE_NAMESPACE_URI, QUALIFIER + name()); + } + + @Override + public QName qName() { + return name; + } - public String getRolePrefix() { + @Deprecated + private String getRolePrefix() { return "org.argeo.suite"; } + @Deprecated public String dn() { - return new StringBuilder(LdapAttrs.cn.name()).append("=").append(getRolePrefix()).append(".").append(name()) - .append(",").append(CmsConstants.ROLES_BASEDN).toString(); + return new StringBuilder(LdapAttr.cn.name()).append("=").append(getRolePrefix()).append(".").append(name()) + .append(",").append(CmsConstants.SYSTEM_ROLES_BASEDN).toString(); } } diff --git a/org.argeo.app.api/src/org/argeo/app/api/entity.cnd b/org.argeo.app.api/src/org/argeo/app/api/entity.cnd index 2ea89f9..396b6f2 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/entity.cnd +++ b/org.argeo.app.api/src/org/argeo/app/api/entity.cnd @@ -4,6 +4,7 @@ // see https://www.w3.org/2003/01/geo/ + @@ -95,7 +96,9 @@ mixin mixin - ldap:sn (String) - ldap:givenName (String) +- ldap:cn (String) - ldap:mail (String) * +- ldap:description (String) [entity:user] > entity:person mixin diff --git a/org.argeo.app.core/.classpath b/org.argeo.app.core/.classpath index e801ebf..81fe078 100644 --- a/org.argeo.app.core/.classpath +++ b/org.argeo.app.core/.classpath @@ -1,6 +1,6 @@ - + diff --git a/org.argeo.app.core/OSGI-INF/geoToolsTest.xml b/org.argeo.app.core/OSGI-INF/geoToolsTest.xml new file mode 100644 index 0000000..68a53ab --- /dev/null +++ b/org.argeo.app.core/OSGI-INF/geoToolsTest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/org.argeo.app.core/OSGI-INF/maintenanceService.xml b/org.argeo.app.core/OSGI-INF/maintenanceService.xml index b88d68c..965d82b 100644 --- a/org.argeo.app.core/OSGI-INF/maintenanceService.xml +++ b/org.argeo.app.core/OSGI-INF/maintenanceService.xml @@ -1,7 +1,8 @@ - + - - + + + diff --git a/org.argeo.app.core/OSGI-INF/termsManager.xml b/org.argeo.app.core/OSGI-INF/termsManager.xml index 92f84c6..797c5a3 100644 --- a/org.argeo.app.core/OSGI-INF/termsManager.xml +++ b/org.argeo.app.core/OSGI-INF/termsManager.xml @@ -1,7 +1,7 @@ - + - + diff --git a/org.argeo.app.core/bnd.bnd b/org.argeo.app.core/bnd.bnd index 8604ec9..9d8228b 100644 --- a/org.argeo.app.core/bnd.bnd +++ b/org.argeo.app.core/bnd.bnd @@ -6,6 +6,7 @@ OSGI-INF/maintenanceService.xml,\ OSGI-INF/dbk4Converter.xml,\ Import-Package:\ +tech.units.indriya.unit,\ org.osgi.service.useradmin,\ javax.jcr.nodetype,\ javax.jcr.security,\ diff --git a/org.argeo.app.core/build.properties b/org.argeo.app.core/build.properties index 6210e84..76d3ee9 100644 --- a/org.argeo.app.core/build.properties +++ b/org.argeo.app.core/build.properties @@ -3,3 +3,4 @@ bin.includes = META-INF/,\ .,\ OSGI-INF/ source.. = src/ +additional.bundles = org.argeo.init diff --git a/org.argeo.app.core/src/org/argeo/app/core/CustomMaintenanceService.java b/org.argeo.app.core/src/org/argeo/app/core/CustomMaintenanceService.java index 4b69883..a4b1fff 100644 --- a/org.argeo.app.core/src/org/argeo/app/core/CustomMaintenanceService.java +++ b/org.argeo.app.core/src/org/argeo/app/core/CustomMaintenanceService.java @@ -25,7 +25,7 @@ public abstract class CustomMaintenanceService extends AbstractMaintenanceServic } protected String getTypologiesLoadBase() { - return "/sys/terms"; + return ""; } protected void loadTypologies(Node customBaseNode) throws RepositoryException, IOException { @@ -44,9 +44,11 @@ public abstract class CustomMaintenanceService extends AbstractMaintenanceServic try { // if (termsBase.hasNode(name)) // return; - - String termsLoadPath = getTypologiesLoadBase() + '/' + name + ".xml"; - URL termsUrl = getClass().getClassLoader().getResource(termsLoadPath); + String typologiesLoadBase = getTypologiesLoadBase(); + if (typologiesLoadBase.contains("/") && !typologiesLoadBase.endsWith("/")) + typologiesLoadBase = typologiesLoadBase + "/"; + String termsLoadPath = typologiesLoadBase + name + ".xml"; + URL termsUrl = getClass().getResource(termsLoadPath); if (termsUrl == null) throw new IllegalArgumentException("Terms '" + name + "' not found."); try (InputStream in = termsUrl.openStream()) { diff --git a/org.argeo.app.core/src/org/argeo/app/core/SuiteContentNamespace.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteContentNamespace.java new file mode 100644 index 0000000..48c508b --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/SuiteContentNamespace.java @@ -0,0 +1,95 @@ +package org.argeo.app.core; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Objects; + +import org.argeo.api.acr.spi.ContentNamespace; + +public enum SuiteContentNamespace implements ContentNamespace { + // + // ARGEO + // + ENTITY("entity", "http://www.argeo.org/ns/entity", "entity.xsd", null), + // + ARGEO_DBK("argeodbk", "http://www.argeo.org/ns/argeodbk", null, null), + // + // EXTERNAL + // + DOCBOOK5("dbk", "http://docbook.org/ns/docbook", "docbook.xsd", "http://docbook.org/xml/5.0.1/xsd/docbook.xsd"), + // + XML_EVENTS("ev", "http://www.w3.org/2001/xml-events", "xml-events-attribs-1.xsd", + "http://www.w3.org/MarkUp/SCHEMA/xml-events-attribs-1.xsd"), + // + XFORMS("xforms", "http://www.w3.org/2002/xforms", "XForms-11-Schema.xsd", + "https://www.w3.org/MarkUp/Forms/2007/XForms-11-Schema.xsd"), + // + XCARD("xcard", "urn:ietf:params:xml:ns:vcard-4.0", "xCard-4.0.xsd", null), + // + XSL_FO("fo", "http://www.w3.org/1999/XSL/Format", "fop.xsd", + "https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/fop/src/foschema/fop.xsd"), + // +// XCAL_2_0("xcal", "urn:ietf:params:xml:ns:icalendar-2.0", "xCal-2.0.xsd", null), + // + XHTML("h", "http://www.w3.org/1999/xhtml", null, "https://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd"), + // + // ODK + // + JR("jr", "http://openrosa.org/javarosa", null, null), + // + ORX("orx", "http://openrosa.org/xforms", null, null), + // + ORX_LIST("orxList", "http://openrosa.org/xforms/xformsList", null, null), + // + ORX_MANIFEST("orxManifest", "http://openrosa.org/xforms/xformsManifest", null, null), + // + ODK("odk", "http://www.opendatakit.org/xforms", null, null), + // + WGS84("geo", "http://www.w3.org/2003/01/geo/wgs84_pos#", null, null), + // + ; + + private final static String RESOURCE_BASE = "/org/argeo/app/core/schemas/"; + + private String defaultPrefix; + private String namespace; + private URL resource; + private URL publicUrl; + + SuiteContentNamespace(String defaultPrefix, String namespace, String resourceFileName, String publicUrl) { + Objects.requireNonNull(namespace); + this.defaultPrefix = defaultPrefix; + Objects.requireNonNull(namespace); + this.namespace = namespace; + if (resourceFileName != null) { + resource = getClass().getResource(RESOURCE_BASE + resourceFileName); + Objects.requireNonNull(resource); + } + if (publicUrl != null) + try { + this.publicUrl = new URL(publicUrl); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Cannot interpret public URL", e); + } + } + + @Override + public String getDefaultPrefix() { + return defaultPrefix; + } + + @Override + public String getNamespaceURI() { + return namespace; + } + + @Override + public URL getSchemaResource() { + return resource; + } + + public URL getPublicUrl() { + return publicUrl; + } + +} diff --git a/org.argeo.app.core/src/org/argeo/app/core/SuiteMaintenanceService.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteMaintenanceService.java index 532b7dd..9c74dde 100644 --- a/org.argeo.app.core/src/org/argeo/app/core/SuiteMaintenanceService.java +++ b/org.argeo.app.core/src/org/argeo/app/core/SuiteMaintenanceService.java @@ -1,20 +1,65 @@ package org.argeo.app.core; import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.nodetype.NodeType; import javax.jcr.security.Privilege; +import javax.measure.Quantity; +import javax.measure.quantity.Area; +import org.argeo.api.acr.spi.ContentNamespace; import org.argeo.api.cms.CmsConstants; import org.argeo.app.api.EntityType; import org.argeo.jcr.JcrUtils; import org.argeo.maintenance.AbstractMaintenanceService; +import org.geotools.gml3.v3_2.GML; + +import si.uom.SI; +import tech.units.indriya.quantity.Quantities; /** Initialises an Argeo Suite backend. */ public class SuiteMaintenanceService extends AbstractMaintenanceService { + @Override + public void init() { + // make sure that the unit system is initialised + Quantity dummy = Quantities.getQuantity(0, SI.SQUARE_METRE); + + super.init(); + + getContentRepository().registerTypes(SuiteContentNamespace.values()); +// for (SuiteContentTypes types : SuiteContentTypes.values()) { +// getContentRepository().registerTypes(types.getDefaultPrefix(), types.getNamespace(), +// types.getResource() != null ? types.getResource().toExternalForm() : null); +// } + + // GML schema import fails because of xlinks issues + getContentRepository().registerTypes(new ContentNamespace() { + + @Override + public URL getSchemaResource() { + try { + return new URL(GML.getInstance().getSchemaLocation()); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public String getNamespaceURI() { + return GML.getInstance().getNamespaceURI(); + } + + @Override + public String getDefaultPrefix() { + return "gml"; + } + }); + } @Override public boolean prepareJcrTree(Session adminSession) throws RepositoryException, IOException { @@ -33,7 +78,8 @@ public class SuiteMaintenanceService extends AbstractMaintenanceService { public void configurePrivileges(Session adminSession) throws RepositoryException { JcrUtils.addPrivilege(adminSession, EntityType.user.basePath(), CmsConstants.ROLE_USER_ADMIN, Privilege.JCR_ALL); - //JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), Privilege.JCR_READ); + // JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), + // Privilege.JCR_READ); } } diff --git a/org.argeo.app.core/src/org/argeo/app/core/SuiteUtils.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteUtils.java index 0a31b14..f225064 100644 --- a/org.argeo.app.core/src/org/argeo/app/core/SuiteUtils.java +++ b/org.argeo.app.core/src/org/argeo/app/core/SuiteUtils.java @@ -4,50 +4,75 @@ import java.util.HashSet; import java.util.Set; import javax.jcr.Node; +import javax.jcr.NodeIterator; 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 javax.xml.namespace.QName; +import org.argeo.api.acr.Content; +import org.argeo.api.acr.ldap.LdapAttr; +import org.argeo.api.acr.ldap.LdapObj; import org.argeo.api.cms.CmsConstants; import org.argeo.api.cms.CmsSession; import org.argeo.app.api.EntityType; -import org.argeo.app.api.SuiteRole; -import org.argeo.jackrabbit.security.JackrabbitSecurityUtils; +import org.argeo.cms.RoleNameUtils; import org.argeo.jcr.JcrException; import org.argeo.jcr.JcrUtils; -import org.argeo.util.naming.LdapAttrs; /** Utilities around the Argeo Suite APIs. */ public class SuiteUtils { + public final static String USER_STATE_NODE_NAME = "state"; + public final static String USER_DEVICES_NODE_NAME = "devices"; + public final static String USER_SESSIONS_NODE_NAME = "sessions"; - public static String getUserNodePath(LdapName userDn) { - String uid = userDn.getRdn(userDn.size() - 1).getValue().toString(); + public static String getUserNodePath(String userDn) { + String uid = RoleNameUtils.getLastRdnValue(userDn); return EntityType.user.basePath() + '/' + uid; } - public static Node getOrCreateUserNode(Session adminSession, LdapName userDn) { + public static Node getOrCreateUserNode(Session adminSession, String userDn) { try { Node usersBase = adminSession.getNode(EntityType.user.basePath()); - String uid = userDn.getRdn(userDn.size() - 1).getValue().toString(); + String uid = RoleNameUtils.getLastRdnValue(userDn); 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); + userNode.setProperty(LdapAttr.distinguishedName.get(), userDn.toString()); + userNode.setProperty(LdapAttr.uid.get(), uid); + } else { + userNode = usersBase.getNode(uid); + } + + if (!userNode.hasNode(USER_SESSIONS_NODE_NAME)) { + // Migrate existing user node + Node sessionsNode = userNode.addNode(USER_SESSIONS_NODE_NAME, NodeType.NT_UNSTRUCTURED); + oldSessions: for (NodeIterator nit = userNode.getNodes(); nit.hasNext();) { + Node child = nit.nextNode(); + if (USER_SESSIONS_NODE_NAME.equals(child.getName()) || child.getName().startsWith("rep:") + || child.getName().startsWith("jcr:")) + continue oldSessions; + Node target = sessionsNode.addNode(child.getName()); + JcrUtils.copy(child, target); + } + + Node userStateNode = userNode.addNode(USER_STATE_NODE_NAME, NodeType.NT_UNSTRUCTURED); + Node userDevicesNode = userNode.addNode(USER_DEVICES_NODE_NAME, NodeType.NT_UNSTRUCTURED); + adminSession.save(); - JackrabbitSecurityUtils.denyPrivilege(adminSession, userNode.getPath(), SuiteRole.coworker.dn(), - Privilege.JCR_READ); +// 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(), CmsConstants.ROLE_USER_ADMIN, Privilege.JCR_ALL); - } else { - userNode = usersBase.getNode(uid); + + JcrUtils.addPrivilege(adminSession, userStateNode.getPath(), userDn, Privilege.JCR_ALL); + JcrUtils.addPrivilege(adminSession, userDevicesNode.getPath(), userDn, Privilege.JCR_ALL); } return userNode; } catch (RepositoryException e) { @@ -57,7 +82,8 @@ public class SuiteUtils { public static Node getCmsSessionNode(Session session, CmsSession cmsSession) { try { - return session.getNode(getUserNodePath(cmsSession.getUserDn()) + '/' + cmsSession.getUuid().toString()); + return session.getNode(getUserNodePath(cmsSession.getUserDn()) + '/' + USER_SESSIONS_NODE_NAME + '/' + + cmsSession.getUuid().toString()); } catch (RepositoryException e) { throw new JcrException("Cannot get session dir for " + cmsSession, e); } @@ -65,29 +91,19 @@ public class SuiteUtils { public static Node getOrCreateCmsSessionNode(Session adminSession, CmsSession cmsSession) { try { - LdapName userDn = cmsSession.getUserDn(); -// String uid = userDn.get(userDn.size() - 1); + String userDn = cmsSession.getUserDn(); 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); -// } + Node sessionsNode = userNode.getNode(USER_SESSIONS_NODE_NAME); String cmsSessionUuid = cmsSession.getUuid().toString(); Node cmsSessionNode; - if (!userNode.hasNode(cmsSessionUuid)) { - cmsSessionNode = userNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED); + if (!sessionsNode.hasNode(cmsSessionUuid)) { + cmsSessionNode = sessionsNode.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); + cmsSessionNode = sessionsNode.getNode(cmsSessionUuid); } return cmsSessionNode; } catch (RepositoryException e) { @@ -95,11 +111,6 @@ public class SuiteUtils { } } - /** Singleton. */ - private SuiteUtils() { - - } - public static Set extractRoles(String[] semiColArr) { Set res = new HashSet<>(); // TODO factorize and make it more robust @@ -120,4 +131,33 @@ public class SuiteUtils { return res; } + synchronized static public long findNextId(Content hierarchyUnit, QName cclass) { + if (!hierarchyUnit.hasContentClass(LdapObj.posixGroup.qName())) + throw new IllegalArgumentException(hierarchyUnit + " is not a POSIX group"); + + long min = hierarchyUnit.get(LdapAttr.gidNumber.qName(), Long.class).orElseThrow(); + long currentMax = 0l; + for (Content childHu : hierarchyUnit) { + if (!childHu.hasContentClass(LdapObj.organizationalUnit.qName())) + continue; + // FIXME filter out functional hierarchy unit + for (Content role : childHu) { + if (role.hasContentClass(cclass)) { + + if (LdapObj.posixAccount.qName().equals(cclass)) { + Long id = role.get(LdapAttr.uidNumber.qName(), Long.class).orElseThrow(); + if (id > currentMax) + currentMax = id; + } + } + } + } + if (currentMax == 0l) + return min; + return currentMax + 1; + } + + /** Singleton. */ + private SuiteUtils() { + } } diff --git a/org.argeo.app.core/src/org/argeo/app/core/XPathUtils.java b/org.argeo.app.core/src/org/argeo/app/core/XPathUtils.java index f86445c..b0678cd 100644 --- a/org.argeo.app.core/src/org/argeo/app/core/XPathUtils.java +++ b/org.argeo.app.core/src/org/argeo/app/core/XPathUtils.java @@ -78,7 +78,6 @@ public class XPathUtils { * @param propertyName * @param calendar the reference date * @param lowerOrGreater "<", ">" TODO validate ">=" - * @return * @throws RepositoryException */ public static String getPropertyDateComparaison(String propertyName, Calendar cal, String lowerOrGreater) diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/XForms-11-Schema.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/XForms-11-Schema.xsd new file mode 100644 index 0000000..881bfcb --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/XForms-11-Schema.xsd @@ -0,0 +1,1571 @@ + + + + + + + + + + Attributes for _every_ element in XForms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + instance container. + + + + + + + + + + + + + + Definition of bind container. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Attributes for _every_ action in XForms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + submit info container. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This type defines the basic lexical properties for a dataypte that can be used to represent + various ID numbers such as for debit and credit cards. + This type does not apply the Luhn checksum algorithm. + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/XMLSchema.dtd b/org.argeo.app.core/src/org/argeo/app/core/schemas/XMLSchema.dtd new file mode 100644 index 0000000..e8e8f76 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/XMLSchema.dtd @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%xs-datatypes; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/XMLSchema.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/XMLSchema.xsd new file mode 100644 index 0000000..12c2209 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/XMLSchema.xsd @@ -0,0 +1,2534 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]> + + + + Part 1 version: Id: structures.xsd,v 1.2 2004/01/15 11:34:25 ht Exp + Part 2 version: Id: datatypes.xsd,v 1.3 2004/01/23 18:11:13 ht Exp + + + + + + The schema corresponding to this document is normative, + with respect to the syntactic constraints it expresses in the + XML Schema language. The documentation (within <documentation> elements) + below, is not normative, but rather highlights important aspects of + the W3C Recommendation of which this is a part + + + + + The simpleType element and all of its members are defined + towards the end of this schema document + + + + + + Get access to the xml: attribute groups for xml:lang + as declared on 'schema' and 'documentation' below + + + + + + + + This type is extended by almost all schema types + to allow attributes from other namespaces to be + added to user schemas. + + + + + + + + + + + + + This type is extended by all types which allow annotation + other than <schema> itself + + + + + + + + + + + + + + + + This group is for the + elements which occur freely at the top level of schemas. + All of their types are based on the "annotated" type by extension. + + + + + + + + + + + + + This group is for the + elements which can self-redefine (see <redefine> below). + + + + + + + + + + + + + A utility type, not for public use + + + + + + + + + + + A utility type, not for public use + + + + + + + + + + + A utility type, not for public use + + #all or (possibly empty) subset of {extension, restriction} + + + + + + + + + + + + + + + + + A utility type, not for public use + + + + + + + + + + + + + A utility type, not for public use + + #all or (possibly empty) subset of {extension, restriction, list, union} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for maxOccurs + + + + + + + + + + + + for all particles + + + + + + + for element, group and attributeGroup, + which both define and reference + + + + + + + + 'complexType' uses this + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This branch is short for + <complexContent> + <restriction base="xs:anyType"> + ... + </restriction> + </complexContent> + + + + + + + + + + + + + + + Will be restricted to required or forbidden + + + + + + Not allowed if simpleContent child is chosen. + May be overriden by setting on complexContent child. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This choice is added simply to + make this a valid restriction per the REC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Overrides any setting on complexType parent. + + + + + + + + + + + + + + + This choice is added simply to + make this a valid restriction per the REC + + + + + + + + + + + + + + + + + No typeDefParticle group reference + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A utility type, not for public use + + #all or (possibly empty) subset of {substitution, extension, + restriction} + + + + + + + + + + + + + + + + + + + + + + + + + The element element can be used either + at the top level to define an element-type binding globally, + or within a content model to either reference a globally-defined + element or type or declare an element-type binding locally. + The ref form is not allowed at the top level. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + group type for explicit groups, named top-level groups and + group references + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + group type for the three kinds of group + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This choice with min/max is here to + avoid a pblm with the Elt:All/Choice/Seq + Particle derivation constraint + + + + + + + + + + restricted max/min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Only elements allowed inside + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple type for the value of the 'namespace' attr of + 'any' and 'anyAttribute' + + + + Value is + ##any - - any non-conflicting WFXML/attribute at all + + ##other - - any non-conflicting WFXML/attribute from + namespace other than targetNS + + ##local - - any unqualified non-conflicting WFXML/attribute + + one or - - any non-conflicting WFXML/attribute from + more URI the listed namespaces + references + (space separated) + + ##targetNamespace or ##local may appear in the above list, to + refer to the targetNamespace of the enclosing + schema or an absent targetNamespace respectively + + + + + + A utility type, not for public use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A subset of XPath expressions for use +in selectors + A utility type, not for public +use + + + + The following pattern is intended to allow XPath + expressions per the following EBNF: + Selector ::= Path ( '|' Path )* + Path ::= ('.//')? Step ( '/' Step )* + Step ::= '.' | NameTest + NameTest ::= QName | '*' | NCName ':' '*' + child:: is also allowed + + + + + + + + + + + + + + + + + + + + + + + A subset of XPath expressions for use +in fields + A utility type, not for public +use + + + + The following pattern is intended to allow XPath + expressions per the same EBNF as for selector, + with the following change: + Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest ) + + + + + + + + + + + + + + + + + + + + + + + + + + + The three kinds of identity constraints, all with + type of or derived from 'keybase'. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A utility type, not for public use + + A public identifier, per ISO 8879 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + notations for use within XML Schema schemas + + + + + + + + + Not the real urType, but as close an approximation as we can + get in the XML representation + + + + + + + + + + First the built-in primitive datatypes. These definitions are for + information only, the real built-in definitions are magic. + + + + For each built-in datatype in this schema (both primitive and + derived) can be uniquely addressed via a URI constructed + as follows: + 1) the base URI is the URI of the XML Schema namespace + 2) the fragment identifier is the name of the datatype + + For example, to address the int datatype, the URI is: + + http://www.w3.org/2001/XMLSchema#int + + Additionally, each facet definition element can be uniquely + addressed via a URI constructed as follows: + 1) the base URI is the URI of the XML Schema namespace + 2) the fragment identifier is the name of the facet + + For example, to address the maxInclusive facet, the URI is: + + http://www.w3.org/2001/XMLSchema#maxInclusive + + Additionally, each facet usage in a built-in datatype definition + can be uniquely addressed via a URI constructed as follows: + 1) the base URI is the URI of the XML Schema namespace + 2) the fragment identifier is the name of the datatype, followed + by a period (".") followed by the name of the facet + + For example, to address the usage of the maxInclusive facet in + the definition of int, the URI is: + + http://www.w3.org/2001/XMLSchema#int.maxInclusive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NOTATION cannot be used directly in a schema; rather a type + must be derived from it by specifying at least one enumeration + facet whose value is the name of a NOTATION declared in the + schema. + + + + + + + + + + Now the derived primitive types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pattern specifies the content of section 2.12 of XML 1.0e2 + and RFC 3066 (Revised version of RFC 1766). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pattern matches production 7 from the XML spec + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pattern matches production 5 from the XML spec + + + + + + + + + + + + + + + pattern matches production 4 from the Namespaces in XML spec + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A utility type, not for public use + + + + + + + + + + + + + + + + + + + + + + #all or (possibly empty) subset of {restriction, union, list} + + + A utility type, not for public use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Can be restricted to required or forbidden + + + + + + + + + + + + + + + + + + Required at the top level + + + + + + + + + + + + + + + + + + + Forbidden when nested + + + + + + + + + + + + + + + + + + + We should use a substitution group for facets, but + that's ruled out because it would allow users to + add their own, which we're not ready for yet. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + base attribute and simpleType child are mutually + exclusive, but one or other is required + + + + + + + + + + + + + + + + itemType attribute and simpleType child are mutually + exclusive, but one or other is required + + + + + + + + + + + + + + + + + + memberTypes attribute must be non-empty or there must be + at least one simpleType child + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/datatypes.dtd b/org.argeo.app.core/src/org/argeo/app/core/schemas/datatypes.dtd new file mode 100644 index 0000000..8e48553 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/datatypes.dtd @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/docbook.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/docbook.xsd new file mode 100644 index 0000000..f2c9aed --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/docbook.xsd @@ -0,0 +1,17461 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/entity.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/entity.xsd new file mode 100644 index 0000000..a2fbfcd --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/entity.xsd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/fop.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/fop.xsd new file mode 100644 index 0000000..a787bf3 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/fop.xsd @@ -0,0 +1,4313 @@ + + + + + + + + + I'm not sure where to place this. + It applies to the page context (NOT implemented) + + + I have not coded for the functions described in 5.10 Core Function Library + They need to be segregated into groups and then inserted in the types + + common_functions + object inherited-property-value(NCName) + object from-parent( NCName) + object from-nearest-specified-value( NCName) + object merge-property-values( NCName) + + font_functions + object system-font( NCName , NCName) + + length_functions + numeric floor( numeric) + numeric ceiling(numeric) + numeric round(numeric) + numeric min( numeric , numeric) + numeric max(numeric , numeric) + numeric abs( numeric) + + table_cell_or_descendants_functions + object from-table-column( NCName) + + color_functions + color rgb(numeric , numeric , numeric) + color rgb-icc(numeric , numeric , numeric , NCName , numeric , numeric) + color system-color( NCName) + + label_functions + numeric body-start() + numeric label-end() + + (defined) + table-column_functions + numeric proportional-column-width( numeric) + + This schema has been developed in order to validate XSL FO documents for FOP + All of the elements need to be prefixed with fo: + The namespace prefix is xmlns:fo = "http://www.w3.org/1999/XSL/Format". + + This schema, as delivered, may either validate the full spec, or, just the FOP portion. + (What it validates depends upon what I was doing with it when released.) + + If you want to restrict it to just those elements and attributes implemented by FOP, + you need to edit the and tags to exclude the groups ending with _Not + + Some schema tools complain about the placement of comments in this schema and will remove or reorder them + There are fop_result and fop_fail comments on specific features not implemented by FOP + + FOP does not enforce the following schema requirements + + fo:simple-page-master model = "(region-body,region-before?,region-after?,region-start?,region-end?)" + elements can be in any order + + fo:table-cell model = "(%block;)+" + Can be empty + + fo:flow model = "(%block;)+" + Can be empty + + This schema allows the length attribute to be negative for some elements like margins. + There may be instances where I've entered %integer_Type; and it should be positive-integer or number + The schema trys to handle the text based rules re: fo:markers, fo:float, footer and fo:initial-property-set + But, allows you to do illegal things if you want because I couldn't figure out how to constrain against the illegal actions. + + Please e-mail your comments to cpaussa@myrealbox.com + + Contribution by Oleg Tkachenko + (Declarations able to include non-xsl children) + + This declaration assumes that all elements must come before other stuff, + which is not required by spec, but I cannot see any way to express such constraints in schema, + one could use instead of , but this way we lose control over (color-profile)+ constraint. + + VCP 21-Oct-2002 + Updated all (px|pt|mm|cm|in|em) to (px|pt|mm|cm|in|em|%) to allow percentage types. + Updated the restriction base of those types from NMTOKEN to string + + + + + + + + + + + + + empty group so cannot be defined + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + empty group so cannot be defined + + + + + + + + + + + + + + empty group + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Removed because I'm not sure how to handle this + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + Inheritable attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inherited + + + + + + + + + + + + + + + + + + + + + + Inherited + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inherited + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Font properties are all inheritable + + + + + + + + + + + Font properties are all inheritable + + + + + + + + + + + + + + + + The hyphenation properties are all inheritable and so superceeded by that list + + + + + + + + + + + + + The hyphenation properties are all inheritable and so superceeded by that list + + + + + + + + + + + + + + + + + + Indent properties are inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Simple Types definitions + + + + + + A signed integer value which consists of an optional '+' or '-' character followed by a sequence of digits. A property may define additional constraints on the value. + + + + + + + + + + + + + + + A signed real number which consists of an optional '+' or '-' character followed by a sequence of digits followed by an optional '.' character and sequence of digits. A property may define additional constraints on the value. + + + + + + + + + + + + + A signed length value where a 'length' is a real number plus a unit qualification. A property may define additional constraints on the value. + + + + + + + + + + + + + + + + A compound datatype, with components: minimum, optimum, maximum. Each component is a . If "minimum" is greater than optimum, it will be treated as if it had been set to "optimum". If "maximum" is less than optimum, it will be treated as if it had been set to "optimum". A property may define additional constraints on the values. + + + + + + + + + + + + + + + + + + + + + A compound datatype, with components: length, conditionality. The length component is a . The conditionality component is either "discard" or "retain". A property may define additional constraints on the values. + + + + + + + + + + + + + + + + + + + + + + + + A compound datatype, with components: block-progression-direction, and inline-progression-direction. Each component is a . A property may define additional constraints on the values. + + + + + + + + + + + + + + + + + + + + + A compound datatype, with components: minimum, optimum, maximum, precedence, and conditionality. The minimum, optimum, and maximum components are s. The precedence component is either "force" or an . The conditionality component is either "discard" or "retain". If "minimum" is greater than optimum, it will be treated as if it had been set to "optimum". If "maximum" is less than optimum, it will be treated as if it had been set to "optimum". + + + + + + + + + + + + + A representation of an angle consisting of an optional '+' or '-' character immediately followed by a immediately followed by an angle unit identifier. Angle unit identifiers are: 'deg' (for degrees), 'grad' (for grads), and 'rad' (for radians). The specified values are normalized to the range 0deg to 360deg. A property may define additional constraints on the value. + + + + + + + + + + + + + A signed real percentage which consists of an optional '+' or '-' character followed by a sequence of digits followed by an optional '.' character and sequence of digits followed by '%'. A property may define additional constraints on the value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + A string of characters representing a name. It must conform to the definition of an NCName in + + + + + + + + + + A string of characters identifying a font. + + + + + + + + + + + + + + + + + + + + + + + Either a string of characters representing a keyword or a color function defined in . The list of keyword color names is: aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, and yellow. + + + + + + + + + + + + The function proportional-column-width(N[0]) + This returns a width as a fraction of the available width as ( N[0] / sum1 ) * available space + The parent table must have width="x" and table-layout="fixed" + + + + + + + + + + + , , proportional-column-width, or common-functions + + + + + + + + + A string of characters conforming to an ISO 15924 script code. + + + + + A string of characters conforming to the definition of an NCName in and is unique within the stylesheet. + + + + + A string of characters conforming to the definition of an NCName in and that matches an ID property value used within the stylesheet. + + + + + A sequence of characters that is "url(", followed by optional white space, followed by an optional single quote (') or double quote (") character, followed by a URI reference as defined in , followed by an optional single quote (') or double quote (") character, followed by optional white space, followed by ")". The two quote characters must be the same and must both be present or absent. If the URI reference contains a single quote, the two quote characters must be present and be double quotes. + + + + + A immediately followed by a time unit identifier. Time unit identifiers are: 'ms' (for milliseconds) and 's' (for seconds). + + + + + A immediately followed by a frequency unit identifier. Frequency unit identifiers are: 'Hz' (for Hertz) and 'kHz' (for kilo Hertz). + + + + + The following generic families are defined: "serif", "sans-serif", "cursive", "fantasy", and "monospace". Please see the section on generic font families for descriptions of these families. Generic font family names are keywords, and therefore must not be quoted. + + + + + + An keyword refers to an entry in a table of font sizes computed and kept by the user agent. Possible values are: [ xx-small | x-small | small | medium | large | x-large | xx-large ] On a computer screen a scaling factor of 1.2 is suggested between adjacent indexes; if the "medium" font is 12pt, the "large" font could be 14.4pt. Different media may need different scaling factors. Also, the user agent should take the quality and availability of fonts into account when computing the table. The table may be different from one font family to another. Note. In CSS1, the suggested scaling factor between adjacent indexes was 1.5 which user experience proved to be too large. + + + + + + + + + + + + + + + + A keyword is interpreted relative to the table of font sizes and the font size of the parent element. Possible values are: [ larger | smaller ] For example, if the parent element has a font size of "medium", a value of "larger" will make the font size of the current element be "large". If the parent element's size is not close to a table entry, the user agent is free to interpolate between table entries or round off to the closest one. The user agent may have to extrapolate table values if the numerical value goes beyond the keywords. + + + + + + + + + + + shape_Type In CSS2, the only valid value is: rect (, , , ) where , , and specify offsets from the respective sides of the box. , , , and may either have a value or "auto". Negative lengths are permitted. The value "auto" means that a given edge of the clipping region will be the same as the edge of the element's generated box (i.e., "auto" means the same as "0".) When coordinates are rounded to pixel coordinates, care should be taken that no pixels remain visible when + is equal to the element's width (or + equals the element's height), and conversely that no pixels remain hidden when these values are 0. + + + + + + length_Type{1,2} + + + + + + + + + + "fo:width_Type fo:border_style_Type fo:color_Type" + + + + + + + + + + + + + "fo:width_Type{1,4} fo:inherit_Type" + + + + + + + + + + + + + + + + + + + + + + + "fo:border_style_Type{1,4} fo:inherit_Type" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "fo:background_color_Type{1,4}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + heavier than no value + + + + + + + lighter than normal unknown font + + + + + + + lighter than normal unknown font + + + + + + + same as normal + + + + + + + same as normal + + + + + + + same as normal + + + + + + + same as normal + + + + + + + same as normal + + + + + + + same as normal + + + + + + + same as bold + + + + + + + same as bold + + + + + + + same as bold + + + + + + + lighter than normal unknown font + + + + + + + + + + + + + + unknown font + + + + + + + unknown font + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown enumerated value + + + + + + + + + + + + + + + A compound datatype, with components: within-line, within-column, within-page. Each component is a . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown enumerated value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown enumerated value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Here to document the acceptable measurements + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A string of characters conforming to an ISO 3166 country code. + + + + + + country-name = "AFGHANISTAN"/ + country-name = "ALBANIA"/ + country-name = "ALGERIA"/ + country-name = "AMERICANSAMOA"/ + country-name = "ANDORRA"/ + country-name = "ANGOLA"/ + country-name = "ANGUILLA"/ + country-name = "ANTARCTICA"/ + country-name = "ANTIGUAANDBARBUDA"/ + country-name = "ARGENTINA"/ + country-name = "ARMENIA"/ + country-name = "ARUBA"/ + country-name = "AUSTRALIA"/ + country-name = "AUSTRIA"/ + country-name = "AZERBAIJAN"/ + country-name = "BAHAMAS"/ + country-name = "BAHRAIN"/ + country-name = "BANGLADESH"/ + country-name = "BARBADOS"/ + country-name = "BELARUS"/ + country-name = "BELGIUM"/ + country-name = "BELIZE"/ + country-name = "BENIN"/ + country-name = "BERMUDA"/ + country-name = "BHUTAN"/ + country-name = "BOLIVIA"/ + country-name = "BOSNIAANDHERZEGOVINA"/ + country-name = "BOTSWANA"/ + country-name = "BOUVETISLAND"/ + country-name = "BRAZIL"/ + country-name = "BRITISHINDIANOCEANTERRITORY"/ + country-name = "BRUNEIDARUSSALAM"/ + country-name = "BULGARIA"/ + country-name = "BURKINAFASO"/ + country-name = "BURUNDI"/ + country-name = "CAMBODIA"/ + country-name = "CAMEROON"/ + country-name = "CANADA"/ + country-name = "CAPEVERDE"/ + country-name = "CAYMANISLANDS"/ + country-name = "CENTRALAFRICANREPUBLIC"/ + country-name = "CHAD"/ + country-name = "CHILE"/ + country-name = "CHINA"/ + country-name = "CHRISTMASISLAND"/ + country-name = "COCOS(KEELING)ISLANDS"/ + country-name = "COLOMBIA"/ + country-name = "COMOROS"/ + country-name = "CONGO"/ + country-name = "CONGO,THEDEMOCRATICREPUBLICOFTHE"/ + country-name = "COOKISLANDS"/ + country-name = "COSTARICA"/ + country-name = "COTED'IVOIRE"/ + country-name = "CROATIA"/ + country-name = "CUBA"/ + country-name = "CYPRUS"/ + country-name = "CZECHREPUBLIC"/ + country-name = "DENMARK"/ + country-name = "DJIBOUTI"/ + country-name = "DOMINICA"/ + country-name = "DOMINICANREPUBLIC"/ + country-name = "EASTTIMOR"/ + country-name = "ECUADOR"/ + country-name = "EGYPT"/ + country-name = "ELSALVADOR"/ + country-name = "EQUATORIALGUINEA"/ + country-name = "ERITREA"/ + country-name = "ESTONIA"/ + country-name = "ETHIOPIA"/ + country-name = "FALKLANDISLANDS(MALVINAS)"/ + country-name = "FAROEISLANDS"/ + country-name = "FIJI"/ + country-name = "FINLAND"/ + country-name = "FRANCE"/ + country-name = "FRENCHGUIANA"/ + country-name = "FRENCHPOLYNESIA"/ + country-name = "FRENCHSOUTHERNTERRITORIES"/ + country-name = "GABON"/ + country-name = "GAMBIA"/ + country-name = "GEORGIA"/ + country-name = "GERMANY"/ + country-name = "GHANA"/ + country-name = "GIBRALTAR"/ + country-name = "GREECE"/ + country-name = "GREENLAND"/ + country-name = "GRENADA"/ + country-name = "GUADELOUPE"/ + country-name = "GUAM"/ + country-name = "GUATEMALA"/ + country-name = "GUINEA"/ + country-name = "GUINEA-BISSAU"/ + country-name = "GUYANA"/ + country-name = "HAITI"/ + country-name = "HEARDISLANDANDMCDONALDISLANDS"/ + country-name = "HOLYSEE(VATICANCITYSTATE)"/ + country-name = "HONDURAS"/ + country-name = "HONGKONG"/ + country-name = "HUNGARY"/ + country-name = "ICELAND"/ + country-name = "INDIA"/ + country-name = "INDONESIA"/ + country-name = "IRAN,ISLAMICREPUBLICOF"/ + country-name = "IRAQ"/ + country-name = "IRELAND"/ + country-name = "ISRAEL"/ + country-name = "ITALY"/ + country-name = "JAMAICA"/ + country-name = "JAPAN"/ + country-name = "JORDAN"/ + country-name = "KAZAKSTAN"/ + country-name = "KENYA"/ + country-name = "KIRIBATI"/ + country-name = "KOREA,DEMOCRATICPEOPLE'SREPUBLICOF"/ + country-name = "KOREA,REPUBLICOF"/ + country-name = "KUWAIT"/ + country-name = "KYRGYZSTAN"/ + country-name = "LAOPEOPLE'SDEMOCRATICREPUBLIC"/ + country-name = "LATVIA"/ + country-name = "LEBANON"/ + country-name = "LESOTHO"/ + country-name = "LIBERIA"/ + country-name = "LIBYANARABJAMAHIRIYA"/ + country-name = "LIECHTENSTEIN"/ + country-name = "LITHUANIA"/ + country-name = "LUXEMBOURG"/ + country-name = "MACAU"/ + country-name = "MACEDONIA,THEFORMERYUGOSLAVREPUBLICOF"/ + country-name = "MADAGASCAR"/ + country-name = "MALAWI"/ + country-name = "MALAYSIA"/ + country-name = "MALDIVES"/ + country-name = "MALI"/ + country-name = "MALTA"/ + country-name = "MARSHALLISLANDS"/ + country-name = "MARTINIQUE"/ + country-name = "MAURITANIA"/ + country-name = "MAURITIUS"/ + country-name = "MAYOTTE"/ + country-name = "MEXICO"/ + country-name = "MICRONESIA,FEDERATEDSTATESOF"/ + country-name = "MOLDOVA,REPUBLICOF"/ + country-name = "MONACO"/ + country-name = "MONGOLIA"/ + country-name = "MONTSERRAT"/ + country-name = "MOROCCO"/ + country-name = "MOZAMBIQUE"/ + country-name = "MYANMAR"/ + country-name = "NAMIBIA"/ + country-name = "NAURU"/ + country-name = "NEPAL"/ + country-name = "NETHERLANDS"/ + country-name = "NETHERLANDSANTILLES"/ + country-name = "NEWCALEDONIA"/ + country-name = "NEWZEALAND"/ + country-name = "NICARAGUA"/ + country-name = "NIGER"/ + country-name = "NIGERIA"/ + country-name = "NIUE"/ + country-name = "NORFOLKISLAND"/ + country-name = "NORTHERNMARIANAISLANDS"/ + country-name = "NORWAY"/ + country-name = "OMAN"/ + country-name = "PAKISTAN"/ + country-name = "PALAU"/ + country-name = "PALESTINIANTERRITORY,OCCUPIED"/ + country-name = "PANAMA"/ + country-name = "PAPUANEWGUINEA"/ + country-name = "PARAGUAY"/ + country-name = "PERU"/ + country-name = "PHILIPPINES"/ + country-name = "PITCAIRN"/ + country-name = "POLAND"/ + country-name = "PORTUGAL"/ + country-name = "PUERTORICO"/ + country-name = "QATAR"/ + country-name = "R+UNION"/ + country-name = "ROMANIA"/ + country-name = "RUSSIANFEDERATION"/ + country-name = "RWANDA"/ + country-name = "SAINTHELENA"/ + country-name = "SAINTKITTSANDNEVIS"/ + country-name = "SAINTLUCIA"/ + country-name = "SAINTPIERREANDMIQUELON"/ + country-name = "SAINTVINCENTANDTHEGRENADINES"/ + country-name = "SAMOA"/ + country-name = "SANMARINO"/ + country-name = "SAOTOMEANDPRINCIPE"/ + country-name = "SAUDIARABIA"/ + country-name = "SENEGAL"/ + country-name = "SEYCHELLES"/ + country-name = "SIERRALEONE"/ + country-name = "SINGAPORE"/ + country-name = "SLOVAKIA"/ + country-name = "SLOVENIA"/ + country-name = "SOLOMONISLANDS"/ + country-name = "SOMALIA"/ + country-name = "SOUTHAFRICA"/ + country-name = "SOUTHGEORGIAANDTHESOUTHSANDWICHISLANDS"/ + country-name = "SPAIN"/ + country-name = "SRILANKA"/ + country-name = "SUDAN"/ + country-name = "SURINAME"/ + country-name = "SVALBARDANDJANMAYEN"/ + country-name = "SWAZILAND"/ + country-name = "SWEDEN"/ + country-name = "SWITZERLAND"/ + country-name = "SYRIANARABREPUBLIC"/ + country-name = "TAIWAN,PROVINCEOFCHINA"/ + country-name = "TAJIKISTAN"/ + country-name = "TANZANIA,UNITEDREPUBLICOF"/ + country-name = "THAILAND"/ + country-name = "TOGO"/ + country-name = "TOKELAU"/ + country-name = "TONGA"/ + country-name = "TRINIDADANDTOBAGO"/ + country-name = "TUNISIA"/ + country-name = "TURKEY"/ + country-name = "TURKMENISTAN"/ + country-name = "TURKSANDCAICOSISLANDS"/ + country-name = "TUVALU"/ + country-name = "UGANDA"/ + country-name = "UKRAINE"/ + country-name = "UNITEDARABEMIRATES"/ + country-name = "UNITEDKINGDOM"/ + country-name = "UNITEDSTATES"/ + country-name = "UNITEDSTATESMINOROUTLYINGISLANDS"/ + country-name = "URUGUAY"/ + country-name = "UZBEKISTAN"/ + country-name = "VANUATU"/ + country-name = "VENEZUELA"/ + country-name = "VIETNAM"/ + country-name = "VIRGINISLANDS,BRITISH"/ + country-name = "VIRGINISLANDS,U.S."/ + country-name = "WALLISANDFUTUNA"/ + country-name = "WESTERNSAHARA"/ + country-name = "YEMEN"/ + country-name = "YUGOSLAVIA"/ + country-name = "ZAMBIA"/ + country-name = "ZIMBABWE"/ + + + + A string of characters conforming to the ISO 639 3-letter code. (Rather odd since all of them have 2 letters) + + + + language-name = "AYMARA" language-family = "AMERINDIAN"/ + language-name = "GUARANI" language-family = "AMERINDIAN"/ + language-name = "QUECHUA" language-family = "AMERINDIAN"/ + language-name = "BHUTANI" language-family = "ASIAN"/ + language-name = "BURMESE" language-family = "ASIAN"/ + language-name = "CAMBODIAN" language-family = "ASIAN"/ + language-name = "CHINESE" language-family = "ASIAN"/ + language-name = "JAPANESE" language-family = "ASIAN"/ + language-name = "KOREAN" language-family = "ASIAN"/ + language-name = "LAOTHIAN" language-family = "ASIAN"/ + language-name = "THAI" language-family = "ASIAN"/ + language-name = "TIBETAN" language-family = "ASIAN"/ + language-name = "VIETNAMESE" language-family = "ASIAN"/ + language-name = "LATVIAN;LETTISH" language-family = "BALTIC"/ + language-name = "LITHUANIAN" language-family = "BALTIC"/ + language-name = "BASQUE" language-family = "BASQUE"/ + language-name = "BRETON" language-family = "CELTIC"/ + language-name = "IRISH" language-family = "CELTIC"/ + language-name = "SCOTS-GAELIC" language-family = "CELTIC"/ + language-name = "WELSH" language-family = "CELTIC"/ + language-name = "KANNADA" language-family = "DRAVIDIAN"/ + language-name = "MALAYALAM" language-family = "DRAVIDIAN"/ + language-name = "TAMIL" language-family = "DRAVIDIAN"/ + language-name = "TELUGU" language-family = "DRAVIDIAN"/ + language-name = "GREENLANDIC" language-family = "ESKIMO"/ + language-name = "INUPIAK" language-family = "ESKIMO"/ + language-name = "ESTONIAN" language-family = "FINNO-UGRIC"/ + language-name = "FINNISH" language-family = "FINNO-UGRIC"/ + language-name = "HUNGARIAN" language-family = "FINNO-UGRIC"/ + language-name = "AFRIKAANS" language-family = "GERMANIC"/ + language-name = "DANISH" language-family = "GERMANIC"/ + language-name = "DUTCH" language-family = "GERMANIC"/ + language-name = "ENGLISH" language-family = "GERMANIC"/ + language-name = "FAROESE" language-family = "GERMANIC"/ + language-name = "FRISIAN" language-family = "GERMANIC"/ + language-name = "GERMAN" language-family = "GERMANIC"/ + language-name = "ICELANDIC" language-family = "GERMANIC"/ + language-name = "NORWEGIAN" language-family = "GERMANIC"/ + language-name = "SWEDISH" language-family = "GERMANIC"/ + language-name = "YIDDISH" language-family = "GERMANIC"/ + language-name = "AFAN-(OROMO)" language-family = "HAMITIC"/ + language-name = "AFAR" language-family = "HAMITIC"/ + language-name = "SOMALI" language-family = "HAMITIC"/ + language-name = "ABKHAZIAN" language-family = "IBERO-CAUCASIAN"/ + language-name = "GEORGIAN" language-family = "IBERO-CAUCASIAN"/ + language-name = "ASSAMESE" language-family = "INDIAN"/ + language-name = "BENGALI;BANGLA" language-family = "INDIAN"/ + language-name = "BIHARI" language-family = "INDIAN"/ + language-name = "GUJARATI" language-family = "INDIAN"/ + language-name = "HINDI" language-family = "INDIAN"/ + language-name = "KASHMIRI" language-family = "INDIAN"/ + language-name = "MARATHI" language-family = "INDIAN"/ + language-name = "NEPALI" language-family = "INDIAN"/ + language-name = "ORIYA" language-family = "INDIAN"/ + language-name = "PUNJABI" language-family = "INDIAN"/ + language-name = "SANSKRIT" language-family = "INDIAN"/ + language-name = "SINDHI" language-family = "INDIAN"/ + language-name = "SINGHALESE" language-family = "INDIAN"/ + language-name = "URDU" language-family = "INDIAN"/ + language-name = "ALBANIAN" language-family = "INDO-EUROPEAN(OTHER)"/ + language-name = "ARMENIAN" language-family = "INDO-EUROPEAN(OTHER)"/ + language-name = "ESPERANTO" language-family = "INTERNATIONAL-AUX."/ + language-name = "INTERLINGUA" language-family = "INTERNATIONAL-AUX."/ + language-name = "INTERLINGUE" language-family = "INTERNATIONAL-AUX."/ + language-name = "VOLAPUK" language-family = "INTERNATIONAL-AUX."/ + language-name = "KURDISH" language-family = "IRANIAN"/ + language-name = "PASHTO;PUSHTO" language-family = "IRANIAN"/ + language-name = "PERSIAN-(farsi)" language-family = "IRANIAN"/ + language-name = "TAJIK" language-family = "IRANIAN"/ + language-name = "GREEK" language-family = "LATIN/GREEK"/ + language-name = "LATIN" language-family = "LATIN/GREEK"/ + language-name = "HAUSA" language-family = "NEGRO-AFRICAN"/ + language-name = "KINYARWANDA" language-family = "NEGRO-AFRICAN"/ + language-name = "KURUNDI" language-family = "NEGRO-AFRICAN"/ + language-name = "LINGALA" language-family = "NEGRO-AFRICAN"/ + language-name = "SANGHO" language-family = "NEGRO-AFRICAN"/ + language-name = "SESOTHO" language-family = "NEGRO-AFRICAN"/ + language-name = "SETSWANA" language-family = "NEGRO-AFRICAN"/ + language-name = "SHONA" language-family = "NEGRO-AFRICAN"/ + language-name = "SISWATI" language-family = "NEGRO-AFRICAN"/ + language-name = "SWAHILI" language-family = "NEGRO-AFRICAN"/ + language-name = "TSONGA" language-family = "NEGRO-AFRICAN"/ + language-name = "TWI" language-family = "NEGRO-AFRICAN"/ + language-name = "WOLOF" language-family = "NEGRO-AFRICAN"/ + language-name = "XHOSA" language-family = "NEGRO-AFRICAN"/ + language-name = "YORUBA" language-family = "NEGRO-AFRICAN"/ + language-name = "ZULU" language-family = "NEGRO-AFRICAN"/ + language-name = "FIJI" language-family = "OCEANIC/INDONESIAN"/ + language-name = "INDONESIAN" language-family = "OCEANIC/INDONESIAN"/ + language-name = "JAVANESE" language-family = "OCEANIC/INDONESIAN"/ + language-name = "MALAGASY" language-family = "OCEANIC/INDONESIAN"/ + language-name = "MALAY" language-family = "OCEANIC/INDONESIAN"/ + language-name = "MAORI" language-family = "OCEANIC/INDONESIAN"/ + language-name = "SAMOAN" language-family = "OCEANIC/INDONESIAN"/ + language-name = "SUNDANESE" language-family = "OCEANIC/INDONESIAN"/ + language-name = "TAGALOG" language-family = "OCEANIC/INDONESIAN"/ + language-name = "TONGA" language-family = "OCEANIC/INDONESIAN"/ + language-name = "CATALAN" language-family = "ROMANCE"/ + language-name = "CORSICAN" language-family = "ROMANCE"/ + language-name = "FRENCH" language-family = "ROMANCE"/ + language-name = "GALICIAN" language-family = "ROMANCE"/ + language-name = "ITALIAN" language-family = "ROMANCE"/ + language-name = "MOLDAVIAN" language-family = "ROMANCE"/ + language-name = "OCCITAN" language-family = "ROMANCE"/ + language-name = "PORTUGUESE" language-family = "ROMANCE"/ + language-name = "RHAETO-ROMANCE" language-family = "ROMANCE"/ + language-name = "ROMANIAN" language-family = "ROMANCE"/ + language-name = "SPANISH" language-family = "ROMANCE"/ + language-name = "AMHARIC" language-family = "SEMITIC"/ + language-name = "ARABIC" language-family = "SEMITIC"/ + language-name = "HEBREW" language-family = "SEMITIC"/ + language-name = "MALTESE" language-family = "SEMITIC"/ + language-name = "TIGRINYA" language-family = "SEMITIC"/ + language-name = "BULGARIAN" language-family = "SLAVIC"/ + language-name = "BYELORUSSIAN" language-family = "SLAVIC"/ + language-name = "CROATIAN" language-family = "SLAVIC"/ + language-name = "CZECH" language-family = "SLAVIC"/ + language-name = "MACEDONIAN" language-family = "SLAVIC"/ + language-name = "POLISH" language-family = "SLAVIC"/ + language-name = "RUSSIAN" language-family = "SLAVIC"/ + language-name = "SERBIAN" language-family = "SLAVIC"/ + language-name = "SERBO-CROATIAN" language-family = "SLAVIC"/ + language-name = "SLOVAK" language-family = "SLAVIC"/ + language-name = "SLOVENIAN" language-family = "SLAVIC"/ + language-name = "UKRAINIAN" language-family = "SLAVIC"/ + language-name = "AZERBAIJANI" language-family = "TURKIC/ALTAIC"/ + language-name = "BASHKIR" language-family = "TURKIC/ALTAIC"/ + language-name = "KAZAKH" language-family = "TURKIC/ALTAIC"/ + language-name = "KIRGHIZ" language-family = "TURKIC/ALTAIC"/ + language-name = "TATAR" language-family = "TURKIC/ALTAIC"/ + language-name = "TURKISH" language-family = "TURKIC/ALTAIC"/ + language-name = "TURKMEN" language-family = "TURKIC/ALTAIC"/ + language-name = "UZBEK" language-family = "TURKIC/ALTAIC"/ + language-name = "BISLAMA" language-family = "[not-given]"/ + language-name = "MONGOLIAN" language-family = "[not-given]"/ + language-name = "NAURU" language-family = "[not-given]"/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown enumerated value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + property ignored + + + + + + + + + + + + + + + property is not implemented yet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown enumerated value + + + + + + + + + + + + + Unknown enumerated value + + + + + + + + + + + + + + + + + + + + + + + Unknown enumerated value + + + + + + + + + + + + + + + + + + + + + + + + + + + not implemented + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown enumerated value + + + + + + + Unknown enumerated value + + + + + + + Unknown enumerated value + + + + + + + Unknown enumerated value + + + + + + + Unknown enumerated value + + + + + + + + + + + + + + + Unknown enumerated value + + + + + + + Unknown enumerated value + + + + + + + + + Unknown enumerated value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + property is not implemented yet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "fo:width_Type fo:border_style_Type fo:color_Type" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Element definitions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + Border and background properties not implemented + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inheritable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0-RFC6321.rnc b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0-RFC6321.rnc new file mode 100644 index 0000000..d18211d --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0-RFC6321.rnc @@ -0,0 +1,1192 @@ + default namespace = "urn:ietf:params:xml:ns:icalendar-2.0" + + # 3.2 Property Parameters + + # 3.2.1 Alternate Text Representation + + altrepparam = element altrep { + value-uri + } + + # 3.2.2 Common Name + + cnparam = element cn { + value-text + } + + # 3.2.3 Calendar User Type + + cutypeparam = element cutype { + element text { + "INDIVIDUAL" | + "GROUP" | + "RESOURCE" | + "ROOM" | + "UNKNOWN" + } + } + + # 3.2.4 Delegators + + delfromparam = element delegated-from { + value-cal-address+ + } + + # 3.2.5 Delegatees + + deltoparam = element delegated-to { + value-cal-address+ + } + + # 3.2.6 Directory Entry Reference + + dirparam = element dir { + value-uri + } + + # 3.2.7 Inline Encoding + + encodingparam = element encoding { + element text { + "8BIT" | + "BASE64" + } + } + + # 3.2.8 Format Type + + fmttypeparam = element fmttype { + value-text + } + + # 3.2.9 Free/Busy Time Type + + fbtypeparam = element fbtype { + element text { + "FREE" | + "BUSY" | + "BUSY-UNAVAILABLE" | + "BUSY-TENTATIVE" + } + } + + # 3.2.10 Language + + languageparam = element language { + value-text + } + + # 3.2.11 Group or List Membership + + memberparam = element member { + value-cal-address+ + } + + # 3.2.12 Participation Status + + partstatparam = element partstat { + type-partstat-event | + type-partstat-todo | + type-partstat-jour + } + + type-partstat-event = ( + element text { + "NEEDS-ACTION" | + "ACCEPTED" | + "DECLINED" | + "TENTATIVE" | + "DELEGATED" + } + ) + + type-partstat-todo = ( + element text { + "NEEDS-ACTION" | + "ACCEPTED" | + "DECLINED" | + "TENTATIVE" | + "DELEGATED" | + "COMPLETED" | + "IN-PROCESS" + } + ) + + type-partstat-jour = ( + element text { + "NEEDS-ACTION" | + "ACCEPTED" | + "DECLINED" + } + ) + + # 3.2.13 Recurrence Identifier Range + + rangeparam = element range { + element text { + "THISANDFUTURE" + } + } + + # 3.2.14 Alarm Trigger Relationship + + trigrelparam = element related { + element text { + "START" | + "END" + } + } + + # 3.2.15 Relationship Type + + reltypeparam = element reltype { + element text { + "PARENT" | + "CHILD" | + "SIBLING" + } + } + + # 3.2.16 Participation Role + + roleparam = element role { + element text { + "CHAIR" | + "REQ-PARTICIPANT" | + "OPT-PARTICIPANT" | + "NON-PARTICIPANT" + } + } + + # 3.2.17 RSVP Expectation + + rsvpparam = element rsvp { + value-boolean + } + + # 3.2.18 Sent By + + sentbyparam = element sent-by { + value-cal-address + } + + # 3.2.19 Time Zone Identifier + + tzidparam = element tzid { + value-text + } + + # 3.3 Property Value Data Types + + # 3.3.1 BINARY + + value-binary = element binary { + xsd:string + } + + # 3.3.2 BOOLEAN + + value-boolean = element boolean { + xsd:boolean + } + + # 3.3.3 CAL-ADDRESS + + value-cal-address = element cal-address { + xsd:anyURI + } + + # 3.3.4 DATE + + pattern-date = xsd:string { + pattern = "\d\d\d\d-\d\d-\d\d" + } + + value-date = element date { + pattern-date + } + + # 3.3.5 DATE-TIME + + pattern-date-time = xsd:string { + pattern = "\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ?" + } + + value-date-time = element date-time { + pattern-date-time + } + + # 3.3.6 DURATION + + pattern-duration = xsd:string { + pattern = "(+|-)?P(\d+W)|(\d+D)?" + ~ "(T(\d+H(\d+M)?(\d+S)?)|" + ~ "(\d+M(\d+S)?)|" + ~ "(\d+S))?" + } + + value-duration = element duration { + pattern-duration + } + + # 3.3.7 FLOAT + + value-float = element float { + xsd:float + } + + # 3.3.8 INTEGER + + value-integer = element integer { + xsd:integer + } + + # 3.3.9 PERIOD + + value-period = element period { + element start { + pattern-date-time + }, + ( + element end { + pattern-date-time + } | + element duration { + pattern-duration + } + ) + } + + # 3.3.10 RECUR + + value-recur = element recur { + type-freq, + (type-until | type-count)?, + element interval { + xsd:positiveInteger + }?, + type-bysecond*, + type-byminute*, + type-byhour*, + type-byday*, + type-bymonthday*, + type-byyearday*, + type-byweekno*, + type-bymonth*, + type-bysetpos*, + element wkst { type-weekday }? + } + + type-freq = element freq { + "SECONDLY" | + "MINUTELY" | + "HOURLY" | + "DAILY" | + "WEEKLY" | + "MONTHLY" | + "YEARLY" + } + + type-until = element until { + type-date | + type-date-time + } + + type-count = element count { + xsd:positiveInteger + } + + type-bysecond = element bysecond { + xsd:positiveInteger + } + + type-byminute = element byminute { + xsd:positiveInteger + } + + type-byhour = element byhour { + xsd:positiveInteger + } + + type-weekday = ( + "SU" | + "MO" | + "TU" | + "WE" | + "TH" | + "FR" | + "SA" + ) + + type-byday = element byday { + xsd:integer?, + type-weekday + } + + type-bymonthday = element bymonthday { + xsd:integer + } + + type-byyearday = element byyearday { + xsd:integer + } + + type-byweekno = element byweekno { + xsd:integer + } + + type-bymonth = element bymonth { + xsd:positiveInteger + } + + type-bysetpos = element bysetpos { + xsd:integer + } + + # 3.3.11 TEXT + + value-text = element text { + xsd:string + } + + # 3.3.12 TIME + + pattern-time = xsd:string { + pattern = "\d\d:\d\d:\d\dZ?" + } + + value-time = element time { + pattern-time + } + + # 3.3.13 URI + + value-uri = element uri { + xsd:anyURI + } + + # 3.3.14 UTC-OFFSET + + value-utc-offset = element utc-offset { + xsd:string { pattern = "(+|-)\d\d:\d\d(:\d\d)?" } + } + + # UNKNOWN + + value-unknown = element unknown { + xsd:string + } + + # 3.4 iCalendar Stream + + start = element icalendar { + vcalendar+ + } + + # 3.6 Calendar Components + + vcalendar = element vcalendar { + type-calprops, + type-component + } + + type-calprops = element properties { + property-prodid & + property-version & + property-calscale? & + property-method? + } + + type-component = element components { + ( + component-vevent | + component-vtodo | + component-vjournal | + component-vfreebusy | + component-vtimezone + )* + } + + # 3.6.1 Event Component + + component-vevent = element vevent { + type-eventprop, + element components { + component-valarm+ + }? + } + + type-eventprop = element properties { + property-dtstamp & + property-dtstart & + property-uid & + + property-class? & + property-created? & + property-description? & + property-geo? & + property-last-mod? & + property-location? & + property-organizer? & + property-priority? & + property-seq? & + property-status-event? & + + property-summary? & + property-transp? & + property-url? & + property-recurid? & + + property-rrule? & + + (property-dtend | property-duration)? & + + property-attach* & + property-attendee* & + property-categories* & + property-comment* & + property-contact* & + property-exdate* & + property-rstatus* & + property-related* & + property-resources* & + property-rdate* + } + + # 3.6.2 To-do Component + + component-vtodo = element vtodo { + type-todoprop, + element components { + component-valarm+ + }? + } + + type-todoprop = element properties { + property-dtstamp & + property-uid & + + property-class? & + property-completed? & + property-created? & + property-description? & + property-geo? & + property-last-mod? & + property-location? & + property-organizer? & + property-percent? & + property-priority? & + property-recurid? & + property-seq? & + property-status-todo? & + property-summary? & + + property-url? & + + property-rrule? & + + ( + (property-dtstart?, property-dtend? ) | + (property-dtstart, property-duration)? + ) & + + property-attach* & + property-attendee* & + property-categories* & + property-comment* & + property-contact* & + property-exdate* & + property-rstatus* & + property-related* & + property-resources* & + property-rdate* + } + + # 3.6.3 Journal Component + + component-vjournal = element vjournal { + type-jourprop + } + + type-jourprop = element properties { + property-dtstamp & + property-uid & + + property-class? & + property-created? & + property-dtstart? & + property-last-mod? & + property-organizer? & + property-recurid? & + property-seq? & + property-status-jour? & + property-summary? & + property-url? & + + property-rrule? & + + property-attach* & + property-attendee* & + property-categories* & + property-comment* & + property-contact* & + property-description? & + property-exdate* & + property-related* & + property-rdate* & + property-rstatus* + } + + # 3.6.4 Free/Busy Component + + component-vfreebusy = element vfreebusy { + type-fbprop + } + + type-fbprop = element properties { + property-dtstamp & + property-uid & + + property-contact? & + property-dtstart? & + property-dtend? & + property-duration? & + property-organizer? & + property-url? & + + property-attendee* & + property-comment* & + property-freebusy* & + property-rstatus* + } + + # 3.6.5 Time Zone Component + + component-vtimezone = element vtimezone { + element properties { + property-tzid & + + property-last-mod? & + property-tzuurl? + }, + element components { + (component-standard | component-daylight) & + component-standard* & + component-daylight* + } + } + + component-standard = element standard { + type-tzprop + } + + component-daylight = element daylight { + type-tzprop + } + + type-tzprop = element properties { + property-dtstart & + property-tzoffsetto & + property-tzoffsetfrom & + + property-rrule? & + + property-comment* & + property-rdate* & + property-tzname* + } + + # 3.6.6 Alarm Component + + component-valarm = element valarm { + audioprop | dispprop | emailprop + } + + type-audioprop = element properties { + property-action & + + property-trigger & + + (property-duration, property-repeat)? & + + property-attach? + } + + type-dispprop = element properties { + property-action & + property-description & + property-trigger & + property-summary & + + property-attendee+ & + + (property-duration, property-repeat)? & + + property-attach* + } + + type-emailprop = element properties { + property-action & + property-description & + property-trigger & + + (property-duration, property-repeat)? + } + + # 3.7 Calendar Properties + + # 3.7.1 Calendar Scale + + property-calscale = element calscale { + + element parameters { empty }?, + + element text { "GREGORIAN" } + } + + # 3.7.2 Method + + property-method = element method { + + element parameters { empty }?, + + value-text + } + + # 3.7.3 Product Identifier + + property-prodid = element prodid { + + element parameters { empty }?, + + value-text + } + + # 3.7.4 Version + + property-version = element version { + + element parameters { empty }?, + + element text { "2.0" } + } + + # 3.8 Component Properties + + # 3.8.1 Descriptive Component Properties + + # 3.8.1.1 Attachment + + property-attach = element attach { + + element parameters { + fmttypeparam? & + encodingparam? + }?, + + value-uri | value-binary + } + + # 3.8.1.2 Categories + + property-categories = element categories { + + element parameters { + languageparam? & + }?, + + value-text+ + } + + # 3.8.1.3 Classification + + property-class = element class { + + element parameters { empty }?, + + element text { + "PUBLIC" | + "PRIVATE" | + "CONFIDENTIAL" + } + } + + # 3.8.1.4 Comment + + property-comment = element comment { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.1.5 Description + + property-description = element description { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.1.6 Geographic Position + + property-geo = element geo { + + element parameters { empty }?, + + element latitude { xsd:float }, + element longitude { xsd:float } + } + + # 3.8.1.7 Location + + property-location = element location { + + element parameters { + + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.1.8 Percent Complete + + property-percent = element percent-complete { + + element parameters { empty }?, + + value-integer + } + + + # 3.8.1.9 Priority + + property-priority = element priority { + + element parameters { empty }?, + + value-integer + } + + # 3.8.1.10 Resources + + property-resources = element resources { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text+ + } + + # 3.8.1.11 Status + + property-status-event = element status { + + element parameters { empty }?, + + element text { + "TENTATIVE" | + "CONFIRMED" | + "CANCELLED" + } + } + + property-status-todo = element status { + + element parameters { empty }?, + + element text { + "NEEDS-ACTION" | + "COMPLETED" | + "IN-PROCESS" | + "CANCELLED" + } + } + + property-status-jour = element status { + + element parameters { empty }?, + + element text { + "DRAFT" | + "FINAL" | + "CANCELLED" + } + } + + # 3.8.1.12 Summary + + property-summary = element summary { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.2 Date and Time Component Properties + + # 3.8.2.1 Date/Time Completed + + property-completed = element completed { + + element parameters { empty }?, + + value-date-time + } + + # 3.8.2.2 Date/Time End + + property-dtend = element dtend { + + element parameters { + tzidparam? + }?, + + value-date-time | + value-date + } + + # 3.8.2.3 Date/Time Due + + property-due = element due { + + element parameters { + tzidparam? + }?, + + value-date-time | + value-date + } + + # 3.8.2.4 Date/Time Start + + property-dtstart = element dtstart { + + element parameters { + tzidparam? + }?, + + value-date-time | + value-date + } + + # 3.8.2.5 Duration + + property-duration = element duration { + + element parameters { empty }?, + + value-duration + } + + # 3.8.2.6 Free/Busy Time + + property-freebusy = element freebusy { + + element parameters { + fbtypeparam? + }?, + + + value-period+ + } + + # 3.8.2.7 Time Transparency + + property-transp = element transp { + + + element parameters { empty }?, + + element text { + "OPAQUE" | + "TRANSPARENT" + } + } + + # 3.8.3 Time Zone Component Properties + + # 3.8.3.1 Time Zone Identifier + + property-tzid = element tzid { + + element parameters { empty }?, + + value-text + } + + # 3.8.3.2 Time Zone Name + + property-tzname = element tzname { + + element parameters { + languageparam? + }?, + + value-text + } + + # 3.8.3.3 Time Zone Offset From + + property-tzoffsetfrom = element tzoffsetfrom { + + element parameters { empty }?, + + value-utc-offset + } + + # 3.8.3.4 Time Zone Offset To + + property-tzoffsetto = element tzoffsetto { + + element parameters { empty }?, + + value-utc-offset + } + + # 3.8.3.5 Time Zone URL + + property-tzurl = element tzurl { + + element parameters { empty }?, + + value-uri + } + + # 3.8.4 Relationship Component Properties + + # 3.8.4.1 Attendee + + property-attendee = element attendee { + + element parameters { + cutypeparam? & + memberparam? & + roleparam? & + partstatparam? & + rsvpparam? & + deltoparam? & + delfromparam? & + sentbyparam? & + cnparam? & + dirparam? & + languageparam? + }?, + + value-cal-address + } + + # 3.8.4.2 Contact + + property-contact = element contact { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.4.3 Organizer + + property-organizer = element organizer { + + element parameters { + cnparam? & + dirparam? & + sentbyparam? & + languageparam? + }?, + + value-cal-address + } + + # 3.8.4.4 Recurrence ID + + property-recurid = element recurrence-id { + + element parameters { + tzidparam? & + rangeparam? + }?, + + value-date-time | + value-date + } + + # 3.8.4.5 Related-To + + property-related = element related-to { + + element parameters { + reltypeparam? + }?, + + value-text + } + + # 3.8.4.6 Uniform Resource Locator + + property-url = element url { + + element parameters { empty }?, + + value-uri + } + + # 3.8.4.7 Unique Identifier + + property-uid = element uid { + + element parameters { empty }?, + value-text + } + + # 3.8.5 Recurrence Component Properties + + # 3.8.5.1 Exception Date/Times + + property-exdate = element exdate { + + element parameters { + tzidparam? + }?, + + value-date-time+ | + value-date+ + } + + # 3.8.5.2 Recurrence Date/Times + + property-rdate = element rdate { + + element parameters { + tzidparam? + }?, + + value-date-time+ | + value-date+ | + value-period+ + } + + # 3.8.5.3 Recurrence Rule + + property-rrule = element rrule { + + element parameters { empty }?, + + value-recur + } + + # 3.8.6 Alarm Component Properties + + # 3.8.6.1 Action + + property-action = element action { + + element parameters { empty }?, + element text { + "AUDIO" | + "DISPLAY" | + "EMAIL" + } + } + + # 3.8.6.2 Repeat Count + + property-repeat = element repeat { + + element parameters { empty }?, + + value-integer + } + + # 3.8.6.3 Trigger + + property-trigger = element trigger { + + ( + element parameters { + trigrelparam? + }?, + + value-duration + ) | + ( + element parameters { empty }?, + + value-date-time + ) + } + + # 3.8.7 Change Management Component Properties + + # 3.8.7.1 Date/Time Created + + property-created = element created { + + element parameters { empty }?, + + value-date-time + } + + # 3.8.7.2 Date/Time Stamp + + property-dtstamp = element dtstamp { + element parameters { empty }?, + + value-date-time + } + + # 3.8.7.3 Last Modified + + property-last-mod = element last-modified { + + element parameters { empty }?, + + value-date-time + } + + # 3.8.7.4 Sequence Number + + property-seq = element sequence { + + element parameters { empty }?, + + value-integer + } + + # 3.8.8 Miscellaneous Component Properties + + # 3.8.8.3 Request Status + + property-rstatus = element request-status { + + element parameters { + languageparam? + }?, + + element code { xsd:string }, + element description { xsd:string }, + element data { xsd:string }? + } + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0.rnc b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0.rnc new file mode 100644 index 0000000..4c863be --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0.rnc @@ -0,0 +1,1207 @@ + default namespace = "urn:ietf:params:xml:ns:icalendar-2.0" + + # 3.2 Property Parameters + + # 3.2.1 Alternate Text Representation + + altrepparam = element altrep { + value-uri + } + + # 3.2.2 Common Name + + cnparam = element cn { + value-text + } + + # 3.2.3 Calendar User Type + + cutypeparam = element cutype { + element text { + "INDIVIDUAL" | + "GROUP" | + "RESOURCE" | + "ROOM" | + "UNKNOWN" + } + } + + # 3.2.4 Delegators + + delfromparam = element delegated-from { + value-cal-address+ + } + + # 3.2.5 Delegatees + + deltoparam = element delegated-to { + value-cal-address+ + } + + # 3.2.6 Directory Entry Reference + + dirparam = element dir { + value-uri + } + + # 3.2.7 Inline Encoding + + encodingparam = element encoding { + element text { + "8BIT" | + "BASE64" + } + } + + # 3.2.8 Format Type + + fmttypeparam = element fmttype { + value-text + } + + # 3.2.9 Free/Busy Time Type + + fbtypeparam = element fbtype { + element text { + "FREE" | + "BUSY" | + "BUSY-UNAVAILABLE" | + "BUSY-TENTATIVE" + } + } + + # 3.2.10 Language + + languageparam = element language { + value-text + } + + # 3.2.11 Group or List Membership + + memberparam = element member { + value-cal-address+ + } + + # 3.2.12 Participation Status + + partstatparam = element partstat { + type-partstat-event | + type-partstat-todo | + type-partstat-jour + } + + type-partstat-event = ( + element text { + "NEEDS-ACTION" | + "ACCEPTED" | + "DECLINED" | + "TENTATIVE" | + "DELEGATED" + } + ) + + type-partstat-todo = ( + element text { + "NEEDS-ACTION" | + "ACCEPTED" | + "DECLINED" | + "TENTATIVE" | + "DELEGATED" | + "COMPLETED" | + "IN-PROCESS" + } + ) + + type-partstat-jour = ( + element text { + "NEEDS-ACTION" | + "ACCEPTED" | + "DECLINED" + } + ) + + # 3.2.13 Recurrence Identifier Range + + rangeparam = element range { + element text { + "THISANDFUTURE" + } + } + + # 3.2.14 Alarm Trigger Relationship + + trigrelparam = element related { + element text { + "START" | + "END" + } + } + + # 3.2.15 Relationship Type + + reltypeparam = element reltype { + element text { + "PARENT" | + "CHILD" | + "SIBLING" + } + } + + # 3.2.16 Participation Role + + roleparam = element role { + element text { + "CHAIR" | + "REQ-PARTICIPANT" | + "OPT-PARTICIPANT" | + "NON-PARTICIPANT" + } + } + + # 3.2.17 RSVP Expectation + + rsvpparam = element rsvp { + value-boolean + } + + # 3.2.18 Sent By + + sentbyparam = element sent-by { + value-cal-address + } + + # 3.2.19 Time Zone Identifier + + tzidparam = element tzid { + value-text + } + + # 3.3 Property Value Data Types + + # 3.3.1 BINARY + + value-binary = element binary { + xsd:string + } + + # 3.3.2 BOOLEAN + + value-boolean = element boolean { + xsd:boolean + } + + # 3.3.3 CAL-ADDRESS + + value-cal-address = element cal-address { + xsd:anyURI + } + + # 3.3.4 DATE + + pattern-date = xsd:string { + pattern = "\d\d\d\d-\d\d-\d\d" + } + + value-date = element date { + pattern-date + } + + # 3.3.5 DATE-TIME + + pattern-date-time = xsd:string { + pattern = "\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ?" + } + + value-date-time = element date-time { + pattern-date-time + } + + # 3.3.6 DURATION + + pattern-duration = xsd:string { + # mbaudier - 2022-05-31 : corrected regexp from RFC 6321 + pattern = "(\+|-)?P(\d+W)|(\d+D)?" + ~ "(T(\d+H(\d+M)?(\d+S)?)|" + ~ "(\d+M(\d+S)?)|" + ~ "(\d+S))?" + } + + value-duration = element duration { + pattern-duration + } + + # 3.3.7 FLOAT + + value-float = element float { + xsd:float + } + + # 3.3.8 INTEGER + + value-integer = element integer { + xsd:integer + } + + # 3.3.9 PERIOD + + value-period = element period { + element start { + pattern-date-time + }, + ( + element end { + pattern-date-time + } | + element duration { + pattern-duration + } + ) + } + + # 3.3.10 RECUR + + value-recur = element recur { + type-freq, + (type-until | type-count)?, + element interval { + xsd:positiveInteger + }?, + type-bysecond*, + type-byminute*, + type-byhour*, + type-byday*, + type-bymonthday*, + type-byyearday*, + type-byweekno*, + type-bymonth*, + type-bysetpos*, + element wkst { type-weekday }? + } + + type-freq = element freq { + "SECONDLY" | + "MINUTELY" | + "HOURLY" | + "DAILY" | + "WEEKLY" | + "MONTHLY" | + "YEARLY" + } + + type-until = element until { + # mbaudier - 2022-05-31 : corrected undefined pattern from RFC 6321 + value-date | + value-date-time + } + + type-count = element count { + xsd:positiveInteger + } + + type-bysecond = element bysecond { + xsd:positiveInteger + } + + type-byminute = element byminute { + xsd:positiveInteger + } + + type-byhour = element byhour { + xsd:positiveInteger + } + + type-weekday = ( + "SU" | + "MO" | + "TU" | + "WE" | + "TH" | + "FR" | + "SA" + ) + + type-byday = element byday { + # mbaudier - 2022-05-31 : corrected (?) grouping data is only allowed inside list from RFC 6321 + xsd:integer? | + type-weekday + } + + type-bymonthday = element bymonthday { + xsd:integer + } + + type-byyearday = element byyearday { + xsd:integer + } + + type-byweekno = element byweekno { + xsd:integer + } + + type-bymonth = element bymonth { + xsd:positiveInteger + } + + type-bysetpos = element bysetpos { + xsd:integer + } + + # 3.3.11 TEXT + + value-text = element text { + xsd:string + } + + # 3.3.12 TIME + + pattern-time = xsd:string { + pattern = "\d\d:\d\d:\d\dZ?" + } + + value-time = element time { + pattern-time + } + + # 3.3.13 URI + + value-uri = element uri { + xsd:anyURI + } + + # 3.3.14 UTC-OFFSET + + value-utc-offset = element utc-offset { + # mbaudier - 2022-05-31 : corrected regexp from RFC 6321 + xsd:string { pattern = "(\+|-)\d\d:\d\d(:\d\d)?" } + } + + # UNKNOWN + + value-unknown = element unknown { + xsd:string + } + + # 3.4 iCalendar Stream + + start = element icalendar { + vcalendar+ + } + + # 3.6 Calendar Components + + vcalendar = element vcalendar { + type-calprops, + type-component + } + + type-calprops = element properties { + property-prodid & + property-version & + property-calscale? & + property-method? + } + + type-component = element components { + ( + component-vevent | + component-vtodo | + component-vjournal | + component-vfreebusy | + component-vtimezone + )* + } + + # 3.6.1 Event Component + + component-vevent = element vevent { + type-eventprop, + element components { + component-valarm+ + }? + } + + type-eventprop = element properties { + property-dtstamp & + property-dtstart & + property-uid & + + property-class? & + property-created? & + property-description? & + property-geo? & + property-last-mod? & + property-location? & + property-organizer? & + property-priority? & + property-seq? & + property-status-event? & + + property-summary? & + property-transp? & + property-url? & + property-recurid? & + + property-rrule? & + + (property-dtend | property-duration)? & + + property-attach* & + property-attendee* & + property-categories* & + property-comment* & + property-contact* & + property-exdate* & + property-rstatus* & + property-related* & + property-resources* & + property-rdate* + } + + # 3.6.2 To-do Component + + component-vtodo = element vtodo { + type-todoprop, + element components { + component-valarm+ + }? + } + + type-todoprop = element properties { + property-dtstamp & + property-uid & + + property-class? & + property-completed? & + property-created? & + property-description? & + property-geo? & + property-last-mod? & + property-location? & + property-organizer? & + property-percent? & + property-priority? & + property-recurid? & + property-seq? & + property-status-todo? & + property-summary? & + + property-url? & + + property-rrule? & + + ( + (property-dtstart?, property-dtend? ) | + (property-dtstart, property-duration)? + ) & + + property-attach* & + property-attendee* & + property-categories* & + property-comment* & + property-contact* & + property-exdate* & + property-rstatus* & + property-related* & + property-resources* & + property-rdate* + } + + # 3.6.3 Journal Component + + component-vjournal = element vjournal { + type-jourprop + } + + type-jourprop = element properties { + property-dtstamp & + property-uid & + + property-class? & + property-created? & + property-dtstart? & + property-last-mod? & + property-organizer? & + property-recurid? & + property-seq? & + property-status-jour? & + property-summary? & + property-url? & + + property-rrule? & + + property-attach* & + property-attendee* & + property-categories* & + property-comment* & + property-contact* & + property-description? & + property-exdate* & + property-related* & + property-rdate* & + property-rstatus* + } + + # 3.6.4 Free/Busy Component + + component-vfreebusy = element vfreebusy { + type-fbprop + } + + type-fbprop = element properties { + property-dtstamp & + property-uid & + + property-contact? & + property-dtstart? & + property-dtend? & + property-duration? & + property-organizer? & + property-url? & + + property-attendee* & + property-comment* & + property-freebusy* & + property-rstatus* + } + + # 3.6.5 Time Zone Component + + component-vtimezone = element vtimezone { + element properties { + property-tzid & + + property-last-mod? & + # mbaudier - 2022-05-31 : corrected undefined reference from RFC 6321 + property-tzurl? + }, + element components { + (component-standard | component-daylight) & + component-standard* & + component-daylight* + } + } + + component-standard = element standard { + type-tzprop + } + + component-daylight = element daylight { + type-tzprop + } + + type-tzprop = element properties { + property-dtstart & + property-tzoffsetto & + property-tzoffsetfrom & + + property-rrule? & + + property-comment* & + property-rdate* & + property-tzname* + } + + # 3.6.6 Alarm Component + + component-valarm = element valarm { + # mbaudier - 2022-05-31 : corrected undefined reference from RFC 6321 + type-audioprop | type-dispprop | type-emailprop + } + + type-audioprop = element properties { + property-action & + + property-trigger & + + (property-duration, property-repeat)? & + + property-attach? + } + + type-dispprop = element properties { + property-action & + property-description & + property-trigger & + property-summary & + + property-attendee+ & + + (property-duration, property-repeat)? & + + property-attach* + } + + type-emailprop = element properties { + property-action & + property-description & + property-trigger & + + (property-duration, property-repeat)? + } + + # 3.7 Calendar Properties + + # 3.7.1 Calendar Scale + + property-calscale = element calscale { + + element parameters { empty }?, + + element text { "GREGORIAN" } + } + + # 3.7.2 Method + + property-method = element method { + + element parameters { empty }?, + + value-text + } + + # 3.7.3 Product Identifier + + property-prodid = element prodid { + + element parameters { empty }?, + + value-text + } + + # 3.7.4 Version + + property-version = element version { + + element parameters { empty }?, + + element text { "2.0" } + } + + # 3.8 Component Properties + + # 3.8.1 Descriptive Component Properties + + # 3.8.1.1 Attachment + + property-attach = element attach { + + element parameters { + fmttypeparam? & + encodingparam? + }?, + + # mbaudier - 2022-05-31 : corrected syntax error from RFC 6321 + (value-uri | + value-binary) + } + + # 3.8.1.2 Categories + + property-categories = element categories { + + element parameters { + # mbaudier - 2022-05-31 : corrected syntax error from RFC 6321 + languageparam? + }?, + + value-text+ + } + + # 3.8.1.3 Classification + + property-class = element class { + + element parameters { empty }?, + + element text { + "PUBLIC" | + "PRIVATE" | + "CONFIDENTIAL" + } + } + + # 3.8.1.4 Comment + + property-comment = element comment { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.1.5 Description + + property-description = element description { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.1.6 Geographic Position + + property-geo = element geo { + + element parameters { empty }?, + + element latitude { xsd:float }, + element longitude { xsd:float } + } + + # 3.8.1.7 Location + + property-location = element location { + + element parameters { + + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.1.8 Percent Complete + + property-percent = element percent-complete { + + element parameters { empty }?, + + value-integer + } + + + # 3.8.1.9 Priority + + property-priority = element priority { + + element parameters { empty }?, + + value-integer + } + + # 3.8.1.10 Resources + + property-resources = element resources { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text+ + } + + # 3.8.1.11 Status + + property-status-event = element status { + + element parameters { empty }?, + + element text { + "TENTATIVE" | + "CONFIRMED" | + "CANCELLED" + } + } + + property-status-todo = element status { + + element parameters { empty }?, + + element text { + "NEEDS-ACTION" | + "COMPLETED" | + "IN-PROCESS" | + "CANCELLED" + } + } + + property-status-jour = element status { + + element parameters { empty }?, + + element text { + "DRAFT" | + "FINAL" | + "CANCELLED" + } + } + + # 3.8.1.12 Summary + + property-summary = element summary { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.2 Date and Time Component Properties + + # 3.8.2.1 Date/Time Completed + + property-completed = element completed { + + element parameters { empty }?, + + value-date-time + } + + # 3.8.2.2 Date/Time End + + property-dtend = element dtend { + + element parameters { + tzidparam? + }?, + + # mbaudier - 2022-05-31 : corrected syntax error from RFC 6321 + (value-date-time | + value-date) + } + + # 3.8.2.3 Date/Time Due + + property-due = element due { + + element parameters { + tzidparam? + }?, + + # mbaudier - 2022-05-31 : corrected syntax error from RFC 6321 + (value-date-time | + value-date) + } + + # 3.8.2.4 Date/Time Start + + property-dtstart = element dtstart { + + element parameters { + tzidparam? + }?, + + # mbaudier - 2022-05-31 : corrected syntax error from RFC 6321 + (value-date-time | + value-date) + } + + # 3.8.2.5 Duration + + property-duration = element duration { + + element parameters { empty }?, + + value-duration + } + + # 3.8.2.6 Free/Busy Time + + property-freebusy = element freebusy { + + element parameters { + fbtypeparam? + }?, + + + value-period+ + } + + # 3.8.2.7 Time Transparency + + property-transp = element transp { + + + element parameters { empty }?, + + element text { + "OPAQUE" | + "TRANSPARENT" + } + } + + # 3.8.3 Time Zone Component Properties + + # 3.8.3.1 Time Zone Identifier + + property-tzid = element tzid { + + element parameters { empty }?, + + value-text + } + + # 3.8.3.2 Time Zone Name + + property-tzname = element tzname { + + element parameters { + languageparam? + }?, + + value-text + } + + # 3.8.3.3 Time Zone Offset From + + property-tzoffsetfrom = element tzoffsetfrom { + + element parameters { empty }?, + + value-utc-offset + } + + # 3.8.3.4 Time Zone Offset To + + property-tzoffsetto = element tzoffsetto { + + element parameters { empty }?, + + value-utc-offset + } + + # 3.8.3.5 Time Zone URL + + property-tzurl = element tzurl { + + element parameters { empty }?, + + value-uri + } + + # 3.8.4 Relationship Component Properties + + # 3.8.4.1 Attendee + + property-attendee = element attendee { + + element parameters { + cutypeparam? & + memberparam? & + roleparam? & + partstatparam? & + rsvpparam? & + deltoparam? & + delfromparam? & + sentbyparam? & + cnparam? & + dirparam? & + languageparam? + }?, + + value-cal-address + } + + # 3.8.4.2 Contact + + property-contact = element contact { + + element parameters { + altrepparam? & + languageparam? + }?, + + value-text + } + + # 3.8.4.3 Organizer + + property-organizer = element organizer { + + element parameters { + cnparam? & + dirparam? & + sentbyparam? & + languageparam? + }?, + + value-cal-address + } + + # 3.8.4.4 Recurrence ID + + property-recurid = element recurrence-id { + + element parameters { + tzidparam? & + rangeparam? + }?, + + # mbaudier - 2022-05-31 : corrected syntax error from RFC 6321 + (value-date-time | + value-date) + } + + # 3.8.4.5 Related-To + + property-related = element related-to { + + element parameters { + reltypeparam? + }?, + + value-text + } + + # 3.8.4.6 Uniform Resource Locator + + property-url = element url { + + element parameters { empty }?, + + value-uri + } + + # 3.8.4.7 Unique Identifier + + property-uid = element uid { + + element parameters { empty }?, + value-text + } + + # 3.8.5 Recurrence Component Properties + + # 3.8.5.1 Exception Date/Times + + property-exdate = element exdate { + + element parameters { + tzidparam? + }?, + + # mbaudier - 2022-05-31 : corrected syntax error from RFC 6321 + (value-date-time+ | + value-date+) + } + + # 3.8.5.2 Recurrence Date/Times + + property-rdate = element rdate { + + element parameters { + tzidparam? + }?, + + # mbaudier - 2022-05-31 : corrected syntax error from RFC 6321 + (value-date-time+ | + value-date+ | + value-period+) + } + + # 3.8.5.3 Recurrence Rule + + property-rrule = element rrule { + + element parameters { empty }?, + + value-recur + } + + # 3.8.6 Alarm Component Properties + + # 3.8.6.1 Action + + property-action = element action { + + element parameters { empty }?, + element text { + "AUDIO" | + "DISPLAY" | + "EMAIL" + } + } + + # 3.8.6.2 Repeat Count + + property-repeat = element repeat { + + element parameters { empty }?, + + value-integer + } + + # 3.8.6.3 Trigger + + property-trigger = element trigger { + + ( + element parameters { + trigrelparam? + }?, + + value-duration + ) | + ( + element parameters { empty }?, + + value-date-time + ) + } + + # 3.8.7 Change Management Component Properties + + # 3.8.7.1 Date/Time Created + + property-created = element created { + + element parameters { empty }?, + + value-date-time + } + + # 3.8.7.2 Date/Time Stamp + + property-dtstamp = element dtstamp { + element parameters { empty }?, + + value-date-time + } + + # 3.8.7.3 Last Modified + + property-last-mod = element last-modified { + + element parameters { empty }?, + + value-date-time + } + + # 3.8.7.4 Sequence Number + + property-seq = element sequence { + + element parameters { empty }?, + + value-integer + } + + # 3.8.8 Miscellaneous Component Properties + + # 3.8.8.3 Request Status + + property-rstatus = element request-status { + + element parameters { + languageparam? + }?, + + element code { xsd:string }, + element description { xsd:string }, + element data { xsd:string }? + } + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0.xsd new file mode 100644 index 0000000..d0bb31e --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCal-2.0.xsd @@ -0,0 +1,1489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0-RFC6351.rnc b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0-RFC6351.rnc new file mode 100644 index 0000000..9f4f163 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0-RFC6351.rnc @@ -0,0 +1,382 @@ +default namespace = "urn:ietf:params:xml:ns:vcard-4.0" + +### Section 3.3: vCard Format Specification +# +# 3.3 +iana-token = xsd:string { pattern = "[a-zA-Z0-9-]+" } +x-name = xsd:string { pattern = "x-[a-zA-Z0-9-]+" } + +### Section 4: Value types +# +# 4.1 +value-text = element text { text } +value-text-list = value-text+ + +# 4.2 +value-uri = element uri { xsd:anyURI } + +# 4.3.1 +value-date = element date { + xsd:string { pattern = "\d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d" } + } + +# 4.3.2 +value-time = element time { + xsd:string { pattern = "(\d\d(\d\d(\d\d)?)?|-\d\d(\d\d?)|--\d\d)" + ~ "(Z|[+\-]\d\d(\d\d)?)?" } + } + +# 4.3.3 +value-date-time = element date-time { + xsd:string { pattern = "(\d{8}|--\d{4}|---\d\d)T\d\d(\d\d(\d\d)?)?" + ~ "(Z|[+\-]\d\d(\d\d)?)?" } + } + +# 4.3.4 +value-date-and-or-time = value-date | value-date-time | value-time + +# 4.3.5 +value-timestamp = element timestamp { + xsd:string { pattern = "\d{8}T\d{6}(Z|[+\-]\d\d(\d\d)?)?" } + } + +# 4.4 +value-boolean = element boolean { xsd:boolean } + +# 4.5 +value-integer = element integer { xsd:integer } + +# 4.6 +value-float = element float { xsd:float } + +# 4.7 +value-utc-offset = element utc-offset { + xsd:string { pattern = "[+\-]\d\d(\d\d)?" } + } + +# 4.8 +value-language-tag = element language-tag { + xsd:string { pattern = "([a-z]{2,3}((-[a-z]{3}){0,3})?|[a-z]{4,8})" + ~ "(-[a-z]{4})?(-([a-z]{2}|\d{3}))?" + ~ "(-([0-9a-z]{5,8}|\d[0-9a-z]{3}))*" + ~ "(-[0-9a-wyz](-[0-9a-z]{2,8})+)*" + ~ "(-x(-[0-9a-z]{1,8})+)?|x(-[0-9a-z]{1,8})+|" + ~ "[a-z]{1,3}(-[0-9a-z]{2,8}){1,2}" } + } + +### Section 5: Parameters +# +# 5.1 +param-language = element language { value-language-tag }? + +# 5.2 +param-pref = element pref { + element integer { + xsd:integer { minInclusive = "1" maxInclusive = "100" } + } + }? + +# 5.4 +param-altid = element altid { value-text }? + +# 5.5 +param-pid = element pid { + element text { xsd:string { pattern = "\d+(\.\d+)?" } }+ + }? + +# 5.6 +param-type = element type { element text { "work" | "home" }+ }? + +# 5.7 +param-mediatype = element mediatype { value-text }? + +# 5.8 +param-calscale = element calscale { element text { "gregorian" } }? + +# 5.9 +param-sort-as = element sort-as { value-text+ }? + +# 5.10 +param-geo = element geo { value-uri }? + +# 5.11 +param-tz = element tz { value-text | value-uri }? + +### Section 6: Properties +# +# 6.1.3 +property-source = element source { + element parameters { param-altid, param-pid, param-pref, + param-mediatype }, + value-uri + } + +# 6.1.4 +property-kind = element kind { + element text { "individual" | "group" | "org" | "location" | + x-name | iana-token }* + } + +# 6.2.1 +property-fn = element fn { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text + } + +# 6.2.2 +property-n = element n { + element parameters { param-language, param-sort-as, param-altid }?, + element surname { text }+, + element given { text }+, + element additional { text }+, + element prefix { text }+, + element suffix { text }+ + } + +# 6.2.3 +property-nickname = element nickname { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text-list + } + +# 6.2.4 +property-photo = element photo { + element parameters { param-altid, param-pid, param-pref, param-type, + param-mediatype }?, + value-uri + } + +# 6.2.5 +property-bday = element bday { + element parameters { param-altid, param-calscale }?, + (value-date-and-or-time | value-text) + } + +# 6.2.6 +property-anniversary = element anniversary { + element parameters { param-altid, param-calscale }?, + (value-date-and-or-time | value-text) + } + +# 6.2.7 +property-gender = element gender { + element sex { "" | "M" | "F" | "O" | "N" | "U" }, + element identity { text }? + } + +# 6.3.1 +param-label = element label { value-text }? +property-adr = element adr { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type, param-geo, param-tz, + param-label }?, + element pobox { text }+, + element ext { text }+, + element street { text }+, + element locality { text }+, + element region { text }+, + element code { text }+, + element country { text }+ + } + +# 6.4.1 +property-tel = element tel { + element parameters { + param-altid, + param-pid, + param-pref, + element type { + element text { "work" | "home" | "text" | "voice" + | "fax" | "cell" | "video" | "pager" + | "textphone" }+ + }?, + param-mediatype + }?, + (value-text | value-uri) + } + +# 6.4.2 +property-email = element email { + element parameters { param-altid, param-pid, param-pref, + param-type }?, + value-text + } + +# 6.4.3 +property-impp = element impp { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.4.4 +property-lang = element lang { + element parameters { param-altid, param-pid, param-pref, + param-type }?, + value-language-tag + } + +# 6.5.1 +property-tz = element tz { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + (value-text | value-uri | value-utc-offset) + } + +# 6.5.2 +property-geo = element geo { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.6.1 +property-title = element title { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text + } + +# 6.6.2 +property-role = element role { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text + } + +# 6.6.3 +property-logo = element logo { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type, param-mediatype }?, + value-uri + } + +# 6.6.4 +property-org = element org { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type, param-sort-as }?, + value-text-list + } + +# 6.6.5 +property-member = element member { + element parameters { param-altid, param-pid, param-pref, + param-mediatype }?, + value-uri + } + +# 6.6.6 +property-related = element related { + element parameters { + param-altid, + param-pid, + param-pref, + element type { + element text { + "work" | "home" | "contact" | "acquaintance" | + "friend" | "met" | "co-worker" | "colleague" | "co-resident" | + "neighbor" | "child" | "parent" | "sibling" | "spouse" | + "kin" | "muse" | "crush" | "date" | "sweetheart" | "me" | + "agent" | "emergency" + }+ + }?, + param-mediatype + }?, + (value-uri | value-text) + } + +# 6.7.1 +property-categories = element categories { + element parameters { param-altid, param-pid, param-pref, + param-type }?, + value-text-list + } + +# 6.7.2 +property-note = element note { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text + } + +# 6.7.3 +property-prodid = element prodid { value-text } + +# 6.7.4 +property-rev = element rev { value-timestamp } + +# 6.7.5 +property-sound = element sound { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type, param-mediatype }?, + value-uri + } + +# 6.7.6 +property-uid = element uid { value-uri } + +# 6.7.7 +property-clientpidmap = element clientpidmap { + element sourceid { xsd:positiveInteger }, + value-uri + } + +# 6.7.8 +property-url = element url { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.8.1 +property-key = element key { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + (value-uri | value-text) + } + +# 6.9.1 +property-fburl = element fburl { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.9.2 +property-caladruri = element caladruri { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.9.3 +property-caluri = element caluri { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# Top-level grammar +property = property-adr | property-anniversary | property-bday + | property-caladruri | property-caluri | property-categories + | property-clientpidmap | property-email | property-fburl + | property-fn | property-geo | property-impp | property-key + | property-kind | property-lang | property-logo + | property-member | property-n | property-nickname + | property-note | property-org | property-photo + | property-prodid | property-related | property-rev + | property-role | property-gender | property-sound + | property-source | property-tel | property-title + | property-tz | property-uid | property-url +start = element vcards { + element vcard { + (property + | element group { + attribute name { text }, + property* + })+ + }+ + } + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0.rnc b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0.rnc new file mode 100644 index 0000000..5494882 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0.rnc @@ -0,0 +1,385 @@ +default namespace = "urn:ietf:params:xml:ns:vcard-4.0" + +### Section 3.3: vCard Format Specification +# +# 3.3 + +# mbaudier - 2022-05-31 : corrected regexp from RFC 6351 +iana-token = xsd:string { pattern = "[a-zA-Z0-9]+" } +# mbaudier - 2022-05-31 : corrected regexp from RFC 6351 +x-name = xsd:string { pattern = "x-[a-zA-Z0-9]+" } + +### Section 4: Value types +# +# 4.1 +value-text = element text { text } +value-text-list = value-text+ + +# 4.2 +value-uri = element uri { xsd:anyURI } + +# 4.3.1 +value-date = element date { + xsd:string { pattern = "\d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d" } + } + +# 4.3.2 +value-time = element time { + xsd:string { pattern = "(\d\d(\d\d(\d\d)?)?|-\d\d(\d\d?)|--\d\d)" + ~ "(Z|[+\-]\d\d(\d\d)?)?" } + } + +# 4.3.3 +value-date-time = element date-time { + xsd:string { pattern = "(\d{8}|--\d{4}|---\d\d)T\d\d(\d\d(\d\d)?)?" + ~ "(Z|[+\-]\d\d(\d\d)?)?" } + } + +# 4.3.4 +value-date-and-or-time = value-date | value-date-time | value-time + +# 4.3.5 +value-timestamp = element timestamp { + xsd:string { pattern = "\d{8}T\d{6}(Z|[+\-]\d\d(\d\d)?)?" } + } + +# 4.4 +value-boolean = element boolean { xsd:boolean } + +# 4.5 +value-integer = element integer { xsd:integer } + +# 4.6 +value-float = element float { xsd:float } + +# 4.7 +value-utc-offset = element utc-offset { + xsd:string { pattern = "[+\-]\d\d(\d\d)?" } + } + +# 4.8 +value-language-tag = element language-tag { + xsd:string { pattern = "([a-z]{2,3}((-[a-z]{3}){0,3})?|[a-z]{4,8})" + ~ "(-[a-z]{4})?(-([a-z]{2}|\d{3}))?" + ~ "(-([0-9a-z]{5,8}|\d[0-9a-z]{3}))*" + ~ "(-[0-9a-wyz](-[0-9a-z]{2,8})+)*" + ~ "(-x(-[0-9a-z]{1,8})+)?|x(-[0-9a-z]{1,8})+|" + ~ "[a-z]{1,3}(-[0-9a-z]{2,8}){1,2}" } + } + +### Section 5: Parameters +# +# 5.1 +param-language = element language { value-language-tag }? + +# 5.2 +param-pref = element pref { + element integer { + xsd:integer { minInclusive = "1" maxInclusive = "100" } + } + }? + +# 5.4 +param-altid = element altid { value-text }? + +# 5.5 +param-pid = element pid { + element text { xsd:string { pattern = "\d+(\.\d+)?" } }+ + }? + +# 5.6 +param-type = element type { element text { "work" | "home" }+ }? + +# 5.7 +param-mediatype = element mediatype { value-text }? + +# 5.8 +param-calscale = element calscale { element text { "gregorian" } }? + +# 5.9 +param-sort-as = element sort-as { value-text+ }? + +# 5.10 +param-geo = element geo { value-uri }? + +# 5.11 +param-tz = element tz { value-text | value-uri }? + +### Section 6: Properties +# +# 6.1.3 +property-source = element source { + element parameters { param-altid, param-pid, param-pref, + param-mediatype }, + value-uri + } + +# 6.1.4 +property-kind = element kind { + element text { "individual" | "group" | "org" | "location" | + x-name | iana-token }* + } + +# 6.2.1 +property-fn = element fn { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text + } + +# 6.2.2 +property-n = element n { + element parameters { param-language, param-sort-as, param-altid }?, + element surname { text }+, + element given { text }+, + element additional { text }+, + element prefix { text }+, + element suffix { text }+ + } + +# 6.2.3 +property-nickname = element nickname { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text-list + } + +# 6.2.4 +property-photo = element photo { + element parameters { param-altid, param-pid, param-pref, param-type, + param-mediatype }?, + value-uri + } + +# 6.2.5 +property-bday = element bday { + element parameters { param-altid, param-calscale }?, + (value-date-and-or-time | value-text) + } + +# 6.2.6 +property-anniversary = element anniversary { + element parameters { param-altid, param-calscale }?, + (value-date-and-or-time | value-text) + } + +# 6.2.7 +property-gender = element gender { + element sex { "" | "M" | "F" | "O" | "N" | "U" }, + element identity { text }? + } + +# 6.3.1 +param-label = element label { value-text }? +property-adr = element adr { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type, param-geo, param-tz, + param-label }?, + element pobox { text }+, + element ext { text }+, + element street { text }+, + element locality { text }+, + element region { text }+, + element code { text }+, + element country { text }+ + } + +# 6.4.1 +property-tel = element tel { + element parameters { + param-altid, + param-pid, + param-pref, + element type { + element text { "work" | "home" | "text" | "voice" + | "fax" | "cell" | "video" | "pager" + | "textphone" }+ + }?, + param-mediatype + }?, + (value-text | value-uri) + } + +# 6.4.2 +property-email = element email { + element parameters { param-altid, param-pid, param-pref, + param-type }?, + value-text + } + +# 6.4.3 +property-impp = element impp { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.4.4 +property-lang = element lang { + element parameters { param-altid, param-pid, param-pref, + param-type }?, + value-language-tag + } + +# 6.5.1 +property-tz = element tz { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + (value-text | value-uri | value-utc-offset) + } + +# 6.5.2 +property-geo = element geo { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.6.1 +property-title = element title { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text + } + +# 6.6.2 +property-role = element role { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text + } + +# 6.6.3 +property-logo = element logo { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type, param-mediatype }?, + value-uri + } + +# 6.6.4 +property-org = element org { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type, param-sort-as }?, + value-text-list + } + +# 6.6.5 +property-member = element member { + element parameters { param-altid, param-pid, param-pref, + param-mediatype }?, + value-uri + } + +# 6.6.6 +property-related = element related { + element parameters { + param-altid, + param-pid, + param-pref, + element type { + element text { + "work" | "home" | "contact" | "acquaintance" | + "friend" | "met" | "co-worker" | "colleague" | "co-resident" | + "neighbor" | "child" | "parent" | "sibling" | "spouse" | + "kin" | "muse" | "crush" | "date" | "sweetheart" | "me" | + "agent" | "emergency" + }+ + }?, + param-mediatype + }?, + (value-uri | value-text) + } + +# 6.7.1 +property-categories = element categories { + element parameters { param-altid, param-pid, param-pref, + param-type }?, + value-text-list + } + +# 6.7.2 +property-note = element note { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type }?, + value-text + } + +# 6.7.3 +property-prodid = element prodid { value-text } + +# 6.7.4 +property-rev = element rev { value-timestamp } + +# 6.7.5 +property-sound = element sound { + element parameters { param-language, param-altid, param-pid, + param-pref, param-type, param-mediatype }?, + value-uri + } + +# 6.7.6 +property-uid = element uid { value-uri } + +# 6.7.7 +property-clientpidmap = element clientpidmap { + element sourceid { xsd:positiveInteger }, + value-uri + } + +# 6.7.8 +property-url = element url { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.8.1 +property-key = element key { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + (value-uri | value-text) + } + +# 6.9.1 +property-fburl = element fburl { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.9.2 +property-caladruri = element caladruri { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# 6.9.3 +property-caluri = element caluri { + element parameters { param-altid, param-pid, param-pref, + param-type, param-mediatype }?, + value-uri + } + +# Top-level grammar +property = property-adr | property-anniversary | property-bday + | property-caladruri | property-caluri | property-categories + | property-clientpidmap | property-email | property-fburl + | property-fn | property-geo | property-impp | property-key + | property-kind | property-lang | property-logo + | property-member | property-n | property-nickname + | property-note | property-org | property-photo + | property-prodid | property-related | property-rev + | property-role | property-gender | property-sound + | property-source | property-tel | property-title + | property-tz | property-uid | property-url +start = element vcards { + element vcard { + (property + | element group { + attribute name { text }, + property* + })+ + }+ + } + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0.xsd new file mode 100644 index 0000000..bb1b175 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xCard-4.0.xsd @@ -0,0 +1,1041 @@ + + + + + + + Section 3.3: vCard Format Specification + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Section 5: Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xlink.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/xlink.xsd new file mode 100644 index 0000000..e9ce635 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xlink.xsd @@ -0,0 +1,293 @@ + + + + + This schema is not normative, or even definitive. The +prose copy in the XLink 1.1 recommendation (http://www.w3.org/TR/xlink11/) is +definitive, although it should not differ from this file, except for the +absence of these two initial comments. + + + + In keeping with the W3C's standard versioning + policy, this schema document will persist at + http://www.w3.org/XML/2008/06/xlink.xsd. + At the date of issue it can also be found at + http://www.w3.org/1999/xlink.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself, or with the XLink namespace itself. In other words, if the XML + Schema or XLink namespaces change, the version of this document at + http://www.w3.org/1999/xlink.xsd will change + accordingly; the version at + http://www.w3.org/2008/06/xlink.xsd will not change. + + + + + This schema document provides attribute declarations and +attribute group, complex type and simple type definitions which can be used in +the construction of user schemas to define the structure of particular linking +constructs, e.g. + +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:xl="http://www.w3.org/1999/xlink"> + + <xs:import namespace="http://www.w3.org/1999/xlink" + location="http://www.w3.org/1999/xlink.xsd"> + + <xs:element name="mySimple"> + <xs:complexType> + ... + <xs:attributeGroup ref="xl:simpleAttrs"/> + ... + </xs:complexType> + </xs:element> + ... +</xs:schema> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Intended for use as the type of user-declared elements to make them + simple links. + + + + + + + + + + + + + + + + + + + + + + + + + Intended for use as the type of user-declared elements to make them + extended links. + Note that the elements referenced in the content model are all abstract. + The intention is that by simply declaring elements with these as their + substitutionGroup, all the right things will happen. + + + + + + + + + + + + + + xml:lang is not required, but provides much of the + motivation for title elements in addition to attributes, and so + is provided here for convenience. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + label is not required, but locators have no particular + XLink function if they are not labeled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from and to have default behavior when values are missing + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xml-events-attribs-1.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/xml-events-attribs-1.xsd new file mode 100644 index 0000000..ef99128 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xml-events-attribs-1.xsd @@ -0,0 +1,73 @@ + + + + + + This is the XML Schema for XML Events global attributes + + URI: http://www.w3.org/MarkUp/SCHEMA/xml-events-attribs-1.xsd + $Id: xml-events-attribs-1.xsd,v 1.7 2004/11/22 17:09:15 ahby Exp $ + + + + + + + XML Event Attributes + + These "global" event attributes are defined in "Attaching + Attributes Directly to the Observer Element" of the XML + Events specification. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/xml.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/xml.xsd new file mode 100644 index 0000000..aea7d0d --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/schemas/xml.xsd @@ -0,0 +1,287 @@ + + + + + + +
+

About the XML namespace

+ +
+

+ This schema document describes the XML namespace, in a form + suitable for import by other schema documents. +

+

+ See + http://www.w3.org/XML/1998/namespace.html and + + http://www.w3.org/TR/REC-xml for information + about this namespace. +

+

+ Note that local names in this namespace are intended to be + defined only by the World Wide Web Consortium or its subgroups. + The names currently defined in this namespace are listed below. + They should not be used with conflicting semantics by any Working + Group, specification, or document instance. +

+

+ See further below in this document for more information about how to refer to this schema document from your own + XSD schema documents and about the + namespace-versioning policy governing this schema document. +

+
+
+ + + + + + +
+ +

lang (as an attribute name)

+

+ denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification.

+ +
+
+

Notes

+

+ Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. +

+

+ See BCP 47 at + http://www.rfc-editor.org/rfc/bcp/bcp47.txt + and the IANA language subtag registry at + + http://www.iana.org/assignments/language-subtag-registry + for further information. +

+

+ The union allows for the 'un-declaration' of xml:lang with + the empty string. +

+
+
+
+ + + + + + + + + +
+ + + + +
+ +

space (as an attribute name)

+

+ denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification.

+ +
+
+
+ + + + + + +
+ + + +
+ +

base (as an attribute name)

+

+ denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification.

+ +

+ See http://www.w3.org/TR/xmlbase/ + for information about this attribute. +

+
+
+
+
+ + + + +
+ +

id (as an attribute name)

+

+ denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification.

+ +

+ See http://www.w3.org/TR/xml-id/ + for information about this attribute. +

+
+
+
+
+ + + + + + + + + + +
+ +

Father (in any context at all)

+ +
+

+ denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: +

+
+

+ In appreciation for his vision, leadership and + dedication the W3C XML Plenary on this 10th day of + February, 2000, reserves for Jon Bosak in perpetuity + the XML name "xml:Father". +

+
+
+
+
+
+ + + +
+

About this schema document

+ +
+

+ This schema defines attributes and an attribute group suitable + for use by schemas wishing to allow xml:base, + xml:lang, xml:space or + xml:id attributes on elements they define. +

+

+ To enable this, such a schema must import this schema for + the XML namespace, e.g. as follows: +

+
+          <schema . . .>
+           . . .
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     
+

+ or +

+
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     
+

+ Subsequently, qualified reference to any of the attributes or the + group defined below will have the desired effect, e.g. +

+
+          <type . . .>
+           . . .
+           <attributeGroup ref="xml:specialAttrs"/>
+     
+

+ will define a type which will schema-validate an instance element + with any of those attributes. +

+
+
+
+
+ + + +
+

Versioning policy for this schema document

+
+

+ In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + + http://www.w3.org/2009/01/xml.xsd. +

+

+ At the date of issue it can also be found at + + http://www.w3.org/2001/xml.xsd. +

+

+ The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML + Schema itself, or with the XML namespace itself. In other words, + if the XML Schema or XML namespaces change, the version of this + document at + http://www.w3.org/2001/xml.xsd + + will change accordingly; the version at + + http://www.w3.org/2009/01/xml.xsd + + will not change. +

+

+ Previous dated (and unchanging) versions of this schema + document are at: +

+ +
+
+
+
+ + + diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkAcrUtils.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkAcrUtils.java new file mode 100644 index 0000000..8dda2b4 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/docbook/DbkAcrUtils.java @@ -0,0 +1,29 @@ +package org.argeo.app.docbook; + +import org.argeo.api.acr.Content; + +public class DbkAcrUtils { + /** Whether this DocBook element is of this type. */ + public static boolean isDbk(Content content, DbkType type) { + return content.isContentClass(type.qName()); + } + + public static String getMediaFileref(Content node) { + Content mediadata; + if (node.hasChild(DbkType.imageobject)) { + mediadata = node.child(DbkType.imageobject).child(DbkType.imagedata); + } else { + mediadata = node.child(DbkType.videoobject).child(DbkType.videodata); + } + + if (mediadata.containsKey(DbkAttr.fileref)) { + return mediadata.attr(DbkAttr.fileref); + } else { + return null; + } + } + + /** singleton */ + private DbkAcrUtils() { + } +} diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkAttr.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkAttr.java index f6cf839..df10c8b 100644 --- a/org.argeo.app.core/src/org/argeo/app/docbook/DbkAttr.java +++ b/org.argeo.app.core/src/org/argeo/app/docbook/DbkAttr.java @@ -1,7 +1,9 @@ package org.argeo.app.docbook; +import org.argeo.api.acr.QNamed; + /** Supported DocBook attributes. */ -public enum DbkAttr { +public enum DbkAttr implements QNamed.Unqualified { role, // fileref, contentwidth, contentdepth diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkType.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkType.java index 3e3585f..ff83002 100644 --- a/org.argeo.app.core/src/org/argeo/app/docbook/DbkType.java +++ b/org.argeo.app.core/src/org/argeo/app/docbook/DbkType.java @@ -1,9 +1,9 @@ package org.argeo.app.docbook; -import org.argeo.app.api.JcrName; +import org.argeo.api.acr.QNamed; /** Supported DocBook elements */ -public enum DbkType implements JcrName { +public enum DbkType implements QNamed { book, article, section, // info, title, para, @@ -14,11 +14,12 @@ public enum DbkType implements JcrName { // ; - @Override - public String getPrefix() { - return prefix(); - } +// @Override +// public String getPrefix() { +// return prefix(); +// } + @Deprecated public static String prefix() { return "dbk"; } @@ -32,4 +33,9 @@ public enum DbkType implements JcrName { return "http://docbook.org/ns/docbook"; } + @Override + public String getDefaultPrefix() { + return "dbk"; + } + } diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java index 6c959f4..b0d352b 100644 --- a/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java +++ b/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java @@ -70,7 +70,7 @@ public class DbkUtils { public static void setTitle(Node node, String txt) { Node titleNode = getOrAddDbk(node, DbkType.title); - JcrxApi.setXmlValue(node, titleNode, txt); + JcrxApi.setXmlValue(titleNode, txt); } public static Node getMetadata(Node infoContainer) { @@ -103,7 +103,7 @@ public class DbkUtils { public static Node addParagraph(Node node, String txt) { Node p = addDbk(node, para); - JcrxApi.setXmlValue(node, p, txt); + JcrxApi.setXmlValue(p, txt); return p; } diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GeoToolsTest.java b/org.argeo.app.core/src/org/argeo/app/geo/GeoToolsTest.java new file mode 100644 index 0000000..a771196 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/geo/GeoToolsTest.java @@ -0,0 +1,221 @@ +package org.argeo.app.geo; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.geotools.data.DataUtilities; +import org.geotools.data.DefaultTransaction; +import org.geotools.data.Transaction; +import org.geotools.data.collection.ListFeatureCollection; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.ShapefileDataStoreFactory; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.geotools.data.simple.SimpleFeatureSource; +import org.geotools.data.simple.SimpleFeatureStore; +import org.geotools.feature.simple.SimpleFeatureBuilder; +import org.geotools.geometry.jts.JTSFactoryFinder; +import org.geotools.swing.data.JFileDataStoreChooser; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.Point; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; + +public class GeoToolsTest { + public GeoToolsTest() { + + } + + public void init() { + try { + main(null); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void destroy() { + + } + + public static void main(String[] args) throws Exception { + final SimpleFeatureType TYPE = DataUtilities.createType("Location", "the_geom:Point:srid=4326," + // <- the + // geometry + // attribute: + // Point + // type + "name:String," + // <- a String attribute + "number:Integer" // a number attribute + ); + final SimpleFeatureType TYPE_HULL = DataUtilities.createType("Hull", "the_geom:MultiPolygon:srid=4326"); + System.out.println("TYPE:" + TYPE); + + /* + * A list to collect features as we create them. + */ + List features = new ArrayList<>(); + List coordinates = new ArrayList<>(); + + /* + * GeometryFactory will be used to create the geometry attribute of each + * feature, using a Point object for the location. + */ + GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); + + SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE); + + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(GeoToolsTest.class.getResourceAsStream("/org/djapps/on/apaf/locations.csv")))) { + /* First line of the data file is the header */ + String line = reader.readLine(); + System.out.println("Header: " + line); + + for (line = reader.readLine(); line != null; line = reader.readLine()) { + if (line.trim().length() > 0) { // skip blank lines + String[] tokens = line.split("\\,"); + + double latitude = Double.parseDouble(tokens[0]); + double longitude = Double.parseDouble(tokens[1]); + String name = tokens[2].trim(); + int number = Integer.parseInt(tokens[3].trim()); + + /* Longitude (= x coord) first ! */ + Coordinate coordinate = new Coordinate(longitude, latitude); + coordinates.add(coordinate); + Point point = geometryFactory.createPoint(coordinate); + + featureBuilder.add(point); + featureBuilder.add(name); + featureBuilder.add(number); + SimpleFeature feature = featureBuilder.buildFeature(null); + features.add(feature); + } + } + } + + LineString lineString = geometryFactory + .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); + Geometry convexHull = lineString.convexHull(); + System.out.println(convexHull.toText()); + SimpleFeatureBuilder hullFeatureBuilder = new SimpleFeatureBuilder(TYPE_HULL); + hullFeatureBuilder.add(convexHull); + SimpleFeature hull = hullFeatureBuilder.buildFeature(null); + + /* + * Get an output file name and create the new shapefile + */ + File newFile = getNewShapeFile(); + + ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); + + Map params = new HashMap<>(); + params.put("url", newFile.toURI().toURL()); + params.put("create spatial index", Boolean.TRUE); + + ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params); + + /* + * TYPE is used as a template to describe the file contents + */ + newDataStore.createSchema(TYPE_HULL); + + /* + * Write the features to the shapefile + */ + Transaction transaction = new DefaultTransaction("create"); + + String typeName = newDataStore.getTypeNames()[0]; + SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName); + SimpleFeatureType SHAPE_TYPE = featureSource.getSchema(); + /* + * The Shapefile format has a couple limitations: - "the_geom" is always first, + * and used for the geometry attribute name - "the_geom" must be of type Point, + * MultiPoint, MuiltiLineString, MultiPolygon - Attribute names are limited in + * length - Not all data types are supported (example Timestamp represented as + * Date) + * + * Each data store has different limitations so check the resulting + * SimpleFeatureType. + */ + System.out.println("SHAPE:" + SHAPE_TYPE); + + if (featureSource instanceof SimpleFeatureStore) { + SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; + /* + * SimpleFeatureStore has a method to add features from a + * SimpleFeatureCollection object, so we use the ListFeatureCollection class to + * wrap our list of features. + */ + SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, Collections.singletonList(hull)); + featureStore.setTransaction(transaction); + try { + featureStore.addFeatures(collection); + transaction.commit(); + } catch (Exception problem) { + problem.printStackTrace(); + transaction.rollback(); + } finally { + transaction.close(); + } + } else { + System.out.println(typeName + " does not support read/write access"); + } +// if (featureSource instanceof SimpleFeatureStore) { +// SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; +// /* +// * SimpleFeatureStore has a method to add features from a +// * SimpleFeatureCollection object, so we use the ListFeatureCollection class to +// * wrap our list of features. +// */ +// SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features); +// featureStore.setTransaction(transaction); +// try { +// featureStore.addFeatures(collection); +// transaction.commit(); +// } catch (Exception problem) { +// problem.printStackTrace(); +// transaction.rollback(); +// } finally { +// transaction.close(); +// } +// } else { +// System.out.println(typeName + " does not support read/write access"); +// } + } + + /** + * Prompt the user for the name and path to use for the output shapefile + * + * @param csvFile the input csv file used to create a default shapefile name + * @return name and path for the shapefile as a new File object + */ + private static File getNewShapeFile() { +// String path = csvFile.getAbsolutePath(); +// String newPath = path.substring(0, path.length() - 4) + ".shp"; + + JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp"); + chooser.setDialogTitle("Save shapefile"); +// chooser.setSelectedFile(new File(newPath)); + + int returnVal = chooser.showSaveDialog(null); + + if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) { + // the user cancelled the dialog + System.exit(0); + } + + File newFile = chooser.getSelectedFile(); + + return newFile; + } + +} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GeoUtils.java b/org.argeo.app.core/src/org/argeo/app/geo/GeoUtils.java new file mode 100644 index 0000000..1b9ce72 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/geo/GeoUtils.java @@ -0,0 +1,109 @@ +package org.argeo.app.geo; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +import javax.measure.Quantity; +import javax.measure.quantity.Area; + +import org.geotools.data.simple.SimpleFeatureCollection; +import org.geotools.data.simple.SimpleFeatureIterator; +import org.geotools.geometry.jts.JTS; +import org.geotools.referencing.CRS; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.geometry.MismatchedDimensionException; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; + +import si.uom.SI; +import tech.units.indriya.quantity.Quantities; + +/** Utilities around geographical format, mostly wrapping GeoTools patterns. */ +public class GeoUtils { + + /** In square meters. */ + public static Quantity calcArea(SimpleFeature feature) { + try { + Polygon p = (Polygon) feature.getDefaultGeometry(); + Point centroid = p.getCentroid(); + String code = "AUTO:42001," + centroid.getX() + "," + centroid.getY(); + CoordinateReferenceSystem auto = CRS.decode(code); + + MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto); + + Polygon projed = (Polygon) JTS.transform(p, transform); + return Quantities.getQuantity(projed.getArea(), SI.SQUARE_METRE); + } catch (MismatchedDimensionException | FactoryException | TransformException e) { + throw new IllegalStateException("Cannot claculate area of feature"); + } + } + + public static void exportToSvg(SimpleFeatureCollection features, Writer out, int width, int height) { + try { + double minY = Double.POSITIVE_INFINITY; + double maxY = Double.NEGATIVE_INFINITY; + double minX = Double.POSITIVE_INFINITY; + double maxX = Double.NEGATIVE_INFINITY; + List shapes = new ArrayList<>(); + for (SimpleFeatureIterator it = features.features(); it.hasNext();) { + SimpleFeature feature = it.next(); + StringBuffer sb = new StringBuffer(); + sb.append(" maxX) + maxX = x; + double y = -coord.y; + if (y < minY) + minY = y; + if (y > maxY) + maxY = y; + sb.append(x + "," + y + " "); + } + sb.append("\">"); + sb.append("\n"); + shapes.add(sb.toString()); + + } + double viewportHeight = maxY - minY; + double viewportWidth = maxX - minX; + out.write("\n"); + for (String shape : shapes) { + out.write(shape); + out.write("\n"); + } + out.write(""); + } catch (IOException | FactoryException | MismatchedDimensionException | TransformException e) { + throw new RuntimeException("Cannot export to SVG", e); + } + } + + /** Singleton. */ + private GeoUtils() { + } +} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GmlAttr.java b/org.argeo.app.core/src/org/argeo/app/geo/GmlAttr.java new file mode 100644 index 0000000..77b0885 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/geo/GmlAttr.java @@ -0,0 +1,22 @@ +package org.argeo.app.geo; + +import org.argeo.api.acr.QNamed; + +public enum GmlAttr implements QNamed { + uom + // + ; + + public final static String UOM_SQUARE_METERS = "m2"; + + @Override + public String getNamespace() { + return "http://www.opengis.net/gml/3.2"; + } + + @Override + public String getDefaultPrefix() { + return "gml"; + } + +} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GmlType.java b/org.argeo.app.core/src/org/argeo/app/geo/GmlType.java new file mode 100644 index 0000000..980a5e4 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/geo/GmlType.java @@ -0,0 +1,20 @@ +package org.argeo.app.geo; + +import org.argeo.api.acr.QNamed; + +public enum GmlType implements QNamed { + measure + // + ; + + @Override + public String getNamespace() { + return "http://www.opengis.net/gml/3.2"; + } + + @Override + public String getDefaultPrefix() { + return "gml"; + } + +} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GpxUtils.java b/org.argeo.app.core/src/org/argeo/app/geo/GpxUtils.java new file mode 100644 index 0000000..5bb7d5c --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/geo/GpxUtils.java @@ -0,0 +1,67 @@ +package org.argeo.app.geo; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.geotools.data.DataUtilities; +import org.geotools.feature.SchemaException; +import org.geotools.feature.simple.SimpleFeatureBuilder; +import org.geotools.geometry.jts.JTSFactoryFinder; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.Polygon; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** Utilities around the GPX format. */ +public class GpxUtils { + + public static SimpleFeature parseGpxToPolygon(InputStream in) { + try { + final SimpleFeatureType TYPE = DataUtilities.createType("Area", "the_geom:Polygon:srid=4326"); + SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE); + + GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); + List coordinates = new ArrayList<>(); + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser saxParser = factory.newSAXParser(); + + saxParser.parse(in, new DefaultHandler() { + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if ("trkpt".equals(qName)) { + Double latitude = Double.parseDouble(attributes.getValue("lat")); + Double longitude = Double.parseDouble(attributes.getValue("lon")); + Coordinate coordinate = new Coordinate(longitude, latitude); + coordinates.add(coordinate); + } + } + + }); + // close the line string + coordinates.add(coordinates.get(0)); + + Polygon polygon = geometryFactory.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); + featureBuilder.add(polygon); + SimpleFeature area = featureBuilder.buildFeature(null); + return area; + } catch (ParserConfigurationException | SAXException | IOException | SchemaException e) { + throw new RuntimeException("Cannot convert GPX", e); + } + } + + /** Singleton. */ + private GpxUtils() { + } +} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java b/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java index 52456bb..be2b507 100644 --- a/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java +++ b/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java @@ -10,8 +10,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.argeo.util.CsvParser; -import org.argeo.util.CsvWriter; +import org.argeo.cms.util.CsvParser; +import org.argeo.cms.util.CsvWriter; /** Import GeoNames administrative division from the main table. */ public class ImportGeonamesAdmin { diff --git a/org.argeo.app.core/src/org/argeo/app/image/ImageProcessor.java b/org.argeo.app.core/src/org/argeo/app/image/ImageProcessor.java index 7fd308d..72c334f 100644 --- a/org.argeo.app.core/src/org/argeo/app/image/ImageProcessor.java +++ b/org.argeo.app.core/src/org/argeo/app/image/ImageProcessor.java @@ -66,9 +66,9 @@ public class ImageProcessor { Files.deleteIfExists(temp); } } else { - try (OutputStream out = outSupplier.call()) { - copyWithMetadata(() -> in, metadata); - } +// try (OutputStream out = outSupplier.call()) { + copyWithMetadata(() -> in, metadata); +// } } } } catch (Exception e) { diff --git a/org.argeo.app.core/src/org/argeo/app/library/DocxExtractor.java b/org.argeo.app.core/src/org/argeo/app/library/DocxExtractor.java index 17c6cf2..c96126c 100644 --- a/org.argeo.app.core/src/org/argeo/app/library/DocxExtractor.java +++ b/org.argeo.app.core/src/org/argeo/app/library/DocxExtractor.java @@ -22,7 +22,7 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -import org.argeo.util.DigestUtils; +import org.argeo.cms.util.DigestUtils; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; diff --git a/org.argeo.app.core/src/org/argeo/app/mail/EmailMigration.java b/org.argeo.app.core/src/org/argeo/app/mail/EmailMigration.java new file mode 100644 index 0000000..8c899c2 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/mail/EmailMigration.java @@ -0,0 +1,524 @@ +package org.argeo.app.mail; + +import static java.lang.System.Logger.Level.DEBUG; +import static java.lang.System.Logger.Level.ERROR; +import static org.argeo.app.mail.EmailUtils.describe; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.System.Logger; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.time.Instant; +import java.util.Date; +import java.util.Enumeration; +import java.util.Properties; + +import javax.mail.FetchProfile; +import javax.mail.Folder; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Store; +import javax.mail.URLName; +import javax.mail.internet.InternetHeaders; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.search.HeaderTerm; +import javax.mail.util.SharedFileInputStream; + +import com.sun.mail.imap.IMAPFolder; +import com.sun.mail.mbox.MboxFolder; +import com.sun.mail.mbox.MboxMessage; + +/** Migrates emails from one storage to the another one. */ +public class EmailMigration { + private final static Logger logger = System.getLogger(EmailMigration.class.getName()); + +// private String targetBaseDir; + + private String sourceServer; + private String sourceUsername; + private String sourcePassword; + + private String targetServer; + private String targetUsername; + private String targetPassword; + + private boolean targetSupportDualTypeFolders = true; + + public void process() throws MessagingException, IOException { +// Path baseDir = Paths.get(targetBaseDir).resolve(sourceUsername).resolve("mbox"); + + Store sourceStore = null; + try { + Properties sourceProperties = System.getProperties(); + sourceProperties.setProperty("mail.store.protocol", "imaps"); + + Session sourceSession = Session.getInstance(sourceProperties, null); + // session.setDebug(true); + sourceStore = sourceSession.getStore("imaps"); + sourceStore.connect(sourceServer, sourceUsername, sourcePassword); + + Folder defaultFolder = sourceStore.getDefaultFolder(); +// migrateFolders(baseDir, defaultFolder); + + // Always start with Inbox +// Folder inboxFolder = sourceStore.getFolder(EmailUtils.INBOX); +// migrateFolder(baseDir, inboxFolder); + + Properties targetProperties = System.getProperties(); + targetProperties.setProperty("mail.imap.starttls.enable", "true"); + targetProperties.setProperty("mail.imap.auth", "true"); + + Session targetSession = Session.getInstance(targetProperties, null); + // session.setDebug(true); + Store targetStore = targetSession.getStore("imap"); + targetStore.connect(targetServer, targetUsername, targetPassword); + +// Folder targetFolder = targetStore.getFolder(EmailUtils.INBOX); +// logger.log(DEBUG, "Source message count " + inboxFolder.getMessageCount()); +// logger.log(DEBUG, "Target message count " + targetFolder.getMessageCount()); + + migrateFolders(defaultFolder, targetStore); + } finally { + if (sourceStore != null) + sourceStore.close(); + + } + } + + protected void migrateFolders(Folder sourceParentFolder, Store targetStore) throws MessagingException, IOException { + folders: for (Folder sourceFolder : sourceParentFolder.list()) { + String sourceFolderName = sourceFolder.getName(); + + String sourceFolderFullName = sourceFolder.getFullName(); + char sourceFolderSeparator = sourceParentFolder.getSeparator(); + char targetFolderSeparator = targetStore.getDefaultFolder().getSeparator(); + String targetFolderFullName = sourceFolderFullName.replace(sourceFolderSeparator, targetFolderSeparator); + + // GMail specific + if (sourceFolderFullName.equals("[Gmail]")) { + migrateFolders(sourceFolder, targetStore); + continue folders; + } + if (sourceFolderFullName.startsWith("[Gmail]")) { + String subFolderName = null; + // Make it configurable + switch (sourceFolderName) { + case "All Mail": + case "Important": + case "Spam": + continue folders; + case "Sent Mail": + subFolderName = "Sent"; + default: + // does nothing + } + targetFolderFullName = subFolderName == null ? sourceFolder.getName() : subFolderName; + } + + // nature of the source folder + int messageCount = (sourceFolder.getType() & Folder.HOLDS_MESSAGES) != 0 ? sourceFolder.getMessageCount() + : 0; + boolean hasSubFolders = (sourceFolder.getType() & Folder.HOLDS_FOLDERS) != 0 + ? sourceFolder.list().length != 0 + : false; + + Folder targetFolder; + if (targetSupportDualTypeFolders) { + targetFolder = targetStore.getFolder(targetFolderFullName); + if (!targetFolder.exists()) { + targetFolder.create(Folder.HOLDS_FOLDERS | Folder.HOLDS_MESSAGES); + logger.log(DEBUG, "Created HOLDS_FOLDERS | HOLDS_MESSAGES folder " + targetFolder.getFullName()); + } + + } else { + if (hasSubFolders) {// has sub-folders + if (messageCount == 0) { + targetFolder = targetStore.getFolder(targetFolderFullName); + if (!targetFolder.exists()) { + targetFolder.create(Folder.HOLDS_FOLDERS); + logger.log(DEBUG, "Created HOLDS_FOLDERS folder " + targetFolder.getFullName()); + } + } else {// also has messages + Folder parentFolder = targetStore.getFolder(targetFolderFullName); + if (!parentFolder.exists()) { + parentFolder.create(Folder.HOLDS_FOLDERS); + logger.log(DEBUG, "Created HOLDS_FOLDERS folder " + parentFolder.getFullName()); + } + String miscFullName = targetFolderFullName + targetFolderSeparator + "_Misc"; + targetFolder = targetStore.getFolder(miscFullName); + if (!targetFolder.exists()) { + targetFolder.create(Folder.HOLDS_MESSAGES); + logger.log(DEBUG, "Created HOLDS_MESSAGES folder " + targetFolder.getFullName()); + } + } + } else {// no sub-folders + if (messageCount == 0) { // empty + logger.log(DEBUG, "Skip empty folder " + targetFolderFullName); + continue folders; + } + targetFolder = targetStore.getFolder(targetFolderFullName); + if (!targetFolder.exists()) { + targetFolder.create(Folder.HOLDS_MESSAGES); + logger.log(DEBUG, "Created HOLDS_MESSAGES folder " + targetFolder.getFullName()); + } + } + } + + if (messageCount != 0) { + + targetFolder.open(Folder.READ_WRITE); + try { + long begin = System.currentTimeMillis(); + sourceFolder.open(Folder.READ_ONLY); + migrateFolder(sourceFolder, targetFolder); + long duration = System.currentTimeMillis() - begin; + logger.log(DEBUG, targetFolderFullName + " - Migration of " + messageCount + " messages took " + + (duration / 1000) + " s (" + (duration / messageCount) + " ms per message)"); + } finally { + sourceFolder.close(); + targetFolder.close(); + } + } + + // recursive + if (hasSubFolders) { + migrateFolders(sourceFolder, targetStore); + } + } + } + + protected void migrateFoldersToFs(Path baseDir, Folder sourceFolder) throws MessagingException, IOException { + folders: for (Folder folder : sourceFolder.list()) { + String folderName = folder.getName(); + + if ((folder.getType() & Folder.HOLDS_MESSAGES) != 0) { + // Make it configurable + switch (folderName) { + case "All Mail": + case "Important": + continue folders; + default: + // doe nothing + } + migrateFolderToFs(baseDir, folder); + } + if ((folder.getType() & Folder.HOLDS_FOLDERS) != 0) { + migrateFoldersToFs(baseDir.resolve(folder.getName()), folder); + } + } + } + + protected void migrateFolderToFs(Path baseDir, Folder sourceFolder) throws MessagingException, IOException { + + String folderName = sourceFolder.getName(); + sourceFolder.open(Folder.READ_ONLY); + + Folder targetFolder = null; + try { + int messageCount = sourceFolder.getMessageCount(); + logger.log(DEBUG, folderName + " - Message count : " + messageCount); + if (messageCount == 0) + return; +// logger.log(DEBUG, folderName + " - Unread Messages : " + sourceFolder.getUnreadMessageCount()); + + boolean saveAsFiles = false; + + if (saveAsFiles) { + Message messages[] = sourceFolder.getMessages(); + + for (int i = 0; i < messages.length; ++i) { +// logger.log(DEBUG, "MESSAGE #" + (i + 1) + ":"); + Message msg = messages[i]; +// String from = "unknown"; +// if (msg.getReplyTo().length >= 1) { +// from = msg.getReplyTo()[0].toString(); +// } else if (msg.getFrom().length >= 1) { +// from = msg.getFrom()[0].toString(); +// } + String subject = msg.getSubject(); + Instant sentDate = msg.getSentDate().toInstant(); +// logger.log(DEBUG, "Saving ... " + subject + " from " + from + " (" + sentDate + ")"); + String fileName = sentDate + " " + subject; + Path file = baseDir.resolve(fileName); + savePartsAsFiles(msg.getContent(), file); + } + } else { + long begin = System.currentTimeMillis(); + targetFolder = openMboxTargetFolder(sourceFolder, baseDir); + migrateFolder(sourceFolder, targetFolder); + long duration = System.currentTimeMillis() - begin; + logger.log(DEBUG, folderName + " - Migration of " + messageCount + " messages took " + (duration / 1000) + + " s (" + (duration / messageCount) + " ms per message)"); + } + } finally { + sourceFolder.close(); + if (targetFolder != null) + targetFolder.close(); + } + } + + protected Folder migrateFolder(Folder sourceFolder, Folder targetFolder) throws MessagingException, IOException { + String folderName = targetFolder.getName(); + + int lastSourceNumber; + int currentTargetMessageCount = targetFolder.getMessageCount(); + if (currentTargetMessageCount != 0) { + MimeMessage lastTargetMessage = (MimeMessage) targetFolder.getMessage(currentTargetMessageCount); + logger.log(DEBUG, folderName + " - Last target message " + describe(lastTargetMessage)); + Date lastTargetSent = lastTargetMessage.getReceivedDate(); + Message[] lastSourceMessage = sourceFolder + .search(new HeaderTerm(EmailUtils.MESSAGE_ID, lastTargetMessage.getMessageID())); + if (lastSourceMessage.length == 0) + throw new IllegalStateException("No message found with message ID " + lastTargetMessage.getMessageID()); + if (lastSourceMessage.length != 1) { + for (Message msg : lastSourceMessage) { + logger.log(ERROR, "Message " + describe(msg)); + + } + throw new IllegalStateException( + lastSourceMessage.length + " messages found with received date " + lastTargetSent.toInstant()); + } + lastSourceNumber = lastSourceMessage[0].getMessageNumber(); + } else { + lastSourceNumber = 0; + } + logger.log(DEBUG, folderName + " - Last source message number " + lastSourceNumber); + + int countToRetrieve = sourceFolder.getMessageCount() - lastSourceNumber; + + FetchProfile fetchProfile = new FetchProfile(); + fetchProfile.add(FetchProfile.Item.FLAGS); + fetchProfile.add(FetchProfile.Item.ENVELOPE); + fetchProfile.add(FetchProfile.Item.CONTENT_INFO); + fetchProfile.add(FetchProfile.Item.SIZE); + if (sourceFolder instanceof IMAPFolder) { + // IMAPFolder sourceImapFolder = (IMAPFolder) sourceFolder; + fetchProfile.add(IMAPFolder.FetchProfileItem.HEADERS); + fetchProfile.add(IMAPFolder.FetchProfileItem.MESSAGE); + } + + int batchSize = 100; + int batchCount = countToRetrieve / batchSize; + if (countToRetrieve % batchSize != 0) + batchCount = batchCount + 1; + // int batchCount = 2; // for testing + for (int i = 0; i < batchCount; i++) { + long begin = System.currentTimeMillis(); + + int start = lastSourceNumber + i * batchSize + 1; + int end = lastSourceNumber + (i + 1) * batchSize; + if (end >= (lastSourceNumber + countToRetrieve + 1)) + end = lastSourceNumber + countToRetrieve; + Message[] sourceMessages = sourceFolder.getMessages(start, end); + sourceFolder.fetch(sourceMessages, fetchProfile); + // targetFolder.appendMessages(sourceMessages); + // sourceFolder.copyMessages(sourceMessages,targetFolder); + + copyMessages(sourceMessages, targetFolder); +// copyMessagesToMbox(sourceMessages, targetFolder); + + String describeLast = describe(sourceMessages[sourceMessages.length - 1]); + +// if (i % 10 == 9) { + // free memory from fetched messages + sourceFolder.close(); + targetFolder.close(); + + sourceFolder.open(Folder.READ_ONLY); + targetFolder.open(Folder.READ_WRITE); +// logger.log(DEBUG, "Open/close folder in order to free memory"); +// } + + long duration = System.currentTimeMillis() - begin; + logger.log(DEBUG, folderName + " - batch " + i + " took " + (duration / 1000) + " s, " + + (duration / (end - start + 1)) + " ms per message. Last message " + describeLast); + } + + return targetFolder; + } + + protected Folder openMboxTargetFolder(Folder sourceFolder, Path baseDir) throws MessagingException, IOException { + String folderName = sourceFolder.getName(); + if (sourceFolder.getName().equals(EmailUtils.INBOX_UPPER_CASE)) + folderName = EmailUtils.INBOX;// Inbox + + Path targetDir = baseDir;// .resolve("mbox"); + Files.createDirectories(targetDir); + Path targetPath; + if (((sourceFolder.getType() & Folder.HOLDS_FOLDERS) != 0) && sourceFolder.list().length != 0) { + Path dir = targetDir.resolve(folderName); + Files.createDirectories(dir); + targetPath = dir.resolve("_Misc"); + } else { + targetPath = targetDir.resolve(folderName); + } + if (!Files.exists(targetPath)) + Files.createFile(targetPath); + URLName targetUrlName = new URLName("mbox:" + targetPath.toString()); + Properties targetProperties = new Properties(); + // targetProperties.setProperty("mail.mime.address.strict", "false"); + Session targetSession = Session.getDefaultInstance(targetProperties); + Folder targetFolder = targetSession.getFolder(targetUrlName); + targetFolder.open(Folder.READ_WRITE); + + return targetFolder; + } + + protected void copyMessages(Message[] sourceMessages, Folder targetFolder) throws MessagingException { + targetFolder.appendMessages(sourceMessages); + } + + protected void copyMessagesToMbox(Message[] sourceMessages, Folder targetFolder) + throws MessagingException, IOException { + Message[] targetMessages = new Message[sourceMessages.length]; + for (int j = 0; j < sourceMessages.length; j++) { + MimeMessage sourceMm = (MimeMessage) sourceMessages[j]; + InternetHeaders ih = new InternetHeaders(); + for (Enumeration e = sourceMm.getAllHeaderLines(); e.hasMoreElements();) { + ih.addHeaderLine(e.nextElement()); + } + Path tmpFileSource = Files.createTempFile("argeo-mbox-source", ".txt"); + Path tmpFileTarget = Files.createTempFile("argeo-mbox-target", ".txt"); + Files.copy(sourceMm.getRawInputStream(), tmpFileSource, StandardCopyOption.REPLACE_EXISTING); + + // we use ISO_8859_1 because it is more robust than US_ASCII with regard to + // missing characters + try (BufferedReader reader = Files.newBufferedReader(tmpFileSource, StandardCharsets.ISO_8859_1); + BufferedWriter writer = Files.newBufferedWriter(tmpFileTarget, StandardCharsets.ISO_8859_1);) { + int lineNumber = 0; + String line = null; + try { + while ((line = reader.readLine()) != null) { + lineNumber++; + if (line.startsWith("From ")) { + writer.write(">" + line); + logger.log(DEBUG, + "Fix line " + lineNumber + " in " + EmailUtils.describe(sourceMm) + ": " + line); + } else { + writer.write(line); + } + writer.newLine(); + } + } catch (IOException e) { + logger.log(ERROR, "Error around line " + lineNumber + " of " + tmpFileSource); + throw e; + } + } + + MboxMessage mboxMessage = new MboxMessage((MboxFolder) targetFolder, ih, + new SharedFileInputStream(tmpFileTarget.toFile()), sourceMm.getMessageNumber(), + EmailUtils.getUnixFrom(sourceMm), true); + targetMessages[j] = mboxMessage; + + // clean up + Files.delete(tmpFileSource); + Files.delete(tmpFileTarget); + } + targetFolder.appendMessages(targetMessages); + + } + + /** Save body parts and attachments as plain files. */ + protected void savePartsAsFiles(Object content, Path fileBase) throws IOException, MessagingException { + OutputStream out = null; + InputStream in = null; + try { + if (content instanceof Multipart) { + Multipart multi = ((Multipart) content); + int parts = multi.getCount(); + for (int j = 0; j < parts; ++j) { + MimeBodyPart part = (MimeBodyPart) multi.getBodyPart(j); + if (part.getContent() instanceof Multipart) { + // part-within-a-part, do some recursion... + savePartsAsFiles(part.getContent(), fileBase); + } else { + String extension = ""; + if (part.isMimeType("text/html")) { + extension = "html"; + } else { + if (part.isMimeType("text/plain")) { + extension = "txt"; + } else { + // Try to get the name of the attachment + extension = part.getDataHandler().getName(); + } + } + String filename = fileBase + "." + extension; + System.out.println("... " + filename); + out = new FileOutputStream(new File(filename)); + in = part.getInputStream(); + int k; + while ((k = in.read()) != -1) { + out.write(k); + } + } + } + } + } finally { + if (in != null) { + in.close(); + } + if (out != null) { + out.flush(); + out.close(); + } + } + } + + public void setSourceServer(String sourceServer) { + this.sourceServer = sourceServer; + } + + public void setSourceUsername(String sourceUsername) { + this.sourceUsername = sourceUsername; + } + + public void setSourcePassword(String sourcePassword) { + this.sourcePassword = sourcePassword; + } + + public void setTargetServer(String targetServer) { + this.targetServer = targetServer; + } + + public void setTargetUsername(String targetUsername) { + this.targetUsername = targetUsername; + } + + public void setTargetPassword(String targetPassword) { + this.targetPassword = targetPassword; + } + + public static void main(String args[]) throws Exception { + if (args.length < 6) + throw new IllegalArgumentException( + "usage: "); + String sourceServer = args[0]; + String sourceUsername = args[1]; + String sourcePassword = args[2]; + String targetServer = args[3]; + String targetUsername = args[4]; + String targetPassword = args[5]; + + EmailMigration emailMigration = new EmailMigration(); + emailMigration.setSourceServer(sourceServer); + emailMigration.setSourceUsername(sourceUsername); + emailMigration.setSourcePassword(sourcePassword); + emailMigration.setTargetServer(targetServer); + emailMigration.setTargetUsername(targetUsername); + emailMigration.setTargetPassword(targetPassword); + + emailMigration.process(); + } +} diff --git a/org.argeo.app.core/src/org/argeo/app/mail/EmailUtils.java b/org.argeo.app.core/src/org/argeo/app/mail/EmailUtils.java new file mode 100644 index 0000000..694c17c --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/mail/EmailUtils.java @@ -0,0 +1,118 @@ +package org.argeo.app.mail; + +import java.util.Date; + +import javax.mail.Address; +import javax.mail.Flags; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; + +/** Utilities around emails. */ +public class EmailUtils { + public final static String INBOX = "Inbox"; + public final static String INBOX_UPPER_CASE = "INBOX"; + public final static String MESSAGE_ID = "Message-ID"; + + public static String getMessageId(Message msg) { + try { + return msg instanceof MimeMessage ? ((MimeMessage) msg).getMessageID() : ""; + } catch (MessagingException e) { + throw new IllegalStateException("Cannot extract message id from " + msg, e); + } + } + + public static String describe(Message msg) { + try { + return "Message " + msg.getMessageNumber() + " " + msg.getSentDate().toInstant() + " " + getMessageId(msg); + } catch (MessagingException e) { + throw new IllegalStateException("Cannot describe " + msg, e); + } + } + + static void setHeadersFromFlags(MimeMessage msg, Flags flags) { + try { + StringBuilder status = new StringBuilder(); + if (flags.contains(Flags.Flag.SEEN)) + status.append('R'); + if (!flags.contains(Flags.Flag.RECENT)) + status.append('O'); + if (status.length() > 0) + msg.setHeader("Status", status.toString()); + else + msg.removeHeader("Status"); + + boolean sims = false; + String s = msg.getHeader("X-Status", null); + // is it a SIMS 2.0 format X-Status header? + sims = s != null && s.length() == 4 && s.indexOf('$') >= 0; + //status.setLength(0); + if (flags.contains(Flags.Flag.DELETED)) + status.append('D'); + else if (sims) + status.append('$'); + if (flags.contains(Flags.Flag.FLAGGED)) + status.append('F'); + else if (sims) + status.append('$'); + if (flags.contains(Flags.Flag.ANSWERED)) + status.append('A'); + else if (sims) + status.append('$'); + if (flags.contains(Flags.Flag.DRAFT)) + status.append('T'); + else if (sims) + status.append('$'); + if (status.length() > 0) + msg.setHeader("X-Status", status.toString()); + else + msg.removeHeader("X-Status"); + + String[] userFlags = flags.getUserFlags(); + if (userFlags.length > 0) { + status.setLength(0); + for (int i = 0; i < userFlags.length; i++) + status.append(userFlags[i]).append(' '); + status.setLength(status.length() - 1); // smash trailing space + msg.setHeader("X-Keywords", status.toString()); + } + if (flags.contains(Flags.Flag.DELETED)) { + s = msg.getHeader("X-Dt-Delete-Time", null); + if (s == null) + // XXX - should be time + msg.setHeader("X-Dt-Delete-Time", "1"); + } + } catch (MessagingException e) { + // ignore it + } + } + + protected static String getUnixFrom(MimeMessage msg) { + Address[] afrom; + String from; + Date ddate; + String date; + try { + if ((afrom = msg.getFrom()) == null || + !(afrom[0] instanceof InternetAddress) || + (from = ((InternetAddress)afrom[0]).getAddress()) == null) + from = "UNKNOWN"; + if ((ddate = msg.getReceivedDate()) == null || + (ddate = msg.getSentDate()) == null) + ddate = new Date(); + } catch (MessagingException e) { + from = "UNKNOWN"; + ddate = new Date(); + } + date = ddate.toString(); + // date is of the form "Sat Aug 12 02:30:00 PDT 1995" + // need to strip out the timezone + return "From " + from + " " + + date.substring(0, 20) + date.substring(24); + } + + /** Singleton. */ + private EmailUtils() { + } +} diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OdkUtils.java b/org.argeo.app.core/src/org/argeo/app/odk/OdkUtils.java index ddb5650..4d2f521 100644 --- a/org.argeo.app.core/src/org/argeo/app/odk/OdkUtils.java +++ b/org.argeo.app.core/src/org/argeo/app/odk/OdkUtils.java @@ -18,10 +18,10 @@ import javax.jcr.nodetype.NodeType; import org.argeo.api.cms.CmsLog; import org.argeo.app.api.EntityMimeType; import org.argeo.app.api.EntityType; +import org.argeo.cms.util.DigestUtils; import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrUtils; import org.argeo.jcr.JcrxApi; -import org.argeo.util.DigestUtils; /** Utilities around ODK. */ public class OdkUtils { diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OrxListName.java b/org.argeo.app.core/src/org/argeo/app/odk/OrxListName.java index ec9b699..3c432ad 100644 --- a/org.argeo.app.core/src/org/argeo/app/odk/OrxListName.java +++ b/org.argeo.app.core/src/org/argeo/app/odk/OrxListName.java @@ -1,28 +1,20 @@ package org.argeo.app.odk; -import org.argeo.app.api.JcrName; +import org.argeo.api.acr.QNamed; /** Types related to the http://openrosa.org/xforms/xformsList namespace. */ -public enum OrxListName implements JcrName { +public enum OrxListName implements QNamed { xform, // names formID, version; @Override - public String getPrefix() { - return prefix(); - } - - public static String prefix() { + public String getDefaultPrefix() { return "orxList"; } @Override public String getNamespace() { - return namespace(); - } - - public static String namespace() { return "http://openrosa.org/xforms/xformsList"; } diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OrxManifestName.java b/org.argeo.app.core/src/org/argeo/app/odk/OrxManifestName.java index 5c93c41..2b68b90 100644 --- a/org.argeo.app.core/src/org/argeo/app/odk/OrxManifestName.java +++ b/org.argeo.app.core/src/org/argeo/app/odk/OrxManifestName.java @@ -1,26 +1,18 @@ package org.argeo.app.odk; -import org.argeo.app.api.JcrName; +import org.argeo.api.acr.QNamed; /** Types related to the http://openrosa.org/xforms/xformsList namespace. */ -public enum OrxManifestName implements JcrName { +public enum OrxManifestName implements QNamed { manifest, mediaFile; @Override - public String getPrefix() { - return prefix(); - } - - public static String prefix() { + public String getDefaultPrefix() { return "orxManifest"; } @Override public String getNamespace() { - return namespace(); - } - - public static String namespace() { return "http://openrosa.org/xforms/xformsManifest"; } diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OrxType.java b/org.argeo.app.core/src/org/argeo/app/odk/OrxType.java index cf88eb9..77ae7ae 100644 --- a/org.argeo.app.core/src/org/argeo/app/odk/OrxType.java +++ b/org.argeo.app.core/src/org/argeo/app/odk/OrxType.java @@ -1,26 +1,18 @@ package org.argeo.app.odk; -import org.argeo.app.api.JcrName; +import org.argeo.api.acr.QNamed; /** Types related to the http://openrosa.org/xforms/xformsList namespace. */ -public enum OrxType implements JcrName { +public enum OrxType implements QNamed { submission, xml_submission_file; @Override - public String getPrefix() { - return prefix(); - } - - public static String prefix() { + public String getDefaultPrefix() { return "orx"; } @Override public String getNamespace() { - return namespace(); - } - - public static String namespace() { return "http://openrosa.org/xforms"; } diff --git a/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java b/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java index 7122892..0dff64c 100644 --- a/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java +++ b/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java @@ -5,6 +5,9 @@ import javax.jcr.RepositoryException; /** Called when a user has received a new form submission. */ public interface FormSubmissionListener { - /** Called after a form submission has been stored in the user area. */ + /** + * Called after a form submission has been stored in the user area. The + * submission will be deleted if any exception is thrown. + */ void formSubmissionReceived(Node node) throws RepositoryException; } diff --git a/org.argeo.app.profile.acr.fs/.classpath b/org.argeo.app.profile.acr.fs/.classpath new file mode 100644 index 0000000..81fe078 --- /dev/null +++ b/org.argeo.app.profile.acr.fs/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.app.profile.acr.fs/.project b/org.argeo.app.profile.acr.fs/.project new file mode 100644 index 0000000..bc3f767 --- /dev/null +++ b/org.argeo.app.profile.acr.fs/.project @@ -0,0 +1,33 @@ + + + org.argeo.app.profile.acr.fs + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.app.profile.acr.fs/OSGI-INF/srvContentProvider.xml b/org.argeo.app.profile.acr.fs/OSGI-INF/srvContentProvider.xml new file mode 100644 index 0000000..debf19c --- /dev/null +++ b/org.argeo.app.profile.acr.fs/OSGI-INF/srvContentProvider.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/org.argeo.app.profile.acr.fs/OSGI-INF/sysContentProvider.xml b/org.argeo.app.profile.acr.fs/OSGI-INF/sysContentProvider.xml new file mode 100644 index 0000000..0cbc7f0 --- /dev/null +++ b/org.argeo.app.profile.acr.fs/OSGI-INF/sysContentProvider.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.argeo.app.profile.acr.fs/bnd.bnd b/org.argeo.app.profile.acr.fs/bnd.bnd new file mode 100644 index 0000000..f976da0 --- /dev/null +++ b/org.argeo.app.profile.acr.fs/bnd.bnd @@ -0,0 +1,8 @@ +Import-Package: \ +org.argeo.cms.acr.fs,\ +org.argeo.cms.jcr.acr,\ +* + +Service-Component:\ +OSGI-INF/sysContentProvider.xml,\ +OSGI-INF/srvContentProvider.xml,\ diff --git a/org.argeo.app.profile.acr.fs/build.properties b/org.argeo.app.profile.acr.fs/build.properties new file mode 100644 index 0000000..c58ea21 --- /dev/null +++ b/org.argeo.app.profile.acr.fs/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + OSGI-INF/ diff --git a/org.argeo.app.profile.acr.fs/src/.gitignore b/org.argeo.app.profile.acr.fs/src/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/org.argeo.app.profile.acr.jcr/.classpath b/org.argeo.app.profile.acr.jcr/.classpath new file mode 100644 index 0000000..81fe078 --- /dev/null +++ b/org.argeo.app.profile.acr.jcr/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.app.profile.acr.jcr/.project b/org.argeo.app.profile.acr.jcr/.project new file mode 100644 index 0000000..632c90e --- /dev/null +++ b/org.argeo.app.profile.acr.jcr/.project @@ -0,0 +1,33 @@ + + + org.argeo.app.profile.acr.jcr + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.app.profile.acr.jcr/OSGI-INF/srvContentProvider.xml b/org.argeo.app.profile.acr.jcr/OSGI-INF/srvContentProvider.xml new file mode 100644 index 0000000..704fec7 --- /dev/null +++ b/org.argeo.app.profile.acr.jcr/OSGI-INF/srvContentProvider.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.argeo.app.profile.acr.jcr/OSGI-INF/sysContentProvider.xml b/org.argeo.app.profile.acr.jcr/OSGI-INF/sysContentProvider.xml new file mode 100644 index 0000000..0cbc7f0 --- /dev/null +++ b/org.argeo.app.profile.acr.jcr/OSGI-INF/sysContentProvider.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.argeo.app.profile.acr.jcr/bnd.bnd b/org.argeo.app.profile.acr.jcr/bnd.bnd new file mode 100644 index 0000000..625b5f4 --- /dev/null +++ b/org.argeo.app.profile.acr.jcr/bnd.bnd @@ -0,0 +1,7 @@ +Import-Package: \ +org.argeo.cms.jcr.acr,\ +* + +Service-Component:\ +OSGI-INF/sysContentProvider.xml,\ +OSGI-INF/srvContentProvider.xml,\ diff --git a/org.argeo.app.profile.acr.jcr/build.properties b/org.argeo.app.profile.acr.jcr/build.properties new file mode 100644 index 0000000..c58ea21 --- /dev/null +++ b/org.argeo.app.profile.acr.jcr/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + OSGI-INF/ diff --git a/org.argeo.app.profile.acr.jcr/src/.gitignore b/org.argeo.app.profile.acr.jcr/src/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/org.argeo.app.servlet.odk/.classpath b/org.argeo.app.servlet.odk/.classpath index e801ebf..81fe078 100644 --- a/org.argeo.app.servlet.odk/.classpath +++ b/org.argeo.app.servlet.odk/.classpath @@ -1,6 +1,6 @@ - + diff --git a/org.argeo.app.servlet.odk/OSGI-INF/odkFormListServlet.xml b/org.argeo.app.servlet.odk/OSGI-INF/odkFormListServlet.xml index 18f3465..3430eda 100644 --- a/org.argeo.app.servlet.odk/OSGI-INF/odkFormListServlet.xml +++ b/org.argeo.app.servlet.odk/OSGI-INF/odkFormListServlet.xml @@ -6,6 +6,5 @@ - - + diff --git a/org.argeo.app.servlet.odk/OSGI-INF/odkFormServlet.xml b/org.argeo.app.servlet.odk/OSGI-INF/odkFormServlet.xml index 816524a..82ed712 100644 --- a/org.argeo.app.servlet.odk/OSGI-INF/odkFormServlet.xml +++ b/org.argeo.app.servlet.odk/OSGI-INF/odkFormServlet.xml @@ -6,6 +6,5 @@ - - + diff --git a/org.argeo.app.servlet.odk/OSGI-INF/odkManifestServlet.xml b/org.argeo.app.servlet.odk/OSGI-INF/odkManifestServlet.xml index 503a148..6cac13e 100644 --- a/org.argeo.app.servlet.odk/OSGI-INF/odkManifestServlet.xml +++ b/org.argeo.app.servlet.odk/OSGI-INF/odkManifestServlet.xml @@ -6,5 +6,5 @@ - + diff --git a/org.argeo.app.servlet.odk/OSGI-INF/odkSubmissionServlet.xml b/org.argeo.app.servlet.odk/OSGI-INF/odkSubmissionServlet.xml index b9380d5..40ed568 100644 --- a/org.argeo.app.servlet.odk/OSGI-INF/odkSubmissionServlet.xml +++ b/org.argeo.app.servlet.odk/OSGI-INF/odkSubmissionServlet.xml @@ -7,6 +7,6 @@ - + diff --git a/org.argeo.app.servlet.odk/bnd.bnd b/org.argeo.app.servlet.odk/bnd.bnd index f5cd217..a32d5d3 100644 --- a/org.argeo.app.servlet.odk/bnd.bnd +++ b/org.argeo.app.servlet.odk/bnd.bnd @@ -14,4 +14,5 @@ Import-Package:\ org.osgi.service.http.context,\ javax.jcr.nodetype,\ javax.servlet.*;version="[3,5)",\ +org.argeo.api.acr,\ * diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormListServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormListServlet.java index 21b3421..41a3039 100644 --- a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormListServlet.java +++ b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormListServlet.java @@ -23,6 +23,7 @@ import org.argeo.app.odk.OrxListName; import org.argeo.app.odk.OrxManifestName; import org.argeo.cms.auth.RemoteAuthUtils; import org.argeo.cms.servlet.ServletHttpRequest; +import org.argeo.cms.servlet.ServletUtils; import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrxApi; @@ -39,9 +40,17 @@ public class OdkFormListServlet extends HttpServlet { resp.setHeader("X-OpenRosa-Version", "1.0"); resp.setDateHeader("Date", System.currentTimeMillis()); - String serverName = req.getServerName(); - int serverPort = req.getServerPort(); - String protocol = serverPort == 443 || req.isSecure() ? "https" : "http"; +//// String serverName = req.getServerName(); +//// int serverPort = req.getServerPort(); +//// String protocol = serverPort == 443 || req.isSecure() ? "https" : "http"; +//// String baseServer = protocol + "://" + serverName +//// + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort); +// String requestUri=req.getRequestURI(); +// String forwardedHost = req.getHeader("X-Forwarded-Host"); +// URL requestUrl = new URL(req.getRequestURL().toString()); +// String baseServer = requestUrl.getProtocol() + "://" + requestUrl.getHost() +// + (requestUrl.getPort() > 0 ? ":" + requestUrl.getPort() : ""); + StringBuilder baseServer = ServletUtils.getRequestUrlBase(req); String pathInfo = req.getPathInfo(); @@ -77,23 +86,17 @@ public class OdkFormListServlet extends HttpServlet { sb.append("md5:" + JcrxApi.getChecksum(node, JcrxApi.MD5) + ""); if (node.hasProperty(Property.JCR_DESCRIPTION)) sb.append("" + node.getProperty(Property.JCR_DESCRIPTION).getString() + ""); - sb.append("" + protocol + "://" + serverName - + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/form" - + node.getPath() + ""); + sb.append("" + baseServer + "/api/odk/form" + node.getPath() + ""); if (node.hasNode(OrxManifestName.manifest.name())) { - sb.append("" + protocol + "://" + serverName - + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) - + "/api/odk/formManifest" + node.getNode(OrxManifestName.manifest.name()).getPath() - + ""); + sb.append("" + baseServer + "/api/odk/formManifest" + + node.getNode(OrxManifestName.manifest.name()).getPath() + ""); } sb.append(""); } else if (node.isNodeType(EntityType.formSet.get())) { sb.append(""); sb.append("" + node.getPath() + ""); sb.append("" + node.getProperty(Property.JCR_TITLE).getString() + ""); - sb.append("" + protocol + "://" + serverName - + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/formList" - + node.getPath() + ""); + sb.append("" + baseServer + "/api/odk/formList" + node.getPath() + ""); sb.append(""); } String str = sb.toString(); diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java index f296170..2c62ba1 100644 --- a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java +++ b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java @@ -33,10 +33,11 @@ import org.argeo.app.api.EntityMimeType; import org.argeo.app.odk.OrxManifestName; import org.argeo.cms.auth.RemoteAuthUtils; import org.argeo.cms.servlet.ServletHttpRequest; +import org.argeo.cms.servlet.ServletUtils; +import org.argeo.cms.util.CsvWriter; +import org.argeo.cms.util.DigestUtils; import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrException; -import org.argeo.util.CsvWriter; -import org.argeo.util.DigestUtils; /** Describe additional files. */ public class OdkManifestServlet extends HttpServlet { @@ -53,9 +54,12 @@ public class OdkManifestServlet extends HttpServlet { if (pathInfo.startsWith("//")) pathInfo = pathInfo.substring(1); - String serverName = req.getServerName(); - int serverPort = req.getServerPort(); - String protocol = serverPort == 443 || req.isSecure() ? "https" : "http"; +// String serverName = req.getServerName(); +// int serverPort = req.getServerPort(); +// String protocol = serverPort == 443 || req.isSecure() ? "https" : "http"; +// String baseServer = protocol + "://" + serverName +// + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort); + StringBuilder baseServer = ServletUtils.getRequestUrlBase(req); Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req)); @@ -98,9 +102,8 @@ public class OdkManifestServlet extends HttpServlet { writer.append("md5sum:" + DigestUtils.toHexString(out.getMessageDigest().digest())); writer.append(""); } - writer.append("" + protocol + "://" + serverName - + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) - + "/api/odk/formManifest" + file.getPath() + ""); + writer.append("" + baseServer + "/api/odk/formManifest" + file.getPath() + + ""); } writer.append(""); } diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkServletContext.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkServletContext.java index 4e2d535..9406145 100644 --- a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkServletContext.java +++ b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkServletContext.java @@ -1,18 +1,17 @@ package org.argeo.app.servlet.odk; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - +import org.argeo.cms.auth.RemoteAuthRequest; +import org.argeo.cms.auth.RemoteAuthResponse; import org.argeo.cms.servlet.PrivateWwwAuthServletContext; -/** ODK specific authentication (with additional headers).*/ +/** ODK specific authentication (with additional headers). */ public class OdkServletContext extends PrivateWwwAuthServletContext { @Override - protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) { - super.askForWwwAuth(request, response); - response.setHeader("X-OpenRosa-Version", "1.0"); - response.setDateHeader("Date", System.currentTimeMillis()); + protected boolean authIsRequired(RemoteAuthRequest remoteAuthRequest, RemoteAuthResponse remoteAuthResponse) { + remoteAuthResponse.setHeader("X-OpenRosa-Version", "1.0"); + remoteAuthResponse.setHeader("Date", Long.toString(System.currentTimeMillis())); + return true; } diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java index a5864d8..8dd8b0b 100644 --- a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java +++ b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java @@ -14,7 +14,6 @@ import javax.jcr.ImportUUIDBehavior; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.Repository; -import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.nodetype.NodeType; import javax.servlet.ServletException; @@ -60,24 +59,24 @@ public class OdkSubmissionServlet extends HttpServlet { RemoteAuthRequest request = new ServletHttpRequest(req); Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), request); - try { - CmsSession cmsSession = RemoteAuthUtils.getCmsSession(request); + CmsSession cmsSession = RemoteAuthUtils.getCmsSession(request); - Session adminSession = null; - try { - // TODO centralise at a deeper level - adminSession = CmsJcrUtils.openDataAdminSession(repository, null); - SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession); - } finally { - Jcr.logout(adminSession); - } + Session adminSession = null; + try { + // TODO centralise at a deeper level + adminSession = CmsJcrUtils.openDataAdminSession(repository, null); + SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession); + } finally { + Jcr.logout(adminSession); + } + try { Node cmsSessionNode = SuiteUtils.getCmsSessionNode(session, cmsSession); Node submission = cmsSessionNode.addNode(submissionNameFormatter.format(Instant.now()), OrxType.submission.get()); for (Part part : req.getParts()) { - if (log.isDebugEnabled()) - log.debug("Part: " + part.getName() + ", " + part.getContentType()); + if (log.isTraceEnabled()) + log.trace("Part: " + part.getName() + ", " + part.getContentType()); if (part.getName().equals(XML_SUBMISSION_FILE)) { Node xml = submission.addNode(XML_SUBMISSION_FILE, NodeType.NT_UNSTRUCTURED); @@ -112,12 +111,22 @@ public class OdkSubmissionServlet extends HttpServlet { } } } + session.save(); - for (FormSubmissionListener submissionListener : submissionListeners) { - submissionListener.formSubmissionReceived(submission); + try { + for (FormSubmissionListener submissionListener : submissionListeners) { + submissionListener.formSubmissionReceived(submission); + } + } catch (Exception e) { + log.error("Cannot save submision, cancelling...", e); + submission.remove(); + session.save(); + resp.setStatus(503); + return; } - } catch (RepositoryException e) { - e.printStackTrace(); + + } catch (Exception e) { + log.error("Cannot save submision", e); resp.setStatus(503); return; } finally { diff --git a/org.argeo.app.servlet.publish/.classpath b/org.argeo.app.servlet.publish/.classpath index e801ebf..81fe078 100644 --- a/org.argeo.app.servlet.publish/.classpath +++ b/org.argeo.app.servlet.publish/.classpath @@ -1,6 +1,6 @@ - + diff --git a/org.argeo.app.servlet.publish/bnd.bnd b/org.argeo.app.servlet.publish/bnd.bnd index 60f0d37..5535251 100644 --- a/org.argeo.app.servlet.publish/bnd.bnd +++ b/org.argeo.app.servlet.publish/bnd.bnd @@ -1,13 +1,11 @@ Import-Package:\ +org.apache.xmlgraphics.image.loader,\ org.osgi.service.http.context,\ javax.jcr.nodetype,\ -org.osgi.service.event,\ -org.eclipse.swt,\ -org.eclipse.jface.viewers,\ org.osgi.framework,\ org.apache.xml.serializer,\ -org.eclipse.rap.rwt,\ org.argeo.app.api,\ +org.argeo.cms.acr.xml,\ javax.servlet.*;version="[3,5)",\ * diff --git a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/DbkServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/DbkServlet.java index b84905c..f2d38e1 100644 --- a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/DbkServlet.java +++ b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/DbkServlet.java @@ -1,9 +1,14 @@ package org.argeo.app.servlet.publish; +import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -30,12 +35,16 @@ import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.IOUtils; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; import org.apache.xalan.processor.TransformerFactoryImpl; -import org.argeo.api.cms.CmsTheme; +import org.argeo.api.cms.CmsLog; +import org.argeo.api.cms.ux.CmsTheme; import org.argeo.app.docbook.DbkType; import org.argeo.app.docbook.DbkUtils; import org.argeo.cms.auth.RemoteAuthUtils; @@ -51,14 +60,21 @@ import org.w3c.dom.Document; public class DbkServlet extends HttpServlet { private static final long serialVersionUID = 6906020513498289335L; + private CmsLog log = CmsLog.getLog(DbkServlet.class); + private Repository repository; private DocumentBuilderFactory documentBuilderFactory; private TransformerFactory transformerFactory; - private Templates docBoookTemplates; + private Templates docBoookHtmlTemplates; + + // FOP + private Templates docBoookFoTemplates; private Map themes = Collections.synchronizedMap(new HashMap<>()); + private String xslBase; + @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -84,6 +100,14 @@ public class DbkServlet extends HttpServlet { path = path.substring(0, path.length() - "/index.html".length()); } + boolean pdf = false; + if (path.toLowerCase().endsWith(".pdf")) { + pdf = true; + if (path.toLowerCase().endsWith("/index.pdf")) { + path = path.substring(0, path.length() - "/index.pdf".length()); + } + } + Session session = null; try { session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req)); @@ -109,42 +133,68 @@ public class DbkServlet extends HttpServlet { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { session.exportDocumentView(dbkNode.getPath(), out, true, false); arr = out.toByteArray(); -// System.out.println(new String(arr, StandardCharsets.UTF_8)); } catch (RepositoryException e) { throw new JcrException(e); } - try (InputStream in = new ByteArrayInputStream(arr); -// ByteArrayOutputStream out = new ByteArrayOutputStream(); - ) { - - Result xmlOutput = new StreamResult(resp.getOutputStream()); + try (InputStream in = new ByteArrayInputStream(arr);) { DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder(); -// Document doc = docBuilder.parse(new File( -// System.getProperty("user.home") + "/dev/git/gpl/argeo-qa/doc/platform/argeo-platform.dbk.xml")); Document doc = docBuilder.parse(in); Source xmlInput = new DOMSource(doc); - Transformer transformer = docBoookTemplates.newTransformer(); + if (pdf) { + // String baseUri = req.getRequestURI(); + FopFactory fopFactory = FopFactory.newInstance(URI.create(req.getRequestURL().toString())); + resp.setContentType("application/pdf"); + +// // DocBook to FO +// byte[] foBytes; +// try (ByteArrayOutputStream out = new ByteArrayOutputStream();) { +// Result xmlOutput = new StreamResult(out); +// Transformer docBookTransformer = docBoookFoTemplates.newTransformer(); +// docBookTransformer.transform(xmlInput, xmlOutput); +// foBytes = out.toByteArray(); +// } +// +// // FO to PDF +// try (InputStream foIn = new ByteArrayInputStream(foBytes)) { +// Fop fop = fopFactory.newFop("application/pdf", resp.getOutputStream()); +// Transformer fopTransformer = transformerFactory.newTransformer(); // identity +// Source src = new StreamSource(foIn); +// Result fopResult = new SAXResult(fop.getDefaultHandler()); +// fopTransformer.transform(src, fopResult); +// } +// - // gather CSS - if (cmsTheme != null) { - StringBuilder sb = new StringBuilder(); - for (String cssPath : cmsTheme.getWebCssPaths()) { - sb.append(req.getContextPath()).append(req.getServletPath()).append('/'); - sb.append(themeId).append('/').append(cssPath).append(' '); + Fop fop = fopFactory.newFop("application/pdf", resp.getOutputStream()); + Transformer docBookTransformer = getDocBoookFoTemplates().newTransformer(); + Result fopResult = new SAXResult(fop.getDefaultHandler()); + docBookTransformer.transform(xmlInput, fopResult); + + } else { + Result xmlOutput = new StreamResult(resp.getOutputStream()); + resp.setContentType("text/html"); + Transformer docBookTransformer = getDocBoookHtmlTemplates().newTransformer(); + + // gather CSS + if (cmsTheme != null) { + StringBuilder sb = new StringBuilder(); + for (String cssPath : cmsTheme.getWebCssPaths()) { + sb.append(req.getContextPath()).append(req.getServletPath()).append('/'); + sb.append(themeId).append('/').append(cssPath).append(' '); + } + // FIXME make it more generic + sb.append("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap") + .append(' '); + sb.append( + "https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,600;1,400&display=swap") + .append(' '); + if (sb.length() > 0) + docBookTransformer.setParameter("html.stylesheet", sb.toString()); } - // FIXME make it more generic - sb.append("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap") - .append(' '); - sb.append( - "https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,600;1,400&display=swap") - .append(' '); - if (sb.length() > 0) - transformer.setParameter("html.stylesheet", sb.toString()); + docBookTransformer.transform(xmlInput, xmlOutput); } - transformer.transform(xmlInput, xmlOutput); // resp.getOutputStream().write(out.toByteArray()); } catch (Exception e) { throw new ServletException("Cannot transform " + path, e); @@ -181,39 +231,60 @@ public class DbkServlet extends HttpServlet { public void init() throws ServletException { // TODO improve configuration and provisioning of DocBook XSL - String xslBase = System.getProperty("argeo.docbook.xsl"); + xslBase = System.getProperty("argeo.docbook.xsl"); if (xslBase == null) { // We need namespace aware XSL! // Fedora (sudo dnf install docbook5-style-xsl) - String defaultXslBase = "/usr/share/sgml/docbook/xsl-ns-stylesheets"; + String defaultXslBase = "/usr/share/xml/docbook/stylesheet/docbook-xsl-ns/"; if (!Files.exists(Paths.get(defaultXslBase))) { defaultXslBase = "/opt/docbook-xsl"; if (!Files.exists(Paths.get(defaultXslBase))) { - throw new ServletException("System property argeo.docbook.xsl is not set and default location " - + defaultXslBase + " does not exist."); + log.error("System property argeo.docbook.xsl is not set and default location " + defaultXslBase + + " does not exist."); } } xslBase = defaultXslBase; } - String xsl = xslBase + "/html/docbook.xsl"; documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setXIncludeAware(true); documentBuilderFactory.setNamespaceAware(true); - // We must explicitly use the non-XSLTC transformer, as XSLTC is not working - // with DocBook stylesheets - transformerFactory = new TransformerFactoryImpl(); + } - Source xslSource = new StreamSource(xsl); + protected Templates createDocBookTemplates(String xsl) { try { - docBoookTemplates = transformerFactory.newTemplates(xslSource); - if (docBoookTemplates == null) - throw new ServletException("Could not instantiate XSL " + xsl); + if (transformerFactory == null) { + // We must explicitly use the non-XSLTC transformer, as XSLTC is not working + // with DocBook stylesheets + transformerFactory = new TransformerFactoryImpl(); + } + Source xslSource = new StreamSource(xsl); + Templates templates = transformerFactory.newTemplates(xslSource); + if (templates == null) + throw new IllegalStateException("Could not instantiate XSL " + xsl); + return templates; } catch (TransformerConfigurationException e) { - throw new ServletException("Cannot instantiate XSL " + xsl, e); + throw new IllegalStateException("Cannot instantiate XSL " + xsl, e); + } + + } + + protected Templates getDocBoookHtmlTemplates() { + if (docBoookHtmlTemplates == null) { + String htmlXsl = xslBase + "/html/docbook.xsl"; + docBoookHtmlTemplates = createDocBookTemplates(htmlXsl); + } + return docBoookHtmlTemplates; + } + + protected Templates getDocBoookFoTemplates() { + if (docBoookFoTemplates == null) { + String foXsl = xslBase + "/fo/docbook.xsl"; + docBoookFoTemplates = createDocBookTemplates(foXsl); } + return docBoookFoTemplates; } public void setRepository(Repository repository) { @@ -228,4 +299,40 @@ public class DbkServlet extends HttpServlet { themes.remove(theme.getThemeId()); } + public static void main(String[] args) throws Exception { + // Step 1: Construct a FopFactory by specifying a reference to the configuration + // file + // (reuse if you plan to render multiple documents!) + FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); + + // Step 2: Set up output stream. + // Note: Using BufferedOutputStream for performance reasons (helpful with + // FileOutputStreams). + OutputStream out = new BufferedOutputStream(new FileOutputStream(new File( + System.getProperty("user.home") + "/dev/git/unstable/argeo-qa/doc/platform/argeo-platform-test.pdf"))); + + try { + // Step 3: Construct fop with desired output format + Fop fop = fopFactory.newFop("application/pdf", out); + + // Step 4: Setup JAXP using identity transformer + TransformerFactory fopTransformerFactory = TransformerFactory.newInstance(); + Transformer fopTransformer = fopTransformerFactory.newTransformer(); // identity transformer + + // Step 5: Setup input and output for XSLT transformation + // Setup input stream + Source src = new StreamSource(new File( + System.getProperty("user.home") + "/dev/git/unstable/argeo-qa/doc/platform/argeo-platform.fo")); + + // Resulting SAX events (the generated FO) must be piped through to FOP + Result res = new SAXResult(fop.getDefaultHandler()); + + // Step 6: Start XSLT transformation and FOP processing + fopTransformer.transform(src, res); + + } finally { + // Clean-up + out.close(); + } + } } diff --git a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FontsServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FontsServlet.java index 01e212e..3e65d65 100644 --- a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FontsServlet.java +++ b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FontsServlet.java @@ -12,7 +12,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; -import org.argeo.api.cms.CmsTheme; +import org.argeo.api.cms.ux.CmsTheme; /** Serves fonts locally. */ public class FontsServlet extends HttpServlet { diff --git a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java new file mode 100644 index 0000000..1ee19f0 --- /dev/null +++ b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java @@ -0,0 +1,222 @@ +package org.argeo.app.servlet.publish; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.URI; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Map; +import java.util.Objects; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.URIResolver; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.FopFactoryBuilder; +import org.apache.xalan.processor.TransformerFactoryImpl; +import org.apache.xmlgraphics.io.Resource; +import org.apache.xmlgraphics.io.ResourceResolver; +import org.argeo.api.acr.Content; +import org.argeo.api.acr.ContentRepository; +import org.argeo.api.acr.ContentSession; +import org.argeo.app.geo.GeoUtils; +import org.argeo.app.geo.GpxUtils; +import org.argeo.cms.acr.xml.XmlNormalizer; +import org.argeo.cms.auth.RemoteAuthUtils; +import org.argeo.cms.servlet.ServletHttpRequest; +import org.argeo.cms.util.LangUtils; +import org.geotools.data.collection.ListFeatureCollection; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.opengis.feature.simple.SimpleFeature; + +/** + * A servlet transforming an XML view of the data to either FOP or PDF. + */ +public class FopServlet extends HttpServlet { + private static final long serialVersionUID = 6906020513498289335L; + + private final static String PROP_ARGEO_FO_XSL = "argeo.fo.xsl"; + + private ContentRepository contentRepository; + + private DocumentBuilderFactory documentBuilderFactory; + private TransformerFactory transformerFactory; + private Templates foTemplates; + + private URL xslUrl; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String servletPath = req.getServletPath(); + String ext = servletPath.substring(servletPath.lastIndexOf('.')); + servletPath = servletPath.substring(1, servletPath.lastIndexOf('.')); + servletPath = servletPath.substring(servletPath.indexOf('/'), servletPath.length()); + String path = URLDecoder.decode(servletPath, StandardCharsets.UTF_8); + + boolean pdf = ".pdf".equals(ext); + ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(), new ServletHttpRequest(req)); + Content content = session.get(path); + + // dev only + final boolean DEV = false; + if (DEV) { + try (InputStream in = xslUrl.openStream()) { + Source xslSource = new StreamSource(in); + foTemplates = transformerFactory.newTemplates(xslSource); + if (foTemplates == null) + throw new IllegalStateException("Could not instantiate XSL " + xslUrl); + } catch (TransformerConfigurationException | IOException e) { + throw new IllegalStateException("Cannot instantiate XSL " + xslUrl, e); + } + + Source xmlInput = content.adapt(Source.class); + XmlNormalizer.print(xmlInput,0); + } + + Source xmlInput = content.adapt(Source.class); + String systemId = req.getRequestURL().toString(); + xmlInput.setSystemId(systemId); + + URIResolver uriResolver = (href, base) -> { + try { + URI url = URI.create(href); + if (url.getScheme() != null) { + if (url.getScheme().equals("file")) { + InputStream in = Files.newInputStream(Paths.get(URI.create(url.toString()))); + return new StreamSource(in); + } + if (url.getScheme().equals("geo2svg")) { + String includePath = path + url.getPath(); + String geoExt = includePath.substring(includePath.lastIndexOf('.')); + Content geoContent = session.get(includePath); + if (".gpx".equals(geoExt)) { + try (InputStream in = geoContent.open(InputStream.class)) { + SimpleFeature field = GpxUtils.parseGpxToPolygon(in); + SimpleFeatureCollection features = new ListFeatureCollection(field.getType(), field); + try (StringWriter writer = new StringWriter()) { + GeoUtils.exportToSvg(features, writer, 100, 100); + StreamSource res = new StreamSource(new StringReader(writer.toString())); + return res; + } + } + } else { + throw new UnsupportedOperationException(geoExt + " is not supported"); + } + } + } + } catch (IOException e) { + throw new RuntimeException("Cannot process " + href); + } + + String p = href.startsWith("/") ? href : path + '/' + href; + Content subContent = session.get(p); + return subContent.adapt(Source.class); + }; + + ResourceResolver resourceResolver = new ResourceResolver() { + + @Override + public Resource getResource(URI uri) throws IOException { + String subPath = uri.getPath(); + Content subContent = session.get(subPath); + InputStream in = subContent.open(InputStream.class); + return new Resource(in); + } + + @Override + public OutputStream getOutputStream(URI uri) throws IOException { + return null; + } + }; + + try { + if (pdf) { + FopFactoryBuilder builder = new FopFactoryBuilder(URI.create(req.getRequestURL().toString()), + resourceResolver); + FopFactory fopFactory = builder.build(); +// FopFactory fopFactory = FopFactory.newInstance(URI.create(req.getRequestURL().toString())); + resp.setContentType("application/pdf"); + Fop fop = fopFactory.newFop("application/pdf", resp.getOutputStream()); + Transformer transformer = foTemplates.newTransformer(); + transformer.setURIResolver(uriResolver); + Result fopResult = new SAXResult(fop.getDefaultHandler()); + transformer.transform(xmlInput, fopResult); + + } else { + Result xmlOutput = new StreamResult(resp.getOutputStream()); + resp.setContentType("application/xml"); + Transformer transformer = foTemplates.newTransformer(); +// transformer = transformerFactory.newTransformer();// identity + transformer.setURIResolver(uriResolver); + transformer.transform(xmlInput, xmlOutput); + } + } catch (FOPException | IOException | TransformerException e) { + throw new RuntimeException("Cannot process " + path, e); + } + + } + + @Override + public void init() throws ServletException { +// for (Enumeration it = getServletConfig().getInitParameterNames(); it.hasMoreElements();) +// System.out.println(it.nextElement()); +// for (String str : getServletContext().getResourcePaths("/")) +// System.out.println(str); + } + + public void start(Map properties) { + documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setXIncludeAware(true); + documentBuilderFactory.setNamespaceAware(true); + + // We must explicitly use the non-XSLTC transformer, as XSLTC is not working + // with DocBook stylesheets + transformerFactory = new TransformerFactoryImpl(); +// transformerFactory = TransformerFactory.newDefaultInstance(); + try { + String xslStr = LangUtils.get(properties, PROP_ARGEO_FO_XSL); + Objects.requireNonNull(xslStr); + xslUrl = new URL(xslStr); + try (InputStream in = xslUrl.openStream()) { + Source xslSource = new StreamSource(in); + foTemplates = transformerFactory.newTemplates(xslSource); + if (foTemplates == null) + throw new IllegalStateException("Could not instantiate XSL " + xslUrl); + } + + } catch (TransformerConfigurationException | IOException e) { + throw new IllegalStateException("Cannot instantiate XSL " + xslUrl, e); + } + } + + public void stop(Map properties) { + + } + + public void setContentRepository(ContentRepository contentRepository) { + this.contentRepository = contentRepository; + } + +} diff --git a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/GeoToSvgServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/GeoToSvgServlet.java new file mode 100644 index 0000000..c22b834 --- /dev/null +++ b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/GeoToSvgServlet.java @@ -0,0 +1,67 @@ +package org.argeo.app.servlet.publish; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.argeo.api.acr.Content; +import org.argeo.api.acr.ContentRepository; +import org.argeo.api.acr.ContentSession; +import org.argeo.app.geo.GeoUtils; +import org.argeo.app.geo.GpxUtils; +import org.argeo.cms.auth.RemoteAuthUtils; +import org.argeo.cms.servlet.ServletHttpRequest; +import org.geotools.data.collection.ListFeatureCollection; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.opengis.feature.simple.SimpleFeature; + +/** + * A servlet transforming an geographical data to SVG. + */ +public class GeoToSvgServlet extends HttpServlet { + private static final long serialVersionUID = -6346379324580671894L; + private ContentRepository contentRepository; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String servletPath = req.getServletPath(); + + servletPath = servletPath.substring(1, servletPath.lastIndexOf('.')); + servletPath = servletPath.substring(servletPath.indexOf('/'), servletPath.length()); + String path = URLDecoder.decode(servletPath, StandardCharsets.UTF_8); + String ext = servletPath.substring(path.lastIndexOf('.')); + + resp.setContentType("image/svg+xml"); + + ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(), new ServletHttpRequest(req)); + Content content = session.get(path); + if (".gpx".equals(ext)) { + try (InputStream in = content.open(InputStream.class)) { + SimpleFeature field = GpxUtils.parseGpxToPolygon(in); + + SimpleFeatureCollection features = new ListFeatureCollection(field.getType(), field); + GeoUtils.exportToSvg(features, resp.getWriter(), 100, 100); +// log.debug("SVG:\n" + writer.toString() + "\n"); + } + } + } + + public void start(Map properties) { + } + + public void stop(Map properties) { + + } + + public void setContentRepository(ContentRepository contentRepository) { + this.contentRepository = contentRepository; + } + +} diff --git a/org.argeo.app.theme.default/.classpath b/org.argeo.app.theme.default/.classpath index e801ebf..81fe078 100644 --- a/org.argeo.app.theme.default/.classpath +++ b/org.argeo.app.theme.default/.classpath @@ -1,6 +1,6 @@ - + diff --git a/org.argeo.app.theme.default/OSGI-INF/cmsTheme.xml b/org.argeo.app.theme.default/OSGI-INF/cmsTheme.xml index 1a4e589..bcb5ecb 100644 --- a/org.argeo.app.theme.default/OSGI-INF/cmsTheme.xml +++ b/org.argeo.app.theme.default/OSGI-INF/cmsTheme.xml @@ -1,8 +1,9 @@ - + - + + diff --git a/org.argeo.app.theme.default/bnd.bnd b/org.argeo.app.theme.default/bnd.bnd index 45dc19e..4743076 100644 --- a/org.argeo.app.theme.default/bnd.bnd +++ b/org.argeo.app.theme.default/bnd.bnd @@ -1,7 +1,11 @@ Service-Component:\ OSGI-INF/cmsTheme.xml +Private-Package: * + +Export-Package: !* + Import-Package:\ -org.argeo.cms.swt.osgi,\ +org.argeo.cms.swt.osgi;resolution:="optional",\ javax.servlet.*;version="[3,5)",\ * \ No newline at end of file diff --git a/org.argeo.app.theme.default/icons/types/.gitignore b/org.argeo.app.theme.default/icons/types/.gitignore new file mode 100644 index 0000000..098a566 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/.gitignore @@ -0,0 +1,2 @@ +!svg/ +**/*.png diff --git a/org.argeo.app.theme.default/icons/types/svg/activity.svg b/org.argeo.app.theme.default/icons/types/svg/activity.svg new file mode 100644 index 0000000..1fbbc20 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/activity.svg @@ -0,0 +1,16 @@ + + + + + image/svg+xml + + activity + + + + + + + activity + + diff --git a/org.argeo.app.theme.default/icons/types/svg/add.svg b/org.argeo.app.theme.default/icons/types/svg/add.svg new file mode 100644 index 0000000..bbc6670 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/add.svg @@ -0,0 +1,10 @@ + + + + + add + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/addressBook.svg b/org.argeo.app.theme.default/icons/types/svg/addressBook.svg new file mode 100644 index 0000000..f8564d6 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/addressBook.svg @@ -0,0 +1 @@ +addressBook \ No newline at end of file diff --git a/org.argeo.app.theme.default/icons/types/svg/ascending.svg b/org.argeo.app.theme.default/icons/types/svg/ascending.svg new file mode 100644 index 0000000..d1a171c --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/ascending.svg @@ -0,0 +1,14 @@ + + + + + ascending + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/calendar.svg b/org.argeo.app.theme.default/icons/types/svg/calendar.svg new file mode 100644 index 0000000..60e0ee5 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/calendar.svg @@ -0,0 +1,20 @@ + + + + + calendar + + + + + + + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/close.svg b/org.argeo.app.theme.default/icons/types/svg/close.svg new file mode 100644 index 0000000..242c922 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/close.svg @@ -0,0 +1,10 @@ + + + + + close + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/closeAll.svg b/org.argeo.app.theme.default/icons/types/svg/closeAll.svg new file mode 100644 index 0000000..775f7a7 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/closeAll.svg @@ -0,0 +1,12 @@ + + + + + closeAll + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/dashboard.svg b/org.argeo.app.theme.default/icons/types/svg/dashboard.svg new file mode 100644 index 0000000..852cd6a --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/dashboard.svg @@ -0,0 +1,12 @@ + + + + + dashboard + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/delete.svg b/org.argeo.app.theme.default/icons/types/svg/delete.svg new file mode 100644 index 0000000..b2800d4 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/delete.svg @@ -0,0 +1,14 @@ + + + + + delete + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/descending.svg b/org.argeo.app.theme.default/icons/types/svg/descending.svg new file mode 100644 index 0000000..4f363b0 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/descending.svg @@ -0,0 +1,14 @@ + + + + + descending + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/document.svg b/org.argeo.app.theme.default/icons/types/svg/document.svg new file mode 100644 index 0000000..5265430 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/document.svg @@ -0,0 +1,11 @@ + + + + + document + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/documents.svg b/org.argeo.app.theme.default/icons/types/svg/documents.svg new file mode 100644 index 0000000..8e7684f --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/documents.svg @@ -0,0 +1,13 @@ + + + + + documents + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/email.svg b/org.argeo.app.theme.default/icons/types/svg/email.svg new file mode 100644 index 0000000..444445b --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/email.svg @@ -0,0 +1,8 @@ + + + + + email + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/fav.svg b/org.argeo.app.theme.default/icons/types/svg/fav.svg new file mode 100644 index 0000000..b78263c --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/fav.svg @@ -0,0 +1,7 @@ + + + + + fav + + diff --git a/org.argeo.app.theme.default/icons/types/svg/favNot.svg b/org.argeo.app.theme.default/icons/types/svg/favNot.svg new file mode 100644 index 0000000..2902279 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/favNot.svg @@ -0,0 +1,7 @@ + + + + + favNot + + diff --git a/org.argeo.app.theme.default/icons/types/svg/folder.svg b/org.argeo.app.theme.default/icons/types/svg/folder.svg new file mode 100644 index 0000000..3874e6f --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/folder.svg @@ -0,0 +1,8 @@ + + + + + folder + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/group.svg b/org.argeo.app.theme.default/icons/types/svg/group.svg new file mode 100644 index 0000000..4a1ee49 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/group.svg @@ -0,0 +1,10 @@ + + + + + group + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/historyAscending.svg b/org.argeo.app.theme.default/icons/types/svg/historyAscending.svg new file mode 100644 index 0000000..975310e --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/historyAscending.svg @@ -0,0 +1,10 @@ + + + + + historyAscending + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/historyDescending.svg b/org.argeo.app.theme.default/icons/types/svg/historyDescending.svg new file mode 100644 index 0000000..7c35988 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/historyDescending.svg @@ -0,0 +1,10 @@ + + + + + historyDescending + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/home.svg b/org.argeo.app.theme.default/icons/types/svg/home.svg new file mode 100644 index 0000000..0c2ba6f --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/home.svg @@ -0,0 +1,9 @@ + + + + + home + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/inbox.svg b/org.argeo.app.theme.default/icons/types/svg/inbox.svg new file mode 100644 index 0000000..1acd8dd --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/inbox.svg @@ -0,0 +1,13 @@ + + + + + inbox + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/license.svg b/org.argeo.app.theme.default/icons/types/svg/license.svg new file mode 100644 index 0000000..994e2ec --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/license.svg @@ -0,0 +1,11 @@ + + + + + license + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/location.svg b/org.argeo.app.theme.default/icons/types/svg/location.svg new file mode 100644 index 0000000..6bf408b --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/location.svg @@ -0,0 +1,12 @@ + + + + + location + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/logout.svg b/org.argeo.app.theme.default/icons/types/svg/logout.svg new file mode 100644 index 0000000..606f172 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/logout.svg @@ -0,0 +1,8 @@ + + + + + logout + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/map.svg b/org.argeo.app.theme.default/icons/types/svg/map.svg new file mode 100644 index 0000000..0f68569 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/map.svg @@ -0,0 +1 @@ +map \ No newline at end of file diff --git a/org.argeo.app.theme.default/icons/types/svg/milestone.svg b/org.argeo.app.theme.default/icons/types/svg/milestone.svg new file mode 100644 index 0000000..b99b69d --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/milestone.svg @@ -0,0 +1,9 @@ + + + + + milestone + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/mobile.svg b/org.argeo.app.theme.default/icons/types/svg/mobile.svg new file mode 100644 index 0000000..c991bec --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/mobile.svg @@ -0,0 +1,9 @@ + + + + + mobile + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/note.svg b/org.argeo.app.theme.default/icons/types/svg/note.svg new file mode 100644 index 0000000..132478f --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/note.svg @@ -0,0 +1,8 @@ + + + + + note + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/openUserMenu.svg b/org.argeo.app.theme.default/icons/types/svg/openUserMenu.svg new file mode 100644 index 0000000..a84bc65 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/openUserMenu.svg @@ -0,0 +1,70 @@ + + + + + + image/svg+xml + + Artboard 153 + + + + + + + + Artboard 153 + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/organisation.svg b/org.argeo.app.theme.default/icons/types/svg/organisation.svg new file mode 100644 index 0000000..767dc00 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/organisation.svg @@ -0,0 +1,17 @@ + + + + + organisation + + + + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/organisationContact.svg b/org.argeo.app.theme.default/icons/types/svg/organisationContact.svg new file mode 100644 index 0000000..67c9efd --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/organisationContact.svg @@ -0,0 +1 @@ +organisationContact \ No newline at end of file diff --git a/org.argeo.app.theme.default/icons/types/svg/people.svg b/org.argeo.app.theme.default/icons/types/svg/people.svg new file mode 100644 index 0000000..e28542f --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/people.svg @@ -0,0 +1,10 @@ + + + + + people + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/person.svg b/org.argeo.app.theme.default/icons/types/svg/person.svg new file mode 100644 index 0000000..b29b335 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/person.svg @@ -0,0 +1,8 @@ + + + + + person + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/project-01.svg b/org.argeo.app.theme.default/icons/types/svg/project-01.svg new file mode 100644 index 0000000..c94ba9b --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/project-01.svg @@ -0,0 +1,13 @@ + + + + + project-01 + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/refresh.svg b/org.argeo.app.theme.default/icons/types/svg/refresh.svg new file mode 100644 index 0000000..638fd55 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/refresh.svg @@ -0,0 +1,10 @@ + + + + + refresh + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/report.svg b/org.argeo.app.theme.default/icons/types/svg/report.svg new file mode 100644 index 0000000..9321310 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/report.svg @@ -0,0 +1 @@ +report \ No newline at end of file diff --git a/org.argeo.app.theme.default/icons/types/svg/save.svg b/org.argeo.app.theme.default/icons/types/svg/save.svg new file mode 100644 index 0000000..09660dd --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/save.svg @@ -0,0 +1,8 @@ + + + + + save + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/saveAll.svg b/org.argeo.app.theme.default/icons/types/svg/saveAll.svg new file mode 100644 index 0000000..3f2ebde --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/saveAll.svg @@ -0,0 +1,12 @@ + + + + + saveAll + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/search.svg b/org.argeo.app.theme.default/icons/types/svg/search.svg new file mode 100644 index 0000000..6fa30df --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/search.svg @@ -0,0 +1,8 @@ + + + + + search + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/settings.svg b/org.argeo.app.theme.default/icons/types/svg/settings.svg new file mode 100644 index 0000000..da3b784 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/settings.svg @@ -0,0 +1,17 @@ + + + + + settings + + + + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/tag.svg b/org.argeo.app.theme.default/icons/types/svg/tag.svg new file mode 100644 index 0000000..4ce586d --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/tag.svg @@ -0,0 +1,12 @@ + + + + + tag + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/task.svg b/org.argeo.app.theme.default/icons/types/svg/task.svg new file mode 100644 index 0000000..09e81ed --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/task.svg @@ -0,0 +1,13 @@ + + + + + task + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/task_1.svg b/org.argeo.app.theme.default/icons/types/svg/task_1.svg new file mode 100644 index 0000000..246ea19 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/task_1.svg @@ -0,0 +1,14 @@ + + + + + task_1 + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/telephone.svg b/org.argeo.app.theme.default/icons/types/svg/telephone.svg new file mode 100644 index 0000000..b74bc81 --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/telephone.svg @@ -0,0 +1,7 @@ + + + + + telephone + + diff --git a/org.argeo.app.theme.default/icons/types/svg/timeLine.svg b/org.argeo.app.theme.default/icons/types/svg/timeLine.svg new file mode 100644 index 0000000..45c5e7e --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/timeLine.svg @@ -0,0 +1,26 @@ + + + + + timeLine + + + + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/todo.svg b/org.argeo.app.theme.default/icons/types/svg/todo.svg new file mode 100644 index 0000000..fa1652f --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/todo.svg @@ -0,0 +1,16 @@ + + + + + todo + + + + + + + + + + + diff --git a/org.argeo.app.theme.default/icons/types/svg/user.svg b/org.argeo.app.theme.default/icons/types/svg/user.svg new file mode 100644 index 0000000..00997db --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/user.svg @@ -0,0 +1,16 @@ + + + + + image/svg+xml + + + + + + + + + user + + diff --git a/org.argeo.app.theme.default/icons/types/svg/users.svg b/org.argeo.app.theme.default/icons/types/svg/users.svg new file mode 100644 index 0000000..bb0e00d --- /dev/null +++ b/org.argeo.app.theme.default/icons/types/svg/users.svg @@ -0,0 +1 @@ +users \ No newline at end of file diff --git a/org.argeo.app.theme.default/rap/argeo.css b/org.argeo.app.theme.default/rap/argeo.css new file mode 100644 index 0000000..0351d05 --- /dev/null +++ b/org.argeo.app.theme.default/rap/argeo.css @@ -0,0 +1,151 @@ +.argeo-suite-header { + color: white; + background-color: #00294b; +} + +.argeo-suite-headerTitle { + font: bold 24px sans-serif; + color: white; + background-color: #00294b; +} + +.argeo-suite-leadPane { + background-color: #eee; +} + +Label.argeo-suite-leadPane { + color: #888; + background-color: #eee; +} + +Button.argeo-suite-leadPane:hover { + cursor:pointer; +} + +.argeo-suite-recentItems { + font: bold 16px 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 16px sans-serif; + color: white; + background-color: #00294b; +} + +.argeo-suite-subTitleLabel { + font: italic 16px sans-serif; + color: #777; + padding: 4px 8px; +} + +.argeo-suite-simpleLabel { + font: bold 16px sans-serif; + padding: 0px; +} + +.argeo-suite-simpleText { + font: 16px sans-serif; + padding: 0px; +} + +.argeo-suite-titleCell { + font: bold 16px sans-serif; + background-color: #ddd; +} + +.argeo-suite-inlineButton { + padding: 0px 4px; + font: 16px 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 16px 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; +} + +.argeo-suite-navigationBar{ + background-color:#ddd; +} + +.argeo-suite-navigationTitle{ + background-color:#ddd; + font:bold 16px sans-serif; +} + +.argeo-suite-navigationButton{ + color:#777; + background-color:#ddd; + font:bold 16px sans-serif; +} + +.argeo-suite-navigationButton:hover{ + cursor:pointer; + color:#ddd; + background-color:#777; +} diff --git a/org.argeo.app.theme.default/rap/defaults.css b/org.argeo.app.theme.default/rap/defaults.css new file mode 100644 index 0000000..24b1f7c --- /dev/null +++ b/org.argeo.app.theme.default/rap/defaults.css @@ -0,0 +1,43 @@ +Display, +Label, +Text, +Tree, +Table, +Button, +TreeColumn, +TableColumn, +{ + font: 16px sans-serif; +} + +Sash { + border: 1px solid white; + background-image: none; + background-color: white; +} + +Sash:hover { + border: 1px solid #5882b5; + background-color: #5882b5; +} + +Tree-Cell { + padding: 3px 3px 0px; + spacing: 3px; +} + +Table-Cell { + padding: 3px 3px 0px; + spacing: 5px; +} + +Tree-RowOverlay:selected { + color:#fff; + background-color:#5882b5; +} + +Table-RowOverlay:selected { + color:#fff; + background-color:#5882b5; +} + diff --git a/org.argeo.app.theme.default/rap/work.css b/org.argeo.app.theme.default/rap/work.css deleted file mode 100644 index c0aaeb1..0000000 --- a/org.argeo.app.theme.default/rap/work.css +++ /dev/null @@ -1,181 +0,0 @@ -.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; -} diff --git a/org.argeo.app.ui.rap/.gitignore b/org.argeo.app.ui.rap/.gitignore deleted file mode 100644 index 09e3bc9..0000000 --- a/org.argeo.app.ui.rap/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/bin/ -/target/ diff --git a/org.argeo.app.ui.rap/.project b/org.argeo.app.ui.rap/.project deleted file mode 100644 index 51bc8dd..0000000 --- a/org.argeo.app.ui.rap/.project +++ /dev/null @@ -1,27 +0,0 @@ - - - org.argeo.app.ui.rap - - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - org.eclipse.pde.ds.core.builder - - - - - - org.eclipse.pde.PluginNature - - diff --git a/org.argeo.app.ui.rap/META-INF/.gitignore b/org.argeo.app.ui.rap/META-INF/.gitignore deleted file mode 100644 index 4854a41..0000000 --- a/org.argeo.app.ui.rap/META-INF/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/MANIFEST.MF diff --git a/org.argeo.app.ui.rap/OSGI-INF/cmsWebApp.xml b/org.argeo.app.ui.rap/OSGI-INF/cmsWebApp.xml deleted file mode 100644 index 4f807c1..0000000 --- a/org.argeo.app.ui.rap/OSGI-INF/cmsWebApp.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/org.argeo.app.ui.rap/bnd.bnd b/org.argeo.app.ui.rap/bnd.bnd deleted file mode 100644 index 140b5e0..0000000 --- a/org.argeo.app.ui.rap/bnd.bnd +++ /dev/null @@ -1,6 +0,0 @@ -Service-Component: OSGI-INF/cmsWebApp.xml - -Import-Package:\ -org.argeo.cms.web;resolution:=optional,\ -org.eclipse.rap.rwt.application;resolution:=optional,\ -*;resolution:=optional diff --git a/org.argeo.app.ui.rap/build.properties b/org.argeo.app.ui.rap/build.properties deleted file mode 100644 index 6210e84..0000000 --- a/org.argeo.app.ui.rap/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -output.. = bin/ -bin.includes = META-INF/,\ - .,\ - OSGI-INF/ -source.. = src/ diff --git a/org.argeo.app.ui.rap/src/.gitignore b/org.argeo.app.ui.rap/src/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/org.argeo.app.ui/.classpath b/org.argeo.app.ui/.classpath deleted file mode 100644 index e801ebf..0000000 --- a/org.argeo.app.ui/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/org.argeo.app.ui/.gitignore b/org.argeo.app.ui/.gitignore deleted file mode 100644 index 09e3bc9..0000000 --- a/org.argeo.app.ui/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/bin/ -/target/ diff --git a/org.argeo.app.ui/.project b/org.argeo.app.ui/.project deleted file mode 100644 index a7893bd..0000000 --- a/org.argeo.app.ui/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - org.argeo.app.ui - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - org.eclipse.pde.ds.core.builder - - - - - - org.eclipse.pde.PluginNature - org.eclipse.jdt.core.javanature - - diff --git a/org.argeo.app.ui/META-INF/.gitignore b/org.argeo.app.ui/META-INF/.gitignore deleted file mode 100644 index 4854a41..0000000 --- a/org.argeo.app.ui/META-INF/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/MANIFEST.MF diff --git a/org.argeo.app.ui/OSGI-INF/adminLeadPane.xml b/org.argeo.app.ui/OSGI-INF/adminLeadPane.xml deleted file mode 100644 index 0a2818a..0000000 --- a/org.argeo.app.ui/OSGI-INF/adminLeadPane.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - argeo.suite.ui.termsLayer - - - diff --git a/org.argeo.app.ui/OSGI-INF/cmsApp.xml b/org.argeo.app.ui/OSGI-INF/cmsApp.xml deleted file mode 100644 index 20373ae..0000000 --- a/org.argeo.app.ui/OSGI-INF/cmsApp.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/contentEntryArea.xml b/org.argeo.app.ui/OSGI-INF/contentEntryArea.xml deleted file mode 100644 index ecc37c7..0000000 --- a/org.argeo.app.ui/OSGI-INF/contentEntryArea.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/contentLayer.xml b/org.argeo.app.ui/OSGI-INF/contentLayer.xml deleted file mode 100644 index 35c4c3a..0000000 --- a/org.argeo.app.ui/OSGI-INF/contentLayer.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/dashboard.xml b/org.argeo.app.ui/OSGI-INF/dashboard.xml deleted file mode 100644 index 9ee5857..0000000 --- a/org.argeo.app.ui/OSGI-INF/dashboard.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/dashboardLayer.xml b/org.argeo.app.ui/OSGI-INF/dashboardLayer.xml deleted file mode 100644 index 436a8e6..0000000 --- a/org.argeo.app.ui/OSGI-INF/dashboardLayer.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/documentUiProvider.xml b/org.argeo.app.ui/OSGI-INF/documentUiProvider.xml deleted file mode 100644 index 3711fd5..0000000 --- a/org.argeo.app.ui/OSGI-INF/documentUiProvider.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/documentsFolder.xml b/org.argeo.app.ui/OSGI-INF/documentsFolder.xml deleted file mode 100644 index fef4582..0000000 --- a/org.argeo.app.ui/OSGI-INF/documentsFolder.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/eventRecorder.xml b/org.argeo.app.ui/OSGI-INF/eventRecorder.xml deleted file mode 100644 index ab1a6ae..0000000 --- a/org.argeo.app.ui/OSGI-INF/eventRecorder.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/footer.xml b/org.argeo.app.ui/OSGI-INF/footer.xml deleted file mode 100644 index 5e9a857..0000000 --- a/org.argeo.app.ui/OSGI-INF/footer.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/fsEntryArea.xml b/org.argeo.app.ui/OSGI-INF/fsEntryArea.xml deleted file mode 100644 index e7190db..0000000 --- a/org.argeo.app.ui/OSGI-INF/fsEntryArea.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/header.xml b/org.argeo.app.ui/OSGI-INF/header.xml deleted file mode 100644 index 0c83dc6..0000000 --- a/org.argeo.app.ui/OSGI-INF/header.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/l10n/bundle.properties b/org.argeo.app.ui/OSGI-INF/l10n/bundle.properties deleted file mode 100644 index 8b76a47..0000000 --- a/org.argeo.app.ui/OSGI-INF/l10n/bundle.properties +++ /dev/null @@ -1,108 +0,0 @@ -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. - -# People -people=people - -# Library -content=content - -# Geo -map=map - diff --git a/org.argeo.app.ui/OSGI-INF/l10n/bundle_de.properties b/org.argeo.app.ui/OSGI-INF/l10n/bundle_de.properties deleted file mode 100644 index 0af19c2..0000000 --- a/org.argeo.app.ui/OSGI-INF/l10n/bundle_de.properties +++ /dev/null @@ -1,98 +0,0 @@ -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. diff --git a/org.argeo.app.ui/OSGI-INF/l10n/bundle_fr.properties b/org.argeo.app.ui/OSGI-INF/l10n/bundle_fr.properties deleted file mode 100644 index 225e5fd..0000000 --- a/org.argeo.app.ui/OSGI-INF/l10n/bundle_fr.properties +++ /dev/null @@ -1,102 +0,0 @@ -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. diff --git a/org.argeo.app.ui/OSGI-INF/leadPane.xml b/org.argeo.app.ui/OSGI-INF/leadPane.xml deleted file mode 100644 index c2c2104..0000000 --- a/org.argeo.app.ui/OSGI-INF/leadPane.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - argeo.suite.ui.dashboardLayer -argeo.library.ui.contentLayer -argeo.people.ui.peopleLayer -argeo.geo.ui.mapLayer - - - diff --git a/org.argeo.app.ui/OSGI-INF/loginScreen.xml b/org.argeo.app.ui/OSGI-INF/loginScreen.xml deleted file mode 100644 index f79396f..0000000 --- a/org.argeo.app.ui/OSGI-INF/loginScreen.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/mapLayer.xml b/org.argeo.app.ui/OSGI-INF/mapLayer.xml deleted file mode 100644 index f90cd78..0000000 --- a/org.argeo.app.ui/OSGI-INF/mapLayer.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/overviewMap.xml b/org.argeo.app.ui/OSGI-INF/overviewMap.xml deleted file mode 100644 index 662cbe8..0000000 --- a/org.argeo.app.ui/OSGI-INF/overviewMap.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/peopleEntryArea.xml b/org.argeo.app.ui/OSGI-INF/peopleEntryArea.xml deleted file mode 100644 index c68a753..0000000 --- a/org.argeo.app.ui/OSGI-INF/peopleEntryArea.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/peopleLayer.xml b/org.argeo.app.ui/OSGI-INF/peopleLayer.xml deleted file mode 100644 index 159da12..0000000 --- a/org.argeo.app.ui/OSGI-INF/peopleLayer.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/personUiProvider.xml b/org.argeo.app.ui/OSGI-INF/personUiProvider.xml deleted file mode 100644 index 4bcfef1..0000000 --- a/org.argeo.app.ui/OSGI-INF/personUiProvider.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/recentItems.xml b/org.argeo.app.ui/OSGI-INF/recentItems.xml deleted file mode 100644 index 21c23e3..0000000 --- a/org.argeo.app.ui/OSGI-INF/recentItems.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/termsEntryArea.xml b/org.argeo.app.ui/OSGI-INF/termsEntryArea.xml deleted file mode 100644 index 0435f69..0000000 --- a/org.argeo.app.ui/OSGI-INF/termsEntryArea.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/termsLayer.xml b/org.argeo.app.ui/OSGI-INF/termsLayer.xml deleted file mode 100644 index 9483e05..0000000 --- a/org.argeo.app.ui/OSGI-INF/termsLayer.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/OSGI-INF/wwwLayer.xml b/org.argeo.app.ui/OSGI-INF/wwwLayer.xml deleted file mode 100644 index 0fc0edb..0000000 --- a/org.argeo.app.ui/OSGI-INF/wwwLayer.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.app.ui/bnd.bnd b/org.argeo.app.ui/bnd.bnd deleted file mode 100644 index e36f705..0000000 --- a/org.argeo.app.ui/bnd.bnd +++ /dev/null @@ -1,37 +0,0 @@ -Service-Component:\ -OSGI-INF/cmsApp.xml,\ -OSGI-INF/eventRecorder.xml,\ -OSGI-INF/header.xml,\ -OSGI-INF/footer.xml,\ -OSGI-INF/leadPane.xml,\ -OSGI-INF/loginScreen.xml,\ -OSGI-INF/recentItems.xml,\ -OSGI-INF/adminLeadPane.xml,\ -OSGI-INF/termsEntryArea.xml,\ -OSGI-INF/termsLayer.xml,\ -OSGI-INF/dashboard.xml,\ -OSGI-INF/dashboardLayer.xml,\ -OSGI-INF/peopleEntryArea.xml,\ -OSGI-INF/peopleLayer.xml,\ -OSGI-INF/personUiProvider.xml,\ -OSGI-INF/contentEntryArea.xml,\ -OSGI-INF/contentLayer.xml,\ -OSGI-INF/documentsFolder.xml,\ -OSGI-INF/fsEntryArea.xml,\ -OSGI-INF/mapLayer.xml,\ -OSGI-INF/overviewMap.xml,\ -OSGI-INF/wwwLayer.xml,\ -OSGI-INF/documentUiProvider.xml,\ - - - -Import-Package:\ -org.argeo.cms.ui.widgets,\ -org.eclipse.swt,\ -org.osgi.framework,\ -org.eclipse.core.commands.common,\ -org.eclipse.jface.window,\ -org.eclipse.jface.dialogs,\ -org.eclipse.rap.rwt,\ -javax.servlet.*;version="[3,5)",\ -* diff --git a/org.argeo.app.ui/build.properties b/org.argeo.app.ui/build.properties deleted file mode 100644 index d829967..0000000 --- a/org.argeo.app.ui/build.properties +++ /dev/null @@ -1,10 +0,0 @@ -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/ diff --git a/org.argeo.app.ui/config/adminLeadPane.properties b/org.argeo.app.ui/config/adminLeadPane.properties deleted file mode 100644 index 90b9b04..0000000 --- a/org.argeo.app.ui/config/adminLeadPane.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.suite.ui.adminLeadPane diff --git a/org.argeo.app.ui/config/cmsApp.properties b/org.argeo.app.ui/config/cmsApp.properties deleted file mode 100644 index 1dec00e..0000000 --- a/org.argeo.app.ui/config/cmsApp.properties +++ /dev/null @@ -1,3 +0,0 @@ -service.pid=argeo.suite.ui.app - -event.topics=argeo/suite/* \ No newline at end of file diff --git a/org.argeo.app.ui/config/contentEntryArea.properties b/org.argeo.app.ui/config/contentEntryArea.properties deleted file mode 100644 index 855fe97..0000000 --- a/org.argeo.app.ui/config/contentEntryArea.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.library.ui.contentEntryArea diff --git a/org.argeo.app.ui/config/contentLayer.properties b/org.argeo.app.ui/config/contentLayer.properties deleted file mode 100644 index c1ca8e3..0000000 --- a/org.argeo.app.ui/config/contentLayer.properties +++ /dev/null @@ -1,6 +0,0 @@ -service.pid=argeo.library.ui.contentLayer - -title=%content -icon=documents - -entity.type=nt:folder,nt:file,entity:space,entity:document diff --git a/org.argeo.app.ui/config/dashboard.properties b/org.argeo.app.ui/config/dashboard.properties deleted file mode 100644 index 1832543..0000000 --- a/org.argeo.app.ui/config/dashboard.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.suite.ui.dashboard diff --git a/org.argeo.app.ui/config/dashboardLayer.properties b/org.argeo.app.ui/config/dashboardLayer.properties deleted file mode 100644 index 79abe4c..0000000 --- a/org.argeo.app.ui/config/dashboardLayer.properties +++ /dev/null @@ -1,4 +0,0 @@ -service.pid=argeo.suite.ui.dashboardLayer - -title=Dashboard -icon=dashboard \ No newline at end of file diff --git a/org.argeo.app.ui/config/documentUiProvider.properties b/org.argeo.app.ui/config/documentUiProvider.properties deleted file mode 100644 index 855735d..0000000 --- a/org.argeo.app.ui/config/documentUiProvider.properties +++ /dev/null @@ -1,3 +0,0 @@ -service.pid=argeo.publishing.ui.documentUiProvider - -entity.type=entity:document,nt:file \ No newline at end of file diff --git a/org.argeo.app.ui/config/documentsFolder.properties b/org.argeo.app.ui/config/documentsFolder.properties deleted file mode 100644 index 349e930..0000000 --- a/org.argeo.app.ui/config/documentsFolder.properties +++ /dev/null @@ -1 +0,0 @@ -entity.type=nt:folder \ No newline at end of file diff --git a/org.argeo.app.ui/config/eventRecorder.properties b/org.argeo.app.ui/config/eventRecorder.properties deleted file mode 100644 index 6503863..0000000 --- a/org.argeo.app.ui/config/eventRecorder.properties +++ /dev/null @@ -1,3 +0,0 @@ -service.pid=argeo.suite.ui.eventRecorder - -event.topics=argeo/suite/* \ No newline at end of file diff --git a/org.argeo.app.ui/config/footer.properties b/org.argeo.app.ui/config/footer.properties deleted file mode 100644 index 12aca56..0000000 --- a/org.argeo.app.ui/config/footer.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.suite.ui.footer diff --git a/org.argeo.app.ui/config/fsEntryArea.properties b/org.argeo.app.ui/config/fsEntryArea.properties deleted file mode 100644 index 0bceaf0..0000000 --- a/org.argeo.app.ui/config/fsEntryArea.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.library.ui.fsEntryArea diff --git a/org.argeo.app.ui/config/header.properties b/org.argeo.app.ui/config/header.properties deleted file mode 100644 index 034d5f5..0000000 --- a/org.argeo.app.ui/config/header.properties +++ /dev/null @@ -1,4 +0,0 @@ -service.pid=argeo.suite.ui.header -argeo.suite.ui=true - -argeo.suite.ui.header.title=%appTitle \ No newline at end of file diff --git a/org.argeo.app.ui/config/leadPane.properties b/org.argeo.app.ui/config/leadPane.properties deleted file mode 100644 index 0d7b193..0000000 --- a/org.argeo.app.ui/config/leadPane.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.suite.ui.leadPane diff --git a/org.argeo.app.ui/config/loginScreen.properties b/org.argeo.app.ui/config/loginScreen.properties deleted file mode 100644 index 332614d..0000000 --- a/org.argeo.app.ui/config/loginScreen.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.suite.ui.loginScreen diff --git a/org.argeo.app.ui/config/mapLayer.properties b/org.argeo.app.ui/config/mapLayer.properties deleted file mode 100644 index 37bf3c7..0000000 --- a/org.argeo.app.ui/config/mapLayer.properties +++ /dev/null @@ -1,6 +0,0 @@ -service.pid=argeo.geo.ui.mapLayer - -title=%map -icon=map - -entity.type=entity:geopoint diff --git a/org.argeo.app.ui/config/overviewMap.properties b/org.argeo.app.ui/config/overviewMap.properties deleted file mode 100644 index d842c98..0000000 --- a/org.argeo.app.ui/config/overviewMap.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.geo.ui.overviewMap diff --git a/org.argeo.app.ui/config/peopleEntryArea.properties b/org.argeo.app.ui/config/peopleEntryArea.properties deleted file mode 100644 index 37b28f9..0000000 --- a/org.argeo.app.ui/config/peopleEntryArea.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.people.ui.peopleEntryArea diff --git a/org.argeo.app.ui/config/peopleLayer.properties b/org.argeo.app.ui/config/peopleLayer.properties deleted file mode 100644 index adadb7b..0000000 --- a/org.argeo.app.ui/config/peopleLayer.properties +++ /dev/null @@ -1,7 +0,0 @@ -service.pid=argeo.people.ui.peopleLayer - -icon=people -weights=5000,5000 -title=%people - -entity.type=entity:person \ No newline at end of file diff --git a/org.argeo.app.ui/config/personUiProvider.properties b/org.argeo.app.ui/config/personUiProvider.properties deleted file mode 100644 index 8c40c7d..0000000 --- a/org.argeo.app.ui/config/personUiProvider.properties +++ /dev/null @@ -1,3 +0,0 @@ -service.pid=argeo.people.ui.personUiProvider - -entity.type=entity:person \ No newline at end of file diff --git a/org.argeo.app.ui/config/recentItems.properties b/org.argeo.app.ui/config/recentItems.properties deleted file mode 100644 index 7321c55..0000000 --- a/org.argeo.app.ui/config/recentItems.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.suite.ui.recentItems diff --git a/org.argeo.app.ui/config/termsEntryArea.properties b/org.argeo.app.ui/config/termsEntryArea.properties deleted file mode 100644 index cd31517..0000000 --- a/org.argeo.app.ui/config/termsEntryArea.properties +++ /dev/null @@ -1 +0,0 @@ -service.pid=argeo.suite.ui.termsEntryArea diff --git a/org.argeo.app.ui/config/termsLayer.properties b/org.argeo.app.ui/config/termsLayer.properties deleted file mode 100644 index 2c0532e..0000000 --- a/org.argeo.app.ui/config/termsLayer.properties +++ /dev/null @@ -1,5 +0,0 @@ -service.pid=argeo.suite.ui.termsLayer -title=Terms -icon=dashboard - -entity.type=entity:terms,entity:term \ No newline at end of file diff --git a/org.argeo.app.ui/config/wwwLayer.properties b/org.argeo.app.ui/config/wwwLayer.properties deleted file mode 100644 index d29fa5b..0000000 --- a/org.argeo.app.ui/config/wwwLayer.properties +++ /dev/null @@ -1,4 +0,0 @@ -service.pid=argeo.publishing.ui.wwwLayer - -title=Web -icon=map \ No newline at end of file diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultDashboard.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultDashboard.java deleted file mode 100644 index 50fbed6..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultDashboard.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.argeo.app.ui; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.api.cms.CmsView; -import org.argeo.cms.auth.CurrentUser; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.ui.CmsUiProvider; -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 = CmsSwtUtils.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; - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultEditionLayer.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultEditionLayer.java deleted file mode 100644 index 579157d..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultEditionLayer.java +++ /dev/null @@ -1,286 +0,0 @@ -package org.argeo.app.ui; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.api.cms.CmsTheme; -import org.argeo.app.ui.widgets.TabbedArea; -import org.argeo.cms.Localized; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.ui.CmsUiProvider; -import org.argeo.jcr.JcrException; -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; -import org.osgi.framework.BundleContext; -import org.osgi.framework.wiring.BundleWiring; - -/** An app layer based on an entry area and an editor area. */ -public class DefaultEditionLayer implements SuiteLayer { - private CmsUiProvider entryArea; - private CmsUiProvider defaultView; - private CmsUiProvider workArea; - private List weights = new ArrayList<>(); - private boolean startMaximized = false; - private boolean fixedEntryArea = false; - private boolean singleTab = false; - private Localized title = null; - - @Override - public Control createUi(Composite parent, Node context) throws RepositoryException { - // TODO Factorize more, or split into more specialised classes? - if (entryArea != null) { - if (fixedEntryArea) { - FixedEditionArea editionArea = new FixedEditionArea(parent, parent.getStyle()); - Control entryAreaC = entryArea.createUi(editionArea.getEntryArea(), context); - CmsSwtUtils.style(entryAreaC, SuiteStyle.entryArea); - if (this.defaultView != null) { - editionArea.getTabbedArea().view(defaultView, context); - } - return editionArea; - } else { - SashFormEditionArea editionArea = new SashFormEditionArea(parent, parent.getStyle()); - entryArea.createUi(editionArea.getEntryArea(), context); - if (this.defaultView != null) { - editionArea.getTabbedArea().view(defaultView, context); - } - return editionArea; - } - } else { - if (this.workArea != null) { - Composite area = new Composite(parent, SWT.NONE); - this.workArea.createUi(area, context); - return area; - } - CmsTheme theme = CmsSwtUtils.getCmsTheme(parent); - TabbedArea tabbedArea = createTabbedArea(parent, theme); - return tabbedArea; - } - } - - @Override - public void view(CmsUiProvider uiProvider, Composite workAreaC, Node context) { - if (workArea != null) { - try { - CmsSwtUtils.clear(workAreaC); - workArea.createUi(workAreaC, context); - workAreaC.layout(true, true); - return; - } catch (RepositoryException e) { - throw new JcrException("Cannot rebuild work area", e); - } - } - - // tabbed area - TabbedArea tabbedArea = findTabbedArea(workAreaC); - if (tabbedArea == null) - throw new IllegalArgumentException("Unsupported work area " + workAreaC.getClass().getName()); - if (uiProvider == null) { - // reset - tabbedArea.closeAllTabs(); - if (this.defaultView != null) { - tabbedArea.view(defaultView, context); - } - } else { - tabbedArea.view(uiProvider, context); - } - } - - @Override - public Node getCurrentContext(Composite workArea) { - TabbedArea tabbedArea = findTabbedArea(workArea); - if (tabbedArea == null) - return null; - return tabbedArea.getCurrentContext(); - } - - private TabbedArea findTabbedArea(Composite workArea) { - TabbedArea tabbedArea = null; - if (workArea instanceof SashFormEditionArea) { - tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea(); - } else if (workArea instanceof FixedEditionArea) { - tabbedArea = ((FixedEditionArea) workArea).getTabbedArea(); - } else if (workArea instanceof TabbedArea) { - tabbedArea = (TabbedArea) workArea; - } - return tabbedArea; - } - - @Override - public void open(CmsUiProvider uiProvider, Composite workArea, Node context) { - TabbedArea tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea(); - tabbedArea.open(uiProvider, context); - } - - @Override - public Localized getTitle() { - return title; - } - - public void init(BundleContext bundleContext, Map properties) { - weights = LangUtils.toStringList(properties.get(Property.weights.name())); - startMaximized = properties.containsKey(Property.startMaximized.name()) - && "true".equals(properties.get(Property.startMaximized.name())); - fixedEntryArea = properties.containsKey(Property.fixedEntryArea.name()) - && "true".equals(properties.get(Property.fixedEntryArea.name())); - if (fixedEntryArea && weights.size() != 0) { - throw new IllegalArgumentException("Property " + Property.weights.name() + " should not be set if property " - + Property.fixedEntryArea.name() + " is set."); - } - singleTab = properties.containsKey(Property.singleTab.name()) - && "true".equals(properties.get(Property.singleTab.name())); - - String titleStr = (String) properties.get(SuiteLayer.Property.title.name()); - if (titleStr != null) { - if (titleStr.startsWith("%")) { - title = new Localized() { - - @Override - public String name() { - return titleStr; - } - - @Override - public ClassLoader getL10nClassLoader() { - return bundleContext != null - ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader() - : getClass().getClassLoader(); - } - }; - } else { - title = new Localized.Untranslated(titleStr); - } - } - } - - public void destroy(BundleContext bundleContext, Map properties) { - - } - - public void setEntryArea(CmsUiProvider entryArea) { - this.entryArea = entryArea; - } - - public void setWorkArea(CmsUiProvider workArea) { - this.workArea = workArea; - } - - public void setDefaultView(CmsUiProvider defaultView) { - this.defaultView = defaultView; - } - - TabbedArea createTabbedArea(Composite parent, CmsTheme theme) { - TabbedArea tabbedArea = new TabbedArea(parent, SWT.NONE); - tabbedArea.setSingleTab(singleTab); - tabbedArea.setBodyStyle(SuiteStyle.mainTabBody.style()); - tabbedArea.setTabStyle(SuiteStyle.mainTab.style()); - tabbedArea.setTabSelectedStyle(SuiteStyle.mainTabSelected.style()); - tabbedArea.setCloseIcon(SuiteIcon.close.getSmallIcon(theme)); - tabbedArea.setLayoutData(CmsSwtUtils.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 TabbedArea tabbedArea; - private Composite entryC; - - SashFormEditionArea(Composite parent, int style) { - super(parent, SWT.HORIZONTAL); - CmsTheme theme = CmsSwtUtils.getCmsTheme(parent); - - Composite editorC; - if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc. - editorC = new Composite(this, SWT.BORDER); - entryC = new Composite(this, SWT.BORDER); - } else { - entryC = new Composite(this, SWT.NONE); - editorC = new Composite(this, SWT.NONE); - } - - // sash form specific - 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(editorC); - - GridLayout editorAreaLayout = CmsSwtUtils.noSpaceGridLayout(); -// editorAreaLayout.verticalSpacing = 0; -// editorAreaLayout.marginBottom = 0; -// editorAreaLayout.marginHeight = 0; -// editorAreaLayout.marginLeft = 0; -// editorAreaLayout.marginRight = 0; - editorC.setLayout(editorAreaLayout); - - tabbedArea = createTabbedArea(editorC, theme); - } - - TabbedArea getTabbedArea() { - return tabbedArea; - } - - Composite getEntryArea() { - return entryC; - } - - } - - class FixedEditionArea extends Composite { - private static final long serialVersionUID = -5525672639277322465L; - private TabbedArea tabbedArea; - private Composite entryC; - - public FixedEditionArea(Composite parent, int style) { - super(parent, style); - CmsTheme theme = CmsSwtUtils.getCmsTheme(parent); - - setLayout(CmsSwtUtils.noSpaceGridLayout(2)); - - Composite editorC; - if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc. - editorC = new Composite(this, SWT.NONE); - entryC = new Composite(this, SWT.NONE); - } else { - entryC = new Composite(this, SWT.NONE); - editorC = new Composite(this, SWT.NONE); - } - entryC.setLayoutData(CmsSwtUtils.fillHeight()); - - GridLayout editorAreaLayout = CmsSwtUtils.noSpaceGridLayout(); -// editorAreaLayout.verticalSpacing = 0; -// editorAreaLayout.marginBottom = 0; -// editorAreaLayout.marginHeight = 0; -// editorAreaLayout.marginLeft = 0; -// editorAreaLayout.marginRight = 0; - editorC.setLayout(editorAreaLayout); - editorC.setLayoutData(CmsSwtUtils.fillAll()); - - tabbedArea = createTabbedArea(editorC, theme); - } - - TabbedArea getTabbedArea() { - return tabbedArea; - } - - Composite getEntryArea() { - return entryC; - } - } - -} \ No newline at end of file diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultFooter.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultFooter.java deleted file mode 100644 index 62a3a23..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultFooter.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.argeo.app.ui; - -import java.util.Map; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.ui.CmsUiProvider; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.osgi.framework.BundleContext; - -/** Footer of a standard Argeo Suite application. */ -public class DefaultFooter implements CmsUiProvider { - @Override - public Control createUi(Composite parent, Node context) throws RepositoryException { - parent.setLayout(CmsSwtUtils.noSpaceGridLayout()); - Composite content = new Composite(parent, SWT.NONE); - content.setLayoutData(new GridData(0, 0)); - Control contentControl = createContent(content, context); - - // TODO support and guarantee - - return contentControl; - } - - protected Control createContent(Composite parent, Node context) throws RepositoryException { - return parent; - } - - public void init(BundleContext bundleContext, Map properties) { - } - - public void destroy(BundleContext bundleContext, Map properties) { - - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultHeader.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultHeader.java deleted file mode 100644 index d304493..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultHeader.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.argeo.app.ui; - -import java.util.Map; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.api.cms.CmsTheme; -import org.argeo.api.cms.CmsView; -import org.argeo.cms.Localized; -import org.argeo.cms.auth.CurrentUser; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.ui.CmsUiProvider; -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.framework.BundleContext; -import org.osgi.framework.wiring.BundleWiring; - -/** Header of a standard Argeo Suite application. */ -public class DefaultHeader implements CmsUiProvider { - public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title"; - private Localized title = null; - - @Override - public Control createUi(Composite parent, Node context) throws RepositoryException { - CmsView cmsView = CmsSwtUtils.getCmsView(parent); - CmsTheme theme = CmsSwtUtils.getCmsTheme(parent); - - parent.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, true))); - - // TODO right to left - Composite lead = new Composite(parent, SWT.NONE); - CmsSwtUtils.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); -// // TODO expose the localized -// lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString() -// : title); - lbl.setText(title.lead()); - CmsSwtUtils.style(lbl, SuiteStyle.headerTitle); - lbl.setLayoutData(CmsSwtUtils.fillWidth()); - - Composite middle = new Composite(parent, SWT.NONE); - CmsSwtUtils.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); - CmsSwtUtils.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); - CmsSwtUtils.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(BundleContext bundleContext, Map properties) { - String titleStr = (String) properties.get(TITLE_PROPERTY); - if (titleStr != null) { - if (titleStr.startsWith("%")) { - title = new Localized() { - - @Override - public String name() { - return titleStr; - } - - @Override - public ClassLoader getL10nClassLoader() { - return bundleContext != null - ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader() - : getClass().getClassLoader(); - } - }; - } else { - title = new Localized.Untranslated(titleStr); - } - } - } - - public void destroy(BundleContext bundleContext, Map properties) { - - } - - public Localized getTitle() { - return title; - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLeadPane.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLeadPane.java deleted file mode 100644 index 5650e9c..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLeadPane.java +++ /dev/null @@ -1,187 +0,0 @@ -package org.argeo.app.ui; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.api.cms.CmsView; -import org.argeo.app.api.RankedObject; -import org.argeo.app.core.SuiteUtils; -import org.argeo.api.cms.CmsLog; -import org.argeo.cms.Localized; -import org.argeo.cms.auth.CurrentUser; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.ui.CmsUiProvider; -import org.eclipse.swt.SWT; -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.osgi.framework.BundleContext; -import org.osgi.framework.Constants; -import org.osgi.framework.wiring.BundleWiring; - -/** Side pane listing various perspectives. */ -public class DefaultLeadPane implements CmsUiProvider { - private final static CmsLog log = CmsLog.getLog(DefaultLeadPane.class); - - public static enum Property { - defaultLayers, adminLayers; - } - - private Map> layers = Collections.synchronizedSortedMap(new TreeMap<>()); - private List defaultLayers; - private List adminLayers = new ArrayList<>(); - - private ClassLoader l10nClassLoader; - - @Override - public Control createUi(Composite parent, Node node) throws RepositoryException { - CmsView cmsView = CmsSwtUtils.getCmsView(parent); - parent.setLayout(CmsSwtUtils.noSpaceGridLayout()); - Composite appLayersC = new Composite(parent, SWT.NONE); - CmsSwtUtils.style(appLayersC, SuiteStyle.leadPane); - GridLayout layout = new GridLayout(); - layout.verticalSpacing = 10; - layout.marginTop = 10; - layout.marginLeft = 10; - layout.marginRight = 10; - appLayersC.setLayout(layout); - appLayersC.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); - - Composite adminLayersC; - if (!adminLayers.isEmpty()) { - adminLayersC = new Composite(parent, SWT.NONE); - CmsSwtUtils.style(adminLayersC, SuiteStyle.leadPane); - GridLayout adminLayout = new GridLayout(); - adminLayout.verticalSpacing = 10; - adminLayout.marginBottom = 10; - adminLayout.marginLeft = 10; - adminLayout.marginRight = 10; - adminLayersC.setLayout(adminLayout); - adminLayersC.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, false, true)); - } else { - adminLayersC = null; - } - -// boolean isAdmin = cmsView.doAs(() -> CurrentUser.isInRole(NodeConstants.ROLE_USER_ADMIN)); - Set userRoles = cmsView.doAs(() -> CurrentUser.roles()); - Button first = null; - layers: for (String layerDef : defaultLayers) { - layerDef = layerDef.trim(); - if ("".equals(layerDef)) - continue layers;// skip empty lines - String[] semiColArr = layerDef.split(";"); - String layerId = semiColArr[0]; - Set layerRoles = SuiteUtils.extractRoles(semiColArr); - if (layers.containsKey(layerId)) { - if (!layerRoles.isEmpty()) { - Set intersection = new HashSet(layerRoles); - intersection.retainAll(userRoles); - if (intersection.isEmpty()) - continue layers;// skip unauthorized layer - } - RankedObject layerObj = layers.get(layerId); - - Localized title = null; - if (!adminLayers.contains(layerId)) { - String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name()); - if (titleStr != null) { - if (titleStr.startsWith("%")) { - // LocaleUtils.local(titleStr, getClass().getClassLoader()); - title = () -> titleStr; - } else { - 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); - - Composite buttonParent; - if (adminLayers.contains(layerId)) - buttonParent = adminLayersC; - else - buttonParent = appLayersC; - Button b = SuiteUiUtils.createLayerButton(buttonParent, layerId, title, icon, l10nClassLoader); - if (first == null) - first = b; - } - } - return first; - } - - public void init(BundleContext bundleContext, Map properties) { - l10nClassLoader = bundleContext != null ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader() - : getClass().getClassLoader(); - - String[] defaultLayers = (String[]) properties.get(Property.defaultLayers.toString()); - if (defaultLayers == null) - throw new IllegalArgumentException("Default layers must be set."); - this.defaultLayers = Arrays.asList(defaultLayers); - if (log.isDebugEnabled()) - log.debug("Default layers: " + Arrays.asList(defaultLayers)); - String[] adminLayers = (String[]) properties.get(Property.adminLayers.toString()); - if (adminLayers != null) { - this.adminLayers = Arrays.asList(adminLayers); - if (log.isDebugEnabled()) - log.debug("Admin layers: " + Arrays.asList(adminLayers)); - } - } - - public void destroy(BundleContext bundleContext, Map properties) { - - } - - public void addLayer(SuiteLayer layer, Map 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 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(layer, properties))) { - layers.remove(pid); - } - } - } - } - -// protected 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.CENTER); -// CmsUiUtils.style(lbl, SuiteStyle.leadPane); -// // CmsUiUtils.markup(lbl); -// ClassLoader l10nClassLoader = getClass().getClassLoader(); -// String txt = LocaleUtils.lead(msg, l10nClassLoader); -//// String txt = msg.lead(); -// lbl.setText(txt); -// lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false)); -// } -// CmsUiUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer); -// return button; -// } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLoginScreen.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLoginScreen.java deleted file mode 100644 index e9b466f..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLoginScreen.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.argeo.app.ui; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.api.cms.CmsContext; -import org.argeo.api.cms.CmsView; -import org.argeo.cms.auth.CurrentUser; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.swt.auth.CmsLogin; -import org.argeo.cms.ui.CmsUiProvider; -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 { - private CmsContext cmsContext; - - @Override - public Control createUi(Composite parent, Node context) throws RepositoryException { - CmsView cmsView = CmsSwtUtils.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, cmsContext); - cmsLogin.createUi(loginArea); - return cmsLogin.getCredentialsBlock(); - } - - public void setCmsContext(CmsContext cmsContext) { - this.cmsContext = cmsContext; - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/EventRecorder.java b/org.argeo.app.ui/src/org/argeo/app/ui/EventRecorder.java deleted file mode 100644 index 0607952..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/EventRecorder.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.argeo.app.ui; - -import org.argeo.api.cms.CmsLog; -import org.osgi.service.event.Event; -import org.osgi.service.event.EventHandler; - -/** Record UI events. */ -public class EventRecorder implements EventHandler { - private final static CmsLog log = CmsLog.getLog(EventRecorder.class); - - public void init() { - - } - - public void destroy() { - - } - - @Override - public void handleEvent(Event event) { - if (log.isTraceEnabled()) - log.trace(event); - - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/RecentItems.java b/org.argeo.app.ui/src/org/argeo/app/ui/RecentItems.java deleted file mode 100644 index c4272e6..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/RecentItems.java +++ /dev/null @@ -1,364 +0,0 @@ -package org.argeo.app.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.api.cms.CmsTheme; -import org.argeo.app.api.EntityType; -import org.argeo.app.core.XPathUtils; -import org.argeo.app.ui.widgets.DelayedText; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.ui.CmsUiProvider; -import org.argeo.eclipse.ui.EclipseUiUtils; -import org.argeo.jcr.Jcr; -import org.argeo.jcr.JcrUtils; -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.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 = CmsSwtUtils.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(CmsSwtUtils.fillAll()); - - Composite bottom = new Composite(parent, SWT.NONE); - bottom.setLayoutData(CmsSwtUtils.fillWidth()); - bottom.setLayout(CmsSwtUtils.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) - CmsSwtUtils.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) { - CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(), - SuiteEvent.eventProperties(node)); - deleteItem.setEnabled(true); - } else { - deleteItem.setEnabled(false); - } - } - }); - - return entityViewer.filterTxt; - - } - - public void init(Map 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.addListener((s) -> refreshFilteredList()); -// 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 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) newInput; - } - - public Object[] getElements(Object arg0) { - return nodes.toArray(); - } - } - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteApp.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteApp.java deleted file mode 100644 index e4d40cf..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteApp.java +++ /dev/null @@ -1,642 +0,0 @@ -package org.argeo.app.ui; - -import static org.argeo.api.cms.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.Objects; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; -import javax.naming.InvalidNameException; -import javax.naming.ldap.LdapName; - -import org.argeo.api.cms.CmsSession; -import org.argeo.api.cms.CmsTheme; -import org.argeo.api.cms.CmsUi; -import org.argeo.api.cms.CmsView; -import org.argeo.app.api.EntityConstants; -import org.argeo.app.api.EntityNames; -import org.argeo.app.api.EntityType; -import org.argeo.app.api.RankedObject; -import org.argeo.app.core.SuiteUtils; -import org.argeo.api.cms.CmsLog; -import org.argeo.cms.AbstractCmsApp; -import org.argeo.cms.CmsUserManager; -import org.argeo.cms.LocaleUtils; -import org.argeo.cms.Localized; -import org.argeo.cms.jcr.CmsJcrUtils; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.swt.dialogs.CmsFeedback; -import org.argeo.cms.ui.CmsUiProvider; -import org.argeo.eclipse.ui.specific.UiContext; -import org.argeo.jcr.Jcr; -import org.argeo.jcr.JcrException; -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 CmsLog log = CmsLog.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"; - public final static String DEFAULT_LAYER_PROPERTY = "defaultLayer"; - private final static String LOGIN = "login"; - private final static String HOME_STATE = "~"; - - private String publicBasePath = null; - - private String pidPrefix; - private String headerPid; - private String footerPid; - private String leadPanePid; - private String adminLeadPanePid; - private String loginScreenPid; - - private String defaultUiName = "app"; - private String adminUiName = "admin"; - - // FIXME such default names make refactoring more dangerous - @Deprecated - private String defaultLayerPid = "argeo.suite.ui.dashboardLayer"; - @Deprecated - private String defaultThemeId = "org.argeo.app.theme.default"; - - private Map> uiProvidersByPid = Collections.synchronizedMap(new HashMap<>()); - private Map> uiProvidersByType = Collections.synchronizedMap(new HashMap<>()); - private Map> layersByPid = Collections.synchronizedSortedMap(new TreeMap<>()); - private Map> layersByType = Collections.synchronizedSortedMap(new TreeMap<>()); - - private CmsUserManager cmsUserManager; - - // TODO make more optimal or via CmsSession/CmsView - private Map managedUis = new HashMap<>(); - - private Repository repository; - - public void init(Map 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); - if (properties.containsKey(DEFAULT_LAYER_PROPERTY)) - defaultLayerPid = LangUtils.get(properties, DEFAULT_LAYER_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"; - footerPid = pidPrefix + "footer"; - leadPanePid = pidPrefix + "leadPane"; - adminLeadPanePid = pidPrefix + "adminLeadPane"; - loginScreenPid = pidPrefix + "loginScreen"; - } - - public void destroy(Map properties) { - for (SuiteUi ui : managedUis.values()) - if (!ui.isDisposed()) - ui.dispose(); - if (log.isDebugEnabled()) - log.info("Argeo Suite App stopped"); - - } - - @Override - public Set getUiNames() { - HashSet uiNames = new HashSet<>(); - uiNames.add(defaultUiName); - uiNames.add(adminUiName); - return uiNames; - } - - @Override - public CmsUi initUi(Object parent) { - Composite uiParent = (Composite) parent; - String uiName = uiParent.getData(UI_NAME_PROPERTY) != null ? uiParent.getData(UI_NAME_PROPERTY).toString() - : null; - CmsView cmsView = CmsSwtUtils.getCmsView(uiParent); - if (cmsView == null) - throw new IllegalStateException("No CMS view is registered."); - CmsTheme theme = getTheme(uiName); - if (theme != null) - CmsSwtUtils.registerCmsTheme(uiParent.getShell(), theme); - SuiteUi argeoSuiteUi = new SuiteUi(uiParent, 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."); - }); - return argeoSuiteUi; - } - - @Override - public String getThemeId(String uiName) { - String themeId = System.getProperty("org.argeo.app.theme.default"); - if (themeId != null) - return themeId; - return defaultThemeId; - } - - @Override - public void refreshUi(CmsUi cmsUi, String state) { - try { - Node context = null; - SuiteUi ui = (SuiteUi) cmsUi; - - String uiName = Objects.toString(ui.getParent().getData(UI_NAME_PROPERTY), null); - if (uiName == null) - throw new IllegalStateException("UI name should not be null"); - CmsView cmsView = CmsSwtUtils.getCmsView(ui); - CmsUiProvider headerUiProvider = findUiProvider(headerPid); - CmsUiProvider footerUiProvider = findUiProvider(footerPid); - CmsUiProvider leadPaneUiProvider; - if (adminUiName.equals(uiName)) { - leadPaneUiProvider = findUiProvider(adminLeadPanePid); - } else { - leadPaneUiProvider = findUiProvider(leadPanePid); - } - - Localized appTitle = null; - if (headerUiProvider instanceof DefaultHeader) { - appTitle = ((DefaultHeader) headerUiProvider).getTitle(); - } - ui.setTitle(appTitle); - - if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login - ui.logout(); - if (headerUiProvider != null) - refreshPart(headerUiProvider, ui.getHeader(), context); - ui.refreshBelowHeader(false); - refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context); - if (footerUiProvider != null) - refreshPart(footerUiProvider, ui.getFooter(), context); - ui.layout(true, true); - setState(ui, LOGIN); - } else { - if (LOGIN.equals(state)) - state = null; - CmsSession cmsSession = cmsView.getCmsSession(); - if (ui.getUserDir() == null) { - // FIXME NPE on CMSSession when logging in from anonymous - if (cmsSession == null || cmsView.isAnonymous()) { - assert publicBasePath != null; - ui.initSessions(getRepository(), publicBasePath); - } else { - Session adminSession = null; - try { - adminSession = CmsJcrUtils.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(); - - if (headerUiProvider != null) - refreshPart(headerUiProvider, ui.getHeader(), context); - ui.refreshBelowHeader(true); - for (String key : layersByPid.keySet()) { - SuiteLayer layer = layersByPid.get(key).get(); - ui.addLayer(key, layer); - } - - if (leadPaneUiProvider != null) - refreshPart(leadPaneUiProvider, ui.getLeadPane(), context); - if (footerUiProvider != null) - refreshPart(footerUiProvider, ui.getFooter(), context); - ui.layout(true, true); - setState(ui, state != null ? state : defaultLayerPid); - } - } 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) { - CmsSwtUtils.clear(part); - uiProvider.createUiPart(part, context); - } - - private CmsUiProvider findUiProvider(String pid) { - if (!uiProvidersByPid.containsKey(pid)) - return null; - return uiProvidersByPid.get(pid).get(); - } - - private SuiteLayer findLayer(String pid) { - if (!layersByPid.containsKey(pid)) - return null; - return layersByPid.get(pid).get(); - } - - private T findByType(Map> byType, Node context) { - if (context == null) - throw new IllegalArgumentException("A node should be provided"); - try { - // mixins - Set types = new TreeSet<>(); - for (NodeType mixinType : context.getMixinNodeTypes()) { - String mixinTypeName = mixinType.getName(); - if (byType.containsKey(mixinTypeName)) { - types.add(mixinTypeName); - } - for (NodeType superType : mixinType.getDeclaredSupertypes()) { - if (byType.containsKey(superType.getName())) { - types.add(superType.getName()); - } - } - } - // primary node type - NodeType primaryType = context.getPrimaryNodeType(); - String primaryTypeName = primaryType.getName(); - if (byType.containsKey(primaryTypeName)) { - types.add(primaryTypeName); - } - for (NodeType superType : primaryType.getDeclaredSupertypes()) { - if (byType.containsKey(superType.getName())) { - types.add(superType.getName()); - } - } - // entity type - if (context.isNodeType(EntityType.entity.get())) { - if (context.hasProperty(EntityNames.ENTITY_TYPE)) { - String entityTypeName = context.getProperty(EntityNames.ENTITY_TYPE).getString(); - if (byType.containsKey(entityTypeName)) { - types.add(entityTypeName); - } - } - } - -// if (context.getPath().equals("/")) {// root node -// types.add("nt:folder"); -// } - if (CmsJcrUtils.isUserHome(context) && byType.containsKey("nt:folder")) {// home node - types.add("nt:folder"); - } - - if (types.size() == 0) - throw new IllegalArgumentException("No type found for " + context + " (" + listTypes(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); - } - } - - private static String listTypes(Node context) { - try { - StringBuilder sb = new StringBuilder(); - sb.append(context.getPrimaryNodeType().getName()); - for (NodeType superType : context.getPrimaryNodeType().getDeclaredSupertypes()) { - sb.append(' '); - sb.append(superType.getName()); - } - - for (NodeType nodeType : context.getMixinNodeTypes()) { - sb.append(' '); - sb.append(nodeType.getName()); - if (nodeType.getName().equals(EntityType.local.get())) - sb.append('/').append(context.getProperty(EntityNames.ENTITY_TYPE).getString()); - for (NodeType superType : nodeType.getDeclaredSupertypes()) { - sb.append(' '); - sb.append(superType.getName()); - } - } - return sb.toString(); - } catch (RepositoryException e) { - throw new JcrException(e); - } - } - - @Override - public void setState(CmsUi cmsUi, String state) { - if (state == null) - return; - if (!state.startsWith("/")) { - if (cmsUi instanceof SuiteUi) { - SuiteUi ui = (SuiteUi) cmsUi; - if (LOGIN.equals(state)) { - String appTitle = ""; - if (ui.getTitle() != null) - appTitle = ui.getTitle().lead(); - ui.getCmsView().stateChanged(state, appTitle); - return; - } - Map properties = new HashMap<>(); - String layerId = HOME_STATE.equals(state) ? defaultLayerPid : state; - properties.put(SuiteEvent.LAYER, layerId); - properties.put(SuiteEvent.NODE_PATH, HOME_STATE); - ui.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), properties); - } - return; - } - SuiteUi suiteUi = (SuiteUi) cmsUi; - Node node = stateToNode(suiteUi, state); - if (node == null) { - suiteUi.getCmsView().navigateTo(HOME_STATE); - } else { - suiteUi.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), SuiteEvent.eventProperties(node)); - suiteUi.getCmsView().sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(node)); - } - } - - // TODO move it to an internal package? - static 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 appTitle = ""; - if (ui.getTitle() != null) - appTitle = ui.getTitle().lead() + " - "; - -// String currentLayerId = ui.getCurrentLayerId(); -// SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null; - if (SuiteUiUtils.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), appTitle + Jcr.getTitle(node)); - } else if (SuiteUiUtils.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), appTitle + Jcr.getTitle(node)); - } else if (SuiteUiUtils.isTopic(event, SuiteEvent.switchLayer)) { - String layerId = get(event, SuiteEvent.LAYER); - if (layerId != null) { -// ui.switchToLayer(layerId, ui.getUserDir()); - SuiteLayer suiteLayer = findLayer(layerId); - if (suiteLayer == null) - throw new IllegalArgumentException("No layer '" + layerId + "' available."); - Localized layerTitle = suiteLayer.getTitle(); - // FIXME make sure we don't rebuild the work area twice - Composite workArea = ui.getCmsView().doAs(() -> ui.switchToLayer(layerId, ui.getUserDir())); - String title = null; - if (layerTitle != null) - title = layerTitle.lead(); - Node nodeFromState = getNode(ui, event); - if (nodeFromState != null && nodeFromState.getPath().equals(ui.getUserDir().getPath())) { - // default layer view is forced - String state = defaultLayerPid.equals(layerId) ? "~" : layerId; - ui.getCmsView().stateChanged(state, appTitle + title); - suiteLayer.view(null, workArea, nodeFromState); - } else { - Node layerCurrentContext = suiteLayer.getCurrentContext(workArea); - if (layerCurrentContext != null) { - // layer was already showing a context so we set the state to it - ui.getCmsView().stateChanged(nodeToState(layerCurrentContext), - appTitle + Jcr.getTitle(layerCurrentContext)); - } else { - // no context was shown - ui.getCmsView().stateChanged(layerId, appTitle + title); - } - } - } 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); - if (nodePath != null && nodePath.equals(HOME_STATE)) - return ui.getUserDir(); - 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 = CmsJcrUtils.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)); - } - - public 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 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 types = LangUtils.toStringList(properties.get(EntityConstants.TYPE)); - for (String type : types) - RankedObject.putIfHigherRank(uiProvidersByType, type, uiProvider, properties); - } - } - - public void removeUiProvider(CmsUiProvider uiProvider, Map 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(uiProvider, properties))) { - uiProvidersByPid.remove(pid); - } - } - } - if (properties.containsKey(EntityConstants.TYPE)) { - List types = LangUtils.toStringList(properties.get(EntityConstants.TYPE)); - for (String type : types) { - if (uiProvidersByType.containsKey(type)) { - if (uiProvidersByType.get(type).equals(new RankedObject(uiProvider, properties))) { - uiProvidersByType.remove(type); - } - } - } - } - } - - public void addLayer(SuiteLayer layer, Map 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 types = LangUtils.toStringList(properties.get(EntityConstants.TYPE)); - for (String type : types) - RankedObject.putIfHigherRank(layersByType, type, layer, properties); - } - } - - public void removeLayer(SuiteLayer layer, Map 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(layer, properties))) { - layersByPid.remove(pid); - } - } - } - if (properties.containsKey(EntityConstants.TYPE)) { - List types = LangUtils.toStringList(properties.get(EntityConstants.TYPE)); - for (String type : types) { - if (layersByType.containsKey(type)) { - if (layersByType.get(type).equals(new RankedObject(layer, properties))) { - layersByType.remove(type); - } - } - } - } - } - - public void setCmsUserManager(CmsUserManager cmsUserManager) { - this.cmsUserManager = cmsUserManager; - } - - public Repository getRepository() { - return repository; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteEvent.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteEvent.java deleted file mode 100644 index 6eaa607..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.argeo.app.ui; - -import java.util.HashMap; -import java.util.Map; - -import javax.jcr.Node; - -import org.argeo.api.cms.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 eventProperties(Node node) { - Map properties = new HashMap<>(); - properties.put(NODE_PATH, Jcr.getPath(node)); - properties.put(WORKSPACE, Jcr.getWorkspaceName(node)); - return properties; - } - - public static Map eventProperties(User user) { - Map properties = new HashMap<>(); - properties.put(USERNAME, user.getName()); - return properties; - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteIcon.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteIcon.java deleted file mode 100644 index bfc92c3..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteIcon.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.argeo.app.ui; - -import org.argeo.cms.swt.CmsIcon; - -/** Icon names used by Argeo Suite. */ -public enum SuiteIcon implements CmsIcon { - add, save, close, closeAll, search, delete, logout, dashboard, - // people - people, person, organisation, - // library - documents, document, folder, - // admin and settings - settings, user, - // misc - task, tag, location, inbox, map; -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteLayer.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteLayer.java deleted file mode 100644 index a92994f..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteLayer.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.argeo.app.ui; - -import javax.jcr.Node; - -import org.argeo.cms.Localized; -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, singleTab, fixedEntryArea; - } - - void view(CmsUiProvider uiProvider, Composite workArea, Node context); - - Node getCurrentContext(Composite workArea); - - default void open(CmsUiProvider uiProvider, Composite workArea, Node context) { - view(uiProvider, workArea, context); - } - - default Localized getTitle() { - return null; - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteMsg.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteMsg.java deleted file mode 100644 index fae15df..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteMsg.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.argeo.app.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; -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteStyle.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteStyle.java deleted file mode 100644 index 7afd23c..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteStyle.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.argeo.app.ui; - -import org.argeo.api.cms.CmsStyle; - -/** Styles used by Argeo Suite work UI. */ -public enum SuiteStyle implements CmsStyle { - // header - header, headerTitle, headerMenu, headerMenuItem, - // footer - footer, - // recent items - recentItems, - // lead pane - leadPane, leadPaneItem, leadPaneSectionTitle, leadPaneSubSectionTitle, - // entry area - entryArea, - // 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"; - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUi.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUi.java deleted file mode 100644 index b2e4385..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUi.java +++ /dev/null @@ -1,258 +0,0 @@ -package org.argeo.app.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.argeo.api.cms.CmsUi; -import org.argeo.api.cms.CmsView; -import org.argeo.api.cms.CmsLog; -import org.argeo.api.cms.CmsConstants; -import org.argeo.cms.Localized; -import org.argeo.cms.swt.CmsSwtUtils; -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 implements CmsUi { - private static final long serialVersionUID = 6207018859086689108L; - private final static CmsLog log = CmsLog.getLog(SuiteUi.class); - - private Localized title; - private Composite header; - private Composite footer; - private Composite belowHeader; - private Composite leadPane; - private Composite sidePane; - private Composite dynamicArea; - - private Session sysSession; - private Session homeSession; - private Node userDir; - - private Map layers = new HashMap<>(); - private Map workAreas = new HashMap<>(); - private String currentLayerId = null; - - private CmsView cmsView; - - public SuiteUi(Composite parent, int style) { - super(parent, style); - cmsView = CmsSwtUtils.getCmsView(parent); - this.setLayout(CmsSwtUtils.noSpaceGridLayout()); - - header = new Composite(this, SWT.NONE); - header.setLayout(CmsSwtUtils.noSpaceGridLayout()); - CmsSwtUtils.style(header, SuiteStyle.header); - header.setLayoutData(CmsSwtUtils.fillWidth()); - - belowHeader = new Composite(this, SWT.NONE); - belowHeader.setLayoutData(CmsSwtUtils.fillAll()); - - footer = new Composite(this, SWT.NONE); - footer.setLayout(CmsSwtUtils.noSpaceGridLayout()); - CmsSwtUtils.style(footer, SuiteStyle.footer); - footer.setLayoutData(CmsSwtUtils.fillWidth()); - } - - public void refreshBelowHeader(boolean initApp) { - CmsSwtUtils.clear(belowHeader); - int style = getStyle(); - if (initApp) { - belowHeader.setLayout(CmsSwtUtils.noSpaceGridLayout(3)); - - if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc. - sidePane = new Composite(belowHeader, SWT.NONE); - sidePane.setLayout(CmsSwtUtils.noSpaceGridLayout()); - sidePane.setLayoutData(CmsSwtUtils.fillHeight()); - 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); - sidePane = new Composite(belowHeader, SWT.NONE); - sidePane.setLayout(CmsSwtUtils.noSpaceGridLayout()); - sidePane.setLayoutData(CmsSwtUtils.fillHeight()); - } - leadPane.setLayoutData(CmsSwtUtils.fillHeight()); - leadPane.setLayout(CmsSwtUtils.noSpaceGridLayout()); - CmsSwtUtils.style(leadPane, SuiteStyle.leadPane); - - dynamicArea.setLayoutData(CmsSwtUtils.fillAll()); - dynamicArea.setLayout(new FormLayout()); - - } else { - belowHeader.setLayout(CmsSwtUtils.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)); - CmsSwtUtils.style(workArea, SuiteStyle.workArea); - workArea.setLayoutData(CmsSwtUtils.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 getFooter() { - return footer; - } - - Composite getLeadPane() { - return leadPane; - } - - Composite getSidePane() { - return sidePane; - } - - 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(CmsConstants.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 (CmsConstants.SYS_WORKSPACE.equals(workspaceName)) - return sysSession; - else if (CmsConstants.HOME_WORKSPACE.equals(workspaceName)) - return homeSession; - else - throw new IllegalArgumentException("Unknown workspace " + workspaceName); - } - - public CmsView getCmsView() { - return cmsView; - } - - public Localized getTitle() { - return title; - } - - public void setTitle(Localized title) { - this.title = title; - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java deleted file mode 100644 index 504fbd2..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java +++ /dev/null @@ -1,454 +0,0 @@ -package org.argeo.app.ui; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Paths; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.io.IOUtils; -import org.argeo.api.cms.CmsEditable; -import org.argeo.api.cms.CmsEvent; -import org.argeo.api.cms.CmsStyle; -import org.argeo.api.cms.CmsTheme; -import org.argeo.api.cms.CmsView; -import org.argeo.app.api.EntityNames; -import org.argeo.app.api.EntityType; -import org.argeo.app.api.SuiteRole; -import org.argeo.cms.LocaleUtils; -import org.argeo.cms.Localized; -import org.argeo.cms.auth.CurrentUser; -import org.argeo.cms.swt.CmsIcon; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.swt.dialogs.LightweightDialog; -import org.argeo.cms.ui.util.CmsLink; -import org.argeo.cms.ui.util.CmsUiUtils; -import org.argeo.eclipse.ui.EclipseUiUtils; -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; -import org.osgi.service.event.Event; - -/** 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(CmsSwtUtils.fillWidth()); - CmsSwtUtils.style(titleBar, SuiteStyle.titleContainer); - - titleBar.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(2, false))); - Label titleLbl = new Label(titleBar, SWT.NONE); - titleLbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); - CmsSwtUtils.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)); - CmsSwtUtils.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)); - CmsSwtUtils.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)); - CmsSwtUtils.style(txt, SuiteStyle.simpleText); - return txt; - } - - public static Text addFormInputField(Composite parent, String placeholder) { - Text txt = new Text(parent, SWT.BORDER); - - GridData gridData = CmsSwtUtils.fillWidth(); - txt.setLayoutData(gridData); - - if (placeholder != null) - txt.setText(placeholder); - - CmsSwtUtils.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)); - CmsSwtUtils.style(lineComposite, SuiteStyle.formLine); - addFormLabel(lineComposite, label); - Text txt = addFormTextField(lineComposite, text, null); - txt.setEditable(false); - txt.setLayoutData(CmsSwtUtils.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)); - CmsSwtUtils.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(CmsSwtUtils.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)); - CmsSwtUtils.style(lineComposite, SuiteStyle.formLine); - addFormLabel(lineComposite, label); - Text txt = addFormInputField(lineComposite, placeholder); - txt.setLayoutData(CmsSwtUtils.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)); - CmsSwtUtils.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(CmsSwtUtils.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(CmsSwtUtils.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(CmsSwtUtils.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)); - CmsSwtUtils.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 { - return addPicture(parent, fileNode, maxWidth, null); - } - - public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth, Node link) - throws RepositoryException { - Node content = fileNode.getNode(Node.JCR_CONTENT); - - boolean test = false; - if (test) { - try (InputStream in = JcrUtils.getFileAsStream(fileNode); - OutputStream out = Files.newOutputStream(Paths.get("/home/mbaudier/tmp/" + fileNode.getName()));) { -// BufferedImage img = ImageIO.read(in); -// System.out.println(fileNode.getName() + ": width=" + img.getWidth() + ", height=" + img.getHeight()); - IOUtils.copy(in, out); - } catch (IOException e) { - throw new RuntimeException(e); - } - -// try (InputStream in = JcrUtils.getFileAsStream(fileNode);) { -// ImageData imageData = new ImageData(in); -// System.out.println(fileNode.getName() + ": width=" + imageData.width + ", height=" + imageData.height); -// } catch (IOException e) { -// throw new RuntimeException(e); -// } - } - // 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); - CmsSwtUtils.markup(img); - StringBuffer txt = new StringBuffer(); - String target = toLink(link); - if (target != null) - txt.append(""); - txt.append(CmsUiUtils.img(fileNode, width.toString(), height.toString())); - if (target != null) - txt.append(""); - img.setText(txt.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); - } - - if (target == null) - 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(CmsSwtUtils.fillAll()); - scroll.setLayout(CmsSwtUtils.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(CmsSwtUtils.fillAll()); - Label bigImg = new Label(c, SWT.NONE); - CmsSwtUtils.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 String toLink(Node node) { - return node != null ? "#" + CmsUiUtils.cleanPathForUrl(SuiteApp.nodeToState(node)) : null; - } - - public static Control addLink(Composite parent, String label, Node node, CmsStyle style) - throws RepositoryException { - String target = toLink(node); - CmsLink link = new CmsLink(label, target, style); - return link.createUi(parent, node); - } - - public static Control addExternalLink(Composite parent, String label, String url, String plainCssAnchorClass, - boolean newWindow) throws RepositoryException { - Label lbl = new Label(parent, SWT.NONE); - CmsSwtUtils.markup(lbl); - StringBuilder txt = new StringBuilder(); - txt.append(""); - txt.append(label); - txt.append(""); - lbl.setText(txt.toString()); - return lbl; - } - - public static boolean isCoworker(CmsView cmsView) { - boolean coworker = cmsView.doAs(() -> CurrentUser.isInRole(SuiteRole.coworker.dn())); - return coworker; - } - - public static boolean isTopic(Event event, CmsEvent cmsEvent) { - return event.getTopic().equals(cmsEvent.topic()); - } - - public static Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon, - ClassLoader l10nClassLoader) { - CmsTheme theme = CmsSwtUtils.getCmsTheme(parent); - Button button = new Button(parent, SWT.PUSH); - CmsSwtUtils.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.CENTER); - CmsSwtUtils.style(lbl, SuiteStyle.leadPane); - String txt = LocaleUtils.lead(msg, l10nClassLoader); -// String txt = msg.lead(); - lbl.setText(txt); - lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false)); - } - CmsSwtUtils.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); -// } -// } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/TermsEntryArea.java b/org.argeo.app.ui/src/org/argeo/app/ui/TermsEntryArea.java deleted file mode 100644 index 97d8c1f..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/TermsEntryArea.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.argeo.app.ui; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.cms.ui.CmsUiProvider; -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; - -/** Entry area for managing th etypologies. */ -public class TermsEntryArea implements CmsUiProvider { - - @Override - public Control createUi(Composite parent, Node context) throws RepositoryException { - parent.setLayout(new GridLayout()); - Label lbl = new Label(parent, SWT.NONE); - lbl.setText("Typologies"); - return lbl; - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonPage.java b/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonPage.java deleted file mode 100644 index 380330f..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonPage.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.argeo.app.ui.dialogs; - -import org.argeo.app.ui.SuiteMsg; -import org.argeo.app.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); -// } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonWizard.java b/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonWizard.java deleted file mode 100644 index ee9f5b9..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonWizard.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.argeo.app.ui.dialogs; - -import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty; - -import javax.jcr.Node; - -import org.argeo.app.ui.SuiteMsg; -import org.argeo.app.ui.SuiteUiUtils; -import org.argeo.eclipse.ui.EclipseUiUtils; -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(); - } - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewUserWizard.java b/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewUserWizard.java deleted file mode 100644 index 2071872..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewUserWizard.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.argeo.app.ui.dialogs; - -import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty; - -import javax.jcr.Node; - -import org.argeo.app.ui.SuiteMsg; -import org.argeo.app.ui.SuiteUiUtils; -import org.argeo.eclipse.ui.EclipseUiUtils; -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(); - } - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/AbstractDbkViewer.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/AbstractDbkViewer.java deleted file mode 100644 index 5012805..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/AbstractDbkViewer.java +++ /dev/null @@ -1,1034 +0,0 @@ -package org.argeo.app.ui.docbook; - -import static org.argeo.app.docbook.DbkType.para; -import static org.argeo.app.docbook.DbkUtils.addDbk; -import static org.argeo.app.docbook.DbkUtils.isDbk; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Observer; - -import javax.jcr.Item; -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.api.cms.Cms2DSize; -import org.argeo.api.cms.CmsEditable; -import org.argeo.api.cms.CmsLog; -import org.argeo.app.docbook.DbkAttr; -import org.argeo.app.docbook.DbkType; -import org.argeo.app.docbook.DbkUtils; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.ui.viewers.AbstractPageViewer; -import org.argeo.cms.ui.viewers.EditablePart; -import org.argeo.cms.ui.viewers.NodePart; -import org.argeo.cms.ui.viewers.PropertyPart; -import org.argeo.cms.ui.viewers.Section; -import org.argeo.cms.ui.viewers.SectionPart; -import org.argeo.cms.ui.widgets.EditableText; -import org.argeo.cms.ui.widgets.StyledControl; -import org.argeo.jcr.Jcr; -import org.argeo.jcr.JcrException; -import org.argeo.jcr.JcrUtils; -import org.eclipse.rap.fileupload.FileDetails; -import org.eclipse.rap.fileupload.FileUploadEvent; -import org.eclipse.rap.fileupload.FileUploadHandler; -import org.eclipse.rap.fileupload.FileUploadListener; -import org.eclipse.rap.rwt.RWT; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.events.MouseAdapter; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseListener; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -/** Base class for text viewers and editors. */ -public abstract class AbstractDbkViewer extends AbstractPageViewer implements KeyListener, Observer { - private static final long serialVersionUID = -2401274679492339668L; - private final static CmsLog log = CmsLog.getLog(AbstractDbkViewer.class); - - private final Section mainSection; - - private TextInterpreter textInterpreter = new DbkTextInterpreter(); - private DbkImageManager imageManager; - - private FileUploadListener fileUploadListener; - private DbkContextMenu styledTools; - - private final boolean flat; - - private boolean showMainTitle = true; - - private Integer maxMediaWidth = null; - private String defaultSectionStyle; - - protected AbstractDbkViewer(Section parent, int style, CmsEditable cmsEditable) { - super(parent, style, cmsEditable); -// CmsView cmsView = CmsView.getCmsView(parent); -// imageManager = cmsView.getImageManager(); - flat = SWT.FLAT == (style & SWT.FLAT); - - if (getCmsEditable().canEdit()) { - fileUploadListener = new FUL(); - styledTools = new DbkContextMenu(this, parent.getShell()); - } - this.mainSection = parent; - Node baseFolder = Jcr.getParent(mainSection.getNode()); - imageManager = new DbkImageManager(baseFolder); - initModelIfNeeded(mainSection.getNode()); - // layout(this.mainSection); - } - - @Override - public Control getControl() { - return mainSection; - } - - protected void refresh(Control control) throws RepositoryException { - if (!(control instanceof Section)) - return; - long begin = System.currentTimeMillis(); - Section section = (Section) control; - if (section instanceof TextSection) { - CmsSwtUtils.clear(section); - Node node = section.getNode(); - TextSection textSection = (TextSection) section; - String style = node.hasProperty(DbkAttr.role.name()) ? node.getProperty(DbkAttr.role.name()).getString() - : getDefaultSectionStyle(); - if (style != null) - CmsSwtUtils.style(textSection, style); - - // Title - Node titleNode = null; - // We give priority to ./title vs ./info/title, like the DocBook XSL - if (node.hasNode(DbkType.title.get())) { - titleNode = node.getNode(DbkType.title.get()); - } else if (node.hasNode(DbkType.info.get() + '/' + DbkType.title.get())) { - titleNode = node.getNode(DbkType.info.get() + '/' + DbkType.title.get()); - } - - if (titleNode != null) { - boolean showTitle = getMainSection() == section ? showMainTitle : true; - if (showTitle) { - if (section.getHeader() == null) - section.createHeader(); - DbkSectionTitle title = newSectionTitle(textSection, titleNode); - title.setLayoutData(CmsSwtUtils.fillWidth()); - updateContent(title); - } - } - - // content - for (NodeIterator ni = node.getNodes(); ni.hasNext();) { - Node child = ni.nextNode(); - SectionPart sectionPart = null; - if (isDbk(child, DbkType.mediaobject)) { - if (child.hasNode(DbkType.imageobject.get())) { - sectionPart = newImg(textSection, child); - } else if (child.hasNode(DbkType.videoobject.get())) { - sectionPart = newVideo(textSection, child); - } else { - throw new IllegalArgumentException("Unsupported media object " + child); - } - } else if (isDbk(child, DbkType.info)) { - // TODO enrich UI based on info - } else if (isDbk(child, DbkType.title)) { - // already managed - } else if (isDbk(child, para)) { - sectionPart = newParagraph(textSection, child); - } else if (isDbk(child, DbkType.section)) { - sectionPart = newSectionPart(textSection, child); -// if (sectionPart == null) -// throw new IllegalArgumentException("Unsupported node " + child); - // TODO list node types in exception - } else { - throw new IllegalArgumentException("Unsupported node type for " + child); - } - if (sectionPart != null && sectionPart instanceof Control) - ((Control) sectionPart).setLayoutData(CmsSwtUtils.fillWidth()); - } - -// if (!flat) - for (NodeIterator ni = section.getNode().getNodes(DbkType.section.get()); ni.hasNext();) { - Node child = ni.nextNode(); - if (isDbk(child, DbkType.section)) { - TextSection newSection = newTextSection(section, child); - newSection.setLayoutData(CmsSwtUtils.fillWidth()); - refresh(newSection); - } - } - } else { - for (Section s : section.getSubSections().values()) - refresh(s); - } - // section.layout(true, true); - long duration = System.currentTimeMillis() - begin; -// System.out.println(duration + " ms - " + DbkUtils.getTitle(section.getNode())); - } - - /** To be overridden in order to provide additional SectionPart types */ - protected TextSection newTextSection(Section section, Node node) { - return new TextSection(section, SWT.NONE, node); - } - - /** To be overridden in order to provide additional SectionPart types */ - protected SectionPart newSectionPart(TextSection textSection, Node node) { - return null; - } - - // CRUD - protected Paragraph newParagraph(TextSection parent, Node node) throws RepositoryException { - Paragraph paragraph = new Paragraph(parent, parent.getStyle(), node); - updateContent(paragraph); - paragraph.setLayoutData(CmsSwtUtils.fillWidth()); - paragraph.setMouseListener(getMouseListener()); - paragraph.setFocusListener(getFocusListener()); - return paragraph; - } - - protected DbkImg newImg(TextSection parent, Node node) { - try { - DbkImg img = new DbkImg(parent, parent.getStyle(), node, imageManager); - GridData imgGd; - if (maxMediaWidth != null) { - imgGd = new GridData(SWT.CENTER, SWT.FILL, false, false); - imgGd.widthHint = maxMediaWidth; - img.setPreferredSize(new Cms2DSize(maxMediaWidth, 0)); - } else { - imgGd = CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT); - } - img.setLayoutData(imgGd); - updateContent(img); - img.setMouseListener(getMouseListener()); - img.setFocusListener(getFocusListener()); - return img; - } catch (RepositoryException e) { - throw new JcrException("Cannot add new image " + node, e); - } - } - - protected DbkVideo newVideo(TextSection parent, Node node) { - try { - DbkVideo video = new DbkVideo(parent, getCmsEditable().canEdit() ? SWT.NONE : SWT.READ_ONLY, node); - GridData gd; - if (maxMediaWidth != null) { - gd = new GridData(SWT.CENTER, SWT.FILL, false, false); - // TODO, manage size -// gd.widthHint = maxMediaWidth; -// gd.heightHint = (int) (gd.heightHint * 0.5625); - } else { - gd = new GridData(SWT.CENTER, SWT.FILL, false, false); -// gd.widthHint = video.getWidth(); -// gd.heightHint = video.getHeight(); - } - video.setLayoutData(gd); - updateContent(video); - return video; - } catch (RepositoryException e) { - throw new JcrException("Cannot add new image " + node, e); - } - } - - protected DbkSectionTitle newSectionTitle(TextSection parent, Node titleNode) throws RepositoryException { - int style = parent.getStyle(); - Composite titleParent = newSectionHeader(parent); - if (parent.isTitleReadOnly()) - style = style | SWT.READ_ONLY; - DbkSectionTitle title = new DbkSectionTitle(titleParent, style, titleNode); - updateContent(title); - title.setMouseListener(getMouseListener()); - title.setFocusListener(getFocusListener()); - return title; - } - - /** - * To be overridden in order to provide additional processing at the section - * level. - * - * @return the parent to use for the {@link DbkSectionTitle}, by default - * {@link Section#getHeader()} - */ - protected Composite newSectionHeader(TextSection section) { - return section.getHeader(); - } - - protected DbkSectionTitle prepareSectionTitle(Section newSection, String titleText) throws RepositoryException { - Node sectionNode = newSection.getNode(); - Node titleNode = DbkUtils.getOrAddDbk(sectionNode, DbkType.title); - getTextInterpreter().write(titleNode, titleText); - if (newSection.getHeader() == null) - newSection.createHeader(); - DbkSectionTitle sectionTitle = newSectionTitle((TextSection) newSection, sectionNode); - return sectionTitle; - } - - protected void updateContent(EditablePart part) throws RepositoryException { - if (part instanceof SectionPart) { - SectionPart sectionPart = (SectionPart) part; - Node partNode = sectionPart.getNode(); - - if (part instanceof StyledControl && (sectionPart.getSection() instanceof TextSection)) { - TextSection section = (TextSection) sectionPart.getSection(); - StyledControl styledControl = (StyledControl) part; - if (isDbk(partNode, para)) { - String style = partNode.hasProperty(DbkAttr.role.name()) - ? partNode.getProperty(DbkAttr.role.name()).getString() - : section.getDefaultTextStyle(); - styledControl.setStyle(style); - } - } - // use control AFTER setting style, since it may have been reset - - if (part instanceof EditableText) { - EditableText paragraph = (EditableText) part; - if (paragraph == getEdited()) - paragraph.setText(textInterpreter.raw(partNode)); - else - paragraph.setText(textInterpreter.readSimpleHtml(partNode)); - } else if (part instanceof DbkImg) { - DbkImg editableImage = (DbkImg) part; - // imageManager.load(partNode, part.getControl(), - // editableImage.getPreferredImageSize()); - } else if (part instanceof DbkVideo) { - DbkVideo video = (DbkVideo) part; - video.load(part.getControl()); - } - } else if (part instanceof DbkSectionTitle) { - DbkSectionTitle title = (DbkSectionTitle) part; - title.setStyle(title.getSection().getTitleStyle()); - // use control AFTER setting style - if (title == getEdited()) - title.setText(textInterpreter.read(title.getNode())); - else - title.setText(textInterpreter.readSimpleHtml(title.getNode())); - } - } - - // OVERRIDDEN FROM PARENT VIEWER - @Override - protected void save(EditablePart part) throws RepositoryException { - if (part instanceof EditableText) { - EditableText et = (EditableText) part; - if (!et.getEditable()) - return; - String text = ((Text) et.getControl()).getText(); - - // String[] lines = text.split("[\r\n]+"); - String[] lines = { text }; - assert lines.length != 0; - saveLine(part, lines[0]); - if (lines.length > 1) { - ArrayList toLayout = new ArrayList(); - if (part instanceof Paragraph) { - Paragraph currentParagraph = (Paragraph) et; - Section section = currentParagraph.getSection(); - Node sectionNode = section.getNode(); - Node currentParagraphN = currentParagraph.getNode(); - for (int i = 1; i < lines.length; i++) { - Node newNode = addDbk(sectionNode, para); - // newNode.addMixin(CmsTypes.CMS_STYLED); - saveLine(newNode, lines[i]); - // second node was create as last, if it is not the next - // one, it - // means there are some in between and we can take the - // one at - // index+1 for the re-order - if (newNode.getIndex() > currentParagraphN.getIndex() + 1) { - sectionNode.orderBefore(p(newNode.getIndex()), p(currentParagraphN.getIndex() + 1)); - } - Paragraph newParagraph = newParagraph((TextSection) section, newNode); - newParagraph.moveBelow(currentParagraph); - toLayout.add(newParagraph); - - currentParagraph = newParagraph; - currentParagraphN = newNode; - } - } - // TODO or rather return the created paragraphs? - layout(toLayout.toArray(new Control[toLayout.size()])); - } - persistChanges(et.getNode()); - } - } - - protected void saveLine(EditablePart part, String line) { - if (part instanceof NodePart) { - saveLine(((NodePart) part).getNode(), line); - } else if (part instanceof PropertyPart) { - saveLine(((PropertyPart) part).getProperty(), line); - } else { - throw new IllegalArgumentException("Unsupported part " + part); - } - } - - protected void saveLine(Item item, String line) { - line = line.trim(); - textInterpreter.write(item, line); - } - - @Override - protected void prepare(EditablePart part, Object caretPosition) { - Control control = part.getControl(); - if (control instanceof Text) { - Text text = (Text) control; - if (caretPosition != null) - if (caretPosition instanceof Integer) - text.setSelection((Integer) caretPosition); - else if (caretPosition instanceof Point) { -// layout(text); -// // TODO find a way to position the caret at the right place -// Point clickLocation = (Point) caretPosition; -// Point withinText = text.toControl(clickLocation); -// Rectangle bounds = text.getBounds(); -// int width = bounds.width; -// int height = bounds.height; -// int textLength = text.getText().length(); -// float area = width * height; -// float proportion = withinText.y * width + withinText.x; -// int pos = (int) (textLength * (proportion / area)); -// text.setSelection(pos); - } - text.setData(RWT.ACTIVE_KEYS, new String[] { "BACKSPACE", "ESC", "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT", - "ALT+ARROW_RIGHT", "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", "ENTER", "DELETE" }); - text.setData(RWT.CANCEL_KEYS, new String[] { "RETURN", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" }); - text.addKeyListener(this); - } else if (part instanceof DbkImg) { - ((DbkImg) part).setFileUploadListener(fileUploadListener); - } - } - - // REQUIRED BY CONTEXT MENU - void setParagraphStyle(Paragraph paragraph, String style) { - try { - Node paragraphNode = paragraph.getNode(); - if (style == null) {// default - if (paragraphNode.hasProperty(DbkAttr.role.name())) - paragraphNode.getProperty(DbkAttr.role.name()).remove(); - } else { - paragraphNode.setProperty(DbkAttr.role.name(), style); - } - persistChanges(paragraphNode); - updateContent(paragraph); - layoutPage(); - } catch (RepositoryException e1) { - throw new JcrException("Cannot set style " + style + " on " + paragraph, e1); - } - } - - SectionPart insertPart(Section section, Node node) { - try { - refresh(section); - layoutPage(); - for (Control control : section.getChildren()) { - if (control instanceof SectionPart) { - SectionPart sectionPart = (SectionPart) control; - Node partNode = sectionPart.getNode(); - if (partNode.getPath().equals(node.getPath())) - return sectionPart; - } - } - throw new IllegalStateException("New section part " + node + "not found"); - } catch (RepositoryException e) { - throw new JcrException("Cannot insert part " + node + " in section " + section.getNode(), e); - } - } - - void addParagraph(SectionPart partBefore, String txt) { - Section section = partBefore.getSection(); - SectionPart nextSectionPart = section.nextSectionPart(partBefore); - Node newNode = addDbk(section.getNode(), para); - textInterpreter.write(newNode, txt != null ? txt : ""); - if (nextSectionPart != null) { - try { - Node nextNode = nextSectionPart.getNode(); - section.getNode().orderBefore(Jcr.getIndexedName(newNode), Jcr.getIndexedName(nextNode)); - } catch (RepositoryException e) { - throw new JcrException("Cannot order " + newNode + " before " + nextSectionPart.getNode(), e); - } - } - Jcr.save(newNode); - Paragraph paragraph = (Paragraph) insertPart(partBefore.getSection(), newNode); - edit(paragraph, 0); - } - - void deletePart(SectionPart sectionPart) { - try { - Node node = sectionPart.getNode(); - Session session = node.getSession(); - if (sectionPart instanceof DbkImg) { - if (!isDbk(node, DbkType.mediaobject)) - throw new IllegalArgumentException("Node " + node + " is not a media object."); - } - node.remove(); - session.save(); - if (sectionPart instanceof Control) - ((Control) sectionPart).dispose(); - layoutPage(); - } catch (RepositoryException e1) { - throw new JcrException("Cannot delete " + sectionPart, e1); - } - } - - void deleteSection(Section section) { - try { - Node node = section.getNode(); - Session session = node.getSession(); - node.remove(); - session.save(); - section.dispose(); - layoutPage(); - } catch (RepositoryException e1) { - throw new JcrException("Cannot delete " + section, e1); - } - } - - String getRawParagraphText(Paragraph paragraph) { - return textInterpreter.raw(paragraph.getNode()); - } - - // COMMANDS - protected void splitEdit() { - checkEdited(); - try { - if (getEdited() instanceof Paragraph) { - Paragraph paragraph = (Paragraph) getEdited(); - Text text = (Text) paragraph.getControl(); - int caretPosition = text.getCaretPosition(); - String txt = text.getText(); - String first = txt.substring(0, caretPosition); - String second = txt.substring(caretPosition); - Node firstNode = paragraph.getNode(); - Node sectionNode = firstNode.getParent(); - - // FIXME set content the DocBook way - // firstNode.setProperty(CMS_CONTENT, first); - Node secondNode = addDbk(sectionNode, para); - // secondNode.addMixin(CmsTypes.CMS_STYLED); - - // second node was create as last, if it is not the next one, it - // means there are some in between and we can take the one at - // index+1 for the re-order - if (secondNode.getIndex() > firstNode.getIndex() + 1) { - sectionNode.orderBefore(p(secondNode.getIndex()), p(firstNode.getIndex() + 1)); - } - - // if we die in between, at least we still have the whole text - // in the first node - try { - textInterpreter.write(secondNode, second); - textInterpreter.write(firstNode, first); - } catch (Exception e) { - // so that no additional nodes are created: - JcrUtils.discardUnderlyingSessionQuietly(firstNode); - throw e; - } - - persistChanges(firstNode); - - Paragraph secondParagraph = paragraphSplitted(paragraph, secondNode); - edit(secondParagraph, 0); - } else if (getEdited() instanceof DbkSectionTitle) { - DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited(); - Text text = (Text) sectionTitle.getControl(); - String txt = text.getText(); - int caretPosition = text.getCaretPosition(); - Section section = sectionTitle.getSection(); - Node sectionNode = section.getNode(); - Node paragraphNode = addDbk(sectionNode, para); - // paragraphNode.addMixin(CmsTypes.CMS_STYLED); - - textInterpreter.write(paragraphNode, txt.substring(caretPosition)); - textInterpreter.write(sectionNode.getNode(DbkType.title.get()), txt.substring(0, caretPosition)); - sectionNode.orderBefore(p(paragraphNode.getIndex()), p(1)); - persistChanges(sectionNode); - - Paragraph paragraph = sectionTitleSplitted(sectionTitle, paragraphNode); - // section.layout(); - edit(paragraph, 0); - } - } catch (RepositoryException e) { - throw new JcrException("Cannot split " + getEdited(), e); - } - } - - protected void mergeWithPrevious() { - checkEdited(); - try { - Paragraph paragraph = (Paragraph) getEdited(); - Text text = (Text) paragraph.getControl(); - String txt = text.getText(); - Node paragraphNode = paragraph.getNode(); - if (paragraphNode.getIndex() == 1) - return;// do nothing - Node sectionNode = paragraphNode.getParent(); - Node previousNode = sectionNode.getNode(p(paragraphNode.getIndex() - 1)); - String previousTxt = textInterpreter.read(previousNode); - textInterpreter.write(previousNode, previousTxt + txt); - paragraphNode.remove(); - persistChanges(sectionNode); - - Paragraph previousParagraph = paragraphMergedWithPrevious(paragraph, previousNode); - edit(previousParagraph, previousTxt.length()); - } catch (RepositoryException e) { - throw new JcrException("Cannot stop editing", e); - } - } - - protected void mergeWithNext() { - checkEdited(); - try { - Paragraph paragraph = (Paragraph) getEdited(); - Text text = (Text) paragraph.getControl(); - String txt = text.getText(); - Node paragraphNode = paragraph.getNode(); - Node sectionNode = paragraphNode.getParent(); - NodeIterator paragraphNodes = sectionNode.getNodes(DbkType.para.get()); - long size = paragraphNodes.getSize(); - if (paragraphNode.getIndex() == size) - return;// do nothing - Node nextNode = sectionNode.getNode(p(paragraphNode.getIndex() + 1)); - String nextTxt = textInterpreter.read(nextNode); - textInterpreter.write(paragraphNode, txt + nextTxt); - - Section section = paragraph.getSection(); - Paragraph removed = (Paragraph) section.getSectionPart(nextNode.getIdentifier()); - - nextNode.remove(); - persistChanges(sectionNode); - - paragraphMergedWithNext(paragraph, removed); - edit(paragraph, txt.length()); - } catch (RepositoryException e) { - throw new JcrException("Cannot stop editing", e); - } - } - - protected synchronized void upload(EditablePart part) { - try { - if (part instanceof SectionPart) { - SectionPart sectionPart = (SectionPart) part; - Node partNode = sectionPart.getNode(); - int partIndex = partNode.getIndex(); - Section section = sectionPart.getSection(); - Node sectionNode = section.getNode(); - - if (part instanceof Paragraph) { - // FIXME adapt to DocBook -// Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE); -// newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE); -// JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]); -// if (partIndex < newNode.getIndex() - 1) { -// // was not last -// sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1)); -// } -// // sectionNode.orderBefore(p(partNode.getIndex()), -// // p(newNode.getIndex())); -// persistChanges(sectionNode); -// DbkImg img = newImg((TextSection) section, newNode); -// edit(img, null); -// layout(img.getControl()); - } else if (part instanceof DbkImg) { - if (getEdited() == part) - return; - edit(part, null); - layoutPage(); - } - } - } catch (RepositoryException e) { - throw new JcrException("Cannot upload", e); - } - } - - protected void deepen() { - if (flat) - return; - checkEdited(); - try { - if (getEdited() instanceof Paragraph) { - Paragraph paragraph = (Paragraph) getEdited(); - Text text = (Text) paragraph.getControl(); - String txt = text.getText(); - Node paragraphNode = paragraph.getNode(); - Section section = paragraph.getSection(); - Node sectionNode = section.getNode(); - // main title - if (section == mainSection && section instanceof TextSection && paragraphNode.getIndex() == 1 - && !sectionNode.hasNode(DbkType.title.get())) { - DbkSectionTitle sectionTitle = prepareSectionTitle(section, txt); - edit(sectionTitle, 0); - return; - } - Node newSectionNode = addDbk(sectionNode, DbkType.section); - // newSectionNode.addMixin(NodeType.MIX_TITLE); - sectionNode.orderBefore(h(newSectionNode.getIndex()), h(1)); - - int paragraphIndex = paragraphNode.getIndex(); - String sectionPath = sectionNode.getPath(); - String newSectionPath = newSectionNode.getPath(); - while (sectionNode.hasNode(p(paragraphIndex + 1))) { - Node parag = sectionNode.getNode(p(paragraphIndex + 1)); - sectionNode.getSession().move(sectionPath + '/' + p(paragraphIndex + 1), - newSectionPath + '/' + DbkType.para.get()); - SectionPart sp = section.getSectionPart(parag.getIdentifier()); - if (sp instanceof Control) - ((Control) sp).dispose(); - } - // create title - Node titleNode = DbkUtils.addDbk(newSectionNode, DbkType.title); - // newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE); - getTextInterpreter().write(titleNode, txt); - - TextSection newSection = new TextSection(section, section.getStyle(), newSectionNode); - newSection.setLayoutData(CmsSwtUtils.fillWidth()); - newSection.moveBelow(paragraph); - - // dispose - paragraphNode.remove(); - paragraph.dispose(); - - refresh(newSection); - newSection.getParent().layout(); - layout(newSection); - persistChanges(sectionNode); - } else if (getEdited() instanceof DbkSectionTitle) { - DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited(); - Section section = sectionTitle.getSection(); - Section parentSection = section.getParentSection(); - if (parentSection == null) - return;// cannot deepen main section - Node sectionN = section.getNode(); - Node parentSectionN = parentSection.getNode(); - if (sectionN.getIndex() == 1) - return;// cannot deepen first section - Node previousSectionN = parentSectionN.getNode(h(sectionN.getIndex() - 1)); - NodeIterator subSections = previousSectionN.getNodes(DbkType.section.get()); - int subsectionsCount = (int) subSections.getSize(); - previousSectionN.getSession().move(sectionN.getPath(), - previousSectionN.getPath() + "/" + h(subsectionsCount + 1)); - section.dispose(); - TextSection newSection = new TextSection(section, section.getStyle(), sectionN); - refresh(newSection); - persistChanges(previousSectionN); - } - } catch (RepositoryException e) { - throw new JcrException("Cannot deepen " + getEdited(), e); - } - } - - protected void undeepen() { - if (flat) - return; - checkEdited(); - try { - if (getEdited() instanceof Paragraph) { - upload(getEdited()); - } else if (getEdited() instanceof DbkSectionTitle) { - DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited(); - Section section = sectionTitle.getSection(); - Node sectionNode = section.getNode(); - Section parentSection = section.getParentSection(); - if (parentSection == null) - return;// cannot undeepen main section - - // choose in which section to merge - Section mergedSection; - if (sectionNode.getIndex() == 1) - mergedSection = section.getParentSection(); - else { - Map parentSubsections = parentSection.getSubSections(); - ArrayList
lst = new ArrayList
(parentSubsections.values()); - mergedSection = lst.get(sectionNode.getIndex() - 1); - } - Node mergedNode = mergedSection.getNode(); - boolean mergedHasSubSections = mergedNode.hasNode(DbkType.section.get()); - - // title as paragraph - Node newParagrapheNode = addDbk(mergedNode, para); - // newParagrapheNode.addMixin(CmsTypes.CMS_STYLED); - if (mergedHasSubSections) - mergedNode.orderBefore(p(newParagrapheNode.getIndex()), h(1)); - String txt = getTextInterpreter().read(sectionNode.getNode(DbkType.title.get())); - getTextInterpreter().write(newParagrapheNode, txt); - // move - NodeIterator paragraphs = sectionNode.getNodes(para.get()); - while (paragraphs.hasNext()) { - Node p = paragraphs.nextNode(); - SectionPart sp = section.getSectionPart(p.getIdentifier()); - if (sp instanceof Control) - ((Control) sp).dispose(); - mergedNode.getSession().move(p.getPath(), mergedNode.getPath() + '/' + para.get()); - if (mergedHasSubSections) - mergedNode.orderBefore(p(p.getIndex()), h(1)); - } - - Iterator
subsections = section.getSubSections().values().iterator(); - // NodeIterator sections = sectionNode.getNodes(CMS_H); - while (subsections.hasNext()) { - Section subsection = subsections.next(); - Node s = subsection.getNode(); - mergedNode.getSession().move(s.getPath(), mergedNode.getPath() + '/' + DbkType.section.get()); - subsection.dispose(); - } - - // remove section - section.getNode().remove(); - section.dispose(); - - refresh(mergedSection); - mergedSection.getParent().layout(); - layout(mergedSection); - persistChanges(mergedNode); - } - } catch (RepositoryException e) { - throw new JcrException("Cannot undeepen " + getEdited(), e); - } - } - - // UI CHANGES - protected Paragraph paragraphSplitted(Paragraph paragraph, Node newNode) throws RepositoryException { - Section section = paragraph.getSection(); - updateContent(paragraph); - Paragraph newParagraph = newParagraph((TextSection) section, newNode); - newParagraph.setLayoutData(CmsSwtUtils.fillWidth()); - newParagraph.moveBelow(paragraph); - layout(paragraph.getControl(), newParagraph.getControl()); - return newParagraph; - } - - protected Paragraph sectionTitleSplitted(DbkSectionTitle sectionTitle, Node newNode) throws RepositoryException { - updateContent(sectionTitle); - Paragraph newParagraph = newParagraph(sectionTitle.getSection(), newNode); - // we assume beforeFirst is not null since there was a sectionTitle - newParagraph.moveBelow(sectionTitle.getSection().getHeader()); - layout(sectionTitle.getControl(), newParagraph.getControl()); - return newParagraph; - } - - protected Paragraph paragraphMergedWithPrevious(Paragraph removed, Node remaining) throws RepositoryException { - Section section = removed.getSection(); - removed.dispose(); - - Paragraph paragraph = (Paragraph) section.getSectionPart(remaining.getIdentifier()); - updateContent(paragraph); - layout(paragraph.getControl()); - return paragraph; - } - - protected void paragraphMergedWithNext(Paragraph remaining, Paragraph removed) throws RepositoryException { - removed.dispose(); - updateContent(remaining); - layout(remaining.getControl()); - } - - // UTILITIES - protected String p(Integer index) { - StringBuilder sb = new StringBuilder(6); - sb.append(para.get()).append('[').append(index).append(']'); - return sb.toString(); - } - - protected String h(Integer index) { - StringBuilder sb = new StringBuilder(5); - sb.append(DbkType.section.get()).append('[').append(index).append(']'); - return sb.toString(); - } - - // GETTERS / SETTERS - public Section getMainSection() { - return mainSection; - } - - public boolean isFlat() { - return flat; - } - - public TextInterpreter getTextInterpreter() { - return textInterpreter; - } - - // KEY LISTENER - @Override - public void keyPressed(KeyEvent ke) { - if (log.isTraceEnabled()) - log.trace(ke); - - if (getEdited() == null) - return; - boolean altPressed = (ke.stateMask & SWT.ALT) != 0; - boolean shiftPressed = (ke.stateMask & SWT.SHIFT) != 0; - boolean ctrlPressed = (ke.stateMask & SWT.CTRL) != 0; - - try { - // Common - if (ke.keyCode == SWT.ESC) { -// cancelEdit(); - saveEdit(); - } else if (ke.character == '\r') { - if (!shiftPressed) - splitEdit(); - } else if (ke.character == 'z') { - if (ctrlPressed) - cancelEdit(); - } else if (ke.character == 'S') { - if (ctrlPressed) - saveEdit(); - } else if (ke.character == '\t') { - if (!shiftPressed) { - deepen(); - } else if (shiftPressed) { - undeepen(); - } - } else { - if (getEdited() instanceof Paragraph) { - Paragraph paragraph = (Paragraph) getEdited(); - Section section = paragraph.getSection(); - if (altPressed && ke.keyCode == SWT.ARROW_RIGHT) { - edit(section.nextSectionPart(paragraph), 0); - } else if (altPressed && ke.keyCode == SWT.ARROW_LEFT) { - edit(section.previousSectionPart(paragraph), 0); - } else if (ke.character == SWT.BS) { - Text text = (Text) paragraph.getControl(); - int caretPosition = text.getCaretPosition(); - if (caretPosition == 0) { - mergeWithPrevious(); - } - } else if (ke.character == SWT.DEL) { - Text text = (Text) paragraph.getControl(); - int caretPosition = text.getCaretPosition(); - int charcount = text.getCharCount(); - if (caretPosition == charcount) { - mergeWithNext(); - } - } - } - } - } catch (Exception e) { - ke.doit = false; - notifyEditionException(e); - } - } - - @Override - public void keyReleased(KeyEvent e) { - } - - // MOUSE LISTENER - @Override - protected MouseListener createMouseListener() { - return new ML(); - } - - private class ML extends MouseAdapter { - private static final long serialVersionUID = 8526890859876770905L; - - @Override - public void mouseDoubleClick(MouseEvent e) { - if (e.button == 1) { - Control source = (Control) e.getSource(); - EditablePart composite = findDataParent(source); - Point point = new Point(e.x, e.y); - if (composite instanceof DbkImg) { - if (getCmsEditable().canEdit()) { - if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg)) { - if (source == mainSection) - return; - EditablePart part = findDataParent(source); - upload(part); - } else { - getCmsEditable().startEditing(); - } - } - } else if (source instanceof Label) { - Label lbl = (Label) source; - Rectangle bounds = lbl.getBounds(); - float width = bounds.width; - float height = bounds.height; - float textLength = lbl.getText().length(); - float area = width * height; - float charArea = area / textLength; - float lines = textLength / width; - float proportion = point.y * width + point.x; - int pos = (int) (textLength * (proportion / area)); - // TODO refine it - edit(composite, (Integer) pos); - } else { - edit(composite, source.toDisplay(point)); - } - } - } - - @Override - public void mouseDown(MouseEvent e) { - if (getCmsEditable().isEditing()) { - if (e.button == 3) { - EditablePart composite = findDataParent((Control) e.getSource()); - if (styledTools != null) { - List styles = getAvailableStyles(composite); - styledTools.show(composite, new Point(e.x, e.y), styles); - } - } - } - } - - @Override - public void mouseUp(MouseEvent e) { - } - } - - protected List getAvailableStyles(EditablePart editablePart) { - return new ArrayList<>(); - } - - public void setMaxMediaWidth(Integer maxMediaWidth) { - this.maxMediaWidth = maxMediaWidth; - } - - public void setShowMainTitle(boolean showMainTitle) { - this.showMainTitle = showMainTitle; - } - - public String getDefaultSectionStyle() { - return defaultSectionStyle; - } - - public void setDefaultSectionStyle(String defaultSectionStyle) { - this.defaultSectionStyle = defaultSectionStyle; - } - - // FILE UPLOAD LISTENER - private class FUL implements FileUploadListener { - public void uploadProgress(FileUploadEvent event) { - // TODO Monitor upload progress - } - - public void uploadFailed(FileUploadEvent event) { - throw new RuntimeException("Upload failed " + event, event.getException()); - } - - public void uploadFinished(FileUploadEvent event) { - for (FileDetails file : event.getFileDetails()) { - if (log.isDebugEnabled()) - log.debug("Received: " + file.getFileName()); - } - mainSection.getDisplay().syncExec(new Runnable() { - @Override - public void run() { - saveEdit(); - } - }); - FileUploadHandler uploadHandler = (FileUploadHandler) event.getSource(); - uploadHandler.dispose(); - } - } -} \ No newline at end of file diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/CustomDbkEditor.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/CustomDbkEditor.java deleted file mode 100644 index 16845ae..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/CustomDbkEditor.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.argeo.app.ui.docbook; - -import javax.jcr.Node; - -import org.argeo.api.cms.CmsEditable; -import org.argeo.cms.ui.viewers.Section; -import org.eclipse.swt.widgets.Composite; - -/** - * Manages hardcoded sections as an arbitrary hierarchy under the main section, - * which contains no text and no title. - */ -public class CustomDbkEditor extends AbstractDbkViewer { - private static final long serialVersionUID = 656302500183820802L; - - public CustomDbkEditor(Composite parent, int style, Node textNode, CmsEditable cmsEditable) { - this(new Section(parent, style, textNode), style, cmsEditable); - } - - public CustomDbkEditor(Section parent, int style, CmsEditable cmsEditable) { - super(parent, style, cmsEditable); - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkContextMenu.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkContextMenu.java deleted file mode 100644 index cf45ef9..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkContextMenu.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.argeo.app.ui.docbook; - -import java.util.ArrayList; -import java.util.List; - -import javax.jcr.Node; - -import org.argeo.api.cms.CmsEditable; -import org.argeo.app.docbook.DbkMsg; -import org.argeo.app.docbook.DbkUtils; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.swt.MouseDown; -import org.argeo.cms.ui.viewers.EditablePart; -import org.argeo.cms.ui.viewers.NodePart; -import org.argeo.cms.ui.viewers.Section; -import org.argeo.cms.ui.viewers.SectionPart; -import org.argeo.cms.ui.widgets.EditableText; -import org.argeo.cms.ui.widgets.Img; -import org.argeo.jcr.Jcr; -import org.eclipse.rap.rwt.RWT; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.MouseAdapter; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.ShellEvent; -import org.eclipse.swt.graphics.Point; -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.Shell; - -/** Dialog to edit a text part. */ -class DbkContextMenu { - private final AbstractDbkViewer textViewer; - - private Shell shell; - - DbkContextMenu(AbstractDbkViewer textViewer, Shell parentShell) { -// shell = new Shell(display, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP); - shell = new Shell(parentShell, SWT.BORDER); -// super(display, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP); - this.textViewer = textViewer; - shell.setLayout(new GridLayout()); - // shell.setData(RWT.CUSTOM_VARIANT, TEXT_STYLED_TOOLS_DIALOG); - - shell.addShellListener(new ToolsShellListener()); - } - - void show(EditablePart editablePart, Point location, List availableStyles) { - if (shell.isVisible()) - shell.setVisible(false); - CmsSwtUtils.clear(shell); - Composite parent = shell; - CmsEditable cmsEditable = textViewer.getCmsEditable(); -// if (availableStyles.isEmpty()) -// return; - - if (editablePart instanceof Paragraph) { - Paragraph paragraph = (Paragraph) editablePart; - deletePartB(parent, DbkMsg.deleteParagraph.lead(), paragraph); - insertMediaB(parent, paragraph); - - } else if (editablePart instanceof Img) { - Img img = (Img) editablePart; - deletePartB(parent, DbkMsg.deleteMedia.lead(), img); - insertMediaB(parent, img); - insertParagraphB(parent, DbkMsg.insertParagraph.lead(), img); - - } else if (editablePart instanceof DbkSectionTitle) { - DbkSectionTitle sectionTitle = (DbkSectionTitle) editablePart; - TextSection section = sectionTitle.getSection(); - if (!section.isTitleReadOnly()) { - Label deleteB = new Label(shell, SWT.NONE); - deleteB.setText(DbkMsg.deleteSection.lead()); - deleteB.addMouseListener((MouseDown) (e) -> { - textViewer.deleteSection(section); - hide(); - }); - } - insertMediaB(parent, sectionTitle.getSection(), sectionTitle); - } - - StyledToolMouseListener stml = new StyledToolMouseListener(editablePart); - List styleButtons = new ArrayList(); - if (cmsEditable.isEditing()) { - for (String style : availableStyles) { - StyleButton styleButton = new StyleButton(shell, SWT.WRAP); - if (!"".equals(style)) - styleButton.setStyle(style); - else - styleButton.setStyle(null); - styleButton.setMouseListener(stml); - styleButtons.add(styleButton); - } - } else if (cmsEditable.canEdit()) { - // Edit -// Label editButton = new Label(shell, SWT.NONE); -// editButton.setText("Edit"); -// editButton.addMouseListener(stml); - } - - if (editablePart instanceof Paragraph) { - final int size = 32; - String text = textViewer.getRawParagraphText((Paragraph) editablePart); - String textToShow = text.length() > size ? text.substring(0, size - 3) + "..." : text; - for (StyleButton styleButton : styleButtons) { - styleButton.setText((styleButton.style == null ? "default" : styleButton.style) + " : " + textToShow); - } - } - - shell.pack(); - shell.layout(); - if (editablePart instanceof Control) { - int height = shell.getSize().y; - int parentShellHeight = shell.getShell().getSize().y; - if ((location.y + height) < parentShellHeight) { - shell.setLocation(((Control) editablePart).toDisplay(location.x, location.y)); - } else { - shell.setLocation(((Control) editablePart).toDisplay(location.x, location.y - parentShellHeight)); - } - } - - if (shell.getChildren().length != 0) - shell.open(); - } - - void hide() { - shell.setVisible(false); - } - - protected void insertMediaB(Composite parent, SectionPart sectionPart) { - insertMediaB(parent, sectionPart.getSection(), sectionPart); - } - - protected void insertMediaB(Composite parent, Section section, NodePart nodePart) { - Label insertPictureB = new Label(parent, SWT.NONE); - insertPictureB.setText(DbkMsg.insertPicture.lead()); - insertPictureB.addMouseListener((MouseDown) (e) -> { - Node newNode = DbkUtils.insertImageAfter(nodePart.getNode()); - Jcr.save(newNode); - textViewer.insertPart(section, newNode); - hide(); - }); - Label insertVideoB = new Label(parent, SWT.NONE); - insertVideoB.setText(DbkMsg.insertVideo.lead()); - insertVideoB.addMouseListener((MouseDown) (e) -> { - Node newNode = DbkUtils.insertVideoAfter(nodePart.getNode()); - Jcr.save(newNode); - textViewer.insertPart(section, newNode); - hide(); - }); - - } - - protected void insertParagraphB(Composite parent, String msg, SectionPart sectionPart) { - Label insertMediaB = new Label(parent, SWT.NONE); - insertMediaB.setText(msg); - insertMediaB.addMouseListener((MouseDown) (e) -> { - textViewer.addParagraph(sectionPart, null); - hide(); - }); - } - - protected void deletePartB(Composite parent, String msg, SectionPart sectionPart) { - Label deleteB = new Label(shell, SWT.NONE); - deleteB.setText(msg); - deleteB.addMouseListener((MouseDown) (e) -> { - textViewer.deletePart(sectionPart); - hide(); - }); - } - - class StyleButton extends EditableText { - private static final long serialVersionUID = 7731102609123946115L; - - String style; - - public StyleButton(Composite parent, int style) { - super(parent, style); - } - - @Override - public void setStyle(String style) { - this.style = style; - super.setStyle(style); - } - -// private Label label; -// -// public StyleButton(Composite parent, int swtStyle) { -// super(parent, SWT.NONE); -// setLayout(new GridLayout()); -// label = new Label(this, swtStyle); -// } -// -// public Label getLabel() { -// return label; -// } - - } - - class StyledToolMouseListener extends MouseAdapter { - private static final long serialVersionUID = 8516297091549329043L; - private EditablePart editablePart; - - public StyledToolMouseListener(EditablePart editablePart) { - super(); - this.editablePart = editablePart; - } - - @Override - public void mouseDown(MouseEvent e) { - // TODO make it more robust. - Label sb = (Label) e.getSource(); - Object style = sb.getData(RWT.CUSTOM_VARIANT); - textViewer.setParagraphStyle((Paragraph) editablePart, style == null ? null : style.toString()); - hide(); - } - } - - class ToolsShellListener extends org.eclipse.swt.events.ShellAdapter { - private static final long serialVersionUID = 8432350564023247241L; - - @Override - public void shellDeactivated(ShellEvent e) { - hide(); - } - - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImageManager.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImageManager.java deleted file mode 100644 index 32bbdd9..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImageManager.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.argeo.app.ui.docbook; - -import static javax.jcr.Node.JCR_CONTENT; -import static javax.jcr.Property.JCR_DATA; -import static javax.jcr.nodetype.NodeType.NT_FILE; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - -import javax.jcr.Binary; -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.nodetype.NodeType; - -import org.argeo.api.cms.Cms2DSize; -import org.argeo.api.cms.CmsImageManager; -import org.argeo.app.api.EntityNames; -import org.argeo.app.api.EntityType; -import org.argeo.app.docbook.DbkAttr; -import org.argeo.app.docbook.DbkType; -import org.argeo.app.docbook.DbkUtils; -import org.argeo.cms.ui.util.CmsUiUtils; -import org.argeo.cms.ui.util.DefaultImageManager; -import org.argeo.jcr.JcrException; -import org.argeo.jcr.JcrUtils; -import org.eclipse.swt.graphics.ImageData; - -/** Add DocBook images support to {@link CmsImageManager}. */ -public class DbkImageManager extends DefaultImageManager { - private Node baseFolder = null; - - public DbkImageManager(Node baseFolder) { - this.baseFolder = baseFolder; - } - - Node getImageDataNode(Node mediaObjectNode) { - try { - if (mediaObjectNode.hasNode(DbkType.imageobject.get())) { - Node imageDataNode = mediaObjectNode.getNode(DbkType.imageobject.get()) - .getNode(DbkType.imagedata.get()); - return imageDataNode; - } else { - throw new IllegalStateException("No image data found for " + mediaObjectNode); - } - } catch (RepositoryException e) { - throw new JcrException(e); - } - } - - @Override - public Binary getImageBinary(Node node) { - Node fileNode = null; - if (DbkUtils.isDbk(node, DbkType.mediaobject)) { - Node imageDataNode = getImageDataNode(node); - fileNode = getFileNode(imageDataNode); - } - try { - if (node.isNodeType(NT_FILE)) { - fileNode = node; - } - if (fileNode != null) { - return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary(); - } else { - return null; - } - } catch (RepositoryException e) { - throw new JcrException(e); - } - } - - public Cms2DSize getImageSize(Node mediaObjectNode) { - Node imageDataNode = getImageDataNode(mediaObjectNode); - Node fileNode = getFileNode(imageDataNode); - if (fileNode == null) - return new Cms2DSize(0, 0); - try { - Cms2DSize intrinsicSize; - if (fileNode.hasProperty(EntityNames.SVG_WIDTH) && fileNode.hasProperty(EntityNames.SVG_HEIGHT)) { - int width = (int) fileNode.getProperty(EntityNames.SVG_WIDTH).getLong(); - int height = (int) fileNode.getProperty(EntityNames.SVG_HEIGHT).getLong(); - intrinsicSize = new Cms2DSize(width, height); - } else { - try (InputStream in = JcrUtils.getFileAsStream(fileNode)) { - ImageData id = new ImageData(in); - intrinsicSize = updateSize(fileNode, id); - } catch (IOException e) { - throw new RuntimeException("Cannot load file " + fileNode, e); - } - } - // TODO interpret image data infos - return intrinsicSize; - } catch (RepositoryException e) { - throw new JcrException(e); - } - } - - protected Cms2DSize updateSize(Node fileNode, ImageData id) throws RepositoryException { - fileNode.addMixin(EntityType.box.get()); - fileNode.setProperty(EntityNames.SVG_WIDTH, id.width); - fileNode.setProperty(EntityNames.SVG_HEIGHT, id.height); - return new Cms2DSize(id.width, id.height); - } - - @Override - protected void processNewImageFile(Node mediaObjectNode, Node fileNode, ImageData id) - throws RepositoryException, IOException { - Node imageDataNode = getImageDataNode(mediaObjectNode); - updateSize(fileNode, id); - String filePath = fileNode.getPath(); - String relPath = filePath.substring(baseFolder.getPath().length() + 1); - imageDataNode.setProperty(DbkAttr.fileref.name(), relPath); - } - - @Override - public String getImageUrl(Node mediaObjectNode) { - Node imageDataNode = getImageDataNode(mediaObjectNode); - // TODO factorise - String fileref = null; - try { - if (imageDataNode.hasProperty(DbkAttr.fileref.name())) - fileref = imageDataNode.getProperty(DbkAttr.fileref.name()).getString(); - } catch (RepositoryException e) { - throw new JcrException(e); - } - if (fileref == null) - return null; - URI fileUri; - try { - // FIXME it messes up with the '/' - fileUri = new URI(URLEncoder.encode(fileref, StandardCharsets.UTF_8.toString())); - } catch (URISyntaxException | UnsupportedEncodingException e) { - throw new IllegalArgumentException("File ref in " + imageDataNode + " is badly formatted", e); - } - if (fileUri.getScheme() != null) - return fileUri.toString(); - // local - Node fileNode = getFileNode(imageDataNode); - String url = CmsUiUtils.getDataPathForUrl(fileNode); - return url; - } - - protected Node getFileNode(Node imageDataNode) { - // FIXME make URL use case more robust - try { - String fileref = null; - if (imageDataNode.hasProperty(DbkAttr.fileref.name())) - fileref = imageDataNode.getProperty(DbkAttr.fileref.name()).getString(); - if (fileref == null) - return null; - Node fileNode; - if (fileref.startsWith("/")) - fileNode = baseFolder.getSession().getNode(fileref); - else - fileNode = baseFolder.getNode(fileref); - return fileNode; - } catch (RepositoryException e) { - throw new JcrException(e); - } - } - - protected Node getMediaFolder() { - try { - // TODO check edition status - Node mediaFolder = JcrUtils.getOrAdd(baseFolder, EntityNames.MEDIA, NodeType.NT_FOLDER); - return mediaFolder; - } catch (RepositoryException e) { - throw new JcrException("Cannot get media folder", e); - } - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImg.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImg.java deleted file mode 100644 index ca9b388..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImg.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.argeo.app.ui.docbook; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.ui.widgets.Img; -import org.eclipse.rap.fileupload.FileUploadEvent; -import org.eclipse.rap.fileupload.FileUploadHandler; -import org.eclipse.rap.fileupload.FileUploadListener; -import org.eclipse.rap.fileupload.FileUploadReceiver; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; - -/** DocBook specific image area. */ -public class DbkImg extends Img { - private static final long serialVersionUID = -6150996708899219074L; - - public DbkImg(Composite parent, int swtStyle, Node imgNode, DbkImageManager imageManager) - throws RepositoryException { - super(parent, swtStyle, imgNode, imageManager); - } - - @Override - protected Node getUploadFolder() { - Node mediaFolder = ((DbkImageManager) getImageManager()).getMediaFolder(); - return mediaFolder; - } - - @Override - protected String getUploadName() { - return null; - } - - @Override - protected void setContainerLayoutData(Composite composite) { - composite.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); - } - - @Override - protected void setControlLayoutData(Control control) { - control.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); - } - - @Override - protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) { - FileUploadHandler fileUploadHandler = super.prepareUpload(receiver); - fileUploadHandler.addUploadListener(new FileUploadListener() { - - @Override - public void uploadProgress(FileUploadEvent event) { - // TODO Auto-generated method stub - - } - - @Override - public void uploadFinished(FileUploadEvent event) { - } - - @Override - public void uploadFailed(FileUploadEvent event) { - // TODO Auto-generated method stub - - } - }); - return fileUploadHandler; - } - -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkSectionTitle.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkSectionTitle.java deleted file mode 100644 index b537333..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkSectionTitle.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.argeo.app.ui.docbook; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.cms.ui.viewers.EditablePart; -import org.argeo.cms.ui.viewers.NodePart; -import org.argeo.cms.ui.widgets.EditableText; -import org.eclipse.swt.widgets.Composite; - -/** The title of a section, based on an XML text node. */ -public class DbkSectionTitle extends EditableText implements EditablePart, NodePart { - private static final long serialVersionUID = -1787983154946583171L; - - private final TextSection section; - - public DbkSectionTitle(Composite parent, int swtStyle, Node titleNode) throws RepositoryException { - super(parent, swtStyle, titleNode); - section = (TextSection) TextSection.findSection(this); - } - - public TextSection getSection() { - return section; - } - - @Override - public Node getItem() throws RepositoryException { - return getNode(); - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkTextInterpreter.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkTextInterpreter.java deleted file mode 100644 index ff12348..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkTextInterpreter.java +++ /dev/null @@ -1,283 +0,0 @@ -package org.argeo.app.ui.docbook; - -import static org.argeo.app.docbook.DbkType.para; -import static org.argeo.app.docbook.DbkType.title; -import static org.argeo.app.docbook.DbkUtils.isDbk; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.nio.charset.StandardCharsets; -import java.util.List; - -import javax.jcr.ImportUUIDBehavior; -import javax.jcr.Item; -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Property; -import javax.jcr.PropertyIterator; -import javax.jcr.RepositoryException; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.apache.commons.io.IOUtils; -import org.argeo.app.docbook.DbkAttr; -import org.argeo.app.docbook.DbkType; -import org.argeo.jcr.Jcr; -import org.argeo.jcr.JcrException; - -/** Based on HTML with a few Wiki-like shortcuts. */ -public class DbkTextInterpreter implements TextInterpreter { - private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - - private String linkCssClass = DbkType.link.name(); - - @Override - public void write(Item item, String content) { - try { - if (item instanceof Node) { - Node node = (Node) item; - if (isDbk(node, para) || isDbk(node, title)) { - String raw = convertToStorage(node, content); - validateBeforeStoring(raw); - - String jcrUuid = node.getIdentifier(); -// if (node.hasProperty(Property.JCR_UUID)) -// jcrUuid = node.getProperty(Property.JCR_UUID).getString(); -// else { -// // TODO use time based -// jcrUuid = UUID.randomUUID().toString(); -// node.setProperty(Property.JCR_UUID, jcrUuid); -// node.getSession().save(); -// } - - StringBuilder namespaces = new StringBuilder(); - namespaces.append(" xmlns:dbk=\"http://docbook.org/ns/docbook\""); - namespaces.append(" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\""); - namespaces.append(" xmlns:xlink=\"http://www.w3.org/1999/xlink\""); - raw = "<" + node.getName() + " jcr:uuid=\"" + jcrUuid + "\"" + namespaces + ">" + raw + ""; -// System.out.println(raw); - try (InputStream in = new ByteArrayInputStream(raw.getBytes(StandardCharsets.UTF_8))) { - node.getSession().importXML(node.getParent().getPath(), in, - ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING); - // node.getSession().save(); - } catch (IOException e) { - throw new IllegalArgumentException("Cannot parse raw content of " + node, e); - } - -// try { -// DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); -// Document document; -// try (Reader in = new StringReader(raw)) { -// document = documentBuilder.parse(new InputSource(in)); -// } -// NodeList nl = document.getChildNodes(); -// for (int i = 0; i < nl.getLength(); i++) { -// org.w3c.dom.Node n = nl.item(i); -// if (node instanceof Text) { -// -// } -// } -// } catch (ParserConfigurationException | SAXException | IOException e) { -// throw new IllegalArgumentException("Cannot parse raw content of " + node, e); -// } - -// Node jcrText; -// if (!node.hasNode(Jcr.JCR_XMLTEXT)) -// jcrText = node.addNode(Jcr.JCR_XMLTEXT, JcrxType.JCRX_XMLTEXT); -// else -// jcrText = node.getNode(Jcr.JCR_XMLTEXT); -// jcrText.setProperty(Jcr.JCR_XMLCHARACTERS, raw); - } else { - throw new IllegalArgumentException("Don't know how to interpret " + node); - } - } else {// property - Property property = (Property) item; - property.setValue(content); - } - // item.getSession().save(); - } catch (RepositoryException e) { - throw new JcrException("Cannot set content on " + item, e); - } - } - - @Override - public String read(Item item) { - try { - String raw = raw(item); - return convertFromStorage(item, raw); - } catch (RepositoryException e) { - throw new JcrException("Cannot get " + item + " for edit", e); - } - } - - @Override - public String raw(Item item) { - try { - item.getSession().refresh(true); - if (item instanceof Node) { - Node node = (Node) item; - if (isDbk(node, para) || isDbk(node, title)) { - StringBuilder sb = new StringBuilder(); - readXml(node, sb); -// NodeIterator nit = node.getNodes(); -// while (nit.hasNext()) { -// Node child = nit.nextNode(); -// if (child.getName().equals(Jcr.JCR_XMLTEXT)) { -// Node jcrText = node.getNode(Jcr.JCR_XMLTEXT); -// String txt = jcrText.getProperty(Jcr.JCR_XMLCHARACTERS).getString(); -// // TODO make it more robust -// // txt = txt.replace("\n", "").replace("\t", ""); -// txt = txt.replace("\t", " "); -// sb.append(txt); -// } else { -// try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { -// child.getSession().exportDocumentView(child.getPath(), out, true, false); -// sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8)); -// } catch (IOException e) { -// throw new IllegalStateException("Cannot export " + child, e); -// } -// } -// } - return sb.toString(); - } else { - throw new IllegalArgumentException("Don't know how to interpret " + node); - } - } else {// property - Property property = (Property) item; - return property.getString(); - } - } catch (RepositoryException e) { - throw new JcrException("Cannot get " + item + " content", e); - } - } - - private void readXml(Node node, StringBuilder sb) throws RepositoryException { - NodeIterator nit = node.getNodes(); - while (nit.hasNext()) { - Node child = nit.nextNode(); - if (child.getName().equals(Jcr.JCR_XMLTEXT)) { - String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString(); - // TODO make it more robust - // txt = txt.replace("\n", "").replace("\t", ""); - txt = txt.replace("\t", " "); - sb.append(txt); - } else { - sb.append('<').append(child.getName()); - PropertyIterator pit = child.getProperties(); - properties: while (pit.hasNext()) { - Property p = pit.nextProperty(); - if (p.getName().startsWith("jcr:")) - continue properties; - sb.append(' ').append(p.getName()).append("=\"").append(p.getString()).append('\"'); - } - sb.append('>'); - readXml(child, sb); -// try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { -// child.getSession().exportDocumentView(child.getPath(), out, true, false); -// sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8)); -// } catch (IOException e) { -// throw new IllegalStateException("Cannot export " + child, e); -// } - sb.append("'); - } - } - } - - private void readAsSimpleHtml(Node node, StringBuilder sb) throws RepositoryException { - NodeIterator nit = node.getNodes(); - while (nit.hasNext()) { - Node child = nit.nextNode(); - if (child.getName().equals(Jcr.JCR_XMLTEXT)) { - String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString(); - // TODO make it more robust - // txt = txt.replace("\n", "").replace("\t", ""); - txt = txt.replace("\t", " "); - String html = textToSimpleHtml(txt); - sb.append(html); - } else if (child.getName().equals(DbkType.link.get())) { - if (child.hasProperty(DbkAttr.XLINK_HREF)) { - String href = child.getProperty(DbkAttr.XLINK_HREF).getString(); - // TODO deal with other forbidden XML characters? - href = href.replace("&", "&"); - sb.append(""); - readAsSimpleHtml(child, sb); - sb.append(""); - } - } else { - // ignore - } - } - } - - private String textToSimpleHtml(String raw) { - // FIXME the saved data should be corrected instead. - if (raw.indexOf('&') >= 0) { - raw = raw.replace("&", "&"); - } - if (raw.indexOf('<') >= 0) { - raw = raw.replace("<", "<"); - } - if (raw.indexOf('>') >= 0) { - raw = raw.replace(">", ">"); - } - if (raw.indexOf('\"') >= 0) { - raw = raw.replace("\"", """); - } - if (raw.indexOf('\'') >= 0) { - raw = raw.replace("\'", "'"); - } -// raw = "" + raw + ""; - if (raw.length() == 0) - return raw; - try (StringReader reader = new StringReader(raw)) { - List lines = IOUtils.readLines(reader); - if (lines.size() == 1) - return lines.get(0); - StringBuilder sb = new StringBuilder(raw.length() + lines.size() * BR_LENGTH); - for (int i = 0; i < lines.size(); i++) { - if (i != 0) - sb.append("
"); - sb.append(lines.get(i)); - } - return sb.toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - final static int BR_LENGTH = "
".length(); - - public String readSimpleHtml(Item item) { - try { - StringBuilder sb = new StringBuilder(); -// sb.append("
"); - readAsSimpleHtml((Node) item, sb); -// sb.append("
"); -// System.out.println(sb); - return sb.toString(); - } catch (RepositoryException e) { - throw new JcrException("Cannot convert " + item + " to simple HTML", e); - } - } - - // EXTENSIBILITY - /** - * To be overridden, in order to make sure that only valid strings are being - * stored. - */ - protected void validateBeforeStoring(String raw) { - } - - /** To be overridden, in order to support additional formatting. */ - protected String convertToStorage(Item item, String content) throws RepositoryException { - return content; - - } - - /** To be overridden, in order to support additional formatting. */ - protected String convertFromStorage(Item item, String content) throws RepositoryException { - return content; - } -} diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkVideo.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkVideo.java deleted file mode 100644 index c8aee51..0000000 --- a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkVideo.java +++ /dev/null @@ -1,227 +0,0 @@ -package org.argeo.app.ui.docbook; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; -import java.util.Map; - -import javax.jcr.Item; -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.app.docbook.DbkAttr; -import org.argeo.app.docbook.DbkType; -import org.argeo.app.docbook.DbkUtils; -import org.argeo.cms.swt.CmsSwtUtils; -import org.argeo.cms.swt.Selected; -import org.argeo.cms.ui.viewers.NodePart; -import org.argeo.cms.ui.viewers.Section; -import org.argeo.cms.ui.viewers.SectionPart; -import org.argeo.cms.ui.widgets.StyledControl; -import org.argeo.jcr.Jcr; -import org.argeo.jcr.JcrException; -import org.argeo.util.naming.NamingUtils; -import org.eclipse.swt.SWT; -import org.eclipse.swt.browser.Browser; -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.Text; - -public class DbkVideo extends StyledControl implements SectionPart, NodePart { - private static final long serialVersionUID = -8753232181570351880L; - private Section section; - - private int width = 640; - private int height = 360; - - private boolean editable; - - public DbkVideo(Composite parent, int style, Node node) { - this(Section.findSection(parent), parent, style, node); - } - - DbkVideo(Section section, Composite parent, int style, Node node) { - super(parent, style, node); - editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY)); - this.section = section; - setStyle(DbkType.videoobject.name()); - } - - @Override - protected Control createControl(Composite box, String style) { - Node mediaobject = getNode(); - Composite wrapper = new Composite(box, SWT.NONE); - wrapper.setLayout(CmsSwtUtils.noSpaceGridLayout()); - - Composite browserC = new Composite(wrapper, SWT.NONE); - browserC.setLayout(CmsSwtUtils.noSpaceGridLayout()); - GridData gd = new GridData(SWT.CENTER, SWT.FILL, true, true); - gd.widthHint = getWidth(); - gd.heightHint = getHeight(); - browserC.setLayoutData(gd); -// wrapper.setLayoutData(CmsUiUtils.fillAll()); - Browser browser = new Browser(browserC, SWT.NONE); - - if (editable) { - Composite editor = new Composite(wrapper, SWT.BORDER); - editor.setLayout(new GridLayout(3, false)); - editor.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - String fileref = DbkUtils.getMediaFileref(mediaobject); - Text text = new Text(editor, SWT.SINGLE); - if (fileref != null) - text.setText(fileref); - else - text.setMessage("Embed URL of the video"); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - Button updateB = new Button(editor, SWT.FLAT); - updateB.setText("Update"); - updateB.addSelectionListener(new Selected() { - - @Override - public void widgetSelected(SelectionEvent e) { - try { - Node videodata = mediaobject.getNode(DbkType.videoobject.get()) - .getNode(DbkType.videodata.get()); - String txt = text.getText(); - URI uri; - try { - uri = new URI(txt); - } catch (URISyntaxException e1) { - text.setText(""); - text.setMessage("Invalid URL"); - return; - } - - // Transform watch URL in embed - // YouTube - String videoId = null; - if ("www.youtube.com".equals(uri.getHost()) || "youtube.com".equals(uri.getHost()) - || "youtu.be".equals(uri.getHost())) { - if ("www.youtube.com".equals(uri.getHost()) || "youtube.com".equals(uri.getHost())) { - if ("/watch".equals(uri.getPath())) { - Map> map = NamingUtils.queryToMap(uri); - videoId = map.get("v").get(0); - } - } else if ("youtu.be".equals(uri.getHost())) { - videoId = uri.getPath().substring(1); - } - if (videoId != null) { - try { - uri = new URI("https://www.youtube.com/embed/" + videoId); - text.setText(uri.toString()); - } catch (URISyntaxException e1) { - throw new IllegalStateException(e1); - } - } - } - - // Vimeo - if ("vimeo.com".equals(uri.getHost())) { - videoId = uri.getPath().substring(1); - if (videoId != null) { - try { - uri = new URI("https://player.vimeo.com/video/" + videoId); - text.setText(uri.toString()); - } catch (URISyntaxException e1) { - throw new IllegalStateException(e1); - } - } - } - - videodata.setProperty(DbkAttr.fileref.name(), uri.toString()); - // TODO better integrate it in the edition lifecycle - videodata.getSession().save(); - load(browser); - } catch (RepositoryException e1) { - throw new JcrException("Cannot update " + mediaobject, e1); - } - - } - }); - - Button deleteB = new Button(editor, SWT.FLAT); - deleteB.setText("Delete"); - deleteB.addSelectionListener(new Selected() { - - @Override - public void widgetSelected(SelectionEvent e) { - try { - mediaobject.remove(); - mediaobject.getSession().save(); - dispose(); - getSection().getParent().layout(true, true); - } catch (RepositoryException e1) { - throw new JcrException("Cannot update " + mediaobject, e1); - } - - } - }); - } - - // TODO caption - return browser; - } - - public void load(Control control) { - try { - if (control instanceof Browser) { - Browser browser = (Browser) control; - getNode().getSession(); - String fileref = DbkUtils.getMediaFileref(getNode()); - if (fileref != null) { - // TODO manage self-hosted videos - // TODO for YouTube videos, check whether the URL starts with - // https://www.youtube.com/embed/ and not https://www.youtube.com/watch?v= - StringBuilder html = new StringBuilder(); - html.append( - "