<!-- Argeo Commons -->
<dependency>
<groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.node.api</artifactId>
+ <artifactId>org.argeo.api</artifactId>
<version>2.1.88-SNAPSHOT</version>
</dependency>
<dependency>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.api</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+Provide-Capability: cms.datamodel;name=ldap;cnd=/org/argeo/node/ldap.cnd;abstract=true
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>argeo-commons</artifactId>
+ <version>2.1.88-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.api</artifactId>
+ <name>Argeo Node API</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ </dependencies>
+</project>
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api;
+
+/** Framework agnostic interface for log notifications */
+public interface ArgeoLogListener {
+ /**
+ * Appends a log
+ *
+ * @param username
+ * authentified user, null for anonymous
+ * @param level
+ * INFO, DEBUG, WARN, etc. (logging framework specific)
+ * @param category
+ * hierarchy (logging framework specific)
+ * @param thread
+ * name of the thread which logged this message
+ * @param msg
+ * any object as long as its toString() method returns the
+ * message
+ * @param exception
+ * exception in log4j ThrowableStrRep format
+ */
+ public void appendLog(String username, Long timestamp, String level,
+ String category, String thread, Object msg, String[] exception);
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api;
+
+/**
+ * Logging framework agnostic identifying a logging service, to which one can
+ * register
+ */
+public interface ArgeoLogger {
+ /**
+ * Register for events by threads with the same authentication (or all
+ * threads if admin)
+ */
+ public void register(ArgeoLogListener listener,
+ Integer numberOfPreviousEvents);
+
+ /**
+ * For admin use only: register for all users
+ *
+ * @param listener
+ * the log listener
+ * @param numberOfPreviousEvents
+ * the number of previous events to notify
+ * @param everything
+ * if true even anonymous is logged
+ */
+ public void registerForAll(ArgeoLogListener listener,
+ Integer numberOfPreviousEvents, boolean everything);
+
+ public void unregister(ArgeoLogListener listener);
+
+ public void unregisterForAll(ArgeoLogListener listener);
+}
--- /dev/null
+package org.argeo.api;
+
+import java.util.Map;
+
+import javax.security.auth.AuthPermission;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.argeo.api.security.DataAdminPrincipal;
+
+/**
+ * Log-in a system process as data admin. Protection is via
+ * {@link AuthPermission} on this login module, so if it can be accessed it will
+ * always succeed.
+ */
+public class DataAdminLoginModule implements LoginModule {
+ private Subject subject;
+
+ @Override
+ public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
+ Map<String, ?> options) {
+ this.subject = subject;
+ }
+
+ @Override
+ public boolean login() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ subject.getPrincipals().add(new DataAdminPrincipal());
+ return true;
+ }
+
+ @Override
+ public boolean abort() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ subject.getPrincipals().removeAll(subject.getPrincipals(DataAdminPrincipal.class));
+ return true;
+ }
+}
--- /dev/null
+package org.argeo.api;
+
+import org.osgi.resource.Namespace;
+
+/** CMS Data Model capability namespace. */
+public class DataModelNamespace extends Namespace {
+
+ public static final String CMS_DATA_MODEL_NAMESPACE = "cms.datamodel";
+ public static final String NAME = "name";
+ public static final String CND = "cnd";
+ /** If 'true', indicates that no repository should be published */
+ public static final String ABSTRACT = "abstract";
+
+ private DataModelNamespace() {
+ // empty
+ }
+
+}
--- /dev/null
+package org.argeo.api;
+
+import java.util.function.BiFunction;
+
+/**
+ * Stateless UI part creator. Takes a parent view (V) and a model context (M) in
+ * order to create a view part (W) which can then be further configured. Such
+ * object can be used as services and reference other part of the model which
+ * are relevant for all created UI part.
+ */
+@FunctionalInterface
+public interface MvcProvider<V, M, W> extends BiFunction<V, M, W> {
+ /**
+ * Whether this parent view is supported.
+ *
+ * @return true by default.
+ */
+ default boolean isViewSupported(V parent) {
+ return true;
+ }
+
+ /**
+ * Whether this context is supported.
+ *
+ * @return true by default.
+ */
+ default boolean isModelSupported(M context) {
+ return true;
+ }
+
+ default W createUiPart(V parent, M context) {
+ if (!isViewSupported(parent))
+ throw new IllegalArgumentException("Parent view " + parent + "is not supported.");
+ if (!isModelSupported(context))
+ throw new IllegalArgumentException("Model context " + context + "is not supported.");
+ return apply(parent, context);
+ }
+}
--- /dev/null
+package org.argeo.api;
+
+public interface NodeConstants {
+ /*
+ * DN ATTRIBUTES (RFC 4514)
+ */
+ String CN = "cn";
+ String L = "l";
+ String ST = "st";
+ String O = "o";
+ String OU = "ou";
+ String C = "c";
+ String STREET = "street";
+ String DC = "dc";
+ String UID = "uid";
+
+ /*
+ * STANDARD ATTRIBUTES
+ */
+ String LABELED_URI = "labeledUri";
+
+ /*
+ * COMMON NAMES
+ */
+ String NODE = "node";
+ String EGO = "ego";
+ String HOME = "home";
+ String SRV = "srv";
+ String GUESTS = "guests";
+ String PUBLIC = "public";
+
+ /*
+ * BASE DNs
+ */
+ String DEPLOY_BASEDN = "ou=deploy,ou=node";
+
+ /*
+ * STANDARD VALUES
+ */
+ String DEFAULT = "default";
+
+ /*
+ * RESERVED ROLES
+ */
+ String ROLES_BASEDN = "ou=roles,ou=node";
+ String TOKENS_BASEDN = "ou=tokens,ou=node";
+ String ROLE_ADMIN = "cn=admin," + ROLES_BASEDN;
+ String ROLE_USER_ADMIN = "cn=userAdmin," + ROLES_BASEDN;
+ String ROLE_DATA_ADMIN = "cn=dataAdmin," + ROLES_BASEDN;
+ // Special system groups that cannot be edited:
+ // user U anonymous = everyone
+ String ROLE_USER = "cn=user," + ROLES_BASEDN;
+ String ROLE_ANONYMOUS = "cn=anonymous," + ROLES_BASEDN;
+ // Account lifecycle
+ String ROLE_REGISTERING = "cn=registering," + ROLES_BASEDN;
+
+ /*
+ * LOGIN CONTEXTS
+ */
+ String LOGIN_CONTEXT_NODE = "NODE";
+ String LOGIN_CONTEXT_USER = "USER";
+ String LOGIN_CONTEXT_ANONYMOUS = "ANONYMOUS";
+ String LOGIN_CONTEXT_DATA_ADMIN = "DATA_ADMIN";
+ String LOGIN_CONTEXT_SINGLE_USER = "SINGLE_USER";
+ String LOGIN_CONTEXT_KEYRING = "KEYRING";
+
+ /*
+ * PATHS
+ */
+ String PATH_DATA = "/data";
+ String PATH_JCR = "/jcr";
+ String PATH_FILES = "/files";
+ // String PATH_JCR_PUB = "/pub";
+
+ /*
+ * FILE SYSTEMS
+ */
+ String SCHEME_NODE = NODE;
+
+ /*
+ * KERBEROS
+ */
+ String NODE_SERVICE = NODE;
+
+ /*
+ * INIT FRAMEWORK PROPERTIES
+ */
+ String NODE_INIT = "argeo.node.init";
+ String I18N_DEFAULT_LOCALE = "argeo.i18n.defaultLocale";
+ String I18N_LOCALES = "argeo.i18n.locales";
+ // Node Security
+ String ROLES_URI = "argeo.node.roles.uri";
+ String TOKENS_URI = "argeo.node.tokens.uri";
+ /** URI to an LDIF file or LDAP server used as initialization or backend */
+ String USERADMIN_URIS = "argeo.node.useradmin.uris";
+ // Transaction manager
+ String TRANSACTION_MANAGER = "argeo.node.transaction.manager";
+ String TRANSACTION_MANAGER_SIMPLE = "simple";
+ String TRANSACTION_MANAGER_BITRONIX = "bitronix";
+ // Node
+ /** Properties configuring the node repository */
+ String NODE_REPO_PROP_PREFIX = "argeo.node.repo.";
+ /** Additional standalone repositories, related to data models. */
+ String NODE_REPOS_PROP_PREFIX = "argeo.node.repos.";
+ // HTTP
+ String HTTP_PORT = "org.osgi.service.http.port";
+ String HTTP_PORT_SECURE = "org.osgi.service.http.port.secure";
+ /**
+ * The HTTP header used to convey the DN of a client verified by a reverse
+ * proxy. Typically SSL_CLIENT_S_DN for Apache.
+ */
+ String HTTP_PROXY_SSL_DN = "argeo.http.proxy.ssl.dn";
+
+ /*
+ * PIDs
+ */
+ String NODE_STATE_PID = "org.argeo.api.state";
+ String NODE_DEPLOYMENT_PID = "org.argeo.api.deployment";
+ String NODE_INSTANCE_PID = "org.argeo.api.instance";
+
+ String NODE_KEYRING_PID = "org.argeo.api.keyring";
+ String NODE_FS_PROVIDER_PID = "org.argeo.api.fsProvider";
+
+ /*
+ * FACTORY PIDs
+ */
+ String NODE_REPOS_FACTORY_PID = "org.argeo.api.repos";
+ String NODE_USER_ADMIN_PID = "org.argeo.api.userAdmin";
+}
--- /dev/null
+package org.argeo.api;
+
+public interface NodeDeployment {
+ Long getAvailableSince();
+}
--- /dev/null
+package org.argeo.api;
+
+import javax.naming.ldap.LdapName;
+
+/** The structured data */
+public interface NodeInstance {
+ /**
+ * To be used as an identifier of a workgroup, typically as a value for the
+ * 'businessCategory' attribute in LDAP.
+ */
+ public final static String WORKGROUP = "workgroup";
+
+ /** Mark this group as a workgroup */
+ void createWorkgroup(LdapName groupDn);
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api;
+
+/** JCR types in the http://www.argeo.org/node namespace */
+@Deprecated
+public interface NodeNames {
+ String LDAP_UID = "ldap:"+NodeConstants.UID;
+ String LDAP_CN = "ldap:"+NodeConstants.CN;
+}
--- /dev/null
+package org.argeo.api;
+
+interface NodeOID {
+ String BASE = "1.3.6.1.4.1" + ".48308" + ".1";
+
+ // ATTRIBUTE TYPES
+ String ATTRIBUTE_TYPES = BASE + ".4";
+
+ // OBJECT CLASSES
+ String OBJECT_CLASSES = BASE + ".6";
+}
--- /dev/null
+package org.argeo.api;
+
+import java.util.List;
+import java.util.Locale;
+
+public interface NodeState {
+ Locale getDefaultLocale();
+
+ List<Locale> getLocales();
+
+ String getHostname();
+
+ boolean isClean();
+
+ Long getAvailableSince();
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api;
+
+/** JCR types in the http://www.argeo.org/node namespace */
+@Deprecated
+public interface NodeTypes {
+ String NODE_USER_HOME = "node:userHome";
+ String NODE_GROUP_HOME = "node:groupHome";
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api;
+
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.security.auth.AuthPermission;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+/** Utilities related to Argeo model in JCR */
+public class NodeUtils {
+ /**
+ * Wraps the call to the repository factory based on parameter
+ * {@link NodeConstants#CN} in order to simplify it and protect against future
+ * API changes.
+ */
+ public static Repository getRepositoryByAlias(RepositoryFactory repositoryFactory, String alias) {
+ try {
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put(NodeConstants.CN, alias);
+ return repositoryFactory.getRepository(parameters);
+ } catch (RepositoryException e) {
+ throw new RuntimeException("Unexpected exception when trying to retrieve repository with alias " + alias,
+ e);
+ }
+ }
+
+ /**
+ * Wraps the call to the repository factory based on parameter
+ * {@link NodeConstants#LABELED_URI} in order to simplify it and protect against
+ * future API changes.
+ */
+ public static Repository getRepositoryByUri(RepositoryFactory repositoryFactory, String uri) {
+ return getRepositoryByUri(repositoryFactory, uri, null);
+ }
+
+ /**
+ * Wraps the call to the repository factory based on parameter
+ * {@link NodeConstants#LABELED_URI} in order to simplify it and protect against
+ * future API changes.
+ */
+ public static Repository getRepositoryByUri(RepositoryFactory repositoryFactory, String uri, String alias) {
+ try {
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put(NodeConstants.LABELED_URI, uri);
+ if (alias != null)
+ parameters.put(NodeConstants.CN, alias);
+ return repositoryFactory.getRepository(parameters);
+ } catch (RepositoryException e) {
+ throw new RuntimeException("Unexpected exception when trying to retrieve repository with uri " + uri, e);
+ }
+ }
+
+ /**
+ * Returns the home node of the user or null if none was found.
+ *
+ * @param session the session to use in order to perform the search, this can
+ * be a session with a different user ID than the one searched,
+ * typically when a system or admin session is used.
+ * @param username the username of the user
+ */
+ public static Node getUserHome(Session session, String username) {
+// try {
+// QueryObjectModelFactory qomf = session.getWorkspace().getQueryManager().getQOMFactory();
+// Selector sel = qomf.selector(NodeTypes.NODE_USER_HOME, "sel");
+// DynamicOperand dop = qomf.propertyValue(sel.getSelectorName(), NodeNames.LDAP_UID);
+// StaticOperand sop = qomf.literal(session.getValueFactory().createValue(username));
+// Constraint constraint = qomf.comparison(dop, QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, sop);
+// Query query = qomf.createQuery(sel, constraint, null, null);
+// return querySingleNode(query);
+// } catch (RepositoryException e) {
+// throw new RuntimeException("Cannot find home for user " + username, e);
+// }
+
+ try {
+ checkUserWorkspace(session, username);
+ String homePath = getHomePath(username);
+ if (session.itemExists(homePath))
+ return session.getNode(homePath);
+ // legacy
+ homePath = "/home/" + username;
+ if (session.itemExists(homePath))
+ return session.getNode(homePath);
+ return null;
+ } catch (RepositoryException e) {
+ throw new RuntimeException("Cannot find home for user " + username, e);
+ }
+ }
+
+ private static String getHomePath(String username) {
+ LdapName dn;
+ try {
+ dn = new LdapName(username);
+ } catch (InvalidNameException e) {
+ throw new IllegalArgumentException("Invalid name " + username, e);
+ }
+ String userId = dn.getRdn(dn.size() - 1).getValue().toString();
+ return '/' + userId;
+ }
+
+ private static void checkUserWorkspace(Session session, String username) {
+ String workspaceName = session.getWorkspace().getName();
+ if (!NodeConstants.HOME.equals(workspaceName))
+ throw new IllegalArgumentException(workspaceName + " is not the home workspace for user " + username);
+ }
+
+ /**
+ * Returns the home node of the user or null if none was found.
+ *
+ * @param session the session to use in order to perform the search, this can
+ * be a session with a different user ID than the one searched,
+ * typically when a system or admin session is used.
+ * @param groupname the name of the group
+ */
+ public static Node getGroupHome(Session session, String groupname) {
+// try {
+// QueryObjectModelFactory qomf = session.getWorkspace().getQueryManager().getQOMFactory();
+// Selector sel = qomf.selector(NodeTypes.NODE_GROUP_HOME, "sel");
+// DynamicOperand dop = qomf.propertyValue(sel.getSelectorName(), NodeNames.LDAP_CN);
+// StaticOperand sop = qomf.literal(session.getValueFactory().createValue(cn));
+// Constraint constraint = qomf.comparison(dop, QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, sop);
+// Query query = qomf.createQuery(sel, constraint, null, null);
+// return querySingleNode(query);
+// } catch (RepositoryException e) {
+// throw new RuntimeException("Cannot find home for group " + cn, e);
+// }
+
+ try {
+ checkGroupWorkspace(session, groupname);
+ String homePath = getGroupPath(groupname);
+ if (session.itemExists(homePath))
+ return session.getNode(homePath);
+ // legacy
+ homePath = "/groups/" + groupname;
+ if (session.itemExists(homePath))
+ return session.getNode(homePath);
+ return null;
+ } catch (RepositoryException e) {
+ throw new RuntimeException("Cannot find home for group " + groupname, e);
+ }
+
+ }
+
+ private static String getGroupPath(String groupname) {
+ String cn;
+ try {
+ LdapName dn = new LdapName(groupname);
+ cn = dn.getRdn(dn.size() - 1).getValue().toString();
+ } catch (InvalidNameException e) {
+ cn = groupname;
+ }
+ return '/' + cn;
+ }
+
+ private static void checkGroupWorkspace(Session session, String groupname) {
+ String workspaceName = session.getWorkspace().getName();
+ if (!NodeConstants.SRV.equals(workspaceName))
+ throw new IllegalArgumentException(workspaceName + " is not the group workspace for group " + groupname);
+ }
+
+ /**
+ * Queries one single node.
+ *
+ * @return one single node or null if none was found
+ * @throws ArgeoJcrException if more than one node was found
+ */
+ private static Node querySingleNode(Query query) {
+ NodeIterator nodeIterator;
+ try {
+ QueryResult queryResult = query.execute();
+ nodeIterator = queryResult.getNodes();
+ } catch (RepositoryException e) {
+ throw new RuntimeException("Cannot execute query " + query, e);
+ }
+ Node node;
+ if (nodeIterator.hasNext())
+ node = nodeIterator.nextNode();
+ else
+ return null;
+
+ if (nodeIterator.hasNext())
+ throw new RuntimeException("Query returned more than one node.");
+ return node;
+ }
+
+ /** Returns the home node of the session user or null if none was found. */
+ public static Node getUserHome(Session session) {
+ String userID = session.getUserID();
+ return getUserHome(session, userID);
+ }
+
+ /**
+ * Translate the path to this node into a path containing the name of the
+ * repository and the name of the workspace.
+ */
+ public static String getDataPath(String cn, Node node) throws RepositoryException {
+ assert node != null;
+ StringBuilder buf = new StringBuilder(NodeConstants.PATH_DATA);
+ return buf.append('/').append(cn).append('/').append(node.getSession().getWorkspace().getName())
+ .append(node.getPath()).toString();
+ }
+
+ /**
+ * Open a JCR session with full read/write rights on the data, as
+ * {@link NodeConstants#ROLE_USER_ADMIN}, using the
+ * {@link NodeConstants#LOGIN_CONTEXT_DATA_ADMIN} login context. For security
+ * hardened deployement, use {@link AuthPermission} on this login context.
+ */
+ public static Session openDataAdminSession(Repository repository, String workspaceName) {
+ ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
+ LoginContext loginContext;
+ try {
+ loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN);
+ loginContext.login();
+ } catch (LoginException e1) {
+ throw new RuntimeException("Could not login as data admin", e1);
+ } finally {
+ Thread.currentThread().setContextClassLoader(currentCl);
+ }
+ return Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Session>() {
+
+ @Override
+ public Session run() {
+ try {
+ return repository.login(workspaceName);
+ } catch (NoSuchWorkspaceException e) {
+ throw new IllegalArgumentException("No workspace " + workspaceName + " available", e);
+ } catch (RepositoryException e) {
+ throw new RuntimeException("Cannot open data admin session", e);
+ }
+ }
+
+ });
+ }
+
+ /** Singleton. */
+ private NodeUtils() {
+ }
+
+}
--- /dev/null
+<ldap = 'http://www.argeo.org/ns/ldap'>
--- /dev/null
+<node = 'http://www.argeo.org/ns/node'>
+
+[node:userHome]
+mixin
+- ldap:uid (STRING) m
+
+[node:groupHome]
+mixin
+- ldap:cn (STRING) m
--- /dev/null
+/**
+ * Abstractions or constants related to an Argeo Node, an active repository of
+ * linked data.
+ */
+package org.argeo.api;
\ No newline at end of file
--- /dev/null
+package org.argeo.api.security;
+
+import java.security.Principal;
+
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.NodeConstants;
+
+/** Marker for anonymous users. */
+public final class AnonymousPrincipal implements Principal {
+ private final String name = NodeConstants.ROLE_ANONYMOUS;
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+
+ @Override
+ public String toString() {
+ return name.toString();
+ }
+
+ public LdapName getLdapName(){
+ return NodeSecurityUtils.ROLE_ANONYMOUS_NAME;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.security;
+
+/**
+ * Marker interface for an advanced keyring based on cryptography.
+ */
+public interface CryptoKeyring extends Keyring {
+ public void changePassword(char[] oldPassword, char[] newPassword);
+
+ public void unlock(char[] password);
+}
--- /dev/null
+package org.argeo.api.security;
+
+import java.security.Principal;
+
+import org.argeo.api.NodeConstants;
+
+/** Allows to modify any data. */
+public final class DataAdminPrincipal implements Principal {
+ private final String name = NodeConstants.ROLE_DATA_ADMIN;
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof DataAdminPrincipal;
+ }
+
+ @Override
+ public String toString() {
+ return name.toString();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.security;
+
+import java.io.InputStream;
+
+/**
+ * Access to private (typically encrypted) data. The keyring is responsible for
+ * retrieving the necessary credentials. <b>Experimental. This API may
+ * change.</b>
+ */
+public interface Keyring {
+ /**
+ * Returns the confidential information as chars. Must ask for it if it is
+ * not stored.
+ */
+ public char[] getAsChars(String path);
+
+ /**
+ * Returns the confidential information as a stream. Must ask for it if it
+ * is not stored.
+ */
+ public InputStream getAsStream(String path);
+
+ public void set(String path, char[] arr);
+
+ public void set(String path, InputStream in);
+}
--- /dev/null
+package org.argeo.api.security;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.NodeConstants;
+
+public class NodeSecurityUtils {
+ public final static LdapName ROLE_ADMIN_NAME, ROLE_DATA_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME,
+ ROLE_USER_ADMIN_NAME;
+ public final static List<LdapName> RESERVED_ROLES;
+ static {
+ try {
+ ROLE_ADMIN_NAME = new LdapName(NodeConstants.ROLE_ADMIN);
+ ROLE_DATA_ADMIN_NAME = new LdapName(NodeConstants.ROLE_DATA_ADMIN);
+ ROLE_USER_NAME = new LdapName(NodeConstants.ROLE_USER);
+ ROLE_USER_ADMIN_NAME = new LdapName(NodeConstants.ROLE_USER_ADMIN);
+ ROLE_ANONYMOUS_NAME = new LdapName(NodeConstants.ROLE_ANONYMOUS);
+ RESERVED_ROLES = Collections.unmodifiableList(Arrays.asList(
+ new LdapName[] { ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME, ROLE_USER_ADMIN_NAME }));
+ } catch (InvalidNameException e) {
+ throw new Error("Cannot initialize login module class", e);
+ }
+ }
+
+ public static void checkUserName(LdapName name) throws IllegalArgumentException {
+ if (RESERVED_ROLES.contains(name))
+ throw new IllegalArgumentException(name + " is a reserved name");
+ }
+
+ public static void checkImpliedPrincipalName(LdapName roleName) throws IllegalArgumentException {
+// if (ROLE_USER_NAME.equals(roleName) || ROLE_ANONYMOUS_NAME.equals(roleName))
+// throw new IllegalArgumentException(roleName + " cannot be listed as role");
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.security;
+
+import javax.crypto.spec.PBEKeySpec;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.PasswordCallback;
+
+/**
+ * All information required to set up a {@link PBEKeySpec} bar the password
+ * itself (use a {@link PasswordCallback})
+ */
+public class PBEKeySpecCallback implements Callback {
+ private String secretKeyFactory;
+ private byte[] salt;
+ private Integer iterationCount;
+ /** Can be null for some algorithms */
+ private Integer keyLength;
+ /** Can be null, will trigger secret key encryption if not */
+ private String secretKeyEncryption;
+
+ private String encryptedPasswordHashCipher;
+ private byte[] encryptedPasswordHash;
+
+ public void set(String secretKeyFactory, byte[] salt,
+ Integer iterationCount, Integer keyLength,
+ String secretKeyEncryption) {
+ this.secretKeyFactory = secretKeyFactory;
+ this.salt = salt;
+ this.iterationCount = iterationCount;
+ this.keyLength = keyLength;
+ this.secretKeyEncryption = secretKeyEncryption;
+// this.encryptedPasswordHashCipher = encryptedPasswordHashCipher;
+// this.encryptedPasswordHash = encryptedPasswordHash;
+ }
+
+ public String getSecretKeyFactory() {
+ return secretKeyFactory;
+ }
+
+ public byte[] getSalt() {
+ return salt;
+ }
+
+ public Integer getIterationCount() {
+ return iterationCount;
+ }
+
+ public Integer getKeyLength() {
+ return keyLength;
+ }
+
+ public String getSecretKeyEncryption() {
+ return secretKeyEncryption;
+ }
+
+ public String getEncryptedPasswordHashCipher() {
+ return encryptedPasswordHashCipher;
+ }
+
+ public byte[] getEncryptedPasswordHash() {
+ return encryptedPasswordHash;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.tabular;
+
+import java.util.List;
+
+/** Minimal tabular row wrapping an {@link Object} array */
+public class ArrayTabularRow implements TabularRow {
+ private final Object[] arr;
+
+ public ArrayTabularRow(List<?> objs) {
+ this.arr = objs.toArray();
+ }
+
+ public Object get(Integer col) {
+ return arr[col];
+ }
+
+ public int size() {
+ return arr.length;
+ }
+
+ public Object[] toArray() {
+ return arr;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.tabular;
+
+/** The column in a tabular content */
+public class TabularColumn {
+ private String name;
+ /**
+ * JCR types, see
+ * http://www.day.com/maven/javax.jcr/javadocs/jcr-2.0/index.html
+ * ?javax/jcr/PropertyType.html
+ */
+ private Integer type;
+
+ /** column with default type */
+ public TabularColumn(String name) {
+ super();
+ this.name = name;
+ }
+
+ public TabularColumn(String name, Integer type) {
+ super();
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getType() {
+ return type;
+ }
+
+ public void setType(Integer type) {
+ this.type = type;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.tabular;
+
+import java.util.List;
+
+/**
+ * Content organized as a table, possibly with headers. Only JCR types are
+ * supported even though there is not direct dependency on JCR.
+ */
+public interface TabularContent {
+ /** The headers of this table or <code>null</code> is none available. */
+ public List<TabularColumn> getColumns();
+
+ public TabularRowIterator read();
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.tabular;
+
+/** A row of tabular data */
+public interface TabularRow {
+ /** The value at this column index */
+ public Object get(Integer col);
+
+ /** The raw objects (direct references) */
+ public Object[] toArray();
+
+ /** Number of columns */
+ public int size();
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.tabular;
+
+import java.util.Iterator;
+
+/** Navigation of rows */
+public interface TabularRowIterator extends Iterator<TabularRow> {
+ /**
+ * Current row number, has to be incremented by each call to next() ; starts at 0, will
+ * therefore be 1 for the first row returned.
+ */
+ public Long getCurrentRowNumber();
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.api.tabular;
+
+
+/** Write to a tabular content */
+public interface TabularWriter {
+ /** Append a new row of data */
+ public void appendRow(Object[] row);
+
+ /** Finish persisting data and release resources */
+ public void close();
+}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" configuration-policy="optional" name="CMS Demo RAP">
- <implementation class="org.argeo.cms.e4.rap.CmsE4DemoApp"/>
- <service>
- <provide interface="org.eclipse.rap.rwt.application.ApplicationConfiguration"/>
- <property name="contextName" type="String" value="demoXXX"/>
- </service>
-</scr:component>
Bundle-ActivationPolicy: lazy
Service-Component: OSGI-INF/cms-admin-rap.xml
-#OSGI-INF/cms-demo-rap.xml
-#Bundle-Activator: org.argeo.cms.script.ScriptAppActivator
-
-Import-Package: org.argeo.node,\
+Import-Package: org.argeo.api,\
org.eclipse.swt,\
org.eclipse.swt.graphics,\
org.eclipse.e4.ui.workbench,\
+++ /dev/null
-var AppUi = Java.type('org.argeo.cms.script.AppUi')
-var CmsE4EntryPointFactory = Java
- .type('org.argeo.cms.e4.rap.CmsE4EntryPointFactory')
-
-APP.setWebPath('cms')
-APP.setPageTitle('Argeo CMS')
-
-APP.getUi().put(
- 'devops',
- new AppUi(APP, new CmsE4EntryPointFactory(
- 'org.argeo.cms.e4/e4xmi/cms-devops.e4xmi')))
-APP.getUi().get('devops').setPageTitle('Argeo CMS DevOps')
+++ /dev/null
-package org.argeo.cms.e4.rap;
-
-public class CmsE4DemoApp extends AbstractRapE4App {
- public CmsE4DemoApp() {
- setPageTitle("CMS Demo");
- setE4Xmi("org.argeo.cms.e4.rap/e4xmi/cms-demo-rap.e4xmi");
- setPath("/cms-e4");
- }
-
-}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.ui.CmsImageManager;
import org.argeo.cms.ui.CmsView;
import org.argeo.cms.ui.UxContext;
import org.argeo.cms.ui.dialogs.CmsFeedback;
-import org.argeo.cms.util.SimpleImageManager;
-import org.argeo.cms.util.SimpleUxContext;
-import org.argeo.cms.widgets.auth.CmsLoginShell;
+import org.argeo.cms.ui.util.SimpleImageManager;
+import org.argeo.cms.ui.util.SimpleUxContext;
+import org.argeo.cms.ui.widgets.auth.CmsLoginShell;
import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.node.NodeConstants;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
+++ /dev/null
-'Source,Save,Templates,Strike,Subscript,Superscript,CopyFormatting,Outdent,Indent,CreateDiv,JustifyLeft,JustifyCenter,JustifyRight,JustifyBlock,Language,Anchor,Flash,HorizontalRule,Smiley,SpecialChar,PageBreak,Iframe,Format,Font,FontSize,BGColor,TextColor,ShowBlocks,About,Preview,Print,Redo,Replace,Find,Undo,SelectAll,Scayt,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,NewPage,PasteFromWord,Blockquote,BidiLtr,BidiRtl'
\ No newline at end of file
+++ /dev/null
-CKEDITOR.editorConfig = function( config ) {
- config.toolbarGroups = [
- { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
- { name: 'styles', groups: [ 'styles' ] },
- { name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
- { name: 'forms', groups: [ 'forms' ] },
- { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
- { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] },
- { name: 'insert', groups: [ 'insert' ] },
- { name: 'links', groups: [ 'links' ] },
- { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
- { name: 'colors', groups: [ 'colors' ] },
- { name: 'tools', groups: [ 'tools' ] },
- { name: 'others', groups: [ 'others' ] },
- { name: 'about', groups: [ 'about' ] }
- ];
-
- config.removeButtons = 'Source,Save,Templates,Strike,Subscript,Superscript,CopyFormatting,Outdent,Indent,CreateDiv,JustifyLeft,JustifyCenter,JustifyRight,JustifyBlock,BidiLtr,BidiRtl,Language,Anchor,Flash,HorizontalRule,Smiley,SpecialChar,PageBreak,Iframe,Format,Font,FontSize,BGColor,TextColor,Maximize,ShowBlocks,About,Preview,Print,Redo,Replace,Find,Undo,SelectAll,Scayt,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,NewPage,PasteFromWord,Blockquote';
-};
\ No newline at end of file
+++ /dev/null
-[
- {
- "name": "document",
- "groups": [
- "mode",
- "document",
- "doctools"
- ]
- },
- {
- "name": "styles",
- "groups": [
- "styles"
- ]
- },
- {
- "name": "editing",
- "groups": [
- "find",
- "selection",
- "spellchecker",
- "editing"
- ]
- },
- {
- "name": "forms",
- "groups": [
- "forms"
- ]
- },
- {
- "name": "basicstyles",
- "groups": [
- "basicstyles",
- "cleanup"
- ]
- },
- {
- "name": "paragraph",
- "groups": [
- "list",
- "indent",
- "blocks",
- "align",
- "bidi",
- "paragraph"
- ]
- },
- {
- "name": "insert",
- "groups": [
- "insert"
- ]
- },
- {
- "name": "links",
- "groups": [
- "links"
- ]
- },
- {
- "name": "clipboard",
- "groups": [
- "clipboard",
- "undo"
- ]
- },
- {
- "name": "colors",
- "groups": [
- "colors"
- ]
- },
- {
- "name": "tools",
- "groups": [
- "tools"
- ]
- },
- {
- "name": "others",
- "groups": [
- "others"
- ]
- },
- {
- "name": "about",
- "groups": [
- "about"
- ]
- }
-]
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.rap.parts;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-
-import javax.annotation.PostConstruct;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.nebula.widgets.richtext.RichTextEditor;
-import org.eclipse.nebula.widgets.richtext.RichTextEditorConfiguration;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.browser.Browser;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Color;
-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.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-public class HtmlEditor {
-
- @PostConstruct
- public void createUI(Composite parent) {
- String toolbarGroups;
- String removeButtons;
- try {
- toolbarGroups = IOUtils.toString(HtmlEditor.class.getResourceAsStream("CkEditor-toolbarGroups.json"),
- StandardCharsets.UTF_8);
- removeButtons = IOUtils.toString(HtmlEditor.class.getResourceAsStream("CkEditor-removeButtons.js"),
- StandardCharsets.UTF_8);
- } catch (IOException e) {
- throw new CmsException("Cannot configure toolbar", e);
- }
-// System.out.println(toolbarGroups);
-// System.out.println(removeButtons);
- RichTextEditorConfiguration richTextEditorConfig = new RichTextEditorConfiguration();
- richTextEditorConfig.setOption(RichTextEditorConfiguration.TOOLBAR_GROUPS, toolbarGroups);
- richTextEditorConfig.setOption(RichTextEditorConfiguration.REMOVE_BUTTONS, removeButtons);
-// richTextEditorConfig.setRemoveStyles(false);
-// richTextEditorConfig.setRemovePasteFromWord(true);
-// richTextEditorConfig.setRemovePasteText(false);
-
-// richTextEditorConfig.setToolbarCollapsible(true);
-// richTextEditorConfig.setToolbarInitialExpanded(false);
-
- final Display display = parent.getDisplay();
- Composite composite = new Composite(parent, SWT.NONE);
-// composite.setLayoutData(new Fill);
- composite.setLayout(new GridLayout());
- final RichTextEditor richTextEditor = new RichTextEditor(composite, richTextEditorConfig, SWT.BORDER);
- richTextEditor.setText("<a href='http://googl.com'>Google</a>");
- GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
- richTextEditor.setLayoutData(layoutData);
- richTextEditor.setBackground(new Color(display, 247, 247, 247));
- Composite toolbar = new Composite(composite, SWT.NONE);
- toolbar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- toolbar.setLayout(new GridLayout(3, false));
- Button showContent = new Button(toolbar, SWT.PUSH);
- showContent.setText("Show Content");
- showContent.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- showContent(parent, richTextEditor, false);
- }
- });
- Button showSource = new Button(toolbar, SWT.PUSH);
- showSource.setText("Show Source");
- showSource.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- showContent(parent, richTextEditor, true);
- }
- });
- Button clearBtn = new Button(toolbar, SWT.NONE);
- clearBtn.setText("Clear");
- clearBtn.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- richTextEditor.setText("");
- }
- });
-
- }
-
- private static void showContent(Composite parent, RichTextEditor editor, boolean source) {
- int style = SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL;
- final Shell content = new Shell(parent.getShell(), style);
- content.setLayout(new GridLayout(1, true));
- String text = editor.getText();
- if (source) {
- content.setText("Rich Text Source");
- Text viewer = new Text(content, SWT.MULTI | SWT.WRAP);
- viewer.setLayoutData(new GridData(400, 400));
- viewer.setText(text);
- viewer.setEditable(false);
- } else {
- content.setText("Rich Text");
- Browser viewer = new Browser(content, SWT.NONE);
- viewer.setLayoutData(new GridData(400, 400));
- viewer.setText(text);
- viewer.setEnabled(false);
- }
- Button ok = new Button(content, SWT.PUSH);
- ok.setLayoutData(new GridData(SWT.RIGHT, SWT.BOTTOM, false, false));
- ok.setText("OK");
- ok.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- content.dispose();
- }
- });
- content.setDefaultButton(ok);
- content.pack();
- Display display = parent.getDisplay();
- int left = (display.getClientArea().width / 2) - (content.getBounds().width / 2);
- content.setLocation(left, 40);
- content.open();
- ok.setFocus();
- }
-
-}
+++ /dev/null
-{
- "firstName": "John",
- "lastName": "Smith",
- "isAlive": true,
- "age": 27,
- "address": {
- "streetAddress": "21 2nd Street",
- "city": "New York",
- "state": "NY",
- "postalCode": "10021-3100"
- },
- "phoneNumbers": [
- {
- "type": "home",
- "number": "212 555-1234"
- },
- {
- "type": "office",
- "number": "646 555-4567"
- },
- {
- "type": "mobile",
- "number": "123 456-7890"
- }
- ],
- "children": [],
- "spouse": null
-}
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default CallbackHandler">
- <implementation class="org.argeo.cms.widgets.auth.DynamicCallbackHandler"/>
+ <implementation class="org.argeo.cms.ui.widgets.auth.DynamicCallbackHandler"/>
<service>
<provide interface="javax.security.auth.callback.CallbackHandler"/>
</service>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="Home Repository">
- <implementation class="org.argeo.cms.e4.contexts.OsgiFilterContextFunction"/>
+ <implementation class="org.argeo.cms.e4.OsgiFilterContextFunction"/>
<property name="service.context.key" type="String" value="(cn=home)"/>
<service>
<provide interface="org.eclipse.e4.core.contexts.IContextFunction"/>
org.argeo.cms,\
org.eclipse.core.commands.common,\
org.eclipse.jface.window,\
-org.argeo.cms.widgets.auth,\
+org.argeo.cms.ui.widgets.auth,\
*
--- /dev/null
+package org.argeo.cms.e4;
+
+import org.argeo.cms.CmsException;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.IInjector;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/** An Eclipse 4 {@link ContextFunction} based on an OSGi filter. */
+public class OsgiFilterContextFunction extends ContextFunction {
+
+ private BundleContext bc = FrameworkUtil.getBundle(OsgiFilterContextFunction.class).getBundleContext();
+
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ ServiceReference<?>[] srs;
+ try {
+ srs = bc.getServiceReferences((String) null, contextKey);
+ } catch (InvalidSyntaxException e) {
+ throw new CmsException("Context key " + contextKey + " must be a valid osgi filter", e);
+ }
+ if (srs == null || srs.length == 0) {
+ return IInjector.NOT_A_VALUE;
+ } else {
+ // return the first one
+ return bc.getService(srs[0]);
+ }
+ }
+
+}
+++ /dev/null
-package org.argeo.cms.e4.contexts;
-
-import org.argeo.cms.CmsException;
-import org.eclipse.e4.core.contexts.ContextFunction;
-import org.eclipse.e4.core.contexts.IEclipseContext;
-import org.eclipse.e4.core.di.IInjector;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-@SuppressWarnings("restriction")
-public class OsgiFilterContextFunction extends ContextFunction {
-
- private BundleContext bc = FrameworkUtil.getBundle(OsgiFilterContextFunction.class).getBundleContext();
-
- @Override
- public Object compute(IEclipseContext context, String contextKey) {
- ServiceReference<?>[] srs;
- try {
- srs = bc.getServiceReferences((String) null, contextKey);
- } catch (InvalidSyntaxException e) {
- throw new CmsException("Context key " + contextKey + " must be a valid osgi filter", e);
- }
- if (srs == null || srs.length == 0) {
- return IInjector.NOT_A_VALUE;
- } else {
- // return the first one
- return bc.getService(srs[0]);
- }
- }
-
-}
import javax.annotation.PostConstruct;
import javax.inject.Inject;
+import org.argeo.api.NodeUtils;
import org.argeo.cms.CmsException;
import org.argeo.eclipse.ui.fs.AdvancedFsBrowser;
import org.argeo.eclipse.ui.fs.SimpleFsBrowser;
-import org.argeo.node.NodeUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import javax.security.auth.x500.X500Principal;
import javax.transaction.UserTransaction;
+import org.argeo.api.security.CryptoKeyring;
import org.argeo.cms.CmsException;
import org.argeo.cms.ui.dialogs.CmsMessageDialog;
import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.node.security.CryptoKeyring;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.security.CryptoKeyring;
+import org.argeo.api.security.Keyring;
import org.argeo.cms.CmsException;
import org.argeo.cms.ui.jcr.JcrBrowserUtils;
import org.argeo.cms.ui.jcr.NodeContentProvider;
import org.argeo.cms.ui.jcr.OsgiRepositoryRegister;
import org.argeo.cms.ui.jcr.PropertiesContentProvider;
import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.argeo.cms.util.CmsUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.eclipse.ui.EclipseUiException;
import org.argeo.eclipse.ui.TreeParent;
import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
-import org.argeo.eclipse.ui.jcr.utils.NodeViewerComparer;
+import org.argeo.eclipse.ui.jcr.util.NodeViewerComparer;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.security.CryptoKeyring;
-import org.argeo.node.security.Keyring;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.ui.services.EMenuService;
// Create the tree on top of the view
Composite top = new Composite(sashForm, SWT.NONE);
// GridLayout gl = new GridLayout(1, false);
- top.setLayout(CmsUtils.noSpaceGridLayout());
+ top.setLayout(CmsUiUtils.noSpaceGridLayout());
try {
this.userSession = this.nodeRepository.login(NodeConstants.HOME);
// Create the property viewer on the bottom
Composite bottom = new Composite(sashForm, SWT.NONE);
- bottom.setLayout(CmsUtils.noSpaceGridLayout());
+ bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
propertiesViewer = createPropertiesViewer(bottom);
sashForm.setWeights(getWeights());
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.api.security.Keyring;
import org.argeo.cms.ArgeoNames;
import org.argeo.cms.ArgeoTypes;
import org.argeo.cms.e4.jcr.JcrBrowserView;
import org.argeo.eclipse.ui.EclipseUiException;
import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeUtils;
-import org.argeo.node.security.Keyring;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.util.Collection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+abstract class AbstractOsgiComposite extends Composite {
+ private static final long serialVersionUID = -4097415973477517137L;
+ protected final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
+ protected final Log log = LogFactory.getLog(getClass());
+
+ public AbstractOsgiComposite(Composite parent, int style) {
+ super(parent, style);
+ parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+ setLayout(CmsUiUtils.noSpaceGridLayout());
+ setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ initUi(style);
+ }
+
+ protected abstract void initUi(int style);
+
+ protected <T> T getService(Class<? extends T> clazz) {
+ return bc.getService(bc.getServiceReference(clazz));
+ }
+
+ protected <T> Collection<ServiceReference<T>> getServiceReferences(Class<T> clazz, String filter) {
+ try {
+ return bc.getServiceReferences(clazz, filter);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Filter " + filter + " is invalid", e);
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import static org.eclipse.swt.SWT.RIGHT;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.LinkedHashMap;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsLink;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.widgets.EditableImage;
+import org.argeo.cms.ui.widgets.Img;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ILazyContentProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+
+public class Browse implements CmsUiProvider {
+
+ // Some local constants to experiment. should be cleaned
+ private final static String BROWSE_PREFIX = "browse#";
+ private final static int THUMBNAIL_WIDTH = 400;
+ private final static int COLUMN_WIDTH = 160;
+ private DateFormat timeFormatter = new SimpleDateFormat("dd-MM-yyyy', 'HH:mm");
+
+ // keep a cache of the opened nodes
+ // Key is the path
+ private LinkedHashMap<String, FilterEntitiesVirtualTable> browserCols = new LinkedHashMap<String, Browse.FilterEntitiesVirtualTable>();
+ private Composite nodeDisplayParent;
+ private Composite colViewer;
+ private ScrolledComposite scrolledCmp;
+ private Text parentPathTxt;
+ private Text filterTxt;
+ private Node currEdited;
+
+ private String initialPath;
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ if (context == null)
+ // return null;
+ throw new CmsException("Context cannot be null");
+ GridLayout layout = CmsUiUtils.noSpaceGridLayout();
+ layout.numColumns = 2;
+ parent.setLayout(layout);
+
+ // Left
+ Composite leftCmp = new Composite(parent, SWT.NO_FOCUS);
+ leftCmp.setLayoutData(CmsUiUtils.fillAll());
+ createBrowserPart(leftCmp, context);
+
+ // Right
+ nodeDisplayParent = new Composite(parent, SWT.NO_FOCUS | SWT.BORDER);
+ GridData gd = new GridData(SWT.RIGHT, SWT.FILL, false, true);
+ gd.widthHint = THUMBNAIL_WIDTH;
+ nodeDisplayParent.setLayoutData(gd);
+ createNodeView(nodeDisplayParent, context);
+
+ // INIT
+ setEdited(context);
+ initialPath = context.getPath();
+
+ // Workaround we don't yet manage the delete to display parent of the
+ // initial context node
+
+ return null;
+ }
+
+ private void createBrowserPart(Composite parent, Node context) throws RepositoryException {
+ GridLayout layout = CmsUiUtils.noSpaceGridLayout();
+ parent.setLayout(layout);
+ Composite filterCmp = new Composite(parent, SWT.NO_FOCUS);
+ filterCmp.setLayoutData(CmsUiUtils.fillWidth());
+
+ // top filter
+ addFilterPanel(filterCmp);
+
+ // scrolled composite
+ scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER | SWT.NO_FOCUS);
+ scrolledCmp.setLayoutData(CmsUiUtils.fillAll());
+ scrolledCmp.setExpandVertical(true);
+ scrolledCmp.setExpandHorizontal(true);
+ scrolledCmp.setShowFocusedControl(true);
+
+ colViewer = new Composite(scrolledCmp, SWT.NO_FOCUS);
+ scrolledCmp.setContent(colViewer);
+ scrolledCmp.addControlListener(new ControlAdapter() {
+ private static final long serialVersionUID = 6589392045145698201L;
+
+ @Override
+ public void controlResized(ControlEvent e) {
+ Rectangle r = scrolledCmp.getClientArea();
+ scrolledCmp.setMinSize(colViewer.computeSize(SWT.DEFAULT, r.height));
+ }
+ });
+ initExplorer(colViewer, context);
+ }
+
+ private Control initExplorer(Composite parent, Node context) throws RepositoryException {
+ parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+ createBrowserColumn(parent, context);
+ return null;
+ }
+
+ private Control createBrowserColumn(Composite parent, Node context) throws RepositoryException {
+ // TODO style is not correctly managed.
+ FilterEntitiesVirtualTable table = new FilterEntitiesVirtualTable(parent, SWT.BORDER | SWT.NO_FOCUS, context);
+ // CmsUiUtils.style(table, ArgeoOrgStyle.browserColumn.style());
+ table.filterList("*");
+ table.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true));
+ browserCols.put(context.getPath(), table);
+ return null;
+ }
+
+ public void addFilterPanel(Composite parent) {
+
+ parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(2, false)));
+
+ // Text Area for the filter
+ parentPathTxt = new Text(parent, SWT.NO_FOCUS);
+ parentPathTxt.setEditable(false);
+ filterTxt = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL);
+ filterTxt.setMessage("Filter current list");
+ filterTxt.setLayoutData(CmsUiUtils.fillWidth());
+ filterTxt.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = 7709303319740056286L;
+
+ public void modifyText(ModifyEvent event) {
+ modifyFilter(false);
+ }
+ });
+
+ 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;
+ FilterEntitiesVirtualTable currTable = null;
+ if (currEdited != null) {
+ FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited));
+ if (table != null && !table.isDisposed())
+ currTable = table;
+ }
+
+ try {
+ if (e.keyCode == SWT.ARROW_DOWN)
+ currTable.setFocus();
+ else if (e.keyCode == SWT.BS) {
+ if (filterTxt.getText().equals("")
+ && !(getPath(currEdited).equals("/") || getPath(currEdited).equals(initialPath))) {
+ setEdited(currEdited.getParent());
+ e.doit = false;
+ filterTxt.setFocus();
+ }
+ } else if (e.keyCode == SWT.TAB && !shiftPressed) {
+ if (currEdited.getNodes(filterTxt.getText() + "*").getSize() == 1) {
+ setEdited(currEdited.getNodes(filterTxt.getText() + "*").nextNode());
+ }
+ filterTxt.setFocus();
+ e.doit = false;
+ }
+ } catch (RepositoryException e1) {
+ throw new CmsException("Unexpected error in key management for " + currEdited + "with filter "
+ + filterTxt.getText(), e1);
+ }
+
+ }
+ });
+ }
+
+ private void setEdited(Node node) {
+ try {
+ currEdited = node;
+ CmsUiUtils.clear(nodeDisplayParent);
+ createNodeView(nodeDisplayParent, currEdited);
+ nodeDisplayParent.layout();
+ refreshFilters(node);
+ refreshBrowser(node);
+ } catch (RepositoryException re) {
+ throw new CmsException("Unable to update browser for " + node, re);
+ }
+ }
+
+ private void refreshFilters(Node node) throws RepositoryException {
+ String currNodePath = node.getPath();
+ parentPathTxt.setText(currNodePath);
+ filterTxt.setText("");
+ filterTxt.getParent().layout();
+ }
+
+ private void refreshBrowser(Node node) throws RepositoryException {
+
+ // Retrieve
+ String currNodePath = node.getPath();
+ String currParPath = "";
+ if (!"/".equals(currNodePath))
+ currParPath = JcrUtils.parentPath(currNodePath);
+ if ("".equals(currParPath))
+ currParPath = "/";
+
+ Object[][] colMatrix = new Object[browserCols.size()][2];
+
+ int i = 0, j = -1, k = -1;
+ for (String path : browserCols.keySet()) {
+ colMatrix[i][0] = path;
+ colMatrix[i][1] = browserCols.get(path);
+ if (j >= 0 && k < 0 && !currNodePath.equals("/")) {
+ boolean leaveOpened = path.startsWith(currNodePath);
+
+ // workaround for same name siblings
+ // fix me weird side effect when we go left or click on anb
+ // already selected, unfocused node
+ if (leaveOpened && (path.lastIndexOf("/") == 0 && currNodePath.lastIndexOf("/") == 0
+ || JcrUtils.parentPath(path).equals(JcrUtils.parentPath(currNodePath))))
+ leaveOpened = JcrUtils.lastPathElement(path).equals(JcrUtils.lastPathElement(currNodePath));
+
+ if (!leaveOpened)
+ k = i;
+ }
+ if (currParPath.equals(path))
+ j = i;
+ i++;
+ }
+
+ if (j >= 0 && k >= 0)
+ // remove useless cols
+ for (int l = i - 1; l >= k; l--) {
+ browserCols.remove(colMatrix[l][0]);
+ ((FilterEntitiesVirtualTable) colMatrix[l][1]).dispose();
+ }
+
+ // Remove disposed columns
+ // TODO investigate and fix the mechanism that leave them there after
+ // disposal
+ if (browserCols.containsKey(currNodePath)) {
+ FilterEntitiesVirtualTable currCol = browserCols.get(currNodePath);
+ if (currCol.isDisposed())
+ browserCols.remove(currNodePath);
+ }
+
+ if (!browserCols.containsKey(currNodePath))
+ createBrowserColumn(colViewer, node);
+
+ colViewer.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false)));
+ // colViewer.pack();
+ colViewer.layout();
+ // also resize the scrolled composite
+ scrolledCmp.layout();
+ scrolledCmp.getShowFocusedControl();
+ // colViewer.getParent().layout();
+ // if (JcrUtils.parentPath(currNodePath).equals(currBrowserKey)) {
+ // } else {
+ // }
+ }
+
+ private void modifyFilter(boolean fromOutside) {
+ if (!fromOutside)
+ if (currEdited != null) {
+ String filter = filterTxt.getText() + "*";
+ FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited));
+ if (table != null && !table.isDisposed())
+ table.filterList(filter);
+ }
+
+ }
+
+ private String getPath(Node node) {
+ try {
+ return node.getPath();
+ } catch (RepositoryException e) {
+ throw new CmsException("Unable to get path for node " + node, e);
+ }
+ }
+
+ private Point imageWidth = new Point(250, 0);
+
+ /**
+ * Recreates the content of the box that displays information about the current
+ * selected node.
+ */
+ private Control createNodeView(Composite parent, Node context) throws RepositoryException {
+
+ parent.setLayout(new GridLayout(2, false));
+
+ if (isImg(context)) {
+ EditableImage image = new Img(parent, RIGHT, context, imageWidth);
+ image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 2, 1));
+ }
+
+ // Name and primary type
+ Label contextL = new Label(parent, SWT.NONE);
+ CmsUiUtils.markup(contextL);
+ contextL.setText("<b>" + context.getName() + "</b>");
+ new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType().getName());
+
+ // Children
+ for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) {
+ Node child = nIt.nextNode();
+ new CmsLink(child.getName(), BROWSE_PREFIX + child.getPath()).createUi(parent, context);
+ new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType().getName());
+ }
+
+ // Properties
+ for (PropertyIterator pIt = context.getProperties(); pIt.hasNext();) {
+ Property property = pIt.nextProperty();
+ Label label = new Label(parent, SWT.NONE);
+ label.setText(property.getName());
+ label.setToolTipText(JcrUtils.getPropertyDefinitionAsString(property));
+ new Label(parent, SWT.NONE).setText(getPropAsString(property));
+ }
+
+ return null;
+ }
+
+ private boolean isImg(Node node) throws RepositoryException {
+ // TODO support images
+ return false;
+// return node.hasNode(JCR_CONTENT) && node.isNodeType(CmsTypes.CMS_IMAGE);
+ }
+
+ private String getPropAsString(Property property) throws RepositoryException {
+ String result = "";
+ if (property.isMultiple()) {
+ result = getMultiAsString(property, ", ");
+ } else {
+ Value value = property.getValue();
+ if (value.getType() == PropertyType.BINARY)
+ result = "<binary>";
+ else if (value.getType() == PropertyType.DATE)
+ result = timeFormatter.format(value.getDate().getTime());
+ else
+ result = value.getString();
+ }
+ return result;
+ }
+
+ private String getMultiAsString(Property property, String separator) throws RepositoryException {
+ if (separator == null)
+ separator = "; ";
+ Value[] values = property.getValues();
+ StringBuilder builder = new StringBuilder();
+ for (Value val : values) {
+ String currStr = val.getString();
+ if (!"".equals(currStr.trim()))
+ builder.append(currStr).append(separator);
+ }
+ if (builder.lastIndexOf(separator) >= 0)
+ return builder.substring(0, builder.length() - separator.length());
+ else
+ return builder.toString();
+ }
+
+ /** Almost canonical implementation of a table that display entities */
+ private class FilterEntitiesVirtualTable extends Composite {
+ private static final long serialVersionUID = 8798147431706283824L;
+
+ // Context
+ private Node context;
+
+ // UI Objects
+ private TableViewer entityViewer;
+
+ // enable management of multiple columns
+ Node getNode() {
+ return context;
+ }
+
+ @Override
+ public boolean setFocus() {
+ if (entityViewer.getTable().isDisposed())
+ return false;
+ if (entityViewer.getSelection().isEmpty()) {
+ Object first = entityViewer.getElementAt(0);
+ if (first != null) {
+ entityViewer.setSelection(new StructuredSelection(first), true);
+ }
+ }
+ return entityViewer.getTable().setFocus();
+ }
+
+ void filterList(String filter) {
+ try {
+ NodeIterator nit = context.getNodes(filter);
+ refreshFilteredList(nit);
+ } catch (RepositoryException e) {
+ throw new CmsException("Unable to filter " + getNode() + " children with filter " + filter, e);
+ }
+
+ }
+
+ public FilterEntitiesVirtualTable(Composite parent, int style, Node context) {
+ super(parent, SWT.NO_FOCUS);
+ this.context = context;
+ populate();
+ }
+
+ protected void populate() {
+ Composite parent = this;
+ GridLayout layout = CmsUiUtils.noSpaceGridLayout();
+
+ this.setLayout(layout);
+ createTableViewer(parent);
+ }
+
+ private void createTableViewer(final Composite parent) {
+ // the list
+ // We must limit the size of the table otherwise the full list is
+ // loaded
+ // before the layout happens
+ Composite listCmp = new Composite(parent, SWT.NO_FOCUS);
+ GridData gd = new GridData(SWT.LEFT, SWT.FILL, false, true);
+ gd.widthHint = COLUMN_WIDTH;
+ listCmp.setLayoutData(gd);
+ listCmp.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ entityViewer = new TableViewer(listCmp, SWT.VIRTUAL | SWT.SINGLE);
+ Table table = entityViewer.getTable();
+
+ table.setLayoutData(CmsUiUtils.fillAll());
+ table.setLinesVisible(true);
+ table.setHeaderVisible(false);
+ CmsUiUtils.markup(table);
+
+ CmsUiUtils.style(table, MaintenanceStyles.BROWSER_COLUMN);
+
+ // first column
+ TableViewerColumn column = new TableViewerColumn(entityViewer, SWT.NONE);
+ TableColumn tcol = column.getColumn();
+ tcol.setWidth(COLUMN_WIDTH);
+ tcol.setResizable(true);
+ column.setLabelProvider(new SimpleNameLP());
+
+ entityViewer.setContentProvider(new MyLazyCP(entityViewer));
+ entityViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection();
+ if (selection.isEmpty())
+ return;
+ else
+ setEdited((Node) selection.getFirstElement());
+
+ }
+ });
+
+ table.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -330694313896036230L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+
+ IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection();
+ Node selected = null;
+ if (!selection.isEmpty())
+ selected = ((Node) selection.getFirstElement());
+ try {
+ if (e.keyCode == SWT.ARROW_RIGHT) {
+ if (selected != null) {
+ setEdited(selected);
+ browserCols.get(selected.getPath()).setFocus();
+ }
+ } else if (e.keyCode == SWT.ARROW_LEFT) {
+ try {
+ selected = getNode().getParent();
+ String newPath = selected.getPath(); // getNode().getParent()
+ setEdited(selected);
+ if (browserCols.containsKey(newPath))
+ browserCols.get(newPath).setFocus();
+ } catch (ItemNotFoundException ie) {
+ // root silent
+ }
+ }
+ } catch (RepositoryException ie) {
+ throw new CmsException("Error while managing arrow " + "events in the browser for " + selected,
+ ie);
+ }
+ }
+ });
+ }
+
+ private class MyLazyCP implements ILazyContentProvider {
+ private static final long serialVersionUID = 1L;
+ private TableViewer viewer;
+ private Object[] elements;
+
+ public MyLazyCP(TableViewer viewer) {
+ this.viewer = viewer;
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // IMPORTANT: don't forget this: an exception will be thrown if
+ // a selected object is not part of the results anymore.
+ viewer.setSelection(null);
+ this.elements = (Object[]) newInput;
+ }
+
+ public void updateElement(int index) {
+ viewer.replace(elements[index], index);
+ }
+ }
+
+ protected void refreshFilteredList(NodeIterator children) {
+ Object[] rows = JcrUtils.nodeIteratorToList(children).toArray();
+ entityViewer.setInput(rows);
+ entityViewer.setItemCount(rows.length);
+ entityViewer.refresh();
+ }
+
+ public class SimpleNameLP extends ColumnLabelProvider {
+ private static final long serialVersionUID = 2465059387875338553L;
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof Node) {
+ Node curr = ((Node) element);
+ try {
+ return curr.getName();
+ } catch (RepositoryException e) {
+ throw new CmsException("Unable to get name for" + curr);
+ }
+ }
+ return super.getText(element);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.useradmin.UserAdmin;
+
+class ConnectivityDeploymentUi extends AbstractOsgiComposite {
+ private static final long serialVersionUID = 590221539553514693L;
+
+ public ConnectivityDeploymentUi(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void initUi(int style) {
+ StringBuffer text = new StringBuffer();
+ text.append("<span style='font-variant: small-caps;'>Provided Servers</span><br/>");
+
+ ServiceReference<HttpService> userAdminRef = bc.getServiceReference(HttpService.class);
+ if (userAdminRef != null) {
+ // FIXME use constants
+ Object httpPort = userAdminRef.getProperty("http.port");
+ Object httpsPort = userAdminRef.getProperty("https.port");
+ if (httpPort != null)
+ text.append("<b>http</b> ").append(httpPort).append("<br/>");
+ if (httpsPort != null)
+ text.append("<b>https</b> ").append(httpsPort).append("<br/>");
+
+ }
+
+ text.append("<br/>");
+ text.append("<span style='font-variant: small-caps;'>Referenced Servers</span><br/>");
+
+ Label label = new Label(this, SWT.NONE);
+ label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ CmsUiUtils.markup(label);
+ label.setText(text.toString());
+ }
+
+ protected boolean isDeployed() {
+ return bc.getServiceReference(UserAdmin.class) != null;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+
+import org.apache.jackrabbit.core.RepositoryContext;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.ui.util.CmsUiUtils;
+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.Label;
+import org.osgi.framework.ServiceReference;
+
+class DataDeploymentUi extends AbstractOsgiComposite {
+ private static final long serialVersionUID = 590221539553514693L;
+
+ public DataDeploymentUi(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void initUi(int style) {
+ if (isDeployed()) {
+ initCurrentUi(this);
+ } else {
+ initNewUi(this);
+ }
+ }
+
+ private void initNewUi(Composite parent) {
+// try {
+// ConfigurationAdmin confAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class));
+// Configuration[] confs = confAdmin.listConfigurations(
+// "(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + NodeConstants.NODE_REPOS_FACTORY_PID + ")");
+// if (confs == null || confs.length == 0) {
+// Group buttonGroup = new Group(parent, SWT.NONE);
+// buttonGroup.setText("Repository Type");
+// buttonGroup.setLayout(new GridLayout(2, true));
+// buttonGroup.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+//
+// SelectionListener selectionListener = new SelectionAdapter() {
+// private static final long serialVersionUID = 6247064348421088092L;
+//
+// public void widgetSelected(SelectionEvent event) {
+// Button radio = (Button) event.widget;
+// if (!radio.getSelection())
+// return;
+// log.debug(event);
+// JackrabbitType nodeType = (JackrabbitType) radio.getData();
+// if (log.isDebugEnabled())
+// log.debug(" selected = " + nodeType.name());
+// };
+// };
+//
+// for (JackrabbitType nodeType : JackrabbitType.values()) {
+// Button radio = new Button(buttonGroup, SWT.RADIO);
+// radio.setText(nodeType.name());
+// radio.setData(nodeType);
+// if (nodeType.equals(JackrabbitType.localfs))
+// radio.setSelection(true);
+// radio.addSelectionListener(selectionListener);
+// }
+//
+// } else if (confs.length == 1) {
+//
+// } else {
+// throw new CmsException("Multiple repos not yet supported");
+// }
+// } catch (Exception e) {
+// throw new CmsException("Cannot initialize UI", e);
+// }
+
+ }
+
+ private void initCurrentUi(Composite parent) {
+ parent.setLayout(new GridLayout());
+ Collection<ServiceReference<RepositoryContext>> contexts = getServiceReferences(RepositoryContext.class,
+ "(" + NodeConstants.CN + "=*)");
+ StringBuffer text = new StringBuffer();
+ text.append("<span style='font-variant: small-caps;'>Jackrabbit Repositories</span><br/>");
+ for (ServiceReference<RepositoryContext> sr : contexts) {
+ RepositoryContext repositoryContext = bc.getService(sr);
+ String alias = sr.getProperty(NodeConstants.CN).toString();
+ String rootNodeId = repositoryContext.getRootNodeId().toString();
+ RepositoryConfig repositoryConfig = repositoryContext.getRepositoryConfig();
+ Path repoHomePath = new File(repositoryConfig.getHomeDir()).toPath().toAbsolutePath();
+ // TODO check data store
+
+ text.append("<b>" + alias + "</b><br/>");
+ text.append("rootNodeId: " + rootNodeId + "<br/>");
+ try {
+ FileStore fileStore = Files.getFileStore(repoHomePath);
+ text.append("partition: " + fileStore.toString() + "<br/>");
+ text.append(
+ percentUsed(fileStore) + " used (" + humanReadable(fileStore.getUsableSpace()) + " free)<br/>");
+ } catch (IOException e) {
+ log.error("Cannot check fileStore for " + repoHomePath, e);
+ }
+ }
+ Label label = new Label(parent, SWT.NONE);
+ label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ CmsUiUtils.markup(label);
+ label.setText("<span style=''>" + text.toString() + "</span>");
+ }
+
+ private String humanReadable(long bytes) {
+ long mb = bytes / (1024 * 1024);
+ return mb >= 2048 ? Long.toString(mb / 1024) + " GB" : Long.toString(mb) + " MB";
+ }
+
+ private String percentUsed(FileStore fs) throws IOException {
+ long used = fs.getTotalSpace() - fs.getUnallocatedSpace();
+ long percent = used * 100 / fs.getTotalSpace();
+ if (log.isTraceEnabled()) {
+ // output identical to `df -B 1`)
+ log.trace(fs.getTotalSpace() + "," + used + "," + fs.getUsableSpace());
+ }
+ String span;
+ if (percent < 80)
+ span = "<span style='color:green;font-weight:bold'>";
+ else if (percent < 95)
+ span = "<span style='color:orange;font-weight:bold'>";
+ else
+ span = "<span style='color:red;font-weight:bold'>";
+ return span + percent + "%</span>";
+ }
+
+ protected boolean isDeployed() {
+ return bc.getServiceReference(RepositoryContext.class) != null;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeDeployment;
+import org.argeo.api.NodeState;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+
+class DeploymentEntryPoint {
+ private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
+
+ protected void createContents(Composite parent) {
+ // FIXME manage authentication if needed
+ // if (!CurrentUser.roles().contains(AuthConstants.ROLE_ADMIN))
+ // return;
+
+ // parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ if (isDesktop()) {
+ parent.setLayout(new GridLayout(2, true));
+ } else {
+ // TODO add scrolling
+ parent.setLayout(new GridLayout(1, true));
+ }
+
+ initHighLevelSummary(parent);
+
+ Group securityGroup = createHighLevelGroup(parent, "Security");
+ securityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ new SecurityDeploymentUi(securityGroup, SWT.NONE);
+
+ Group dataGroup = createHighLevelGroup(parent, "Data");
+ dataGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ new DataDeploymentUi(dataGroup, SWT.NONE);
+
+ Group logGroup = createHighLevelGroup(parent, "Notifications");
+ logGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
+ new LogDeploymentUi(logGroup, SWT.NONE);
+
+ Group connectivityGroup = createHighLevelGroup(parent, "Connectivity");
+ new ConnectivityDeploymentUi(connectivityGroup, SWT.NONE);
+ connectivityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
+
+ }
+
+ private void initHighLevelSummary(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
+ if (isDesktop())
+ gridData.horizontalSpan = 3;
+ composite.setLayoutData(gridData);
+ composite.setLayout(new FillLayout());
+
+ ServiceReference<NodeState> nodeStateRef = bc.getServiceReference(NodeState.class);
+ if (nodeStateRef == null)
+ throw new IllegalStateException("No CMS state available");
+ NodeState nodeState = bc.getService(nodeStateRef);
+ ServiceReference<NodeDeployment> nodeDeploymentRef = bc.getServiceReference(NodeDeployment.class);
+ Label label = new Label(composite, SWT.WRAP);
+ CmsUiUtils.markup(label);
+ if (nodeDeploymentRef == null) {
+ label.setText("Not yet deployed on <br>" + nodeState.getHostname() + "</br>, please configure below.");
+ } else {
+ Object stateUuid = nodeStateRef.getProperty(NodeConstants.CN);
+ NodeDeployment nodeDeployment = bc.getService(nodeDeploymentRef);
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTimeInMillis(nodeDeployment.getAvailableSince());
+ calendar.setTimeZone(TimeZone.getDefault());
+ label.setText("[" + "<b>" + nodeState.getHostname() + "</b>]# " + "Deployment state " + stateUuid
+ + ", available since <b>" + calendar.getTime() + "</b>");
+ }
+ }
+
+ private static Group createHighLevelGroup(Composite parent, String text) {
+ Group group = new Group(parent, SWT.NONE);
+ group.setText(text);
+ CmsUiUtils.markup(group);
+ return group;
+ }
+
+ private boolean isDesktop() {
+ return true;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Enumeration;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogListener;
+import org.osgi.service.log.LogReaderService;
+
+class LogDeploymentUi extends AbstractOsgiComposite implements LogListener {
+ private static final long serialVersionUID = 590221539553514693L;
+
+ private DateFormat dateFormat = new SimpleDateFormat("MMdd HH:mm");
+
+ private Display display;
+ private Text logDisplay;
+
+ public LogDeploymentUi(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void initUi(int style) {
+ LogReaderService logReader = getService(LogReaderService.class);
+ // FIXME use server push
+ // logReader.addLogListener(this);
+ this.display = getDisplay();
+ this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ logDisplay = new Text(this, SWT.WRAP | SWT.MULTI | SWT.READ_ONLY);
+ logDisplay.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ CmsUiUtils.markup(logDisplay);
+ Enumeration<LogEntry> logEntries = (Enumeration<LogEntry>) logReader.getLog();
+ while (logEntries.hasMoreElements())
+ logDisplay.append(printEntry(logEntries.nextElement()));
+ }
+
+ private String printEntry(LogEntry entry) {
+ StringBuilder sb = new StringBuilder();
+ GregorianCalendar calendar = new GregorianCalendar(TimeZone.getDefault());
+ calendar.setTimeInMillis(entry.getTime());
+ sb.append(dateFormat.format(calendar.getTime())).append(' ');
+ sb.append(entry.getMessage());
+ sb.append('\n');
+ return sb.toString();
+ }
+
+ @Override
+ public void logged(LogEntry entry) {
+ if (display.isDisposed())
+ return;
+ display.asyncExec(() -> {
+ if (logDisplay.isDisposed())
+ return;
+ logDisplay.append(printEntry(entry));
+ });
+ display.wake();
+ }
+
+ // @Override
+ // public void dispose() {
+ // super.dispose();
+ // getService(LogReaderService.class).removeLogListener(this);
+ // }
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+/** Specific styles used by the various maintenance pages . */
+public interface MaintenanceStyles {
+ // General
+ public final static String PREFIX = "maintenance_";
+
+ // Browser
+ public final static String BROWSER_COLUMN = "browser_column";
+ }
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+public class NonAdminPage implements CmsUiProvider{
+
+ @Override
+ public Control createUi(Composite parent, Node context)
+ throws RepositoryException {
+ Composite body = new Composite(parent, SWT.NO_FOCUS);
+ body.setLayoutData(CmsUiUtils.fillAll());
+ body.setLayout(new GridLayout());
+ Label label = new Label(body, SWT.NONE);
+ label.setText("You should be an admin to perform maintenance operations. "
+ + "Are you sure you are logged in?");
+ label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+ return null;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.net.URI;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdmin;
+
+class SecurityDeploymentUi extends AbstractOsgiComposite {
+ private static final long serialVersionUID = 590221539553514693L;
+
+ public SecurityDeploymentUi(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void initUi(int style) {
+ if (isDeployed()) {
+ initCurrentUi(this);
+ } else {
+ initNewUi(this);
+ }
+ }
+
+ private void initNewUi(Composite parent) {
+ new Label(parent, SWT.NONE).setText("Security is not configured");
+ }
+
+ private void initCurrentUi(Composite parent) {
+ ServiceReference<UserAdmin> userAdminRef = bc.getServiceReference(UserAdmin.class);
+ UserAdmin userAdmin = bc.getService(userAdminRef);
+ StringBuffer text = new StringBuffer();
+ text.append("<span style='font-variant: small-caps;'>Domains</span><br/>");
+ domains: for (String key : userAdminRef.getPropertyKeys()) {
+ if (!key.startsWith("/"))
+ continue domains;
+ URI uri;
+ try {
+ uri = new URI(key);
+ } catch (Exception e) {
+ // ignore non URI keys
+ continue domains;
+ }
+
+ String rootDn = uri.getPath().substring(1, uri.getPath().length());
+ // FIXME make reading query options more robust, using utils
+ boolean readOnly = uri.getQuery().equals("readOnly=true");
+ if (readOnly)
+ text.append("<span style='font-weight:bold;font-style: italic'>");
+ else
+ text.append("<span style='font-weight:bold'>");
+
+ text.append(rootDn);
+ text.append("</span><br/>");
+ try {
+ Role[] roles = userAdmin.getRoles("(dn=*," + rootDn + ")");
+ long userCount = 0;
+ long groupCount = 0;
+ for (Role role : roles) {
+ if (role.getType() == Role.USER)
+ userCount++;
+ else
+ groupCount++;
+ }
+ text.append(" " + userCount + " users, " + groupCount +" groups.<br/>");
+ } catch (InvalidSyntaxException e) {
+ log.error("Invalid syntax", e);
+ }
+ }
+ Label label = new Label(parent, SWT.NONE);
+ label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ CmsUiUtils.markup(label);
+ label.setText(text.toString());
+ }
+
+ protected boolean isDeployed() {
+ return bc.getServiceReference(UserAdmin.class) != null;
+ }
+}
Text text = new Text(parent, SWT.BORDER);
text.setText(value);
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- // CmsUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
+ // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
return text;
}
text.setText(value);
text.setLayoutData(new GridData(SWT.LEAD, SWT.FILL, true, false));
text.setEditable(false);
- // CmsUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
+ // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
return text;
}
*/
package org.argeo.cms.e4.users;
+import static org.argeo.api.NodeInstance.WORKGROUP;
import static org.argeo.cms.auth.UserAdminUtils.setProperty;
import static org.argeo.naming.LdapAttrs.businessCategory;
import static org.argeo.naming.LdapAttrs.description;
-import static org.argeo.node.NodeInstance.WORKGROUP;
import java.util.ArrayList;
import java.util.Iterator;
import javax.naming.ldap.LdapName;
import javax.transaction.UserTransaction;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeInstance;
+import org.argeo.api.NodeUtils;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.providers.CommonNameLP;
import org.argeo.cms.e4.users.providers.UserFilter;
import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
import org.argeo.cms.ui.eclipse.forms.IManagedForm;
-import org.argeo.cms.util.CmsUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.eclipse.ui.ColumnDefinition;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
import org.argeo.jcr.JcrUtils;
import org.argeo.naming.LdapAttrs;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeInstance;
-import org.argeo.node.NodeUtils;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ToolBarManager;
// GridLayout layout = new GridLayout(5, false);
GridLayout layout = new GridLayout(2, false);
body.setLayout(layout);
- body.setLayoutData(CmsUtils.fillWidth());
+ body.setLayoutData(CmsUiUtils.fillWidth());
String cn = UserAdminUtils.getProperty(group, LdapAttrs.cn.name());
createReadOnlyLT(body, "Name", cn);
ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
ToolBar toolBar = toolBarManager.createControl(body);
- toolBar.setLayoutData(CmsUtils.fillWidth());
+ toolBar.setLayoutData(CmsUiUtils.fillWidth());
toolBarManager.add(action);
toolBarManager.update(true);
// lbl.setFont(EclipseUiUtils.getBoldFont(parent));
// Text text = toolkit.createText(parent, value, SWT.BORDER);
// text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- // CmsUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
+ // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
// return text;
// }
//
// Text text = toolkit.createText(parent, value, SWT.NONE);
// text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
// text.setEditable(false);
- // CmsUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
+ // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
// return text;
// }
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.e4.users.providers.CommonNameLP;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
import org.argeo.naming.LdapAttrs;
import org.argeo.naming.LdapObjs;
-import org.argeo.node.NodeConstants;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
import javax.transaction.Status;
import javax.transaction.UserTransaction;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
-import org.argeo.node.NodeConstants;
import org.argeo.osgi.useradmin.UserAdminConf;
import org.osgi.service.useradmin.UserAdmin;
import org.osgi.service.useradmin.UserAdminEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
import org.argeo.naming.LdapAttrs;
import org.argeo.naming.LdapObjs;
-import org.argeo.node.NodeConstants;
import org.eclipse.jface.dialogs.IPageChangeProvider;
import org.eclipse.jface.dialogs.IPageChangedListener;
import org.eclipse.jface.dialogs.MessageDialog;
import javax.inject.Inject;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.providers.CommonNameLP;
import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
//import org.argeo.cms.ui.eclipse.forms.FormToolkit;
import org.argeo.cms.ui.eclipse.forms.IManagedForm;
-import org.argeo.cms.util.CmsUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.eclipse.ui.ColumnDefinition;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
import org.argeo.naming.LdapAttrs;
-import org.argeo.node.NodeConstants;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ToolBarManager;
// mainLayout.marginRight = 10;
body.setLayout(mainLayout);
// body.getParent().setLayout(new GridLayout());
- // body.setLayoutData(CmsUtils.fillAll());
+ // body.setLayoutData(CmsUiUtils.fillAll());
User user = getDisplayedUser();
appendOverviewPart(body, user);
// Remove to ability to force the password for his own user. The user
// Composite body= parent;
Composite body = new Composite(parent, SWT.BORDER);
body.setLayout(new GridLayout());
- body.setLayoutData(CmsUtils.fillAll());
+ body.setLayoutData(CmsUiUtils.fillAll());
// boolean isAdmin = CurrentUser.isInRole(NodeConstants.ROLE_ADMIN);
Action action = new RemoveMembershipAction(userViewer, user, tooltip, SecurityAdminImages.ICON_REMOVE_DESC);
ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
ToolBar toolBar = toolBarManager.createControl(body);
- toolBar.setLayoutData(CmsUtils.fillWidth());
+ toolBar.setLayoutData(CmsUiUtils.fillWidth());
toolBarManager.add(action);
toolBarManager.update(true);
return userViewerCmp;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.e4.users.providers.CommonNameLP;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
import org.argeo.naming.LdapAttrs;
import org.argeo.naming.LdapObjs;
-import org.argeo.node.NodeConstants;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
package org.argeo.cms.e4.users.providers;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeInstance;
import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.SecurityAdminImages;
import org.argeo.naming.LdapAttrs;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeInstance;
import org.eclipse.swt.graphics.Image;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.naming.LdapAttrs;
-import org.argeo.node.NodeConstants;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.osgi.service.useradmin.User;
+++ /dev/null
-package org.argeo.cms.forms;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.viewers.EditablePart;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Editable String that displays a browsable link when read-only */
-public class EditableLink extends EditablePropertyString implements
- EditablePart {
- private static final long serialVersionUID = 5055000749992803591L;
-
- private String type;
- private String message;
- private boolean readOnly;
-
- public EditableLink(Composite parent, int style, Node node,
- String propertyName, String type, String message)
- throws RepositoryException {
- super(parent, style, node, propertyName, message);
- this.message = message;
- this.type = type;
-
- readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
- if (node.hasProperty(propertyName)) {
- this.setStyle(FormStyle.propertyText.style());
- this.setText(node.getProperty(propertyName).getString());
- } else {
- this.setStyle(FormStyle.propertyMessage.style());
- this.setText("");
- }
- }
-
- public void setText(String text) {
- Control child = getControl();
- if (child instanceof Label) {
- Label lbl = (Label) child;
- if (EclipseUiUtils.isEmpty(text))
- lbl.setText(message);
- else if (readOnly)
- setLinkValue(lbl, text);
- else
- // if canEdit() we put only the value with no link
- // to avoid glitches of the edition life cycle
- lbl.setText(text);
- } else if (child instanceof Text) {
- Text txt = (Text) child;
- if (EclipseUiUtils.isEmpty(text)) {
- txt.setText("");
- txt.setMessage(message);
- } else
- txt.setText(text);
- }
- }
-
- private void setLinkValue(Label lbl, String text) {
- if (FormStyle.email.style().equals(type))
- lbl.setText(FormUtils.getMailLink(text));
- else if (FormStyle.phone.style().equals(type))
- lbl.setText(FormUtils.getPhoneLink(text));
- else if (FormStyle.website.style().equals(type))
- lbl.setText(FormUtils.getUrlLink(text));
- else if (FormStyle.facebook.style().equals(type)
- || FormStyle.instagram.style().equals(type)
- || FormStyle.linkedIn.style().equals(type)
- || FormStyle.twitter.style().equals(type))
- lbl.setText(FormUtils.getUrlLink(text));
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.forms;
-
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.viewers.EditablePart;
-import org.argeo.cms.widgets.StyledControl;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.events.TraverseEvent;
-import org.eclipse.swt.events.TraverseListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-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;
-
-/** Display, add or remove values from a list in a CMS context */
-public class EditableMultiStringProperty extends StyledControl implements EditablePart {
- private static final long serialVersionUID = -7044614381252178595L;
-
- private String propertyName;
- private String message;
- // TODO implement the ability to provide a list of possible values
- private String[] possibleValues;
- private boolean canEdit;
- private SelectionListener removeValueSL;
- private List<String> values;
-
- // TODO manage within the CSS
- private int rowSpacing = 5;
- private int rowMarging = 0;
- private int oneValueMargingRight = 5;
- private int btnWidth = 16;
- private int btnHeight = 16;
- private int btnHorizontalIndent = 3;
-
- public EditableMultiStringProperty(Composite parent, int style, Node node, String propertyName, List<String> values,
- String[] possibleValues, String addValueMsg, SelectionListener removeValueSelectionListener)
- throws RepositoryException {
- super(parent, style, node, true);
-
- this.propertyName = propertyName;
- this.values = values;
- this.possibleValues = new String[]{"Un", "Deux", "Trois"};
- this.message = addValueMsg;
- this.canEdit = removeValueSelectionListener != null;
- this.removeValueSL = removeValueSelectionListener;
- }
-
- public List<String> getValues() {
- return values;
- }
-
- public void setValues(List<String> values) {
- this.values = values;
- }
-
- // Row layout items do not need explicit layout data
- protected void setControlLayoutData(Control control) {
- }
-
- /** To be overridden */
- protected void setContainerLayoutData(Composite composite) {
- composite.setLayoutData(CmsUtils.fillWidth());
- }
-
- @Override
- public Control getControl() {
- return super.getControl();
- }
-
- @Override
- protected Control createControl(Composite box, String style) {
- Composite row = new Composite(box, SWT.NO_FOCUS);
- row.setLayoutData(EclipseUiUtils.fillAll());
-
- RowLayout rl = new RowLayout(SWT.HORIZONTAL);
- rl.wrap = true;
- rl.spacing = rowSpacing;
- rl.marginRight = rl.marginLeft = rl.marginBottom = rl.marginTop = rowMarging;
- row.setLayout(rl);
-
- if (values != null) {
- for (final String value : values) {
- if (canEdit)
- createRemovableValue(row, SWT.SINGLE, value);
- else
- createValueLabel(row, SWT.SINGLE, value);
- }
- }
-
- if (!canEdit)
- return row;
- else if (isEditing())
- return createText(row, style);
- else
- return createLabel(row, style);
- }
-
- /**
- * Override to provide specific layout for the existing values, typically
- * adding a pound (#) char for tags or anchor info for browsable links. We
- * assume the parent composite already has a layout and it is the caller
- * responsibility to apply corresponding layout data
- */
- protected Label createValueLabel(Composite parent, int style, String value) {
- Label label = new Label(parent, style);
- label.setText("#" + value);
- CmsUtils.markup(label);
- CmsUtils.style(label, FormStyle.propertyText.style());
- return label;
- }
-
- private Composite createRemovableValue(Composite parent, int style, String value) {
- Composite valCmp = new Composite(parent, SWT.NO_FOCUS);
- GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
- gl.marginRight = oneValueMargingRight;
- valCmp.setLayout(gl);
-
- createValueLabel(valCmp, SWT.WRAP, value);
-
- Button deleteBtn = new Button(valCmp, SWT.FLAT);
- deleteBtn.setData(FormConstants.LINKED_VALUE, value);
- deleteBtn.addSelectionListener(removeValueSL);
- CmsUtils.style(deleteBtn, FormStyle.delete.style() + FormStyle.BUTTON_SUFFIX);
- GridData gd = new GridData();
- gd.heightHint = btnHeight;
- gd.widthHint = btnWidth;
- gd.horizontalIndent = btnHorizontalIndent;
- deleteBtn.setLayoutData(gd);
-
- return valCmp;
- }
-
- protected Text createText(Composite box, String style) {
- final Text text = new Text(box, getStyle());
- // The "add new value" text is not meant to change, so we can set it on
- // creation
- text.setMessage(message);
- CmsUtils.style(text, style);
- text.setFocus();
-
- text.addTraverseListener(new TraverseListener() {
- private static final long serialVersionUID = 1L;
-
- public void keyTraversed(TraverseEvent e) {
- if (e.keyCode == SWT.CR) {
- addValue(text);
- e.doit = false;
- }
- }
- });
-
- // The OK button does not work with the focusOut listener
- // because focus out is called before the OK button is pressed
-
- // // we must call layout() now so that the row data can compute the
- // height
- // // of the other controls.
- // text.getParent().layout();
- // int height = text.getSize().y;
- //
- // Button okBtn = new Button(box, SWT.BORDER | SWT.PUSH | SWT.BOTTOM);
- // okBtn.setText("OK");
- // RowData rd = new RowData(SWT.DEFAULT, height - 2);
- // okBtn.setLayoutData(rd);
- //
- // okBtn.addSelectionListener(new SelectionAdapter() {
- // private static final long serialVersionUID = 2780819012423622369L;
- //
- // @Override
- // public void widgetSelected(SelectionEvent e) {
- // addValue(text);
- // }
- // });
-
- return text;
- }
-
- /** Performs the real addition, overwrite to make further sanity checks */
- protected void addValue(Text text) {
- String value = text.getText();
- String errMsg = null;
-
- if (EclipseUiUtils.isEmpty(value))
- return;
-
- if (values.contains(value))
- errMsg = "Dupplicated value: " + value + ", please correct and try again";
- if (errMsg != null)
- MessageDialog.openError(this.getShell(), "Addition not allowed", errMsg);
- else {
- values.add(value);
- Composite newCmp = createRemovableValue(text.getParent(), SWT.SINGLE, value);
- newCmp.moveAbove(text);
- text.setText("");
- newCmp.getParent().layout();
- }
- }
-
- protected Label createLabel(Composite box, String style) {
- if (canEdit) {
- Label lbl = new Label(box, getStyle());
- lbl.setText(message);
- CmsUtils.style(lbl, style);
- CmsUtils.markup(lbl);
- if (mouseListener != null)
- lbl.addMouseListener(mouseListener);
- return lbl;
- }
- return null;
- }
-
- protected void clear(boolean deep) {
- Control child = getControl();
- if (deep)
- super.clear(deep);
- else {
- child.getParent().dispose();
- }
- }
-
- public void setText(String text) {
- Control child = getControl();
- if (child instanceof Label) {
- Label lbl = (Label) child;
- if (canEdit)
- lbl.setText(text);
- else
- lbl.setText("");
- } else if (child instanceof Text) {
- Text txt = (Text) child;
- txt.setText(text);
- }
- }
-
- public synchronized void startEditing() {
- getControl().setData(STYLE, FormStyle.propertyText.style());
- super.startEditing();
- }
-
- public synchronized void stopEditing() {
- getControl().setData(STYLE, FormStyle.propertyMessage.style());
- super.stopEditing();
- }
-
- public String getPropertyName() {
- return propertyName;
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.forms;
-
-import java.text.DateFormat;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.viewers.EditablePart;
-import org.argeo.cms.widgets.StyledControl;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-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.DateTime;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/** CMS form part to display and edit a date */
-public class EditablePropertyDate extends StyledControl implements EditablePart {
- private static final long serialVersionUID = 2500215515778162468L;
-
- // Context
- private String propertyName;
- private String message;
- private DateFormat dateFormat;
-
- // UI Objects
- private Text dateTxt;
- private Button openCalBtn;
-
- // TODO manage within the CSS
- private int fieldBtnSpacing = 5;
-
- /**
- *
- * @param parent
- * @param style
- * @param node
- * @param propertyName
- * @param message
- * @param dateFormat
- * provide a {@link DateFormat} as contract to be able to
- * read/write dates as strings
- * @throws RepositoryException
- */
- public EditablePropertyDate(Composite parent, int style, Node node,
- String propertyName, String message, DateFormat dateFormat)
- throws RepositoryException {
- super(parent, style, node, false);
-
- this.propertyName = propertyName;
- this.message = message;
- this.dateFormat = dateFormat;
-
- if (node.hasProperty(propertyName)) {
- this.setStyle(FormStyle.propertyText.style());
- this.setText(dateFormat.format(node.getProperty(propertyName)
- .getDate().getTime()));
- } else {
- this.setStyle(FormStyle.propertyMessage.style());
- this.setText(message);
- }
- }
-
- public void setText(String text) {
- Control child = getControl();
- if (child instanceof Label) {
- Label lbl = (Label) child;
- if (EclipseUiUtils.isEmpty(text))
- lbl.setText(message);
- else
- lbl.setText(text);
- } else if (child instanceof Text) {
- Text txt = (Text) child;
- if (EclipseUiUtils.isEmpty(text)) {
- txt.setText("");
- } else
- txt.setText(text);
- }
- }
-
- public synchronized void startEditing() {
- // if (dateTxt != null && !dateTxt.isDisposed())
- getControl().setData(STYLE, FormStyle.propertyText.style());
- super.startEditing();
- }
-
- public synchronized void stopEditing() {
- if (EclipseUiUtils.isEmpty(dateTxt.getText()))
- getControl().setData(STYLE, FormStyle.propertyMessage.style());
- else
- getControl().setData(STYLE, FormStyle.propertyText.style());
- super.stopEditing();
- }
-
- public String getPropertyName() {
- return propertyName;
- }
-
- @Override
- protected Control createControl(Composite box, String style) {
- if (isEditing()) {
- return createCustomEditableControl(box, style);
- } else
- return createLabel(box, style);
- }
-
- protected Label createLabel(Composite box, String style) {
- Label lbl = new Label(box, getStyle() | SWT.WRAP);
- lbl.setLayoutData(CmsUtils.fillWidth());
- CmsUtils.style(lbl, style);
- CmsUtils.markup(lbl);
- if (mouseListener != null)
- lbl.addMouseListener(mouseListener);
- return lbl;
- }
-
- private Control createCustomEditableControl(Composite box, String style) {
- box.setLayoutData(CmsUtils.fillWidth());
- Composite dateComposite = new Composite(box, SWT.NONE);
- GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
- false));
- gl.horizontalSpacing = fieldBtnSpacing;
- dateComposite.setLayout(gl);
- dateTxt = new Text(dateComposite, SWT.BORDER);
- CmsUtils.style(dateTxt, style);
- dateTxt.setLayoutData(new GridData(120, SWT.DEFAULT));
- dateTxt.setToolTipText("Enter a date with form \""
- + FormUtils.DEFAULT_SHORT_DATE_FORMAT
- + "\" or use the calendar");
- openCalBtn = new Button(dateComposite, SWT.FLAT);
- CmsUtils.style(openCalBtn, FormStyle.calendar.style()
- + FormStyle.BUTTON_SUFFIX);
- GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
- gd.heightHint = 17;
- openCalBtn.setLayoutData(gd);
- // openCalBtn.setImage(PeopleRapImages.CALENDAR_BTN);
-
- openCalBtn.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = 1L;
-
- public void widgetSelected(SelectionEvent event) {
- CalendarPopup popup = new CalendarPopup(dateTxt);
- popup.open();
- }
- });
-
- // dateTxt.addFocusListener(new FocusListener() {
- // private static final long serialVersionUID = 1L;
- //
- // @Override
- // public void focusLost(FocusEvent event) {
- // String newVal = dateTxt.getText();
- // // Enable reset of the field
- // if (FormUtils.notNull(newVal))
- // calendar = null;
- // else {
- // try {
- // Calendar newCal = parseDate(newVal);
- // // DateText.this.setText(newCal);
- // calendar = newCal;
- // } catch (ParseException pe) {
- // // Silent. Manage error popup?
- // if (calendar != null)
- // EditablePropertyDate.this.setText(calendar);
- // }
- // }
- // }
- //
- // @Override
- // public void focusGained(FocusEvent event) {
- // }
- // });
- return dateTxt;
- }
-
- protected void clear(boolean deep) {
- Control child = getControl();
- if (deep || child instanceof Label)
- super.clear(deep);
- else {
- child.getParent().dispose();
- }
- }
-
- /** Enable setting a custom tooltip on the underlying text */
- @Deprecated
- public void setToolTipText(String toolTipText) {
- dateTxt.setToolTipText(toolTipText);
- }
-
- @Deprecated
- /** Enable setting a custom message on the underlying text */
- public void setMessage(String message) {
- dateTxt.setMessage(message);
- }
-
- @Deprecated
- public void setText(Calendar cal) {
- String newValueStr = "";
- if (cal != null)
- newValueStr = dateFormat.format(cal.getTime());
- if (!newValueStr.equals(dateTxt.getText()))
- dateTxt.setText(newValueStr);
- }
-
- // UTILITIES TO MANAGE THE CALENDAR POPUP
- // TODO manage the popup shell in a cleaner way
- private class CalendarPopup extends Shell {
- private static final long serialVersionUID = 1L;
- private DateTime dateTimeCtl;
-
- public CalendarPopup(Control source) {
- super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
- populate();
- // Add border and shadow style
- CmsUtils.markup(CalendarPopup.this);
- CmsUtils.style(CalendarPopup.this, FormStyle.popupCalendar.style());
- pack();
- layout();
- setLocation(source.toDisplay((source.getLocation().x - 2),
- (source.getSize().y) + 3));
-
- addShellListener(new ShellAdapter() {
- private static final long serialVersionUID = 5178980294808435833L;
-
- @Override
- public void shellDeactivated(ShellEvent e) {
- close();
- dispose();
- }
- });
- open();
- }
-
- private void setProperty() {
- // Direct set does not seems to work. investigate
- // cal.set(dateTimeCtl.getYear(), dateTimeCtl.getMonth(),
- // dateTimeCtl.getDay(), 12, 0);
- Calendar cal = new GregorianCalendar();
- cal.set(Calendar.YEAR, dateTimeCtl.getYear());
- cal.set(Calendar.MONTH, dateTimeCtl.getMonth());
- cal.set(Calendar.DAY_OF_MONTH, dateTimeCtl.getDay());
- String dateStr = dateFormat.format(cal.getTime());
- dateTxt.setText(dateStr);
- }
-
- protected void populate() {
- setLayout(EclipseUiUtils.noSpaceGridLayout());
-
- dateTimeCtl = new DateTime(this, SWT.CALENDAR);
- dateTimeCtl.setLayoutData(EclipseUiUtils.fillAll());
-
- Calendar calendar = FormUtils.parseDate(dateFormat,
- dateTxt.getText());
-
- if (calendar != null)
- dateTimeCtl.setDate(calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH));
-
- dateTimeCtl.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -8414377364434281112L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- setProperty();
- }
- });
-
- dateTimeCtl.addMouseListener(new MouseListener() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void mouseUp(MouseEvent e) {
- }
-
- @Override
- public void mouseDown(MouseEvent e) {
- }
-
- @Override
- public void mouseDoubleClick(MouseEvent e) {
- setProperty();
- close();
- dispose();
- }
- });
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.forms;
-
-import static org.argeo.cms.forms.FormStyle.propertyMessage;
-import static org.argeo.cms.forms.FormStyle.propertyText;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.viewers.EditablePart;
-import org.argeo.cms.widgets.EditableText;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Editable String in a CMS context */
-public class EditablePropertyString extends EditableText implements
- EditablePart {
- private static final long serialVersionUID = 5055000749992803591L;
-
- private String propertyName;
- private String message;
-
- // encode the '&' character in rap
- private final static String AMPERSAND = "&";
- private final static String AMPERSAND_REGEX = "&(?![#a-zA-Z0-9]+;)";
-
- public EditablePropertyString(Composite parent, int style, Node node,
- String propertyName, String message) throws RepositoryException {
- super(parent, style, node, true);
-
- this.propertyName = propertyName;
- this.message = message;
-
- if (node.hasProperty(propertyName)) {
- this.setStyle(propertyText.style());
- this.setText(node.getProperty(propertyName).getString());
- } else {
- this.setStyle(propertyMessage.style());
- this.setText(message + " ");
- }
- }
-
- public void setText(String text) {
- Control child = getControl();
- if (child instanceof Label) {
- Label lbl = (Label) child;
- if (EclipseUiUtils.isEmpty(text))
- lbl.setText(message + " ");
- else
- // TODO enhance this
- lbl.setText(text.replaceAll(AMPERSAND_REGEX, AMPERSAND));
- } else if (child instanceof Text) {
- Text txt = (Text) child;
- if (EclipseUiUtils.isEmpty(text)) {
- txt.setText("");
- txt.setMessage(message + " ");
- } else
- txt.setText(text.replaceAll("<br/>", "\n"));
- }
- }
-
- public synchronized void startEditing() {
- getControl().setData(STYLE, propertyText.style());
- super.startEditing();
- }
-
- public synchronized void stopEditing() {
- if (EclipseUiUtils.isEmpty(((Text) getControl()).getText()))
- getControl().setData(STYLE, propertyMessage.style());
- else
- getControl().setData(STYLE, propertyText.style());
- super.stopEditing();
- }
-
- public String getPropertyName() {
- return propertyName;
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.forms;
-
-/** Constants used in the various CMS Forms */
-public interface FormConstants {
- // DATAKEYS
- public final static String LINKED_VALUE = "LinkedValue";
-}
+++ /dev/null
-package org.argeo.cms.forms;
-
-import java.util.Observable;
-import java.util.Observer;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.ui.CmsEditable;
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-
-/** Add life cycle management abilities to an editable form page */
-public class FormEditorHeader implements SelectionListener, Observer {
- private static final long serialVersionUID = 7392898696542484282L;
-
- // private final Node context;
- private final CmsEditable cmsEditable;
- private Button publishBtn;
-
- // Should we provide here the ability to switch from read only to edition
- // mode?
- // private Button editBtn;
- // private boolean readOnly;
-
- // TODO add information about the current node status, typically if it is
- // dirty or not
-
- private Composite parent;
- private Composite display;
- private Object layoutData;
-
- public FormEditorHeader(Composite parent, int style, Node context,
- CmsEditable cmsEditable) {
- this.cmsEditable = cmsEditable;
- this.parent = parent;
- // readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
- // this.context = context;
- if (this.cmsEditable instanceof Observable)
- ((Observable) this.cmsEditable).addObserver(this);
- refresh();
- }
-
- public void setLayoutData(Object layoutData) {
- this.layoutData = layoutData;
- if (display != null && !display.isDisposed())
- display.setLayoutData(layoutData);
- }
-
- protected void refresh() {
- if (display != null && !display.isDisposed())
- display.dispose();
-
- display = new Composite(parent, SWT.NONE);
- display.setLayoutData(layoutData);
-
- CmsUtils.style(display, FormStyle.header.style());
- display.setBackgroundMode(SWT.INHERIT_FORCE);
-
- display.setLayout(CmsUtils.noSpaceGridLayout());
-
- publishBtn = createSimpleBtn(display, getPublishButtonLabel());
- display.moveAbove(null);
- parent.layout();
- }
-
- private Button createSimpleBtn(Composite parent, String label) {
- Button button = new Button(parent, SWT.FLAT | SWT.PUSH);
- button.setText(label);
- CmsUtils.style(button, FormStyle.header.style());
- button.addSelectionListener(this);
- return button;
- }
-
- private String getPublishButtonLabel() {
- // Rather check if the current node differs from what has been
- // previously committed
- // For the time being, we always reach here, the underlying CmsEditable
- // is always editing.
- if (cmsEditable.isEditing())
- return " Publish ";
- else
- return " Edit ";
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- if (e.getSource() == publishBtn) {
- // For the time being, the underlying CmsEditable
- // is always editing when we reach this point
- if (cmsEditable.isEditing()) {
- // we always leave the node in a check outed state
- cmsEditable.stopEditing();
- cmsEditable.startEditing();
- } else {
- cmsEditable.startEditing();
- }
- }
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- }
-
- @Override
- public void update(Observable o, Object arg) {
- if (o == cmsEditable) {
- refresh();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.forms;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsEditable;
-import org.argeo.cms.ui.CmsImageManager;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.viewers.AbstractPageViewer;
-import org.argeo.cms.viewers.EditablePart;
-import org.argeo.cms.viewers.Section;
-import org.argeo.cms.viewers.SectionPart;
-import org.argeo.cms.widgets.EditableImage;
-import org.argeo.cms.widgets.Img;
-import org.argeo.cms.widgets.StyledControl;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.jface.dialogs.MessageDialog;
-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.fileupload.FileUploadReceiver;
-import org.eclipse.rap.rwt.service.ServerPushSession;
-import org.eclipse.rap.rwt.widgets.FileUpload;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.FormAttachment;
-import org.eclipse.swt.layout.FormData;
-import org.eclipse.swt.layout.FormLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-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;
-
-/** Manage life cycle of a form page that is linked to a given node */
-public class FormPageViewer extends AbstractPageViewer {
- private final static Log log = LogFactory.getLog(FormPageViewer.class);
- private static final long serialVersionUID = 5277789504209413500L;
-
- private final Section mainSection;
-
- // TODO manage within the CSS
- private int labelColWidth = 150;
- private int rowLayoutHSpacing = 8;
-
- // Context cached in the viewer
- // The reference to translate from text to calendar and reverse
- private DateFormat dateFormat = new SimpleDateFormat(FormUtils.DEFAULT_SHORT_DATE_FORMAT);
- private CmsImageManager imageManager;
- private FileUploadListener fileUploadListener;
-
- public FormPageViewer(Section mainSection, int style, CmsEditable cmsEditable) throws RepositoryException {
- super(mainSection, style, cmsEditable);
- this.mainSection = mainSection;
-
- if (getCmsEditable().canEdit()) {
- fileUploadListener = new FUL();
- }
- }
-
- @Override
- protected void prepare(EditablePart part, Object caretPosition) {
- if (part instanceof Img) {
- ((Img) part).setFileUploadListener(fileUploadListener);
- }
- }
-
- /** To be overridden.Save the edited part. */
- protected void save(EditablePart part) throws RepositoryException {
- Node node = null;
- if (part instanceof EditableMultiStringProperty) {
- EditableMultiStringProperty ept = (EditableMultiStringProperty) part;
- // SWT : View
- List<String> values = ept.getValues();
- // JCR : Model
- node = ept.getNode();
- String propName = ept.getPropertyName();
- if (values.isEmpty()) {
- if (node.hasProperty(propName))
- node.getProperty(propName).remove();
- } else {
- node.setProperty(propName, values.toArray(new String[0]));
- }
- // => Viewer : Controller
- } else if (part instanceof EditablePropertyString) {
- EditablePropertyString ept = (EditablePropertyString) part;
- // SWT : View
- String txt = ((Text) ept.getControl()).getText();
- // JCR : Model
- node = ept.getNode();
- String propName = ept.getPropertyName();
- if (EclipseUiUtils.isEmpty(txt)) {
- if (node.hasProperty(propName))
- node.getProperty(propName).remove();
- } else {
- setPropertySilently(node, propName, txt);
- // node.setProperty(propName, txt);
- }
- // node.getSession().save();
- // => Viewer : Controller
- } else if (part instanceof EditablePropertyDate) {
- EditablePropertyDate ept = (EditablePropertyDate) part;
- Calendar cal = FormUtils.parseDate(dateFormat, ((Text) ept.getControl()).getText());
- node = ept.getNode();
- String propName = ept.getPropertyName();
- if (cal == null) {
- if (node.hasProperty(propName))
- node.getProperty(propName).remove();
- } else {
- node.setProperty(propName, cal);
- }
- // node.getSession().save();
- // => Viewer : Controller
- }
- // TODO: make this configurable, sometimes we do not want to save the
- // current session at this stage
- if (node != null && node.getSession().hasPendingChanges()) {
- JcrUtils.updateLastModified(node);
- node.getSession().save();
- }
- }
-
- @Override
- protected void updateContent(EditablePart part) throws RepositoryException {
- if (part instanceof EditableMultiStringProperty) {
- EditableMultiStringProperty ept = (EditableMultiStringProperty) part;
- // SWT : View
- Node node = ept.getNode();
- String propName = ept.getPropertyName();
- List<String> valStrings = new ArrayList<String>();
- if (node.hasProperty(propName)) {
- Value[] values = node.getProperty(propName).getValues();
- for (Value val : values)
- valStrings.add(val.getString());
- }
- ept.setValues(valStrings);
- } else if (part instanceof EditablePropertyString) {
- // || part instanceof EditableLink
- EditablePropertyString ept = (EditablePropertyString) part;
- // JCR : Model
- Node node = ept.getNode();
- String propName = ept.getPropertyName();
- if (node.hasProperty(propName)) {
- String value = node.getProperty(propName).getString();
- ept.setText(value);
- } else
- ept.setText("");
- // => Viewer : Controller
- } else if (part instanceof EditablePropertyDate) {
- EditablePropertyDate ept = (EditablePropertyDate) part;
- // JCR : Model
- Node node = ept.getNode();
- String propName = ept.getPropertyName();
- if (node.hasProperty(propName))
- ept.setText(dateFormat.format(node.getProperty(propName).getDate().getTime()));
- else
- ept.setText("");
- } else if (part instanceof SectionPart) {
- SectionPart sectionPart = (SectionPart) part;
- Node partNode = sectionPart.getNode();
- // use control AFTER setting style, since it may have been reset
- if (part instanceof EditableImage) {
- EditableImage editableImage = (EditableImage) part;
- imageManager().load(partNode, part.getControl(), editableImage.getPreferredImageSize());
- }
- }
- }
-
- // FILE UPLOAD LISTENER
- protected class FUL implements FileUploadListener {
-
- public FUL() {
- }
-
- public void uploadProgress(FileUploadEvent event) {
- // TODO Monitor upload progress
- }
-
- public void uploadFailed(FileUploadEvent event) {
- throw new CmsException("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();
- }
- }
-
- // FOCUS OUT LISTENER
- protected FocusListener createFocusListener() {
- return new FocusOutListener();
- }
-
- private class FocusOutListener implements FocusListener {
- private static final long serialVersionUID = -6069205786732354186L;
-
- @Override
- public void focusLost(FocusEvent event) {
- saveEdit();
- }
-
- @Override
- public void focusGained(FocusEvent event) {
- // does nothing;
- }
- }
-
- // 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();
- if (getCmsEditable().canEdit()) {
- if (getCmsEditable().isEditing() && !(getEdited() instanceof Img)) {
- if (source == mainSection)
- return;
- EditablePart part = findDataParent(source);
- upload(part);
- } else {
- getCmsEditable().startEditing();
- }
- }
- }
- }
-
- @Override
- public void mouseDown(MouseEvent e) {
- if (getCmsEditable().isEditing()) {
- if (e.button == 1) {
- Control source = (Control) e.getSource();
- EditablePart composite = findDataParent(source);
- Point point = new Point(e.x, e.y);
- if (!(composite instanceof Img))
- edit(composite, source.toDisplay(point));
- } else if (e.button == 3) {
- // EditablePart composite = findDataParent((Control) e
- // .getSource());
- // if (styledTools != null)
- // styledTools.show(composite, new Point(e.x, e.y));
- }
- }
- }
-
- protected synchronized void upload(EditablePart part) {
- if (part instanceof SectionPart) {
- if (part instanceof Img) {
- if (getEdited() == part)
- return;
- edit(part, null);
- layout(part.getControl());
- }
- }
- }
- }
-
- @Override
- public Control getControl() {
- return mainSection;
- }
-
- protected CmsImageManager imageManager() {
- if (imageManager == null)
- imageManager = CmsUtils.getCmsView().getImageManager();
- return imageManager;
- }
-
- // LOCAL UI HELPERS
- protected Section createSectionIfNeeded(Composite body, Node node) throws RepositoryException {
- Section section = null;
- if (node != null) {
- section = new Section(body, SWT.NO_FOCUS, node);
- section.setLayoutData(CmsUtils.fillWidth());
- section.setLayout(CmsUtils.noSpaceGridLayout());
- }
- return section;
- }
-
- protected void createSimpleLT(Composite bodyRow, Node node, String propName, String label, String msg)
- throws RepositoryException {
- if (getCmsEditable().canEdit() || node.hasProperty(propName)) {
- createPropertyLbl(bodyRow, label);
- EditablePropertyString eps = new EditablePropertyString(bodyRow, SWT.WRAP | SWT.LEFT, node, propName, msg);
- eps.setMouseListener(getMouseListener());
- eps.setFocusListener(getFocusListener());
- eps.setLayoutData(CmsUtils.fillWidth());
- }
- }
-
- protected void createMultiStringLT(Composite bodyRow, Node node, String propName, String label, String msg)
- throws RepositoryException {
- boolean canEdit = getCmsEditable().canEdit();
- if (canEdit || node.hasProperty(propName)) {
- createPropertyLbl(bodyRow, label);
-
- List<String> valueStrings = new ArrayList<String>();
-
- if (node.hasProperty(propName)) {
- Value[] values = node.getProperty(propName).getValues();
- for (Value value : values)
- valueStrings.add(value.getString());
- }
-
- // TODO use a drop down to display possible values to the end user
- EditableMultiStringProperty emsp = new EditableMultiStringProperty(bodyRow, SWT.SINGLE | SWT.LEAD, node,
- propName, valueStrings, new String[] { "Implement this" }, msg,
- canEdit ? getRemoveValueSelListener() : null);
- addListeners(emsp);
- // emsp.setMouseListener(getMouseListener());
- emsp.setStyle(FormStyle.propertyMessage.style());
- emsp.setLayoutData(CmsUtils.fillWidth());
- }
- }
-
- protected Label createPropertyLbl(Composite parent, String value) {
- return createPropertyLbl(parent, value, SWT.TOP);
- }
-
- protected Label createPropertyLbl(Composite parent, String value, int vAlign) {
- boolean isSmall = CmsUtils.getCmsView().getUxContext().isSmall();
- Label label = new Label(parent, isSmall ? SWT.LEFT : SWT.RIGHT | SWT.WRAP);
- label.setText(value + " ");
- CmsUtils.style(label, FormStyle.propertyLabel.style());
- GridData gd = new GridData(isSmall ? SWT.LEFT : SWT.RIGHT, vAlign, false, false);
- gd.widthHint = labelColWidth;
- label.setLayoutData(gd);
- return label;
- }
-
- protected Label newStyledLabel(Composite parent, String style, String value) {
- Label label = new Label(parent, SWT.NONE);
- label.setText(value);
- CmsUtils.style(label, style);
- return label;
- }
-
- protected Composite createRowLayoutComposite(Composite parent) throws RepositoryException {
- Composite bodyRow = new Composite(parent, SWT.NO_FOCUS);
- bodyRow.setLayoutData(CmsUtils.fillWidth());
- RowLayout rl = new RowLayout(SWT.WRAP);
- rl.type = SWT.HORIZONTAL;
- rl.spacing = rowLayoutHSpacing;
- rl.marginHeight = rl.marginWidth = 0;
- rl.marginTop = rl.marginBottom = rl.marginLeft = rl.marginRight = 0;
- bodyRow.setLayout(rl);
- return bodyRow;
- }
-
- protected Composite createAddImgComposite(final Section section, Composite parent, final Node parentNode)
- throws RepositoryException {
-
- Composite body = new Composite(parent, SWT.NO_FOCUS);
- body.setLayout(new GridLayout());
-
- FormFileUploadReceiver receiver = new FormFileUploadReceiver(section, parentNode, null);
- final FileUploadHandler currentUploadHandler = new FileUploadHandler(receiver);
- if (fileUploadListener != null)
- currentUploadHandler.addUploadListener(fileUploadListener);
-
- // Button creation
- final FileUpload fileUpload = new FileUpload(body, SWT.BORDER);
- fileUpload.setText("Import an image");
- fileUpload.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
- fileUpload.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = 4869523412991968759L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- ServerPushSession pushSession = new ServerPushSession();
- pushSession.start();
- String uploadURL = currentUploadHandler.getUploadUrl();
- fileUpload.submit(uploadURL);
- }
- });
-
- return body;
- }
-
- protected class FormFileUploadReceiver extends FileUploadReceiver {
-
- private Node context;
- private Section section;
- private String name;
-
- public FormFileUploadReceiver(Section section, Node context, String name) {
- this.context = context;
- this.section = section;
- this.name = name;
- }
-
- @Override
- public void receive(InputStream stream, FileDetails details) throws IOException {
-
- if (name == null)
- name = details.getFileName();
-
- // TODO clean image name more carefully
- String cleanedName = name.replaceAll("[^a-zA-Z0-9-.]", "");
- // We add a unique prefix to workaround the cache issue: when
- // deleting and re-adding a new image with same name, the end user
- // browser will use the cache and the image will remain unchanged
- // for a while
- cleanedName = System.currentTimeMillis() % 100000 + "_" + cleanedName;
-
- try {
- imageManager().uploadImage(context, cleanedName, stream);
- // TODO clean refresh strategy
- section.getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- try {
- FormPageViewer.this.refresh(section);
- section.layout();
- section.getParent().layout();
- } catch (RepositoryException re) {
- throw new CmsException("unable to refresh " + "image section for " + context);
- }
- }
- });
- } catch (RepositoryException re) {
- throw new CmsException("unable to upload image " + name + " at " + context);
- }
- }
- }
-
- protected void addListeners(StyledControl control) {
- control.setMouseListener(getMouseListener());
- control.setFocusListener(getFocusListener());
- }
-
- protected Img createImgComposite(Composite parent, Node node, Point preferredSize) throws RepositoryException {
- Img img = new Img(parent, SWT.NONE, node, preferredSize) {
- private static final long serialVersionUID = 1297900641952417540L;
-
- @Override
- protected void setContainerLayoutData(Composite composite) {
- composite.setLayoutData(CmsUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
- }
-
- @Override
- protected void setControlLayoutData(Control control) {
- control.setLayoutData(CmsUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
- }
- };
- img.setLayoutData(CmsUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
- updateContent(img);
- addListeners(img);
- return img;
- }
-
- protected Composite addDeleteAbility(final Section section, final Node sessionNode, int topWeight,
- int rightWeight) {
- Composite comp = new Composite(section, SWT.NONE);
- comp.setLayoutData(CmsUtils.fillAll());
- comp.setLayout(new FormLayout());
-
- // The body to be populated
- Composite body = new Composite(comp, SWT.NO_FOCUS);
- body.setLayoutData(EclipseUiUtils.fillFormData());
-
- if (getCmsEditable().canEdit()) {
- // the delete button
- Button deleteBtn = new Button(comp, SWT.FLAT);
- CmsUtils.style(deleteBtn, FormStyle.deleteOverlay.style());
- FormData formData = new FormData();
- formData.right = new FormAttachment(rightWeight, 0);
- formData.top = new FormAttachment(topWeight, 0);
- deleteBtn.setLayoutData(formData);
- deleteBtn.moveAbove(body);
-
- deleteBtn.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = 4304223543657238462L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- super.widgetSelected(e);
- if (MessageDialog.openConfirm(section.getShell(), "Confirm deletion",
- "Are you really you want to remove this?")) {
- Session session;
- try {
- session = sessionNode.getSession();
- Section parSection = section.getParentSection();
- sessionNode.remove();
- session.save();
- refresh(parSection);
- layout(parSection);
- } catch (RepositoryException re) {
- throw new CmsException("Unable to delete " + sessionNode, re);
- }
-
- }
-
- }
- });
- }
- return body;
- }
-
-// // LOCAL HELPERS FOR NODE MANAGEMENT
-// private Node getOrCreateNode(Node parent, String nodeName, String nodeType) throws RepositoryException {
-// Node node = null;
-// if (getCmsEditable().canEdit() && !parent.hasNode(nodeName)) {
-// node = JcrUtils.mkdirs(parent, nodeName, nodeType);
-// parent.getSession().save();
-// }
-//
-// if (getCmsEditable().canEdit() || parent.hasNode(nodeName))
-// node = parent.getNode(nodeName);
-//
-// return node;
-// }
-
- private SelectionListener getRemoveValueSelListener() {
- return new SelectionAdapter() {
- private static final long serialVersionUID = 9022259089907445195L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- Object source = e.getSource();
- if (source instanceof Button) {
- Button btn = (Button) source;
- Object obj = btn.getData(FormConstants.LINKED_VALUE);
- EditablePart ep = findDataParent(btn);
- if (ep != null && ep instanceof EditableMultiStringProperty) {
- EditableMultiStringProperty emsp = (EditableMultiStringProperty) ep;
- List<String> values = emsp.getValues();
- if (values.contains(obj)) {
- values.remove(values.indexOf(obj));
- emsp.setValues(values);
- try {
- save(emsp);
- // TODO workaround to force refresh
- edit(emsp, 0);
- cancelEdit();
- } catch (RepositoryException e1) {
- throw new CmsException("Unable to remove value " + obj, e1);
- }
- layout(emsp);
- }
- }
- }
- }
- };
- }
-
- protected void setPropertySilently(Node node, String propName, String value) throws RepositoryException {
- try {
- // TODO Clean this:
- // Format strings to replace \n
- value = value.replaceAll("\n", "<br/>");
- // Do not make the update if validation fails
- try {
- MarkupValidatorCopy.getInstance().validate(value);
- } catch (Exception e) {
- log.warn("Cannot set [" + value + "] on prop " + propName + "of " + node
- + ", String cannot be validated - " + e.getMessage());
- return;
- }
- // TODO check if the newly created property is of the correct type,
- // otherwise the property will be silently created with a STRING
- // property type.
- node.setProperty(propName, value);
- } catch (ValueFormatException vfe) {
- log.warn("Cannot set [" + value + "] on prop " + propName + "of " + node + " - " + vfe.getMessage());
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.forms;
-
-/** Syles used */
-public enum FormStyle {
- // Main
- form, title,
- // main part
- header, headerBtn, headerCombo, section, sectionHeader,
- // Property fields
- propertyLabel, propertyText, propertyMessage, errorMessage,
- // Date
- popupCalendar,
- // Buttons
- starred, unstarred, starOverlay, editOverlay, deleteOverlay, updateOverlay, deleteOverlaySmall, calendar, delete,
- // Contacts
- email, address, phone, website,
- // Social Media
- facebook, twitter, linkedIn, instagram;
-
- public String style() {
- return form.name() + '_' + name();
- }
-
- // TODO clean button style management
- public final static String BUTTON_SUFFIX = "_btn";
-}
+++ /dev/null
-package org.argeo.cms.forms;
-
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.fieldassist.ControlDecoration;
-import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Utilitary methods to ease implementation of CMS forms */
-public class FormUtils {
- private final static Log log = LogFactory.getLog(FormUtils.class);
-
- public final static String DEFAULT_SHORT_DATE_FORMAT = "dd/MM/yyyy";
-
- /** Best effort to convert a String to a calendar. Fails silently */
- public static Calendar parseDate(DateFormat dateFormat, String calStr) {
- Calendar cal = null;
- if (EclipseUiUtils.notEmpty(calStr)) {
- try {
- Date date = dateFormat.parse(calStr);
- cal = new GregorianCalendar();
- cal.setTime(date);
- } catch (ParseException pe) {
- // Silent
- log.warn("Unable to parse date: " + calStr + " - msg: "
- + pe.getMessage());
- }
- }
- return cal;
- }
-
- /** Add a double click listener on tables that display a JCR node list */
- public static void addCanonicalDoubleClickListener(final TableViewer v) {
- v.addDoubleClickListener(new IDoubleClickListener() {
-
- @Override
- public void doubleClick(DoubleClickEvent event) {
- CmsView cmsView = CmsUtils.getCmsView();
- Node node = (Node) ((IStructuredSelection) event.getSelection())
- .getFirstElement();
- try {
- cmsView.navigateTo(node.getPath());
- } catch (RepositoryException e) {
- throw new CmsException("Unable to get path for node "
- + node + " before calling navigateTo(path)", e);
- }
- }
- });
- }
-
- // MANAGE ERROR DECORATION
-
- public static ControlDecoration addDecoration(final Text text) {
- final ControlDecoration dynDecoration = new ControlDecoration(text,
- SWT.LEFT);
- Image icon = getDecorationImage(FieldDecorationRegistry.DEC_ERROR);
- dynDecoration.setImage(icon);
- dynDecoration.setMarginWidth(3);
- dynDecoration.hide();
- return dynDecoration;
- }
-
- public static void refreshDecoration(Text text, ControlDecoration deco,
- boolean isValid, boolean clean) {
- if (isValid || clean) {
- text.setBackground(null);
- deco.hide();
- } else {
- text.setBackground(new Color(text.getDisplay(), 250, 200, 150));
- deco.show();
- }
- }
-
- public static Image getDecorationImage(String image) {
- FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
- return registry.getFieldDecoration(image).getImage();
- }
-
- public static void addCompulsoryDecoration(Label label) {
- final ControlDecoration dynDecoration = new ControlDecoration(label,
- SWT.RIGHT | SWT.TOP);
- Image icon = getDecorationImage(FieldDecorationRegistry.DEC_REQUIRED);
- dynDecoration.setImage(icon);
- dynDecoration.setMarginWidth(3);
- }
-
- // TODO the read only generation of read only links for various contact type
- // should be factorised in the cms Utils.
- /**
- * Creates the read-only HTML snippet to display in a label with styling
- * enabled in order to provide a click-able phone number
- */
- public static String getPhoneLink(String value) {
- return getPhoneLink(value, value);
- }
-
- /**
- * Creates the read-only HTML snippet to display in a label with styling
- * enabled in order to provide a click-able phone number
- *
- * @param value
- * @param label
- * a potentially distinct label
- * @return
- */
- public static String getPhoneLink(String value, String label) {
- StringBuilder builder = new StringBuilder();
- builder.append("<a href=\"tel:");
- builder.append(value).append("\" target=\"_blank\" >").append(label)
- .append("</a>");
- return builder.toString();
- }
-
- /**
- * Creates the read-only HTML snippet to display in a label with styling
- * enabled in order to provide a click-able mail
- */
- public static String getMailLink(String value) {
- return getMailLink(value, value);
- }
-
- /**
- * Creates the read-only HTML snippet to display in a label with styling
- * enabled in order to provide a click-able mail
- *
- * @param value
- * @param label
- * a potentially distinct label
- * @return
- */
- public static String getMailLink(String value, String label) {
- StringBuilder builder = new StringBuilder();
- value = replaceAmpersand(value);
- builder.append("<a href=\"mailto:");
- builder.append(value).append("\" >").append(label).append("</a>");
- return builder.toString();
- }
-
- /**
- * Creates the read-only HTML snippet to display in a label with styling
- * enabled in order to provide a click-able link
- */
- public static String getUrlLink(String value) {
- return getUrlLink(value, value);
- }
-
- /**
- * Creates the read-only HTML snippet to display in a label with styling
- * enabled in order to provide a click-able link
- */
- public static String getUrlLink(String value, String label) {
- StringBuilder builder = new StringBuilder();
- value = replaceAmpersand(value);
- label = replaceAmpersand(label);
- if (!(value.startsWith("http://") || value.startsWith("https://")))
- value = "http://" + value;
- builder.append("<a href=\"");
- builder.append(value + "\" target=\"_blank\" >" + label + "</a>");
- return builder.toString();
- }
-
- private static String AMPERSAND = "&";
-
- /**
- * Cleans a String by replacing any '&' by its HTML encoding '&#38;' to
- * avoid <code>SAXParseException</code> while rendering HTML with RWT
- */
- public static String replaceAmpersand(String value) {
- value = value.replaceAll("&(?![#a-zA-Z0-9]+;)", AMPERSAND);
- return value;
- }
-
- // Prevents instantiation
- private FormUtils() {
- }
-}
+++ /dev/null
-package org.argeo.cms.forms;
-
-import java.io.StringReader;
-import java.text.MessageFormat;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.eclipse.rap.rwt.SingletonUtil;
-import org.eclipse.swt.widgets.Widget;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.helpers.DefaultHandler;
-
-/**
- * Copy of RAP v2.3 since it is in an internal package.
- */
-class MarkupValidatorCopy {
-
- // Used by Eclipse Scout project
- public static final String MARKUP_VALIDATION_DISABLED = "org.eclipse.rap.rwt.markupValidationDisabled";
-
- private static final String DTD = createDTD();
- private static final Map<String, String[]> SUPPORTED_ELEMENTS = createSupportedElementsMap();
- private final SAXParser saxParser;
-
- public static MarkupValidatorCopy getInstance() {
- return SingletonUtil.getSessionInstance(MarkupValidatorCopy.class);
- }
-
- public MarkupValidatorCopy() {
- saxParser = createSAXParser();
- }
-
- public void validate(String text) {
- StringBuilder markup = new StringBuilder();
- markup.append(DTD);
- markup.append("<html>");
- markup.append(text);
- markup.append("</html>");
- InputSource inputSource = new InputSource(new StringReader(markup.toString()));
- try {
- saxParser.parse(inputSource, new MarkupHandler());
- } catch (RuntimeException exception) {
- throw exception;
- } catch (Exception exception) {
- throw new IllegalArgumentException("Failed to parse markup text", exception);
- }
- }
-
- public static boolean isValidationDisabledFor(Widget widget) {
- return Boolean.TRUE.equals(widget.getData(MARKUP_VALIDATION_DISABLED));
- }
-
- private static SAXParser createSAXParser() {
- SAXParser result = null;
- SAXParserFactory parserFactory = SAXParserFactory.newInstance();
- try {
- result = parserFactory.newSAXParser();
- } catch (Exception exception) {
- throw new RuntimeException("Failed to create SAX parser", exception);
- }
- return result;
- }
-
- private static String createDTD() {
- StringBuilder result = new StringBuilder();
- result.append("<!DOCTYPE html [");
- result.append("<!ENTITY quot \""\">");
- result.append("<!ENTITY amp \"&\">");
- result.append("<!ENTITY apos \"'\">");
- result.append("<!ENTITY lt \"<\">");
- result.append("<!ENTITY gt \">\">");
- result.append("<!ENTITY nbsp \" \">");
- result.append("<!ENTITY ensp \" \">");
- result.append("<!ENTITY emsp \" \">");
- result.append("<!ENTITY ndash \"–\">");
- result.append("<!ENTITY mdash \"—\">");
- result.append("]>");
- return result.toString();
- }
-
- private static Map<String, String[]> createSupportedElementsMap() {
- Map<String, String[]> result = new HashMap<String, String[]>();
- result.put("html", new String[0]);
- result.put("br", new String[0]);
- result.put("b", new String[] { "style" });
- result.put("strong", new String[] { "style" });
- result.put("i", new String[] { "style" });
- result.put("em", new String[] { "style" });
- result.put("sub", new String[] { "style" });
- result.put("sup", new String[] { "style" });
- result.put("big", new String[] { "style" });
- result.put("small", new String[] { "style" });
- result.put("del", new String[] { "style" });
- result.put("ins", new String[] { "style" });
- result.put("code", new String[] { "style" });
- result.put("samp", new String[] { "style" });
- result.put("kbd", new String[] { "style" });
- result.put("var", new String[] { "style" });
- result.put("cite", new String[] { "style" });
- result.put("dfn", new String[] { "style" });
- result.put("q", new String[] { "style" });
- result.put("abbr", new String[] { "style", "title" });
- result.put("span", new String[] { "style" });
- result.put("img", new String[] { "style", "src", "width", "height", "title", "alt" });
- result.put("a", new String[] { "style", "href", "target", "title" });
- return result;
- }
-
- private static class MarkupHandler extends DefaultHandler {
-
- @Override
- public void startElement(String uri, String localName, String name, Attributes attributes) {
- checkSupportedElements(name, attributes);
- checkSupportedAttributes(name, attributes);
- checkMandatoryAttributes(name, attributes);
- }
-
- private static void checkSupportedElements(String elementName, Attributes attributes) {
- if (!SUPPORTED_ELEMENTS.containsKey(elementName)) {
- throw new IllegalArgumentException("Unsupported element in markup text: " + elementName);
- }
- }
-
- private static void checkSupportedAttributes(String elementName, Attributes attributes) {
- if (attributes.getLength() > 0) {
- List<String> supportedAttributes = Arrays.asList(SUPPORTED_ELEMENTS.get(elementName));
- int index = 0;
- String attributeName = attributes.getQName(index);
- while (attributeName != null) {
- if (!supportedAttributes.contains(attributeName)) {
- String message = "Unsupported attribute \"{0}\" for element \"{1}\" in markup text";
- message = MessageFormat.format(message, new Object[] { attributeName, elementName });
- throw new IllegalArgumentException(message);
- }
- index++;
- attributeName = attributes.getQName(index);
- }
- }
- }
-
- private static void checkMandatoryAttributes(String elementName, Attributes attributes) {
- checkIntAttribute(elementName, attributes, "img", "width");
- checkIntAttribute(elementName, attributes, "img", "height");
- }
-
- private static void checkIntAttribute(String elementName, Attributes attributes, String checkedElementName,
- String checkedAttributeName) {
- if (checkedElementName.equals(elementName)) {
- String attribute = attributes.getValue(checkedAttributeName);
- try {
- Integer.parseInt(attribute);
- } catch (NumberFormatException exception) {
- String message = "Mandatory attribute \"{0}\" for element \"{1}\" is missing or not a valid integer";
- Object[] arguments = new Object[] { checkedAttributeName, checkedElementName };
- message = MessageFormat.format(message, arguments);
- throw new IllegalArgumentException(message);
- }
- }
- }
-
- }
-
-}
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import java.util.Collection;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-abstract class AbstractOsgiComposite extends Composite {
- private static final long serialVersionUID = -4097415973477517137L;
- protected final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
- protected final Log log = LogFactory.getLog(getClass());
-
- public AbstractOsgiComposite(Composite parent, int style) {
- super(parent, style);
- parent.setLayout(CmsUtils.noSpaceGridLayout());
- setLayout(CmsUtils.noSpaceGridLayout());
- setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
- initUi(style);
- }
-
- protected abstract void initUi(int style);
-
- protected <T> T getService(Class<? extends T> clazz) {
- return bc.getService(bc.getServiceReference(clazz));
- }
-
- protected <T> Collection<ServiceReference<T>> getServiceReferences(Class<T> clazz, String filter) {
- try {
- return bc.getServiceReferences(clazz, filter);
- } catch (InvalidSyntaxException e) {
- throw new IllegalArgumentException("Filter " + filter + " is invalid", e);
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import static org.eclipse.swt.SWT.RIGHT;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.LinkedHashMap;
-
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.util.CmsLink;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.widgets.EditableImage;
-import org.argeo.cms.widgets.Img;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ILazyContentProvider;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.Text;
-
-public class Browse implements CmsUiProvider {
-
- // Some local constants to experiment. should be cleaned
- private final static String BROWSE_PREFIX = "browse#";
- private final static int THUMBNAIL_WIDTH = 400;
- private final static int COLUMN_WIDTH = 160;
- private DateFormat timeFormatter = new SimpleDateFormat("dd-MM-yyyy', 'HH:mm");
-
- // keep a cache of the opened nodes
- // Key is the path
- private LinkedHashMap<String, FilterEntitiesVirtualTable> browserCols = new LinkedHashMap<String, Browse.FilterEntitiesVirtualTable>();
- private Composite nodeDisplayParent;
- private Composite colViewer;
- private ScrolledComposite scrolledCmp;
- private Text parentPathTxt;
- private Text filterTxt;
- private Node currEdited;
-
- private String initialPath;
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- if (context == null)
- // return null;
- throw new CmsException("Context cannot be null");
- GridLayout layout = CmsUtils.noSpaceGridLayout();
- layout.numColumns = 2;
- parent.setLayout(layout);
-
- // Left
- Composite leftCmp = new Composite(parent, SWT.NO_FOCUS);
- leftCmp.setLayoutData(CmsUtils.fillAll());
- createBrowserPart(leftCmp, context);
-
- // Right
- nodeDisplayParent = new Composite(parent, SWT.NO_FOCUS | SWT.BORDER);
- GridData gd = new GridData(SWT.RIGHT, SWT.FILL, false, true);
- gd.widthHint = THUMBNAIL_WIDTH;
- nodeDisplayParent.setLayoutData(gd);
- createNodeView(nodeDisplayParent, context);
-
- // INIT
- setEdited(context);
- initialPath = context.getPath();
-
- // Workaround we don't yet manage the delete to display parent of the
- // initial context node
-
- return null;
- }
-
- private void createBrowserPart(Composite parent, Node context) throws RepositoryException {
- GridLayout layout = CmsUtils.noSpaceGridLayout();
- parent.setLayout(layout);
- Composite filterCmp = new Composite(parent, SWT.NO_FOCUS);
- filterCmp.setLayoutData(CmsUtils.fillWidth());
-
- // top filter
- addFilterPanel(filterCmp);
-
- // scrolled composite
- scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER | SWT.NO_FOCUS);
- scrolledCmp.setLayoutData(CmsUtils.fillAll());
- scrolledCmp.setExpandVertical(true);
- scrolledCmp.setExpandHorizontal(true);
- scrolledCmp.setShowFocusedControl(true);
-
- colViewer = new Composite(scrolledCmp, SWT.NO_FOCUS);
- scrolledCmp.setContent(colViewer);
- scrolledCmp.addControlListener(new ControlAdapter() {
- private static final long serialVersionUID = 6589392045145698201L;
-
- @Override
- public void controlResized(ControlEvent e) {
- Rectangle r = scrolledCmp.getClientArea();
- scrolledCmp.setMinSize(colViewer.computeSize(SWT.DEFAULT, r.height));
- }
- });
- initExplorer(colViewer, context);
- }
-
- private Control initExplorer(Composite parent, Node context) throws RepositoryException {
- parent.setLayout(CmsUtils.noSpaceGridLayout());
- createBrowserColumn(parent, context);
- return null;
- }
-
- private Control createBrowserColumn(Composite parent, Node context) throws RepositoryException {
- // TODO style is not correctly managed.
- FilterEntitiesVirtualTable table = new FilterEntitiesVirtualTable(parent, SWT.BORDER | SWT.NO_FOCUS, context);
- // CmsUtils.style(table, ArgeoOrgStyle.browserColumn.style());
- table.filterList("*");
- table.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true));
- browserCols.put(context.getPath(), table);
- return null;
- }
-
- public void addFilterPanel(Composite parent) {
-
- parent.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(2, false)));
-
- // Text Area for the filter
- parentPathTxt = new Text(parent, SWT.NO_FOCUS);
- parentPathTxt.setEditable(false);
- filterTxt = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL);
- filterTxt.setMessage("Filter current list");
- filterTxt.setLayoutData(CmsUtils.fillWidth());
- filterTxt.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = 7709303319740056286L;
-
- public void modifyText(ModifyEvent event) {
- modifyFilter(false);
- }
- });
-
- 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;
- FilterEntitiesVirtualTable currTable = null;
- if (currEdited != null) {
- FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited));
- if (table != null && !table.isDisposed())
- currTable = table;
- }
-
- try {
- if (e.keyCode == SWT.ARROW_DOWN)
- currTable.setFocus();
- else if (e.keyCode == SWT.BS) {
- if (filterTxt.getText().equals("")
- && !(getPath(currEdited).equals("/") || getPath(currEdited).equals(initialPath))) {
- setEdited(currEdited.getParent());
- e.doit = false;
- filterTxt.setFocus();
- }
- } else if (e.keyCode == SWT.TAB && !shiftPressed) {
- if (currEdited.getNodes(filterTxt.getText() + "*").getSize() == 1) {
- setEdited(currEdited.getNodes(filterTxt.getText() + "*").nextNode());
- }
- filterTxt.setFocus();
- e.doit = false;
- }
- } catch (RepositoryException e1) {
- throw new CmsException("Unexpected error in key management for " + currEdited + "with filter "
- + filterTxt.getText(), e1);
- }
-
- }
- });
- }
-
- private void setEdited(Node node) {
- try {
- currEdited = node;
- CmsUtils.clear(nodeDisplayParent);
- createNodeView(nodeDisplayParent, currEdited);
- nodeDisplayParent.layout();
- refreshFilters(node);
- refreshBrowser(node);
- } catch (RepositoryException re) {
- throw new CmsException("Unable to update browser for " + node, re);
- }
- }
-
- private void refreshFilters(Node node) throws RepositoryException {
- String currNodePath = node.getPath();
- parentPathTxt.setText(currNodePath);
- filterTxt.setText("");
- filterTxt.getParent().layout();
- }
-
- private void refreshBrowser(Node node) throws RepositoryException {
-
- // Retrieve
- String currNodePath = node.getPath();
- String currParPath = "";
- if (!"/".equals(currNodePath))
- currParPath = JcrUtils.parentPath(currNodePath);
- if ("".equals(currParPath))
- currParPath = "/";
-
- Object[][] colMatrix = new Object[browserCols.size()][2];
-
- int i = 0, j = -1, k = -1;
- for (String path : browserCols.keySet()) {
- colMatrix[i][0] = path;
- colMatrix[i][1] = browserCols.get(path);
- if (j >= 0 && k < 0 && !currNodePath.equals("/")) {
- boolean leaveOpened = path.startsWith(currNodePath);
-
- // workaround for same name siblings
- // fix me weird side effect when we go left or click on anb
- // already selected, unfocused node
- if (leaveOpened && (path.lastIndexOf("/") == 0 && currNodePath.lastIndexOf("/") == 0
- || JcrUtils.parentPath(path).equals(JcrUtils.parentPath(currNodePath))))
- leaveOpened = JcrUtils.lastPathElement(path).equals(JcrUtils.lastPathElement(currNodePath));
-
- if (!leaveOpened)
- k = i;
- }
- if (currParPath.equals(path))
- j = i;
- i++;
- }
-
- if (j >= 0 && k >= 0)
- // remove useless cols
- for (int l = i - 1; l >= k; l--) {
- browserCols.remove(colMatrix[l][0]);
- ((FilterEntitiesVirtualTable) colMatrix[l][1]).dispose();
- }
-
- // Remove disposed columns
- // TODO investigate and fix the mechanism that leave them there after
- // disposal
- if (browserCols.containsKey(currNodePath)) {
- FilterEntitiesVirtualTable currCol = browserCols.get(currNodePath);
- if (currCol.isDisposed())
- browserCols.remove(currNodePath);
- }
-
- if (!browserCols.containsKey(currNodePath))
- createBrowserColumn(colViewer, node);
-
- colViewer.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false)));
- // colViewer.pack();
- colViewer.layout();
- // also resize the scrolled composite
- scrolledCmp.layout();
- scrolledCmp.getShowFocusedControl();
- // colViewer.getParent().layout();
- // if (JcrUtils.parentPath(currNodePath).equals(currBrowserKey)) {
- // } else {
- // }
- }
-
- private void modifyFilter(boolean fromOutside) {
- if (!fromOutside)
- if (currEdited != null) {
- String filter = filterTxt.getText() + "*";
- FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited));
- if (table != null && !table.isDisposed())
- table.filterList(filter);
- }
-
- }
-
- private String getPath(Node node) {
- try {
- return node.getPath();
- } catch (RepositoryException e) {
- throw new CmsException("Unable to get path for node " + node, e);
- }
- }
-
- private Point imageWidth = new Point(250, 0);
-
- /**
- * Recreates the content of the box that displays information about the current
- * selected node.
- */
- private Control createNodeView(Composite parent, Node context) throws RepositoryException {
-
- parent.setLayout(new GridLayout(2, false));
-
- if (isImg(context)) {
- EditableImage image = new Img(parent, RIGHT, context, imageWidth);
- image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 2, 1));
- }
-
- // Name and primary type
- Label contextL = new Label(parent, SWT.NONE);
- contextL.setData(RWT.MARKUP_ENABLED, true);
- contextL.setText("<b>" + context.getName() + "</b>");
- new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType().getName());
-
- // Children
- for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) {
- Node child = nIt.nextNode();
- new CmsLink(child.getName(), BROWSE_PREFIX + child.getPath()).createUi(parent, context);
- new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType().getName());
- }
-
- // Properties
- for (PropertyIterator pIt = context.getProperties(); pIt.hasNext();) {
- Property property = pIt.nextProperty();
- Label label = new Label(parent, SWT.NONE);
- label.setText(property.getName());
- label.setToolTipText(JcrUtils.getPropertyDefinitionAsString(property));
- new Label(parent, SWT.NONE).setText(getPropAsString(property));
- }
-
- return null;
- }
-
- private boolean isImg(Node node) throws RepositoryException {
- // TODO support images
- return false;
-// return node.hasNode(JCR_CONTENT) && node.isNodeType(CmsTypes.CMS_IMAGE);
- }
-
- private String getPropAsString(Property property) throws RepositoryException {
- String result = "";
- if (property.isMultiple()) {
- result = getMultiAsString(property, ", ");
- } else {
- Value value = property.getValue();
- if (value.getType() == PropertyType.BINARY)
- result = "<binary>";
- else if (value.getType() == PropertyType.DATE)
- result = timeFormatter.format(value.getDate().getTime());
- else
- result = value.getString();
- }
- return result;
- }
-
- private String getMultiAsString(Property property, String separator) throws RepositoryException {
- if (separator == null)
- separator = "; ";
- Value[] values = property.getValues();
- StringBuilder builder = new StringBuilder();
- for (Value val : values) {
- String currStr = val.getString();
- if (!"".equals(currStr.trim()))
- builder.append(currStr).append(separator);
- }
- if (builder.lastIndexOf(separator) >= 0)
- return builder.substring(0, builder.length() - separator.length());
- else
- return builder.toString();
- }
-
- /** Almost canonical implementation of a table that display entities */
- private class FilterEntitiesVirtualTable extends Composite {
- private static final long serialVersionUID = 8798147431706283824L;
-
- // Context
- private Node context;
-
- // UI Objects
- private TableViewer entityViewer;
-
- // enable management of multiple columns
- Node getNode() {
- return context;
- }
-
- @Override
- public boolean setFocus() {
- if (entityViewer.getTable().isDisposed())
- return false;
- if (entityViewer.getSelection().isEmpty()) {
- Object first = entityViewer.getElementAt(0);
- if (first != null) {
- entityViewer.setSelection(new StructuredSelection(first), true);
- }
- }
- return entityViewer.getTable().setFocus();
- }
-
- void filterList(String filter) {
- try {
- NodeIterator nit = context.getNodes(filter);
- refreshFilteredList(nit);
- } catch (RepositoryException e) {
- throw new CmsException("Unable to filter " + getNode() + " children with filter " + filter, e);
- }
-
- }
-
- public FilterEntitiesVirtualTable(Composite parent, int style, Node context) {
- super(parent, SWT.NO_FOCUS);
- this.context = context;
- populate();
- }
-
- protected void populate() {
- Composite parent = this;
- GridLayout layout = CmsUtils.noSpaceGridLayout();
-
- this.setLayout(layout);
- createTableViewer(parent);
- }
-
- private void createTableViewer(final Composite parent) {
- // the list
- // We must limit the size of the table otherwise the full list is
- // loaded
- // before the layout happens
- Composite listCmp = new Composite(parent, SWT.NO_FOCUS);
- GridData gd = new GridData(SWT.LEFT, SWT.FILL, false, true);
- gd.widthHint = COLUMN_WIDTH;
- listCmp.setLayoutData(gd);
- listCmp.setLayout(CmsUtils.noSpaceGridLayout());
-
- entityViewer = new TableViewer(listCmp, SWT.VIRTUAL | SWT.SINGLE);
- Table table = entityViewer.getTable();
-
- table.setLayoutData(CmsUtils.fillAll());
- table.setLinesVisible(true);
- table.setHeaderVisible(false);
- table.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
-
- CmsUtils.style(table, MaintenanceStyles.BROWSER_COLUMN);
-
- // first column
- TableViewerColumn column = new TableViewerColumn(entityViewer, SWT.NONE);
- TableColumn tcol = column.getColumn();
- tcol.setWidth(COLUMN_WIDTH);
- tcol.setResizable(true);
- column.setLabelProvider(new SimpleNameLP());
-
- entityViewer.setContentProvider(new MyLazyCP(entityViewer));
- entityViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection();
- if (selection.isEmpty())
- return;
- else
- setEdited((Node) selection.getFirstElement());
-
- }
- });
-
- table.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -330694313896036230L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
-
- IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection();
- Node selected = null;
- if (!selection.isEmpty())
- selected = ((Node) selection.getFirstElement());
- try {
- if (e.keyCode == SWT.ARROW_RIGHT) {
- if (selected != null) {
- setEdited(selected);
- browserCols.get(selected.getPath()).setFocus();
- }
- } else if (e.keyCode == SWT.ARROW_LEFT) {
- try {
- selected = getNode().getParent();
- String newPath = selected.getPath(); // getNode().getParent()
- setEdited(selected);
- if (browserCols.containsKey(newPath))
- browserCols.get(newPath).setFocus();
- } catch (ItemNotFoundException ie) {
- // root silent
- }
- }
- } catch (RepositoryException ie) {
- throw new CmsException("Error while managing arrow " + "events in the browser for " + selected,
- ie);
- }
- }
- });
- }
-
- private class MyLazyCP implements ILazyContentProvider {
- private static final long serialVersionUID = 1L;
- private TableViewer viewer;
- private Object[] elements;
-
- public MyLazyCP(TableViewer viewer) {
- this.viewer = viewer;
- }
-
- public void dispose() {
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- // IMPORTANT: don't forget this: an exception will be thrown if
- // a selected object is not part of the results anymore.
- viewer.setSelection(null);
- this.elements = (Object[]) newInput;
- }
-
- public void updateElement(int index) {
- viewer.replace(elements[index], index);
- }
- }
-
- protected void refreshFilteredList(NodeIterator children) {
- Object[] rows = JcrUtils.nodeIteratorToList(children).toArray();
- entityViewer.setInput(rows);
- entityViewer.setItemCount(rows.length);
- entityViewer.refresh();
- }
-
- public class SimpleNameLP extends ColumnLabelProvider {
- private static final long serialVersionUID = 2465059387875338553L;
-
- @Override
- public String getText(Object element) {
- if (element instanceof Node) {
- Node curr = ((Node) element);
- try {
- return curr.getName();
- } catch (RepositoryException e) {
- throw new CmsException("Unable to get name for" + curr);
- }
- }
- return super.getText(element);
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.useradmin.UserAdmin;
-
-class ConnectivityDeploymentUi extends AbstractOsgiComposite {
- private static final long serialVersionUID = 590221539553514693L;
-
- public ConnectivityDeploymentUi(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected void initUi(int style) {
- StringBuffer text = new StringBuffer();
- text.append("<span style='font-variant: small-caps;'>Provided Servers</span><br/>");
-
- ServiceReference<HttpService> userAdminRef = bc.getServiceReference(HttpService.class);
- if (userAdminRef != null) {
- // FIXME use constants
- Object httpPort = userAdminRef.getProperty("http.port");
- Object httpsPort = userAdminRef.getProperty("https.port");
- if (httpPort != null)
- text.append("<b>http</b> ").append(httpPort).append("<br/>");
- if (httpsPort != null)
- text.append("<b>https</b> ").append(httpsPort).append("<br/>");
-
- }
-
- text.append("<br/>");
- text.append("<span style='font-variant: small-caps;'>Referenced Servers</span><br/>");
-
- Label label = new Label(this, SWT.NONE);
- label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
- CmsUtils.markup(label);
- label.setText(text.toString());
- }
-
- protected boolean isDeployed() {
- return bc.getServiceReference(UserAdmin.class) != null;
- }
-}
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.FileStore;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Collection;
-
-import org.apache.jackrabbit.core.RepositoryContext;
-import org.apache.jackrabbit.core.config.RepositoryConfig;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.node.NodeConstants;
-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.Label;
-import org.osgi.framework.ServiceReference;
-
-class DataDeploymentUi extends AbstractOsgiComposite {
- private static final long serialVersionUID = 590221539553514693L;
-
- public DataDeploymentUi(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected void initUi(int style) {
- if (isDeployed()) {
- initCurrentUi(this);
- } else {
- initNewUi(this);
- }
- }
-
- private void initNewUi(Composite parent) {
-// try {
-// ConfigurationAdmin confAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class));
-// Configuration[] confs = confAdmin.listConfigurations(
-// "(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + NodeConstants.NODE_REPOS_FACTORY_PID + ")");
-// if (confs == null || confs.length == 0) {
-// Group buttonGroup = new Group(parent, SWT.NONE);
-// buttonGroup.setText("Repository Type");
-// buttonGroup.setLayout(new GridLayout(2, true));
-// buttonGroup.setLayoutData(new GridData(GridData.FILL_VERTICAL));
-//
-// SelectionListener selectionListener = new SelectionAdapter() {
-// private static final long serialVersionUID = 6247064348421088092L;
-//
-// public void widgetSelected(SelectionEvent event) {
-// Button radio = (Button) event.widget;
-// if (!radio.getSelection())
-// return;
-// log.debug(event);
-// JackrabbitType nodeType = (JackrabbitType) radio.getData();
-// if (log.isDebugEnabled())
-// log.debug(" selected = " + nodeType.name());
-// };
-// };
-//
-// for (JackrabbitType nodeType : JackrabbitType.values()) {
-// Button radio = new Button(buttonGroup, SWT.RADIO);
-// radio.setText(nodeType.name());
-// radio.setData(nodeType);
-// if (nodeType.equals(JackrabbitType.localfs))
-// radio.setSelection(true);
-// radio.addSelectionListener(selectionListener);
-// }
-//
-// } else if (confs.length == 1) {
-//
-// } else {
-// throw new CmsException("Multiple repos not yet supported");
-// }
-// } catch (Exception e) {
-// throw new CmsException("Cannot initialize UI", e);
-// }
-
- }
-
- private void initCurrentUi(Composite parent) {
- parent.setLayout(new GridLayout());
- Collection<ServiceReference<RepositoryContext>> contexts = getServiceReferences(RepositoryContext.class,
- "(" + NodeConstants.CN + "=*)");
- StringBuffer text = new StringBuffer();
- text.append("<span style='font-variant: small-caps;'>Jackrabbit Repositories</span><br/>");
- for (ServiceReference<RepositoryContext> sr : contexts) {
- RepositoryContext repositoryContext = bc.getService(sr);
- String alias = sr.getProperty(NodeConstants.CN).toString();
- String rootNodeId = repositoryContext.getRootNodeId().toString();
- RepositoryConfig repositoryConfig = repositoryContext.getRepositoryConfig();
- Path repoHomePath = new File(repositoryConfig.getHomeDir()).toPath().toAbsolutePath();
- // TODO check data store
-
- text.append("<b>" + alias + "</b><br/>");
- text.append("rootNodeId: " + rootNodeId + "<br/>");
- try {
- FileStore fileStore = Files.getFileStore(repoHomePath);
- text.append("partition: " + fileStore.toString() + "<br/>");
- text.append(
- percentUsed(fileStore) + " used (" + humanReadable(fileStore.getUsableSpace()) + " free)<br/>");
- } catch (IOException e) {
- log.error("Cannot check fileStore for " + repoHomePath, e);
- }
- }
- Label label = new Label(parent, SWT.NONE);
- label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
- CmsUtils.markup(label);
- label.setText("<span style=''>" + text.toString() + "</span>");
- }
-
- private String humanReadable(long bytes) {
- long mb = bytes / (1024 * 1024);
- return mb >= 2048 ? Long.toString(mb / 1024) + " GB" : Long.toString(mb) + " MB";
- }
-
- private String percentUsed(FileStore fs) throws IOException {
- long used = fs.getTotalSpace() - fs.getUnallocatedSpace();
- long percent = used * 100 / fs.getTotalSpace();
- if (log.isTraceEnabled()) {
- // output identical to `df -B 1`)
- log.trace(fs.getTotalSpace() + "," + used + "," + fs.getUsableSpace());
- }
- String span;
- if (percent < 80)
- span = "<span style='color:green;font-weight:bold'>";
- else if (percent < 95)
- span = "<span style='color:orange;font-weight:bold'>";
- else
- span = "<span style='color:red;font-weight:bold'>";
- return span + percent + "%</span>";
- }
-
- protected boolean isDeployed() {
- return bc.getServiceReference(RepositoryContext.class) != null;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeDeployment;
-import org.argeo.node.NodeState;
-import org.eclipse.rap.rwt.application.AbstractEntryPoint;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Group;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-
-class DeploymentEntryPoint extends AbstractEntryPoint {
- private static final long serialVersionUID = -881152502968982437L;
- private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
-
- @Override
- protected void createContents(Composite parent) {
- // FIXME manage authentication if needed
- // if (!CurrentUser.roles().contains(AuthConstants.ROLE_ADMIN))
- // return;
-
- // parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- if (isDesktop()) {
- parent.setLayout(new GridLayout(2, true));
- } else {
- // TODO add scrolling
- parent.setLayout(new GridLayout(1, true));
- }
-
- initHighLevelSummary(parent);
-
- Group securityGroup = createHighLevelGroup(parent, "Security");
- securityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
- new SecurityDeploymentUi(securityGroup, SWT.NONE);
-
- Group dataGroup = createHighLevelGroup(parent, "Data");
- dataGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
- new DataDeploymentUi(dataGroup, SWT.NONE);
-
- Group logGroup = createHighLevelGroup(parent, "Notifications");
- logGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
- new LogDeploymentUi(logGroup, SWT.NONE);
-
- Group connectivityGroup = createHighLevelGroup(parent, "Connectivity");
- new ConnectivityDeploymentUi(connectivityGroup, SWT.NONE);
- connectivityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
-
- }
-
- private void initHighLevelSummary(Composite parent) {
- Composite composite = new Composite(parent, SWT.NONE);
- GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
- if (isDesktop())
- gridData.horizontalSpan = 3;
- composite.setLayoutData(gridData);
- composite.setLayout(new FillLayout());
-
- ServiceReference<NodeState> nodeStateRef = bc.getServiceReference(NodeState.class);
- if (nodeStateRef == null)
- throw new IllegalStateException("No CMS state available");
- NodeState nodeState = bc.getService(nodeStateRef);
- ServiceReference<NodeDeployment> nodeDeploymentRef = bc.getServiceReference(NodeDeployment.class);
- Label label = new Label(composite, SWT.WRAP);
- CmsUtils.markup(label);
- if (nodeDeploymentRef == null) {
- label.setText("Not yet deployed on <br>" + nodeState.getHostname() + "</br>, please configure below.");
- } else {
- Object stateUuid = nodeStateRef.getProperty(NodeConstants.CN);
- NodeDeployment nodeDeployment = bc.getService(nodeDeploymentRef);
- GregorianCalendar calendar = new GregorianCalendar();
- calendar.setTimeInMillis(nodeDeployment.getAvailableSince());
- calendar.setTimeZone(TimeZone.getDefault());
- label.setText("[" + "<b>" + nodeState.getHostname() + "</b>]# " + "Deployment state " + stateUuid
- + ", available since <b>" + calendar.getTime() + "</b>");
- }
- }
-
- private static Group createHighLevelGroup(Composite parent, String text) {
- Group group = new Group(parent, SWT.NONE);
- group.setText(text);
- CmsUtils.markup(group);
- return group;
- }
-
- private boolean isDesktop() {
- return true;
- }
-}
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Enumeration;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.log.LogEntry;
-import org.osgi.service.log.LogListener;
-import org.osgi.service.log.LogReaderService;
-
-class LogDeploymentUi extends AbstractOsgiComposite implements LogListener {
- private static final long serialVersionUID = 590221539553514693L;
-
- private DateFormat dateFormat = new SimpleDateFormat("MMdd HH:mm");
-
- private Display display;
- private Text logDisplay;
-
- public LogDeploymentUi(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected void initUi(int style) {
- LogReaderService logReader = getService(LogReaderService.class);
- // FIXME use server push
- // logReader.addLogListener(this);
- this.display = getDisplay();
- this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- logDisplay = new Text(this, SWT.WRAP | SWT.MULTI | SWT.READ_ONLY);
- logDisplay.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- CmsUtils.markup(logDisplay);
- @SuppressWarnings("unchecked")
- Enumeration<LogEntry> logEntries = (Enumeration<LogEntry>) logReader.getLog();
- while (logEntries.hasMoreElements())
- logDisplay.append(printEntry(logEntries.nextElement()));
- }
-
- private String printEntry(LogEntry entry) {
- StringBuilder sb = new StringBuilder();
- GregorianCalendar calendar = new GregorianCalendar(TimeZone.getDefault());
- calendar.setTimeInMillis(entry.getTime());
- sb.append(dateFormat.format(calendar.getTime())).append(' ');
- sb.append(entry.getMessage());
- sb.append('\n');
- return sb.toString();
- }
-
- @Override
- public void logged(LogEntry entry) {
- if (display.isDisposed())
- return;
- display.asyncExec(() -> {
- if (logDisplay.isDisposed())
- return;
- logDisplay.append(printEntry(entry));
- });
- display.wake();
- }
-
- // @Override
- // public void dispose() {
- // super.dispose();
- // getService(LogReaderService.class).removeLogListener(this);
- // }
-}
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-/** Specific styles used by the various maintenance pages . */
-public interface MaintenanceStyles {
- // General
- public final static String PREFIX = "maintenance_";
-
- // Browser
- public final static String BROWSER_COLUMN = "browser_column";
- }
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-
-public class MaintenanceUi implements ApplicationConfiguration {
-
- @Override
- public void configure(Application application) {
- // application.addEntryPoint("/status", DeploymentEntryPoint.class,
- // null);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-public class NonAdminPage implements CmsUiProvider{
-
- @Override
- public Control createUi(Composite parent, Node context)
- throws RepositoryException {
- Composite body = new Composite(parent, SWT.NO_FOCUS);
- body.setLayoutData(CmsUtils.fillAll());
- body.setLayout(new GridLayout());
- Label label = new Label(body, SWT.NONE);
- label.setText("You should be an admin to perform maintenance operations. "
- + "Are you sure you are logged in?");
- label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
- return null;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.maintenance;
-
-import java.net.URI;
-
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.UserAdmin;
-
-class SecurityDeploymentUi extends AbstractOsgiComposite {
- private static final long serialVersionUID = 590221539553514693L;
-
- public SecurityDeploymentUi(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected void initUi(int style) {
- if (isDeployed()) {
- initCurrentUi(this);
- } else {
- initNewUi(this);
- }
- }
-
- private void initNewUi(Composite parent) {
- new Label(parent, SWT.NONE).setText("Security is not configured");
- }
-
- private void initCurrentUi(Composite parent) {
- ServiceReference<UserAdmin> userAdminRef = bc.getServiceReference(UserAdmin.class);
- UserAdmin userAdmin = bc.getService(userAdminRef);
- StringBuffer text = new StringBuffer();
- text.append("<span style='font-variant: small-caps;'>Domains</span><br/>");
- domains: for (String key : userAdminRef.getPropertyKeys()) {
- if (!key.startsWith("/"))
- continue domains;
- URI uri;
- try {
- uri = new URI(key);
- } catch (Exception e) {
- // ignore non URI keys
- continue domains;
- }
-
- String rootDn = uri.getPath().substring(1, uri.getPath().length());
- // FIXME make reading query options more robust, using utils
- boolean readOnly = uri.getQuery().equals("readOnly=true");
- if (readOnly)
- text.append("<span style='font-weight:bold;font-style: italic'>");
- else
- text.append("<span style='font-weight:bold'>");
-
- text.append(rootDn);
- text.append("</span><br/>");
- try {
- Role[] roles = userAdmin.getRoles("(dn=*," + rootDn + ")");
- long userCount = 0;
- long groupCount = 0;
- for (Role role : roles) {
- if (role.getType() == Role.USER)
- userCount++;
- else
- groupCount++;
- }
- text.append(" " + userCount + " users, " + groupCount +" groups.<br/>");
- } catch (InvalidSyntaxException e) {
- log.error("Invalid syntax", e);
- }
- }
- Label label = new Label(parent, SWT.NONE);
- label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
- CmsUtils.markup(label);
- label.setText(text.toString());
- }
-
- protected boolean isDeployed() {
- return bc.getServiceReference(UserAdmin.class) != null;
- }
-}
+++ /dev/null
-package org.argeo.cms.script;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.script.Invocable;
-import javax.script.ScriptException;
-
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.util.CmsPane;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.util.SimpleErgonomics;
-import org.argeo.eclipse.ui.Selected;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.application.EntryPointFactory;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-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;
-
-public class AppUi implements CmsUiProvider, Branding {
- private final CmsScriptApp app;
-
- private CmsUiProvider ui;
- private String createUi;
- private Object impl;
- private String script;
- // private Branding branding = new Branding();
-
- private EntryPointFactory factory;
-
- // Branding
- private String themeId;
- private String additionalHeaders;
- private String bodyHtml;
- private String pageTitle;
- private String pageOverflow;
- private String favicon;
-
- public AppUi(CmsScriptApp app) {
- this.app = app;
- }
-
- public AppUi(CmsScriptApp app, String scriptPath) {
- this.app = app;
- this.ui = new ScriptUi((BundleContext) app.getScriptEngine().get(CmsScriptRwtApplication.BC), app.getScriptEngine(), scriptPath);
- }
-
- public AppUi(CmsScriptApp app, CmsUiProvider uiProvider) {
- this.app = app;
- this.ui = uiProvider;
- }
-
- public AppUi(CmsScriptApp app, EntryPointFactory factory) {
- this.app = app;
- this.factory = factory;
- }
-
- public void apply(Repository repository, Application application, Branding appBranding, String path) {
- Map<String, String> factoryProperties = new HashMap<>();
- if (appBranding != null)
- appBranding.applyBranding(factoryProperties);
- applyBranding(factoryProperties);
- if (factory != null) {
- application.addEntryPoint("/" + path, factory, factoryProperties);
- } else {
- EntryPointFactory entryPointFactory = new EntryPointFactory() {
- @Override
- public EntryPoint create() {
- SimpleErgonomics ergonomics = new SimpleErgonomics(repository, "main", "/home/root/argeo:keyring",
- AppUi.this, factoryProperties);
-// CmsUiProvider header = app.getHeader();
-// if (header != null)
-// ergonomics.setHeader(header);
- app.applySides(ergonomics);
- Integer headerHeight = app.getHeaderHeight();
- if (headerHeight != null)
- ergonomics.setHeaderHeight(headerHeight);
- return ergonomics;
- }
- };
- application.addEntryPoint("/" + path, entryPointFactory, factoryProperties);
- }
- }
-
- public void setUi(CmsUiProvider uiProvider) {
- this.ui = uiProvider;
- }
-
- public void applyBranding(Map<String, String> properties) {
- if (themeId != null)
- properties.put(WebClient.THEME_ID, themeId);
- if (additionalHeaders != null)
- properties.put(WebClient.HEAD_HTML, additionalHeaders);
- if (bodyHtml != null)
- properties.put(WebClient.BODY_HTML, bodyHtml);
- if (pageTitle != null)
- properties.put(WebClient.PAGE_TITLE, pageTitle);
- if (pageOverflow != null)
- properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
- if (favicon != null)
- properties.put(WebClient.FAVICON, favicon);
- }
-
- // public Branding getBranding() {
- // return branding;
- // }
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- CmsPane cmsPane = new CmsPane(parent, SWT.NONE);
-
- if (false) {
- // QA
- CmsUtils.style(cmsPane.getQaArea(), "qa");
- Button reload = new Button(cmsPane.getQaArea(), SWT.FLAT);
- CmsUtils.style(reload, "qa");
- reload.setText("Reload");
- reload.addSelectionListener(new Selected() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- new Thread() {
- @Override
- public void run() {
- app.reload();
- }
- }.start();
- RWT.getClient().getService(JavaScriptExecutor.class)
- .execute("setTimeout('location.reload()',1000)");
- }
- });
-
- // Support
- CmsUtils.style(cmsPane.getSupportArea(), "support");
- Label msg = new Label(cmsPane.getSupportArea(), SWT.NONE);
- CmsUtils.style(msg, "support");
- msg.setText("UNSUPPORTED DEVELOPMENT VERSION");
- }
-
- if (ui != null) {
- ui.createUi(cmsPane.getMainArea(), context);
- }
- if (createUi != null) {
- Invocable invocable = (Invocable) app.getScriptEngine();
- try {
- invocable.invokeFunction(createUi, cmsPane.getMainArea(), context);
-
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- if (impl != null) {
- Invocable invocable = (Invocable) app.getScriptEngine();
- try {
- invocable.invokeMethod(impl, "createUi", cmsPane.getMainArea(), context);
-
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- // Invocable invocable = (Invocable) app.getScriptEngine();
- // try {
- // invocable.invokeMethod(AppUi.this, "initUi", parent, context);
- //
- // } catch (NoSuchMethodException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // } catch (ScriptException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
-
- return null;
- }
-
- public void setCreateUi(String createUi) {
- this.createUi = createUi;
- }
-
- public void setImpl(Object impl) {
- this.impl = impl;
- }
-
- public Object getImpl() {
- return impl;
- }
-
- public String getScript() {
- return script;
- }
-
- public void setScript(String script) {
- this.script = script;
- }
-
- // Branding
- public String getThemeId() {
- return themeId;
- }
-
- public void setThemeId(String themeId) {
- this.themeId = themeId;
- }
-
- public String getAdditionalHeaders() {
- return additionalHeaders;
- }
-
- public void setAdditionalHeaders(String additionalHeaders) {
- this.additionalHeaders = additionalHeaders;
- }
-
- public String getBodyHtml() {
- return bodyHtml;
- }
-
- public void setBodyHtml(String bodyHtml) {
- this.bodyHtml = bodyHtml;
- }
-
- public String getPageTitle() {
- return pageTitle;
- }
-
- public void setPageTitle(String pageTitle) {
- this.pageTitle = pageTitle;
- }
-
- public String getPageOverflow() {
- return pageOverflow;
- }
-
- public void setPageOverflow(String pageOverflow) {
- this.pageOverflow = pageOverflow;
- }
-
- public String getFavicon() {
- return favicon;
- }
-
- public void setFavicon(String favicon) {
- this.favicon = favicon;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.script;
-
-import java.util.Map;
-
-public interface Branding {
- public void applyBranding(Map<String, String> properties);
-
- public String getThemeId();
-
- public String getAdditionalHeaders();
-
- public String getBodyHtml();
-
- public String getPageTitle();
-
- public String getPageOverflow();
-
- public String getFavicon();
-
-}
+++ /dev/null
-package org.argeo.cms.script;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.script.ScriptEngine;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsConstants;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.util.BundleResourceLoader;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.util.SimpleErgonomics;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.Application.OperationMode;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.http.NamespaceException;
-
-public class CmsScriptApp implements Branding {
- public final static String CONTEXT_NAME = "contextName";
-
- ServiceRegistration<ApplicationConfiguration> appConfigReg;
-
- private ScriptEngine scriptEngine;
-
- private final static Log log = LogFactory.getLog(CmsScriptApp.class);
-
- private String webPath;
- private String repo = "(cn=node)";
-
- // private Branding branding = new Branding();
- private Theme theme;
-
- private List<String> resources = new ArrayList<>();
-
- private Map<String, AppUi> ui = new HashMap<>();
-
- private CmsUiProvider header;
- private Integer headerHeight = null;
- private CmsUiProvider lead;
- private CmsUiProvider end;
- private CmsUiProvider footer;
-
- // Branding
- private String themeId;
- private String additionalHeaders;
- private String bodyHtml;
- private String pageTitle;
- private String pageOverflow;
- private String favicon;
-
- public CmsScriptApp(ScriptEngine scriptEngine) {
- super();
- this.scriptEngine = scriptEngine;
- }
-
- public void apply(BundleContext bundleContext, Repository repository, Application application) {
- BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
-
- application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
- // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
-
- application.setExceptionHandler(new CmsExceptionHandler());
-
- // loading animated gif
- application.addResource(CmsConstants.LOADING_IMAGE, createResourceLoader(CmsConstants.LOADING_IMAGE));
- // empty image
- application.addResource(CmsConstants.NO_IMAGE, createResourceLoader(CmsConstants.NO_IMAGE));
-
- for (String resource : resources) {
- application.addResource(resource, bundleRL);
- if (log.isTraceEnabled())
- log.trace("Resource " + resource);
- }
-
- if (theme != null) {
- theme.apply(application);
- String themeHeaders = theme.getAdditionalHeaders();
- if (themeHeaders != null) {
- if (additionalHeaders == null)
- additionalHeaders = themeHeaders;
- else
- additionalHeaders = themeHeaders + "\n" + additionalHeaders;
- }
- themeId = theme.getThemeId();
- }
-
- // client JavaScript
- Bundle appBundle = bundleRL.getBundle();
- BundleContext bc = appBundle.getBundleContext();
- HttpService httpService = bc.getService(bc.getServiceReference(HttpService.class));
- HttpContext httpContext = new BundleHttpContext(bc);
- Enumeration<URL> themeResources = appBundle.findEntries("/js/", "*", true);
- if (themeResources != null)
- bundleResources: while (themeResources.hasMoreElements()) {
- try {
- String name = themeResources.nextElement().getPath();
- if (name.endsWith("/"))
- continue bundleResources;
- String alias = "/" + getWebPath() + name;
-
- httpService.registerResources(alias, name, httpContext);
- if (log.isDebugEnabled())
- log.debug("Mapped " + name + " to alias " + alias);
-
- } catch (NamespaceException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- // App UIs
- for (String appUiName : ui.keySet()) {
- AppUi appUi = ui.get(appUiName);
- appUi.apply(repository, application, this, appUiName);
-
- }
-
- }
-
- public void applySides(SimpleErgonomics simpleErgonomics) {
- simpleErgonomics.setHeader(header);
- simpleErgonomics.setLead(lead);
- simpleErgonomics.setEnd(end);
- simpleErgonomics.setFooter(footer);
- }
-
- public void register(BundleContext bundleContext, ApplicationConfiguration appConfig) {
- Hashtable<String, String> props = new Hashtable<>();
- props.put(CONTEXT_NAME, webPath);
- appConfigReg = bundleContext.registerService(ApplicationConfiguration.class, appConfig, props);
- }
-
- public void reload() {
- BundleContext bundleContext = appConfigReg.getReference().getBundle().getBundleContext();
- ApplicationConfiguration appConfig = bundleContext.getService(appConfigReg.getReference());
- appConfigReg.unregister();
- register(bundleContext, appConfig);
-
- // BundleContext bundleContext = (BundleContext)
- // getScriptEngine().get("bundleContext");
- // try {
- // Bundle bundle = bundleContext.getBundle();
- // bundle.stop();
- // bundle.start();
- // } catch (BundleException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
- }
-
- private static ResourceLoader createResourceLoader(final String resourceName) {
- return new ResourceLoader() {
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- return getClass().getClassLoader().getResourceAsStream(resourceName);
- }
- };
- }
-
- public List<String> getResources() {
- return resources;
- }
-
- public AppUi newUi(String name) {
- if (ui.containsKey(name))
- throw new IllegalArgumentException("There is already an UI named " + name);
- AppUi appUi = new AppUi(this);
- // appUi.setApp(this);
- ui.put(name, appUi);
- return appUi;
- }
-
- public void addUi(String name, AppUi appUi) {
- if (ui.containsKey(name))
- throw new IllegalArgumentException("There is already an UI named " + name);
- // appUi.setApp(this);
- ui.put(name, appUi);
- }
-
- public void applyBranding(Map<String, String> properties) {
- if (themeId != null)
- properties.put(WebClient.THEME_ID, themeId);
- if (additionalHeaders != null)
- properties.put(WebClient.HEAD_HTML, additionalHeaders);
- if (bodyHtml != null)
- properties.put(WebClient.BODY_HTML, bodyHtml);
- if (pageTitle != null)
- properties.put(WebClient.PAGE_TITLE, pageTitle);
- if (pageOverflow != null)
- properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
- if (favicon != null)
- properties.put(WebClient.FAVICON, favicon);
- }
-
- class CmsExceptionHandler implements ExceptionHandler {
-
- @Override
- public void handleException(Throwable throwable) {
- // TODO be smarter
- CmsUtils.getCmsView().exception(throwable);
- }
-
- }
-
- // public Branding getBranding() {
- // return branding;
- // }
-
- ScriptEngine getScriptEngine() {
- return scriptEngine;
- }
-
- public static String toJson(Node node) {
- try {
- StringBuilder sb = new StringBuilder();
- sb.append('{');
- PropertyIterator pit = node.getProperties();
- int count = 0;
- while (pit.hasNext()) {
- Property p = pit.nextProperty();
- int type = p.getType();
- if (type == PropertyType.REFERENCE || type == PropertyType.WEAKREFERENCE || type == PropertyType.PATH) {
- Node ref = p.getNode();
- if (count != 0)
- sb.append(',');
- // TODO limit depth?
- sb.append(toJson(ref));
- count++;
- } else if (!p.isMultiple()) {
- if (count != 0)
- sb.append(',');
- sb.append('\"').append(p.getName()).append("\":\"").append(p.getString()).append('\"');
- count++;
- }
- }
- sb.append('}');
- return sb.toString();
- } catch (RepositoryException e) {
- throw new CmsException("Cannot convert " + node + " to JSON", e);
- }
- }
-
- public void fromJson(Node node, String json) {
- // TODO
- }
-
- public Theme getTheme() {
- return theme;
- }
-
- public void setTheme(Theme theme) {
- this.theme = theme;
- }
-
- public String getWebPath() {
- return webPath;
- }
-
- public void setWebPath(String context) {
- this.webPath = context;
- }
-
- public String getRepo() {
- return repo;
- }
-
- public void setRepo(String repo) {
- this.repo = repo;
- }
-
- public Map<String, AppUi> getUi() {
- return ui;
- }
-
- public void setUi(Map<String, AppUi> ui) {
- this.ui = ui;
- }
-
- // Branding
- public String getThemeId() {
- return themeId;
- }
-
- public void setThemeId(String themeId) {
- this.themeId = themeId;
- }
-
- public String getAdditionalHeaders() {
- return additionalHeaders;
- }
-
- public void setAdditionalHeaders(String additionalHeaders) {
- this.additionalHeaders = additionalHeaders;
- }
-
- public String getBodyHtml() {
- return bodyHtml;
- }
-
- public void setBodyHtml(String bodyHtml) {
- this.bodyHtml = bodyHtml;
- }
-
- public String getPageTitle() {
- return pageTitle;
- }
-
- public void setPageTitle(String pageTitle) {
- this.pageTitle = pageTitle;
- }
-
- public String getPageOverflow() {
- return pageOverflow;
- }
-
- public void setPageOverflow(String pageOverflow) {
- this.pageOverflow = pageOverflow;
- }
-
- public String getFavicon() {
- return favicon;
- }
-
- public void setFavicon(String favicon) {
- this.favicon = favicon;
- }
-
- public CmsUiProvider getHeader() {
- return header;
- }
-
- public void setHeader(CmsUiProvider header) {
- this.header = header;
- }
-
- public Integer getHeaderHeight() {
- return headerHeight;
- }
-
- public void setHeaderHeight(Integer headerHeight) {
- this.headerHeight = headerHeight;
- }
-
- public CmsUiProvider getLead() {
- return lead;
- }
-
- public void setLead(CmsUiProvider lead) {
- this.lead = lead;
- }
-
- public CmsUiProvider getEnd() {
- return end;
- }
-
- public void setEnd(CmsUiProvider end) {
- this.end = end;
- }
-
- public CmsUiProvider getFooter() {
- return footer;
- }
-
- public void setFooter(CmsUiProvider footer) {
- this.footer = footer;
- }
-
- static class BundleHttpContext implements HttpContext {
- private BundleContext bundleContext;
-
- public BundleHttpContext(BundleContext bundleContext) {
- super();
- this.bundleContext = bundleContext;
- }
-
- @Override
- public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
- // TODO Auto-generated method stub
- return true;
- }
-
- @Override
- public URL getResource(String name) {
-
- return bundleContext.getBundle().getEntry(name);
- }
-
- @Override
- public String getMimeType(String name) {
- return null;
- }
-
- }
-
-}
+++ /dev/null
-package org.argeo.cms.script;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.URL;
-
-import javax.jcr.Repository;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.wiring.BundleWiring;
-
-public class CmsScriptRwtApplication implements ApplicationConfiguration {
- public final static String APP = "APP";
- public final static String BC = "BC";
-
- private final Log log = LogFactory.getLog(CmsScriptRwtApplication.class);
-
- BundleContext bundleContext;
- Repository repository;
-
- ScriptEngine engine;
-
- public void init(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
- ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
- try {
-// Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
-// ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
-// engine = scriptEngineManager.getEngineByName("JavaScript");
-// if (engine == null) {// Nashorn
-// Thread.currentThread().setContextClassLoader(originalCcl);
-// scriptEngineManager = new ScriptEngineManager();
-// Thread.currentThread().setContextClassLoader(bundleCl);
-// engine = scriptEngineManager.getEngineByName("JavaScript");
-// }
- engine = loadScriptEngine(originalCcl, bundleCl);
-
- // Load script
- URL appUrl = bundleContext.getBundle().getEntry("cms/app.js");
- // System.out.println("Loading " + appUrl);
- // System.out.println("Loading " + appUrl.getHost());
- // System.out.println("Loading " + appUrl.getPath());
-
- CmsScriptApp app = new CmsScriptApp(engine);
- engine.put(APP, app);
- engine.put(BC, bundleContext);
- try (Reader reader = new InputStreamReader(appUrl.openStream())) {
- engine.eval(reader);
- } catch (IOException | ScriptException e) {
- throw new CmsException("Cannot execute " + appUrl, e);
- }
-
- if (log.isDebugEnabled())
- log.debug("CMS script app initialized from " + appUrl);
-
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- Thread.currentThread().setContextClassLoader(originalCcl);
- }
- }
-
- public void destroy(BundleContext bundleContext) {
- engine = null;
- }
-
- @Override
- public void configure(Application application) {
- load(application);
- }
-
- void load(Application application) {
- CmsScriptApp app = getApp();
- app.apply(bundleContext, repository, application);
- if (log.isDebugEnabled())
- log.debug("CMS script app loaded to " + app.getWebPath());
- }
-
- CmsScriptApp getApp() {
- if (engine == null)
- throw new IllegalStateException("CMS script app is not initialized");
- return (CmsScriptApp) engine.get(APP);
- }
-
- void update() {
-
- try {
- bundleContext.getBundle().update();
- } catch (BundleException e) {
- e.printStackTrace();
- }
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- private static ScriptEngine loadScriptEngine(ClassLoader originalCcl, ClassLoader bundleCl) {
- Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
- ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
- ScriptEngine engine = scriptEngineManager.getEngineByName("JavaScript");
- if (engine == null) {// Nashorn
- Thread.currentThread().setContextClassLoader(originalCcl);
- scriptEngineManager = new ScriptEngineManager();
- Thread.currentThread().setContextClassLoader(bundleCl);
- engine = scriptEngineManager.getEngineByName("JavaScript");
- }
- return engine;
- }
-}
+++ /dev/null
-package org.argeo.cms.script;
-
-import javax.jcr.Repository;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class ScriptAppActivator implements BundleActivator {
- private final static Log log = LogFactory.getLog(ScriptAppActivator.class);
-
- @Override
- public void start(BundleContext context) throws Exception {
- try {
- CmsScriptRwtApplication appConfig = new CmsScriptRwtApplication();
- appConfig.init(context);
- CmsScriptApp app = appConfig.getApp();
- ServiceTracker<Repository, Repository> repoSt = new ServiceTracker<Repository, Repository>(context,
- FrameworkUtil.createFilter("(&" + app.getRepo() + "(objectClass=javax.jcr.Repository))"), null) {
-
- @Override
- public Repository addingService(ServiceReference<Repository> reference) {
- Repository repository = super.addingService(reference);
- appConfig.setRepository(repository);
- CmsScriptApp app = appConfig.getApp();
- app.register(context, appConfig);
- return repository;
- }
-
- };
- repoSt.open();
- } catch (Exception e) {
- log.error("Cannot initialise script bundle " + context.getBundle().getSymbolicName(), e);
- throw e;
- }
- }
-
- @Override
- public void stop(BundleContext context) throws Exception {
- }
-
-}
+++ /dev/null
-package org.argeo.cms.script;
-
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.script.Invocable;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.BundleContext;
-
-class ScriptUi implements CmsUiProvider {
- private final static Log log = LogFactory.getLog(ScriptUi.class);
-
- private boolean development = true;
- private ScriptEngine scriptEngine;
-
- private URL appUrl;
- // private BundleContext bundleContext;
- // private String path;
-
- // private Bindings bindings;
- // private String script;
-
- public ScriptUi(BundleContext bundleContext,ScriptEngine scriptEngine, String path) {
- this.scriptEngine = scriptEngine;
-//// ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
-// ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
-// ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
-// try {
-//// Thread.currentThread().setContextClassLoader(bundleCl);
-//// scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
-//// scriptEngine.put(CmsScriptRwtApplication.BC, bundleContext);
-// scriptEngine = CmsScriptRwtApplication.loadScriptEngine(originalCcl, bundleCl);
-//
-// } catch (Exception e) {
-// e.printStackTrace();
-// } finally {
-// Thread.currentThread().setContextClassLoader(originalCcl);
-// }
- this.appUrl = bundleContext.getBundle().getEntry(path);
- load();
- }
-
- private void load() {
-// try (Reader reader = new InputStreamReader(appUrl.openStream())) {
-// scriptEngine.eval(reader);
-// } catch (IOException | ScriptException e) {
-// log.warn("Cannot execute " + appUrl, e);
-// }
-
- try {
- scriptEngine.eval("load('" + appUrl + "')");
- } catch (ScriptException e) {
- log.warn("Cannot execute " + appUrl, e);
- }
-
- }
-
- // public ScriptUiProvider(ScriptEngine scriptEngine, String script) throws
- // ScriptException {
- // super();
- // this.scriptEngine = scriptEngine;
- // this.script = script;
- // bindings = scriptEngine.createBindings();
- // scriptEngine.eval(script, bindings);
- // }
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- long begin = System.currentTimeMillis();
- // if (bindings == null) {
- // bindings = scriptEngine.createBindings();
- // try {
- // scriptEngine.eval(script, bindings);
- // } catch (ScriptException e) {
- // log.warn("Cannot evaluate script", e);
- // }
- // }
- // Bindings bindings = scriptEngine.createBindings();
- // bindings.put("parent", parent);
- // bindings.put("context", context);
- // URL appUrl = bundleContext.getBundle().getEntry(path);
- // try (Reader reader = new InputStreamReader(appUrl.openStream())) {
- // scriptEngine.eval(reader,bindings);
- // } catch (IOException | ScriptException e) {
- // log.warn("Cannot execute " + appUrl, e);
- // }
-
- if (development)
- load();
-
- Invocable invocable = (Invocable) scriptEngine;
- try {
- invocable.invokeFunction("createUi", parent, context);
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- long duration = System.currentTimeMillis() - begin;
- if (log.isTraceEnabled())
- log.trace(appUrl + " UI in " + duration + " ms");
- return null;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.script;
-
-import org.argeo.cms.util.CmsTheme;
-import org.osgi.framework.BundleContext;
-
-/** @deprecated Use <code>CmsTheme</code> instead. */
-@Deprecated
-public class Theme extends CmsTheme {
-
- public Theme(BundleContext bundleContext, String symbolicName) {
- super(bundleContext, symbolicName);
- }
-
- public Theme(BundleContext bundleContext) {
- super(bundleContext);
- }
-
-}
+++ /dev/null
-// CMS
-var ScrolledPage = Java.type('org.argeo.cms.widgets.ScrolledPage');
-
-var CmsScriptApp = Java.type('org.argeo.cms.script.CmsScriptApp');
-var AppUi = Java.type('org.argeo.cms.script.AppUi');
-var Theme = Java.type('org.argeo.cms.script.Theme');
-var ScriptUi = Java.type('org.argeo.cms.script.ScriptUi');
-var CmsUtils = Java.type('org.argeo.cms.util.CmsUtils');
-var SimpleCmsHeader = Java.type('org.argeo.cms.util.SimpleCmsHeader');
-var CmsLink = Java.type('org.argeo.cms.util.CmsLink');
-var MenuLink = Java.type('org.argeo.cms.util.MenuLink');
-var UserMenuLink = Java.type('org.argeo.cms.util.UserMenuLink');
-
-// SWT
-var SWT = Java.type('org.eclipse.swt.SWT');
-var Composite = Java.type('org.eclipse.swt.widgets.Composite');
-var Label = Java.type('org.eclipse.swt.widgets.Label');
-var Button = Java.type('org.eclipse.swt.widgets.Button');
-var Text = Java.type('org.eclipse.swt.widgets.Text');
-var Browser = Java.type('org.eclipse.swt.browser.Browser');
-
-var FillLayout = Java.type('org.eclipse.swt.layout.FillLayout');
-var GridLayout = Java.type('org.eclipse.swt.layout.GridLayout');
-var RowLayout = Java.type('org.eclipse.swt.layout.RowLayout');
-var FormLayout = Java.type('org.eclipse.swt.layout.FormLayout');
-var GridData = Java.type('org.eclipse.swt.layout.GridData');
-
-function loadNode(node) {
- var json = CmsScriptApp.toJson(node)
- var fromJson = JSON.parse(json)
- return fromJson
-}
-
-function newArea(parent, style, layout) {
- var control = new Composite(parent, SWT.NONE)
- control.setLayout(layout)
- CmsUtils.style(control, style)
- return control
-}
-
-function newLabel(parent, style, text) {
- var control = new Label(parent, SWT.WRAP)
- control.setText(text)
- CmsUtils.style(control, style)
- CmsUtils.markup(control)
- return control
-}
-
-function newButton(parent, style, text) {
- var control = new Button(parent, SWT.FLAT)
- control.setText(text)
- CmsUtils.style(control, style)
- CmsUtils.markup(control)
- return control
-}
-
-function newFormLabel(parent, style, text) {
- return newLabel(parent, style, '<b>' + text + '</b>')
-}
-
-function newText(parent, style, msg) {
- var control = new Text(parent, SWT.NONE)
- control.setMessage(msg)
- CmsUtils.style(control, style)
- return control
-}
-
-function newScrolledPage(parent) {
- var scrolled = new ScrolledPage(parent, SWT.NONE)
- scrolled.setLayoutData(CmsUtils.fillAll())
- scrolled.setLayout(CmsUtils.noSpaceGridLayout())
- var page = new Composite(scrolled, SWT.NONE)
- page.setLayout(CmsUtils.noSpaceGridLayout())
- page.setBackgroundMode(SWT.INHERIT_NONE)
- return page
-}
-
-function gridData(control) {
- var gridData = new GridData()
- control.setLayoutData(gridData)
- return gridData
-}
-
-function gridData(control, hAlign, vAlign) {
- var gridData = new GridData(hAlign, vAlign, false, false)
- control.setLayoutData(gridData)
- return gridData
-}
-
-// print(__FILE__, __LINE__, __DIR__)
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.HttpRequestCallback;
import org.argeo.jcr.JcrUtils;
import org.argeo.naming.AuthPassword;
import org.argeo.naming.SharedSecret;
-import org.argeo.node.NodeConstants;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.application.AbstractEntryPoint;
import org.eclipse.rap.rwt.client.WebClient;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
-import org.argeo.node.MvcProvider;
+import org.argeo.api.MvcProvider;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
package org.argeo.cms.ui.dialogs;
import org.argeo.cms.CmsMsg;
-import org.argeo.cms.util.CmsUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.Selected;
import org.argeo.eclipse.ui.dialogs.LightweightDialog;
body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Label messageLbl = new Label(body, SWT.WRAP);
- CmsUtils.markup(messageLbl);
+ CmsUiUtils.markup(messageLbl);
messageLbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
messageLbl.setFont(EclipseUiUtils.getBoldFont(parent));
if (message != null)
import org.argeo.cms.CmsException;
import org.argeo.cms.CmsMsg;
-import org.argeo.cms.util.CmsUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.Selected;
import org.argeo.eclipse.ui.dialogs.LightweightDialog;
Composite messageArea = new Composite(parent, SWT.NONE);
messageArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
{
- messageArea.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(2, false)));
+ messageArea.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(2, false)));
titleBar = new Label(messageArea, SWT.WRAP);
titleBar.setFont(EclipseUiUtils.getBoldFont(parent));
titleBar.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
IWizardPage[] pages = wizard.getPages();
for (int i = 0; i < pages.length; i++) {
pageBodies[i] = new Composite(body, SWT.NONE);
- pageBodies[i].setLayout(CmsUtils.noSpaceGridLayout());
+ pageBodies[i].setLayout(CmsUiUtils.noSpaceGridLayout());
setSwitchingFormData(pageBodies[i]);
pages[i].createControl(pageBodies[i]);
}
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Editable String that displays a browsable link when read-only */
+public class EditableLink extends EditablePropertyString implements
+ EditablePart {
+ private static final long serialVersionUID = 5055000749992803591L;
+
+ private String type;
+ private String message;
+ private boolean readOnly;
+
+ public EditableLink(Composite parent, int style, Node node,
+ String propertyName, String type, String message)
+ throws RepositoryException {
+ super(parent, style, node, propertyName, message);
+ this.message = message;
+ this.type = type;
+
+ readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
+ if (node.hasProperty(propertyName)) {
+ this.setStyle(FormStyle.propertyText.style());
+ this.setText(node.getProperty(propertyName).getString());
+ } else {
+ this.setStyle(FormStyle.propertyMessage.style());
+ this.setText("");
+ }
+ }
+
+ public void setText(String text) {
+ Control child = getControl();
+ if (child instanceof Label) {
+ Label lbl = (Label) child;
+ if (EclipseUiUtils.isEmpty(text))
+ lbl.setText(message);
+ else if (readOnly)
+ setLinkValue(lbl, text);
+ else
+ // if canEdit() we put only the value with no link
+ // to avoid glitches of the edition life cycle
+ lbl.setText(text);
+ } else if (child instanceof Text) {
+ Text txt = (Text) child;
+ if (EclipseUiUtils.isEmpty(text)) {
+ txt.setText("");
+ txt.setMessage(message);
+ } else
+ txt.setText(text);
+ }
+ }
+
+ private void setLinkValue(Label lbl, String text) {
+ if (FormStyle.email.style().equals(type))
+ lbl.setText(FormUtils.getMailLink(text));
+ else if (FormStyle.phone.style().equals(type))
+ lbl.setText(FormUtils.getPhoneLink(text));
+ else if (FormStyle.website.style().equals(type))
+ lbl.setText(FormUtils.getUrlLink(text));
+ else if (FormStyle.facebook.style().equals(type)
+ || FormStyle.instagram.style().equals(type)
+ || FormStyle.linkedIn.style().equals(type)
+ || FormStyle.twitter.style().equals(type))
+ lbl.setText(FormUtils.getUrlLink(text));
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+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;
+
+/** Display, add or remove values from a list in a CMS context */
+public class EditableMultiStringProperty extends StyledControl implements EditablePart {
+ private static final long serialVersionUID = -7044614381252178595L;
+
+ private String propertyName;
+ private String message;
+ // TODO implement the ability to provide a list of possible values
+ private String[] possibleValues;
+ private boolean canEdit;
+ private SelectionListener removeValueSL;
+ private List<String> values;
+
+ // TODO manage within the CSS
+ private int rowSpacing = 5;
+ private int rowMarging = 0;
+ private int oneValueMargingRight = 5;
+ private int btnWidth = 16;
+ private int btnHeight = 16;
+ private int btnHorizontalIndent = 3;
+
+ public EditableMultiStringProperty(Composite parent, int style, Node node, String propertyName, List<String> values,
+ String[] possibleValues, String addValueMsg, SelectionListener removeValueSelectionListener)
+ throws RepositoryException {
+ super(parent, style, node, true);
+
+ this.propertyName = propertyName;
+ this.values = values;
+ this.possibleValues = new String[]{"Un", "Deux", "Trois"};
+ this.message = addValueMsg;
+ this.canEdit = removeValueSelectionListener != null;
+ this.removeValueSL = removeValueSelectionListener;
+ }
+
+ public List<String> getValues() {
+ return values;
+ }
+
+ public void setValues(List<String> values) {
+ this.values = values;
+ }
+
+ // Row layout items do not need explicit layout data
+ protected void setControlLayoutData(Control control) {
+ }
+
+ /** To be overridden */
+ protected void setContainerLayoutData(Composite composite) {
+ composite.setLayoutData(CmsUiUtils.fillWidth());
+ }
+
+ @Override
+ public Control getControl() {
+ return super.getControl();
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ Composite row = new Composite(box, SWT.NO_FOCUS);
+ row.setLayoutData(EclipseUiUtils.fillAll());
+
+ RowLayout rl = new RowLayout(SWT.HORIZONTAL);
+ rl.wrap = true;
+ rl.spacing = rowSpacing;
+ rl.marginRight = rl.marginLeft = rl.marginBottom = rl.marginTop = rowMarging;
+ row.setLayout(rl);
+
+ if (values != null) {
+ for (final String value : values) {
+ if (canEdit)
+ createRemovableValue(row, SWT.SINGLE, value);
+ else
+ createValueLabel(row, SWT.SINGLE, value);
+ }
+ }
+
+ if (!canEdit)
+ return row;
+ else if (isEditing())
+ return createText(row, style);
+ else
+ return createLabel(row, style);
+ }
+
+ /**
+ * Override to provide specific layout for the existing values, typically
+ * adding a pound (#) char for tags or anchor info for browsable links. We
+ * assume the parent composite already has a layout and it is the caller
+ * responsibility to apply corresponding layout data
+ */
+ protected Label createValueLabel(Composite parent, int style, String value) {
+ Label label = new Label(parent, style);
+ label.setText("#" + value);
+ CmsUiUtils.markup(label);
+ CmsUiUtils.style(label, FormStyle.propertyText.style());
+ return label;
+ }
+
+ private Composite createRemovableValue(Composite parent, int style, String value) {
+ Composite valCmp = new Composite(parent, SWT.NO_FOCUS);
+ GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
+ gl.marginRight = oneValueMargingRight;
+ valCmp.setLayout(gl);
+
+ createValueLabel(valCmp, SWT.WRAP, value);
+
+ Button deleteBtn = new Button(valCmp, SWT.FLAT);
+ deleteBtn.setData(FormConstants.LINKED_VALUE, value);
+ deleteBtn.addSelectionListener(removeValueSL);
+ CmsUiUtils.style(deleteBtn, FormStyle.delete.style() + FormStyle.BUTTON_SUFFIX);
+ GridData gd = new GridData();
+ gd.heightHint = btnHeight;
+ gd.widthHint = btnWidth;
+ gd.horizontalIndent = btnHorizontalIndent;
+ deleteBtn.setLayoutData(gd);
+
+ return valCmp;
+ }
+
+ protected Text createText(Composite box, String style) {
+ final Text text = new Text(box, getStyle());
+ // The "add new value" text is not meant to change, so we can set it on
+ // creation
+ text.setMessage(message);
+ CmsUiUtils.style(text, style);
+ text.setFocus();
+
+ text.addTraverseListener(new TraverseListener() {
+ private static final long serialVersionUID = 1L;
+
+ public void keyTraversed(TraverseEvent e) {
+ if (e.keyCode == SWT.CR) {
+ addValue(text);
+ e.doit = false;
+ }
+ }
+ });
+
+ // The OK button does not work with the focusOut listener
+ // because focus out is called before the OK button is pressed
+
+ // // we must call layout() now so that the row data can compute the
+ // height
+ // // of the other controls.
+ // text.getParent().layout();
+ // int height = text.getSize().y;
+ //
+ // Button okBtn = new Button(box, SWT.BORDER | SWT.PUSH | SWT.BOTTOM);
+ // okBtn.setText("OK");
+ // RowData rd = new RowData(SWT.DEFAULT, height - 2);
+ // okBtn.setLayoutData(rd);
+ //
+ // okBtn.addSelectionListener(new SelectionAdapter() {
+ // private static final long serialVersionUID = 2780819012423622369L;
+ //
+ // @Override
+ // public void widgetSelected(SelectionEvent e) {
+ // addValue(text);
+ // }
+ // });
+
+ return text;
+ }
+
+ /** Performs the real addition, overwrite to make further sanity checks */
+ protected void addValue(Text text) {
+ String value = text.getText();
+ String errMsg = null;
+
+ if (EclipseUiUtils.isEmpty(value))
+ return;
+
+ if (values.contains(value))
+ errMsg = "Dupplicated value: " + value + ", please correct and try again";
+ if (errMsg != null)
+ MessageDialog.openError(this.getShell(), "Addition not allowed", errMsg);
+ else {
+ values.add(value);
+ Composite newCmp = createRemovableValue(text.getParent(), SWT.SINGLE, value);
+ newCmp.moveAbove(text);
+ text.setText("");
+ newCmp.getParent().layout();
+ }
+ }
+
+ protected Label createLabel(Composite box, String style) {
+ if (canEdit) {
+ Label lbl = new Label(box, getStyle());
+ lbl.setText(message);
+ CmsUiUtils.style(lbl, style);
+ CmsUiUtils.markup(lbl);
+ if (mouseListener != null)
+ lbl.addMouseListener(mouseListener);
+ return lbl;
+ }
+ return null;
+ }
+
+ protected void clear(boolean deep) {
+ Control child = getControl();
+ if (deep)
+ super.clear(deep);
+ else {
+ child.getParent().dispose();
+ }
+ }
+
+ public void setText(String text) {
+ Control child = getControl();
+ if (child instanceof Label) {
+ Label lbl = (Label) child;
+ if (canEdit)
+ lbl.setText(text);
+ else
+ lbl.setText("");
+ } else if (child instanceof Text) {
+ Text txt = (Text) child;
+ txt.setText(text);
+ }
+ }
+
+ public synchronized void startEditing() {
+ getControl().setData(STYLE, FormStyle.propertyText.style());
+ super.startEditing();
+ }
+
+ public synchronized void stopEditing() {
+ getControl().setData(STYLE, FormStyle.propertyMessage.style());
+ super.stopEditing();
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+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.DateTime;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/** CMS form part to display and edit a date */
+public class EditablePropertyDate extends StyledControl implements EditablePart {
+ private static final long serialVersionUID = 2500215515778162468L;
+
+ // Context
+ private String propertyName;
+ private String message;
+ private DateFormat dateFormat;
+
+ // UI Objects
+ private Text dateTxt;
+ private Button openCalBtn;
+
+ // TODO manage within the CSS
+ private int fieldBtnSpacing = 5;
+
+ /**
+ *
+ * @param parent
+ * @param style
+ * @param node
+ * @param propertyName
+ * @param message
+ * @param dateFormat
+ * provide a {@link DateFormat} as contract to be able to
+ * read/write dates as strings
+ * @throws RepositoryException
+ */
+ public EditablePropertyDate(Composite parent, int style, Node node,
+ String propertyName, String message, DateFormat dateFormat)
+ throws RepositoryException {
+ super(parent, style, node, false);
+
+ this.propertyName = propertyName;
+ this.message = message;
+ this.dateFormat = dateFormat;
+
+ if (node.hasProperty(propertyName)) {
+ this.setStyle(FormStyle.propertyText.style());
+ this.setText(dateFormat.format(node.getProperty(propertyName)
+ .getDate().getTime()));
+ } else {
+ this.setStyle(FormStyle.propertyMessage.style());
+ this.setText(message);
+ }
+ }
+
+ public void setText(String text) {
+ Control child = getControl();
+ if (child instanceof Label) {
+ Label lbl = (Label) child;
+ if (EclipseUiUtils.isEmpty(text))
+ lbl.setText(message);
+ else
+ lbl.setText(text);
+ } else if (child instanceof Text) {
+ Text txt = (Text) child;
+ if (EclipseUiUtils.isEmpty(text)) {
+ txt.setText("");
+ } else
+ txt.setText(text);
+ }
+ }
+
+ public synchronized void startEditing() {
+ // if (dateTxt != null && !dateTxt.isDisposed())
+ getControl().setData(STYLE, FormStyle.propertyText.style());
+ super.startEditing();
+ }
+
+ public synchronized void stopEditing() {
+ if (EclipseUiUtils.isEmpty(dateTxt.getText()))
+ getControl().setData(STYLE, FormStyle.propertyMessage.style());
+ else
+ getControl().setData(STYLE, FormStyle.propertyText.style());
+ super.stopEditing();
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ if (isEditing()) {
+ return createCustomEditableControl(box, style);
+ } else
+ return createLabel(box, style);
+ }
+
+ protected Label createLabel(Composite box, String style) {
+ Label lbl = new Label(box, getStyle() | SWT.WRAP);
+ lbl.setLayoutData(CmsUiUtils.fillWidth());
+ CmsUiUtils.style(lbl, style);
+ CmsUiUtils.markup(lbl);
+ if (mouseListener != null)
+ lbl.addMouseListener(mouseListener);
+ return lbl;
+ }
+
+ private Control createCustomEditableControl(Composite box, String style) {
+ box.setLayoutData(CmsUiUtils.fillWidth());
+ Composite dateComposite = new Composite(box, SWT.NONE);
+ GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
+ false));
+ gl.horizontalSpacing = fieldBtnSpacing;
+ dateComposite.setLayout(gl);
+ dateTxt = new Text(dateComposite, SWT.BORDER);
+ CmsUiUtils.style(dateTxt, style);
+ dateTxt.setLayoutData(new GridData(120, SWT.DEFAULT));
+ dateTxt.setToolTipText("Enter a date with form \""
+ + FormUtils.DEFAULT_SHORT_DATE_FORMAT
+ + "\" or use the calendar");
+ openCalBtn = new Button(dateComposite, SWT.FLAT);
+ CmsUiUtils.style(openCalBtn, FormStyle.calendar.style()
+ + FormStyle.BUTTON_SUFFIX);
+ GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+ gd.heightHint = 17;
+ openCalBtn.setLayoutData(gd);
+ // openCalBtn.setImage(PeopleRapImages.CALENDAR_BTN);
+
+ openCalBtn.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = 1L;
+
+ public void widgetSelected(SelectionEvent event) {
+ CalendarPopup popup = new CalendarPopup(dateTxt);
+ popup.open();
+ }
+ });
+
+ // dateTxt.addFocusListener(new FocusListener() {
+ // private static final long serialVersionUID = 1L;
+ //
+ // @Override
+ // public void focusLost(FocusEvent event) {
+ // String newVal = dateTxt.getText();
+ // // Enable reset of the field
+ // if (FormUtils.notNull(newVal))
+ // calendar = null;
+ // else {
+ // try {
+ // Calendar newCal = parseDate(newVal);
+ // // DateText.this.setText(newCal);
+ // calendar = newCal;
+ // } catch (ParseException pe) {
+ // // Silent. Manage error popup?
+ // if (calendar != null)
+ // EditablePropertyDate.this.setText(calendar);
+ // }
+ // }
+ // }
+ //
+ // @Override
+ // public void focusGained(FocusEvent event) {
+ // }
+ // });
+ return dateTxt;
+ }
+
+ protected void clear(boolean deep) {
+ Control child = getControl();
+ if (deep || child instanceof Label)
+ super.clear(deep);
+ else {
+ child.getParent().dispose();
+ }
+ }
+
+ /** Enable setting a custom tooltip on the underlying text */
+ @Deprecated
+ public void setToolTipText(String toolTipText) {
+ dateTxt.setToolTipText(toolTipText);
+ }
+
+ @Deprecated
+ /** Enable setting a custom message on the underlying text */
+ public void setMessage(String message) {
+ dateTxt.setMessage(message);
+ }
+
+ @Deprecated
+ public void setText(Calendar cal) {
+ String newValueStr = "";
+ if (cal != null)
+ newValueStr = dateFormat.format(cal.getTime());
+ if (!newValueStr.equals(dateTxt.getText()))
+ dateTxt.setText(newValueStr);
+ }
+
+ // UTILITIES TO MANAGE THE CALENDAR POPUP
+ // TODO manage the popup shell in a cleaner way
+ private class CalendarPopup extends Shell {
+ private static final long serialVersionUID = 1L;
+ private DateTime dateTimeCtl;
+
+ public CalendarPopup(Control source) {
+ super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+ populate();
+ // Add border and shadow style
+ CmsUiUtils.markup(CalendarPopup.this);
+ CmsUiUtils.style(CalendarPopup.this, FormStyle.popupCalendar.style());
+ pack();
+ layout();
+ setLocation(source.toDisplay((source.getLocation().x - 2),
+ (source.getSize().y) + 3));
+
+ addShellListener(new ShellAdapter() {
+ private static final long serialVersionUID = 5178980294808435833L;
+
+ @Override
+ public void shellDeactivated(ShellEvent e) {
+ close();
+ dispose();
+ }
+ });
+ open();
+ }
+
+ private void setProperty() {
+ // Direct set does not seems to work. investigate
+ // cal.set(dateTimeCtl.getYear(), dateTimeCtl.getMonth(),
+ // dateTimeCtl.getDay(), 12, 0);
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.YEAR, dateTimeCtl.getYear());
+ cal.set(Calendar.MONTH, dateTimeCtl.getMonth());
+ cal.set(Calendar.DAY_OF_MONTH, dateTimeCtl.getDay());
+ String dateStr = dateFormat.format(cal.getTime());
+ dateTxt.setText(dateStr);
+ }
+
+ protected void populate() {
+ setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ dateTimeCtl = new DateTime(this, SWT.CALENDAR);
+ dateTimeCtl.setLayoutData(EclipseUiUtils.fillAll());
+
+ Calendar calendar = FormUtils.parseDate(dateFormat,
+ dateTxt.getText());
+
+ if (calendar != null)
+ dateTimeCtl.setDate(calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH));
+
+ dateTimeCtl.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -8414377364434281112L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ setProperty();
+ }
+ });
+
+ dateTimeCtl.addMouseListener(new MouseListener() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ setProperty();
+ close();
+ dispose();
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+import static org.argeo.cms.ui.forms.FormStyle.propertyMessage;
+import static org.argeo.cms.ui.forms.FormStyle.propertyText;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.EditableText;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Editable String in a CMS context */
+public class EditablePropertyString extends EditableText implements
+ EditablePart {
+ private static final long serialVersionUID = 5055000749992803591L;
+
+ private String propertyName;
+ private String message;
+
+ // encode the '&' character in rap
+ private final static String AMPERSAND = "&";
+ private final static String AMPERSAND_REGEX = "&(?![#a-zA-Z0-9]+;)";
+
+ public EditablePropertyString(Composite parent, int style, Node node,
+ String propertyName, String message) throws RepositoryException {
+ super(parent, style, node, true);
+
+ this.propertyName = propertyName;
+ this.message = message;
+
+ if (node.hasProperty(propertyName)) {
+ this.setStyle(propertyText.style());
+ this.setText(node.getProperty(propertyName).getString());
+ } else {
+ this.setStyle(propertyMessage.style());
+ this.setText(message + " ");
+ }
+ }
+
+ public void setText(String text) {
+ Control child = getControl();
+ if (child instanceof Label) {
+ Label lbl = (Label) child;
+ if (EclipseUiUtils.isEmpty(text))
+ lbl.setText(message + " ");
+ else
+ // TODO enhance this
+ lbl.setText(text.replaceAll(AMPERSAND_REGEX, AMPERSAND));
+ } else if (child instanceof Text) {
+ Text txt = (Text) child;
+ if (EclipseUiUtils.isEmpty(text)) {
+ txt.setText("");
+ txt.setMessage(message + " ");
+ } else
+ txt.setText(text.replaceAll("<br/>", "\n"));
+ }
+ }
+
+ public synchronized void startEditing() {
+ getControl().setData(STYLE, propertyText.style());
+ super.startEditing();
+ }
+
+ public synchronized void stopEditing() {
+ if (EclipseUiUtils.isEmpty(((Text) getControl()).getText()))
+ getControl().setData(STYLE, propertyMessage.style());
+ else
+ getControl().setData(STYLE, propertyText.style());
+ super.stopEditing();
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+/** Constants used in the various CMS Forms */
+public interface FormConstants {
+ // DATAKEYS
+ public final static String LINKED_VALUE = "LinkedValue";
+}
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.CmsEditable;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+
+/** Add life cycle management abilities to an editable form page */
+public class FormEditorHeader implements SelectionListener, Observer {
+ private static final long serialVersionUID = 7392898696542484282L;
+
+ // private final Node context;
+ private final CmsEditable cmsEditable;
+ private Button publishBtn;
+
+ // Should we provide here the ability to switch from read only to edition
+ // mode?
+ // private Button editBtn;
+ // private boolean readOnly;
+
+ // TODO add information about the current node status, typically if it is
+ // dirty or not
+
+ private Composite parent;
+ private Composite display;
+ private Object layoutData;
+
+ public FormEditorHeader(Composite parent, int style, Node context,
+ CmsEditable cmsEditable) {
+ this.cmsEditable = cmsEditable;
+ this.parent = parent;
+ // readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
+ // this.context = context;
+ if (this.cmsEditable instanceof Observable)
+ ((Observable) this.cmsEditable).addObserver(this);
+ refresh();
+ }
+
+ public void setLayoutData(Object layoutData) {
+ this.layoutData = layoutData;
+ if (display != null && !display.isDisposed())
+ display.setLayoutData(layoutData);
+ }
+
+ protected void refresh() {
+ if (display != null && !display.isDisposed())
+ display.dispose();
+
+ display = new Composite(parent, SWT.NONE);
+ display.setLayoutData(layoutData);
+
+ CmsUiUtils.style(display, FormStyle.header.style());
+ display.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ display.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ publishBtn = createSimpleBtn(display, getPublishButtonLabel());
+ display.moveAbove(null);
+ parent.layout();
+ }
+
+ private Button createSimpleBtn(Composite parent, String label) {
+ Button button = new Button(parent, SWT.FLAT | SWT.PUSH);
+ button.setText(label);
+ CmsUiUtils.style(button, FormStyle.header.style());
+ button.addSelectionListener(this);
+ return button;
+ }
+
+ private String getPublishButtonLabel() {
+ // Rather check if the current node differs from what has been
+ // previously committed
+ // For the time being, we always reach here, the underlying CmsEditable
+ // is always editing.
+ if (cmsEditable.isEditing())
+ return " Publish ";
+ else
+ return " Edit ";
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (e.getSource() == publishBtn) {
+ // For the time being, the underlying CmsEditable
+ // is always editing when we reach this point
+ if (cmsEditable.isEditing()) {
+ // we always leave the node in a check outed state
+ cmsEditable.stopEditing();
+ cmsEditable.startEditing();
+ } else {
+ cmsEditable.startEditing();
+ }
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+
+ @Override
+ public void update(Observable o, Object arg) {
+ if (o == cmsEditable) {
+ refresh();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsEditable;
+import org.argeo.cms.ui.CmsImageManager;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.AbstractPageViewer;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.cms.ui.viewers.SectionPart;
+import org.argeo.cms.ui.widgets.EditableImage;
+import org.argeo.cms.ui.widgets.Img;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+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.fileupload.FileUploadReceiver;
+import org.eclipse.rap.rwt.service.ServerPushSession;
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+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;
+
+/** Manage life cycle of a form page that is linked to a given node */
+public class FormPageViewer extends AbstractPageViewer {
+ private final static Log log = LogFactory.getLog(FormPageViewer.class);
+ private static final long serialVersionUID = 5277789504209413500L;
+
+ private final Section mainSection;
+
+ // TODO manage within the CSS
+ private int labelColWidth = 150;
+ private int rowLayoutHSpacing = 8;
+
+ // Context cached in the viewer
+ // The reference to translate from text to calendar and reverse
+ private DateFormat dateFormat = new SimpleDateFormat(FormUtils.DEFAULT_SHORT_DATE_FORMAT);
+ private CmsImageManager imageManager;
+ private FileUploadListener fileUploadListener;
+
+ public FormPageViewer(Section mainSection, int style, CmsEditable cmsEditable) throws RepositoryException {
+ super(mainSection, style, cmsEditable);
+ this.mainSection = mainSection;
+
+ if (getCmsEditable().canEdit()) {
+ fileUploadListener = new FUL();
+ }
+ }
+
+ @Override
+ protected void prepare(EditablePart part, Object caretPosition) {
+ if (part instanceof Img) {
+ ((Img) part).setFileUploadListener(fileUploadListener);
+ }
+ }
+
+ /** To be overridden.Save the edited part. */
+ protected void save(EditablePart part) throws RepositoryException {
+ Node node = null;
+ if (part instanceof EditableMultiStringProperty) {
+ EditableMultiStringProperty ept = (EditableMultiStringProperty) part;
+ // SWT : View
+ List<String> values = ept.getValues();
+ // JCR : Model
+ node = ept.getNode();
+ String propName = ept.getPropertyName();
+ if (values.isEmpty()) {
+ if (node.hasProperty(propName))
+ node.getProperty(propName).remove();
+ } else {
+ node.setProperty(propName, values.toArray(new String[0]));
+ }
+ // => Viewer : Controller
+ } else if (part instanceof EditablePropertyString) {
+ EditablePropertyString ept = (EditablePropertyString) part;
+ // SWT : View
+ String txt = ((Text) ept.getControl()).getText();
+ // JCR : Model
+ node = ept.getNode();
+ String propName = ept.getPropertyName();
+ if (EclipseUiUtils.isEmpty(txt)) {
+ if (node.hasProperty(propName))
+ node.getProperty(propName).remove();
+ } else {
+ setPropertySilently(node, propName, txt);
+ // node.setProperty(propName, txt);
+ }
+ // node.getSession().save();
+ // => Viewer : Controller
+ } else if (part instanceof EditablePropertyDate) {
+ EditablePropertyDate ept = (EditablePropertyDate) part;
+ Calendar cal = FormUtils.parseDate(dateFormat, ((Text) ept.getControl()).getText());
+ node = ept.getNode();
+ String propName = ept.getPropertyName();
+ if (cal == null) {
+ if (node.hasProperty(propName))
+ node.getProperty(propName).remove();
+ } else {
+ node.setProperty(propName, cal);
+ }
+ // node.getSession().save();
+ // => Viewer : Controller
+ }
+ // TODO: make this configurable, sometimes we do not want to save the
+ // current session at this stage
+ if (node != null && node.getSession().hasPendingChanges()) {
+ JcrUtils.updateLastModified(node);
+ node.getSession().save();
+ }
+ }
+
+ @Override
+ protected void updateContent(EditablePart part) throws RepositoryException {
+ if (part instanceof EditableMultiStringProperty) {
+ EditableMultiStringProperty ept = (EditableMultiStringProperty) part;
+ // SWT : View
+ Node node = ept.getNode();
+ String propName = ept.getPropertyName();
+ List<String> valStrings = new ArrayList<String>();
+ if (node.hasProperty(propName)) {
+ Value[] values = node.getProperty(propName).getValues();
+ for (Value val : values)
+ valStrings.add(val.getString());
+ }
+ ept.setValues(valStrings);
+ } else if (part instanceof EditablePropertyString) {
+ // || part instanceof EditableLink
+ EditablePropertyString ept = (EditablePropertyString) part;
+ // JCR : Model
+ Node node = ept.getNode();
+ String propName = ept.getPropertyName();
+ if (node.hasProperty(propName)) {
+ String value = node.getProperty(propName).getString();
+ ept.setText(value);
+ } else
+ ept.setText("");
+ // => Viewer : Controller
+ } else if (part instanceof EditablePropertyDate) {
+ EditablePropertyDate ept = (EditablePropertyDate) part;
+ // JCR : Model
+ Node node = ept.getNode();
+ String propName = ept.getPropertyName();
+ if (node.hasProperty(propName))
+ ept.setText(dateFormat.format(node.getProperty(propName).getDate().getTime()));
+ else
+ ept.setText("");
+ } else if (part instanceof SectionPart) {
+ SectionPart sectionPart = (SectionPart) part;
+ Node partNode = sectionPart.getNode();
+ // use control AFTER setting style, since it may have been reset
+ if (part instanceof EditableImage) {
+ EditableImage editableImage = (EditableImage) part;
+ imageManager().load(partNode, part.getControl(), editableImage.getPreferredImageSize());
+ }
+ }
+ }
+
+ // FILE UPLOAD LISTENER
+ protected class FUL implements FileUploadListener {
+
+ public FUL() {
+ }
+
+ public void uploadProgress(FileUploadEvent event) {
+ // TODO Monitor upload progress
+ }
+
+ public void uploadFailed(FileUploadEvent event) {
+ throw new CmsException("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();
+ }
+ }
+
+ // FOCUS OUT LISTENER
+ protected FocusListener createFocusListener() {
+ return new FocusOutListener();
+ }
+
+ private class FocusOutListener implements FocusListener {
+ private static final long serialVersionUID = -6069205786732354186L;
+
+ @Override
+ public void focusLost(FocusEvent event) {
+ saveEdit();
+ }
+
+ @Override
+ public void focusGained(FocusEvent event) {
+ // does nothing;
+ }
+ }
+
+ // 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();
+ if (getCmsEditable().canEdit()) {
+ if (getCmsEditable().isEditing() && !(getEdited() instanceof Img)) {
+ if (source == mainSection)
+ return;
+ EditablePart part = findDataParent(source);
+ upload(part);
+ } else {
+ getCmsEditable().startEditing();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ if (getCmsEditable().isEditing()) {
+ if (e.button == 1) {
+ Control source = (Control) e.getSource();
+ EditablePart composite = findDataParent(source);
+ Point point = new Point(e.x, e.y);
+ if (!(composite instanceof Img))
+ edit(composite, source.toDisplay(point));
+ } else if (e.button == 3) {
+ // EditablePart composite = findDataParent((Control) e
+ // .getSource());
+ // if (styledTools != null)
+ // styledTools.show(composite, new Point(e.x, e.y));
+ }
+ }
+ }
+
+ protected synchronized void upload(EditablePart part) {
+ if (part instanceof SectionPart) {
+ if (part instanceof Img) {
+ if (getEdited() == part)
+ return;
+ edit(part, null);
+ layout(part.getControl());
+ }
+ }
+ }
+ }
+
+ @Override
+ public Control getControl() {
+ return mainSection;
+ }
+
+ protected CmsImageManager imageManager() {
+ if (imageManager == null)
+ imageManager = CmsUiUtils.getCmsView().getImageManager();
+ return imageManager;
+ }
+
+ // LOCAL UI HELPERS
+ protected Section createSectionIfNeeded(Composite body, Node node) throws RepositoryException {
+ Section section = null;
+ if (node != null) {
+ section = new Section(body, SWT.NO_FOCUS, node);
+ section.setLayoutData(CmsUiUtils.fillWidth());
+ section.setLayout(CmsUiUtils.noSpaceGridLayout());
+ }
+ return section;
+ }
+
+ protected void createSimpleLT(Composite bodyRow, Node node, String propName, String label, String msg)
+ throws RepositoryException {
+ if (getCmsEditable().canEdit() || node.hasProperty(propName)) {
+ createPropertyLbl(bodyRow, label);
+ EditablePropertyString eps = new EditablePropertyString(bodyRow, SWT.WRAP | SWT.LEFT, node, propName, msg);
+ eps.setMouseListener(getMouseListener());
+ eps.setFocusListener(getFocusListener());
+ eps.setLayoutData(CmsUiUtils.fillWidth());
+ }
+ }
+
+ protected void createMultiStringLT(Composite bodyRow, Node node, String propName, String label, String msg)
+ throws RepositoryException {
+ boolean canEdit = getCmsEditable().canEdit();
+ if (canEdit || node.hasProperty(propName)) {
+ createPropertyLbl(bodyRow, label);
+
+ List<String> valueStrings = new ArrayList<String>();
+
+ if (node.hasProperty(propName)) {
+ Value[] values = node.getProperty(propName).getValues();
+ for (Value value : values)
+ valueStrings.add(value.getString());
+ }
+
+ // TODO use a drop down to display possible values to the end user
+ EditableMultiStringProperty emsp = new EditableMultiStringProperty(bodyRow, SWT.SINGLE | SWT.LEAD, node,
+ propName, valueStrings, new String[] { "Implement this" }, msg,
+ canEdit ? getRemoveValueSelListener() : null);
+ addListeners(emsp);
+ // emsp.setMouseListener(getMouseListener());
+ emsp.setStyle(FormStyle.propertyMessage.style());
+ emsp.setLayoutData(CmsUiUtils.fillWidth());
+ }
+ }
+
+ protected Label createPropertyLbl(Composite parent, String value) {
+ return createPropertyLbl(parent, value, SWT.TOP);
+ }
+
+ protected Label createPropertyLbl(Composite parent, String value, int vAlign) {
+ boolean isSmall = CmsUiUtils.getCmsView().getUxContext().isSmall();
+ Label label = new Label(parent, isSmall ? SWT.LEFT : SWT.RIGHT | SWT.WRAP);
+ label.setText(value + " ");
+ CmsUiUtils.style(label, FormStyle.propertyLabel.style());
+ GridData gd = new GridData(isSmall ? SWT.LEFT : SWT.RIGHT, vAlign, false, false);
+ gd.widthHint = labelColWidth;
+ label.setLayoutData(gd);
+ return label;
+ }
+
+ protected Label newStyledLabel(Composite parent, String style, String value) {
+ Label label = new Label(parent, SWT.NONE);
+ label.setText(value);
+ CmsUiUtils.style(label, style);
+ return label;
+ }
+
+ protected Composite createRowLayoutComposite(Composite parent) throws RepositoryException {
+ Composite bodyRow = new Composite(parent, SWT.NO_FOCUS);
+ bodyRow.setLayoutData(CmsUiUtils.fillWidth());
+ RowLayout rl = new RowLayout(SWT.WRAP);
+ rl.type = SWT.HORIZONTAL;
+ rl.spacing = rowLayoutHSpacing;
+ rl.marginHeight = rl.marginWidth = 0;
+ rl.marginTop = rl.marginBottom = rl.marginLeft = rl.marginRight = 0;
+ bodyRow.setLayout(rl);
+ return bodyRow;
+ }
+
+ protected Composite createAddImgComposite(final Section section, Composite parent, final Node parentNode)
+ throws RepositoryException {
+
+ Composite body = new Composite(parent, SWT.NO_FOCUS);
+ body.setLayout(new GridLayout());
+
+ FormFileUploadReceiver receiver = new FormFileUploadReceiver(section, parentNode, null);
+ final FileUploadHandler currentUploadHandler = new FileUploadHandler(receiver);
+ if (fileUploadListener != null)
+ currentUploadHandler.addUploadListener(fileUploadListener);
+
+ // Button creation
+ final FileUpload fileUpload = new FileUpload(body, SWT.BORDER);
+ fileUpload.setText("Import an image");
+ fileUpload.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+ fileUpload.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = 4869523412991968759L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ ServerPushSession pushSession = new ServerPushSession();
+ pushSession.start();
+ String uploadURL = currentUploadHandler.getUploadUrl();
+ fileUpload.submit(uploadURL);
+ }
+ });
+
+ return body;
+ }
+
+ protected class FormFileUploadReceiver extends FileUploadReceiver {
+
+ private Node context;
+ private Section section;
+ private String name;
+
+ public FormFileUploadReceiver(Section section, Node context, String name) {
+ this.context = context;
+ this.section = section;
+ this.name = name;
+ }
+
+ @Override
+ public void receive(InputStream stream, FileDetails details) throws IOException {
+
+ if (name == null)
+ name = details.getFileName();
+
+ // TODO clean image name more carefully
+ String cleanedName = name.replaceAll("[^a-zA-Z0-9-.]", "");
+ // We add a unique prefix to workaround the cache issue: when
+ // deleting and re-adding a new image with same name, the end user
+ // browser will use the cache and the image will remain unchanged
+ // for a while
+ cleanedName = System.currentTimeMillis() % 100000 + "_" + cleanedName;
+
+ try {
+ imageManager().uploadImage(context, cleanedName, stream);
+ // TODO clean refresh strategy
+ section.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ FormPageViewer.this.refresh(section);
+ section.layout();
+ section.getParent().layout();
+ } catch (RepositoryException re) {
+ throw new CmsException("unable to refresh " + "image section for " + context);
+ }
+ }
+ });
+ } catch (RepositoryException re) {
+ throw new CmsException("unable to upload image " + name + " at " + context);
+ }
+ }
+ }
+
+ protected void addListeners(StyledControl control) {
+ control.setMouseListener(getMouseListener());
+ control.setFocusListener(getFocusListener());
+ }
+
+ protected Img createImgComposite(Composite parent, Node node, Point preferredSize) throws RepositoryException {
+ Img img = new Img(parent, SWT.NONE, node, preferredSize) {
+ private static final long serialVersionUID = 1297900641952417540L;
+
+ @Override
+ protected void setContainerLayoutData(Composite composite) {
+ composite.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+ }
+
+ @Override
+ protected void setControlLayoutData(Control control) {
+ control.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+ }
+ };
+ img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+ updateContent(img);
+ addListeners(img);
+ return img;
+ }
+
+ protected Composite addDeleteAbility(final Section section, final Node sessionNode, int topWeight,
+ int rightWeight) {
+ Composite comp = new Composite(section, SWT.NONE);
+ comp.setLayoutData(CmsUiUtils.fillAll());
+ comp.setLayout(new FormLayout());
+
+ // The body to be populated
+ Composite body = new Composite(comp, SWT.NO_FOCUS);
+ body.setLayoutData(EclipseUiUtils.fillFormData());
+
+ if (getCmsEditable().canEdit()) {
+ // the delete button
+ Button deleteBtn = new Button(comp, SWT.FLAT);
+ CmsUiUtils.style(deleteBtn, FormStyle.deleteOverlay.style());
+ FormData formData = new FormData();
+ formData.right = new FormAttachment(rightWeight, 0);
+ formData.top = new FormAttachment(topWeight, 0);
+ deleteBtn.setLayoutData(formData);
+ deleteBtn.moveAbove(body);
+
+ deleteBtn.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = 4304223543657238462L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ super.widgetSelected(e);
+ if (MessageDialog.openConfirm(section.getShell(), "Confirm deletion",
+ "Are you really you want to remove this?")) {
+ Session session;
+ try {
+ session = sessionNode.getSession();
+ Section parSection = section.getParentSection();
+ sessionNode.remove();
+ session.save();
+ refresh(parSection);
+ layout(parSection);
+ } catch (RepositoryException re) {
+ throw new CmsException("Unable to delete " + sessionNode, re);
+ }
+
+ }
+
+ }
+ });
+ }
+ return body;
+ }
+
+// // LOCAL HELPERS FOR NODE MANAGEMENT
+// private Node getOrCreateNode(Node parent, String nodeName, String nodeType) throws RepositoryException {
+// Node node = null;
+// if (getCmsEditable().canEdit() && !parent.hasNode(nodeName)) {
+// node = JcrUtils.mkdirs(parent, nodeName, nodeType);
+// parent.getSession().save();
+// }
+//
+// if (getCmsEditable().canEdit() || parent.hasNode(nodeName))
+// node = parent.getNode(nodeName);
+//
+// return node;
+// }
+
+ private SelectionListener getRemoveValueSelListener() {
+ return new SelectionAdapter() {
+ private static final long serialVersionUID = 9022259089907445195L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ Object source = e.getSource();
+ if (source instanceof Button) {
+ Button btn = (Button) source;
+ Object obj = btn.getData(FormConstants.LINKED_VALUE);
+ EditablePart ep = findDataParent(btn);
+ if (ep != null && ep instanceof EditableMultiStringProperty) {
+ EditableMultiStringProperty emsp = (EditableMultiStringProperty) ep;
+ List<String> values = emsp.getValues();
+ if (values.contains(obj)) {
+ values.remove(values.indexOf(obj));
+ emsp.setValues(values);
+ try {
+ save(emsp);
+ // TODO workaround to force refresh
+ edit(emsp, 0);
+ cancelEdit();
+ } catch (RepositoryException e1) {
+ throw new CmsException("Unable to remove value " + obj, e1);
+ }
+ layout(emsp);
+ }
+ }
+ }
+ }
+ };
+ }
+
+ protected void setPropertySilently(Node node, String propName, String value) throws RepositoryException {
+ try {
+ // TODO Clean this:
+ // Format strings to replace \n
+ value = value.replaceAll("\n", "<br/>");
+ // Do not make the update if validation fails
+ try {
+ MarkupValidatorCopy.getInstance().validate(value);
+ } catch (Exception e) {
+ log.warn("Cannot set [" + value + "] on prop " + propName + "of " + node
+ + ", String cannot be validated - " + e.getMessage());
+ return;
+ }
+ // TODO check if the newly created property is of the correct type,
+ // otherwise the property will be silently created with a STRING
+ // property type.
+ node.setProperty(propName, value);
+ } catch (ValueFormatException vfe) {
+ log.warn("Cannot set [" + value + "] on prop " + propName + "of " + node + " - " + vfe.getMessage());
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+/** Syles used */
+public enum FormStyle {
+ // Main
+ form, title,
+ // main part
+ header, headerBtn, headerCombo, section, sectionHeader,
+ // Property fields
+ propertyLabel, propertyText, propertyMessage, errorMessage,
+ // Date
+ popupCalendar,
+ // Buttons
+ starred, unstarred, starOverlay, editOverlay, deleteOverlay, updateOverlay, deleteOverlaySmall, calendar, delete,
+ // Contacts
+ email, address, phone, website,
+ // Social Media
+ facebook, twitter, linkedIn, instagram;
+
+ public String style() {
+ return form.name() + '_' + name();
+ }
+
+ // TODO clean button style management
+ public final static String BUTTON_SUFFIX = "_btn";
+}
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Utilitary methods to ease implementation of CMS forms */
+public class FormUtils {
+ private final static Log log = LogFactory.getLog(FormUtils.class);
+
+ public final static String DEFAULT_SHORT_DATE_FORMAT = "dd/MM/yyyy";
+
+ /** Best effort to convert a String to a calendar. Fails silently */
+ public static Calendar parseDate(DateFormat dateFormat, String calStr) {
+ Calendar cal = null;
+ if (EclipseUiUtils.notEmpty(calStr)) {
+ try {
+ Date date = dateFormat.parse(calStr);
+ cal = new GregorianCalendar();
+ cal.setTime(date);
+ } catch (ParseException pe) {
+ // Silent
+ log.warn("Unable to parse date: " + calStr + " - msg: "
+ + pe.getMessage());
+ }
+ }
+ return cal;
+ }
+
+ /** Add a double click listener on tables that display a JCR node list */
+ public static void addCanonicalDoubleClickListener(final TableViewer v) {
+ v.addDoubleClickListener(new IDoubleClickListener() {
+
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ CmsView cmsView = CmsUiUtils.getCmsView();
+ Node node = (Node) ((IStructuredSelection) event.getSelection())
+ .getFirstElement();
+ try {
+ cmsView.navigateTo(node.getPath());
+ } catch (RepositoryException e) {
+ throw new CmsException("Unable to get path for node "
+ + node + " before calling navigateTo(path)", e);
+ }
+ }
+ });
+ }
+
+ // MANAGE ERROR DECORATION
+
+ public static ControlDecoration addDecoration(final Text text) {
+ final ControlDecoration dynDecoration = new ControlDecoration(text,
+ SWT.LEFT);
+ Image icon = getDecorationImage(FieldDecorationRegistry.DEC_ERROR);
+ dynDecoration.setImage(icon);
+ dynDecoration.setMarginWidth(3);
+ dynDecoration.hide();
+ return dynDecoration;
+ }
+
+ public static void refreshDecoration(Text text, ControlDecoration deco,
+ boolean isValid, boolean clean) {
+ if (isValid || clean) {
+ text.setBackground(null);
+ deco.hide();
+ } else {
+ text.setBackground(new Color(text.getDisplay(), 250, 200, 150));
+ deco.show();
+ }
+ }
+
+ public static Image getDecorationImage(String image) {
+ FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
+ return registry.getFieldDecoration(image).getImage();
+ }
+
+ public static void addCompulsoryDecoration(Label label) {
+ final ControlDecoration dynDecoration = new ControlDecoration(label,
+ SWT.RIGHT | SWT.TOP);
+ Image icon = getDecorationImage(FieldDecorationRegistry.DEC_REQUIRED);
+ dynDecoration.setImage(icon);
+ dynDecoration.setMarginWidth(3);
+ }
+
+ // TODO the read only generation of read only links for various contact type
+ // should be factorised in the cms Utils.
+ /**
+ * Creates the read-only HTML snippet to display in a label with styling
+ * enabled in order to provide a click-able phone number
+ */
+ public static String getPhoneLink(String value) {
+ return getPhoneLink(value, value);
+ }
+
+ /**
+ * Creates the read-only HTML snippet to display in a label with styling
+ * enabled in order to provide a click-able phone number
+ *
+ * @param value
+ * @param label
+ * a potentially distinct label
+ * @return
+ */
+ public static String getPhoneLink(String value, String label) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("<a href=\"tel:");
+ builder.append(value).append("\" target=\"_blank\" >").append(label)
+ .append("</a>");
+ return builder.toString();
+ }
+
+ /**
+ * Creates the read-only HTML snippet to display in a label with styling
+ * enabled in order to provide a click-able mail
+ */
+ public static String getMailLink(String value) {
+ return getMailLink(value, value);
+ }
+
+ /**
+ * Creates the read-only HTML snippet to display in a label with styling
+ * enabled in order to provide a click-able mail
+ *
+ * @param value
+ * @param label
+ * a potentially distinct label
+ * @return
+ */
+ public static String getMailLink(String value, String label) {
+ StringBuilder builder = new StringBuilder();
+ value = replaceAmpersand(value);
+ builder.append("<a href=\"mailto:");
+ builder.append(value).append("\" >").append(label).append("</a>");
+ return builder.toString();
+ }
+
+ /**
+ * Creates the read-only HTML snippet to display in a label with styling
+ * enabled in order to provide a click-able link
+ */
+ public static String getUrlLink(String value) {
+ return getUrlLink(value, value);
+ }
+
+ /**
+ * Creates the read-only HTML snippet to display in a label with styling
+ * enabled in order to provide a click-able link
+ */
+ public static String getUrlLink(String value, String label) {
+ StringBuilder builder = new StringBuilder();
+ value = replaceAmpersand(value);
+ label = replaceAmpersand(label);
+ if (!(value.startsWith("http://") || value.startsWith("https://")))
+ value = "http://" + value;
+ builder.append("<a href=\"");
+ builder.append(value + "\" target=\"_blank\" >" + label + "</a>");
+ return builder.toString();
+ }
+
+ private static String AMPERSAND = "&";
+
+ /**
+ * Cleans a String by replacing any '&' by its HTML encoding '&#38;' to
+ * avoid <code>SAXParseException</code> while rendering HTML with RWT
+ */
+ public static String replaceAmpersand(String value) {
+ value = value.replaceAll("&(?![#a-zA-Z0-9]+;)", AMPERSAND);
+ return value;
+ }
+
+ // Prevents instantiation
+ private FormUtils() {
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.forms;
+
+import java.io.StringReader;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.rap.rwt.SingletonUtil;
+import org.eclipse.swt.widgets.Widget;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Copy of RAP v2.3 since it is in an internal package.
+ */
+class MarkupValidatorCopy {
+
+ // Used by Eclipse Scout project
+ public static final String MARKUP_VALIDATION_DISABLED = "org.eclipse.rap.rwt.markupValidationDisabled";
+
+ private static final String DTD = createDTD();
+ private static final Map<String, String[]> SUPPORTED_ELEMENTS = createSupportedElementsMap();
+ private final SAXParser saxParser;
+
+ public static MarkupValidatorCopy getInstance() {
+ return SingletonUtil.getSessionInstance(MarkupValidatorCopy.class);
+ }
+
+ public MarkupValidatorCopy() {
+ saxParser = createSAXParser();
+ }
+
+ public void validate(String text) {
+ StringBuilder markup = new StringBuilder();
+ markup.append(DTD);
+ markup.append("<html>");
+ markup.append(text);
+ markup.append("</html>");
+ InputSource inputSource = new InputSource(new StringReader(markup.toString()));
+ try {
+ saxParser.parse(inputSource, new MarkupHandler());
+ } catch (RuntimeException exception) {
+ throw exception;
+ } catch (Exception exception) {
+ throw new IllegalArgumentException("Failed to parse markup text", exception);
+ }
+ }
+
+ public static boolean isValidationDisabledFor(Widget widget) {
+ return Boolean.TRUE.equals(widget.getData(MARKUP_VALIDATION_DISABLED));
+ }
+
+ private static SAXParser createSAXParser() {
+ SAXParser result = null;
+ SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ try {
+ result = parserFactory.newSAXParser();
+ } catch (Exception exception) {
+ throw new RuntimeException("Failed to create SAX parser", exception);
+ }
+ return result;
+ }
+
+ private static String createDTD() {
+ StringBuilder result = new StringBuilder();
+ result.append("<!DOCTYPE html [");
+ result.append("<!ENTITY quot \""\">");
+ result.append("<!ENTITY amp \"&\">");
+ result.append("<!ENTITY apos \"'\">");
+ result.append("<!ENTITY lt \"<\">");
+ result.append("<!ENTITY gt \">\">");
+ result.append("<!ENTITY nbsp \" \">");
+ result.append("<!ENTITY ensp \" \">");
+ result.append("<!ENTITY emsp \" \">");
+ result.append("<!ENTITY ndash \"–\">");
+ result.append("<!ENTITY mdash \"—\">");
+ result.append("]>");
+ return result.toString();
+ }
+
+ private static Map<String, String[]> createSupportedElementsMap() {
+ Map<String, String[]> result = new HashMap<String, String[]>();
+ result.put("html", new String[0]);
+ result.put("br", new String[0]);
+ result.put("b", new String[] { "style" });
+ result.put("strong", new String[] { "style" });
+ result.put("i", new String[] { "style" });
+ result.put("em", new String[] { "style" });
+ result.put("sub", new String[] { "style" });
+ result.put("sup", new String[] { "style" });
+ result.put("big", new String[] { "style" });
+ result.put("small", new String[] { "style" });
+ result.put("del", new String[] { "style" });
+ result.put("ins", new String[] { "style" });
+ result.put("code", new String[] { "style" });
+ result.put("samp", new String[] { "style" });
+ result.put("kbd", new String[] { "style" });
+ result.put("var", new String[] { "style" });
+ result.put("cite", new String[] { "style" });
+ result.put("dfn", new String[] { "style" });
+ result.put("q", new String[] { "style" });
+ result.put("abbr", new String[] { "style", "title" });
+ result.put("span", new String[] { "style" });
+ result.put("img", new String[] { "style", "src", "width", "height", "title", "alt" });
+ result.put("a", new String[] { "style", "href", "target", "title" });
+ return result;
+ }
+
+ private static class MarkupHandler extends DefaultHandler {
+
+ @Override
+ public void startElement(String uri, String localName, String name, Attributes attributes) {
+ checkSupportedElements(name, attributes);
+ checkSupportedAttributes(name, attributes);
+ checkMandatoryAttributes(name, attributes);
+ }
+
+ private static void checkSupportedElements(String elementName, Attributes attributes) {
+ if (!SUPPORTED_ELEMENTS.containsKey(elementName)) {
+ throw new IllegalArgumentException("Unsupported element in markup text: " + elementName);
+ }
+ }
+
+ private static void checkSupportedAttributes(String elementName, Attributes attributes) {
+ if (attributes.getLength() > 0) {
+ List<String> supportedAttributes = Arrays.asList(SUPPORTED_ELEMENTS.get(elementName));
+ int index = 0;
+ String attributeName = attributes.getQName(index);
+ while (attributeName != null) {
+ if (!supportedAttributes.contains(attributeName)) {
+ String message = "Unsupported attribute \"{0}\" for element \"{1}\" in markup text";
+ message = MessageFormat.format(message, new Object[] { attributeName, elementName });
+ throw new IllegalArgumentException(message);
+ }
+ index++;
+ attributeName = attributes.getQName(index);
+ }
+ }
+ }
+
+ private static void checkMandatoryAttributes(String elementName, Attributes attributes) {
+ checkIntAttribute(elementName, attributes, "img", "width");
+ checkIntAttribute(elementName, attributes, "img", "height");
+ }
+
+ private static void checkIntAttribute(String elementName, Attributes attributes, String checkedElementName,
+ String checkedAttributeName) {
+ if (checkedElementName.equals(elementName)) {
+ String attribute = attributes.getValue(checkedAttributeName);
+ try {
+ Integer.parseInt(attribute);
+ } catch (NumberFormatException exception) {
+ String message = "Mandatory attribute \"{0}\" for element \"{1}\" is missing or not a valid integer";
+ Object[] arguments = new Object[] { checkedAttributeName, checkedElementName };
+ message = MessageFormat.format(message, arguments);
+ throw new IllegalArgumentException(message);
+ }
+ }
+ }
+
+ }
+
+}
import javax.jcr.Repository;
import javax.jcr.Session;
+import org.argeo.api.NodeUtils;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.util.CmsUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.eclipse.ui.ColumnDefinition;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider;
import org.argeo.eclipse.ui.fs.FsUiUtils;
import org.argeo.eclipse.ui.fs.NioFileLabelProvider;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeUtils;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
else
nameStr = path.getFileName().toString();
elemBtn.setText(nameStr + " >> ");
- CmsUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN);
+ CmsUiUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN);
elemBtn.addSelectionListener(new SelectionAdapter() {
private static final long serialVersionUID = -4103695476023480651L;
}
private void populateBookmarks(Composite parent) {
- CmsUtils.clear(parent);
+ CmsUiUtils.clear(parent);
parent.setLayout(new GridLayout());
ISelectionChangedListener selList = new BookmarksSelChangeListener();
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsException;
-import org.argeo.cms.util.CmsUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.dialogs.SingleValue;
import org.eclipse.jface.dialogs.MessageDialog;
Composite boxCmp = new Composite(this, SWT.NO_FOCUS | SWT.BORDER);
boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
- CmsUtils.style(boxCmp, FsStyles.CONTEXT_MENU_BOX);
+ CmsUiUtils.style(boxCmp, FsStyles.CONTEXT_MENU_BOX);
createContextMenu(boxCmp);
addShellListener(new ActionsShellListener());
Button btn = new Button(boxCmp, SWT.FLAT | SWT.PUSH | SWT.LEAD);
btn.setText(getLabel(actionId));
btn.setLayoutData(EclipseUiUtils.fillWidth());
- CmsUtils.markup(btn);
- CmsUtils.style(btn, actionId + FsStyles.BUTTON_SUFFIX);
+ CmsUiUtils.markup(btn);
+ CmsUiUtils.style(btn, actionId + FsStyles.BUTTON_SUFFIX);
btn.setData(KEY_ACTION_ID, actionId);
btn.addSelectionListener(asl);
actionButtons.put(actionId, btn);
+++ /dev/null
-package org.argeo.cms.ui.img;
-
-public class Dummy {
-
-}
package org.argeo.cms.ui.internal;
-import org.argeo.node.NodeState;
+import org.argeo.api.NodeState;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import javax.jcr.RepositoryException;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.widgets.EditableImage;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.widgets.EditableImage;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
protected String createImgTag() throws RepositoryException {
String imgTag;
if (src != null)
- imgTag = CmsUtils.img(src, imageSize);
+ imgTag = CmsUiUtils.img(src, imageSize);
else
- imgTag = CmsUtils.noImg(imageSize != null ? imageSize
+ imgTag = CmsUiUtils.noImg(imageSize != null ? imageSize
: NO_IMAGE_SIZE);
return imgTag;
}
protected Text createText(Composite box, String style) {
Text text = new Text(box, getStyle());
- CmsUtils.style(text, style);
+ CmsUiUtils.style(text, style);
return text;
}
package org.argeo.cms.ui.internal.rwt;
-import org.argeo.cms.util.LoginEntryPoint;
+import org.argeo.cms.ui.util.LoginEntryPoint;
import org.eclipse.rap.rwt.application.Application;
import org.eclipse.rap.rwt.application.Application.OperationMode;
import org.eclipse.rap.rwt.application.ApplicationConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.argeo.node.NodeConstants;
+import org.argeo.api.NodeConstants;
public class DefaultRepositoryRegister extends Observable implements RepositoryRegister {
/** Key for a JCR repository alias */
import javax.jcr.RepositoryException;
import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.jcr.utils.JcrItemsComparator;
+import org.argeo.eclipse.ui.jcr.util.JcrItemsComparator;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.api.security.Keyring;
import org.argeo.cms.ui.jcr.model.RepositoriesElem;
import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
import org.argeo.eclipse.ui.TreeParent;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeUtils;
-import org.argeo.node.security.Keyring;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import javax.jcr.RepositoryException;
import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.jcr.utils.JcrItemsComparator;
+import org.argeo.eclipse.ui.jcr.util.JcrItemsComparator;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
+import org.argeo.api.NodeUtils;
+import org.argeo.api.security.Keyring;
import org.argeo.cms.ArgeoNames;
import org.argeo.eclipse.ui.EclipseUiException;
import org.argeo.eclipse.ui.TreeParent;
-import org.argeo.node.NodeUtils;
-import org.argeo.node.security.Keyring;
/** Root of a remote repository */
public class RemoteRepositoryElem extends RepositoryElem {
import javax.jcr.RepositoryFactory;
import javax.jcr.Session;
+import org.argeo.api.NodeUtils;
+import org.argeo.api.security.Keyring;
import org.argeo.cms.ArgeoNames;
import org.argeo.cms.ui.jcr.RepositoryRegister;
import org.argeo.eclipse.ui.EclipseUiException;
import org.argeo.eclipse.ui.TreeParent;
import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.node.NodeUtils;
-import org.argeo.node.security.Keyring;
/**
* UI Tree component that implements the Argeo abstraction of a
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.script.Invocable;
+import javax.script.ScriptException;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsPane;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.util.SimpleErgonomics;
+import org.argeo.eclipse.ui.Selected;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.application.EntryPointFactory;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+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;
+
+public class AppUi implements CmsUiProvider, Branding {
+ private final CmsScriptApp app;
+
+ private CmsUiProvider ui;
+ private String createUi;
+ private Object impl;
+ private String script;
+ // private Branding branding = new Branding();
+
+ private EntryPointFactory factory;
+
+ // Branding
+ private String themeId;
+ private String additionalHeaders;
+ private String bodyHtml;
+ private String pageTitle;
+ private String pageOverflow;
+ private String favicon;
+
+ public AppUi(CmsScriptApp app) {
+ this.app = app;
+ }
+
+ public AppUi(CmsScriptApp app, String scriptPath) {
+ this.app = app;
+ this.ui = new ScriptUi((BundleContext) app.getScriptEngine().get(CmsScriptRwtApplication.BC), app.getScriptEngine(), scriptPath);
+ }
+
+ public AppUi(CmsScriptApp app, CmsUiProvider uiProvider) {
+ this.app = app;
+ this.ui = uiProvider;
+ }
+
+ public AppUi(CmsScriptApp app, EntryPointFactory factory) {
+ this.app = app;
+ this.factory = factory;
+ }
+
+ public void apply(Repository repository, Application application, Branding appBranding, String path) {
+ Map<String, String> factoryProperties = new HashMap<>();
+ if (appBranding != null)
+ appBranding.applyBranding(factoryProperties);
+ applyBranding(factoryProperties);
+ if (factory != null) {
+ application.addEntryPoint("/" + path, factory, factoryProperties);
+ } else {
+ EntryPointFactory entryPointFactory = new EntryPointFactory() {
+ @Override
+ public EntryPoint create() {
+ SimpleErgonomics ergonomics = new SimpleErgonomics(repository, "main", "/home/root/argeo:keyring",
+ AppUi.this, factoryProperties);
+// CmsUiProvider header = app.getHeader();
+// if (header != null)
+// ergonomics.setHeader(header);
+ app.applySides(ergonomics);
+ Integer headerHeight = app.getHeaderHeight();
+ if (headerHeight != null)
+ ergonomics.setHeaderHeight(headerHeight);
+ return ergonomics;
+ }
+ };
+ application.addEntryPoint("/" + path, entryPointFactory, factoryProperties);
+ }
+ }
+
+ public void setUi(CmsUiProvider uiProvider) {
+ this.ui = uiProvider;
+ }
+
+ public void applyBranding(Map<String, String> properties) {
+ if (themeId != null)
+ properties.put(WebClient.THEME_ID, themeId);
+ if (additionalHeaders != null)
+ properties.put(WebClient.HEAD_HTML, additionalHeaders);
+ if (bodyHtml != null)
+ properties.put(WebClient.BODY_HTML, bodyHtml);
+ if (pageTitle != null)
+ properties.put(WebClient.PAGE_TITLE, pageTitle);
+ if (pageOverflow != null)
+ properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
+ if (favicon != null)
+ properties.put(WebClient.FAVICON, favicon);
+ }
+
+ // public Branding getBranding() {
+ // return branding;
+ // }
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ CmsPane cmsPane = new CmsPane(parent, SWT.NONE);
+
+ if (false) {
+ // QA
+ CmsUiUtils.style(cmsPane.getQaArea(), "qa");
+ Button reload = new Button(cmsPane.getQaArea(), SWT.FLAT);
+ CmsUiUtils.style(reload, "qa");
+ reload.setText("Reload");
+ reload.addSelectionListener(new Selected() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ new Thread() {
+ @Override
+ public void run() {
+ app.reload();
+ }
+ }.start();
+ RWT.getClient().getService(JavaScriptExecutor.class)
+ .execute("setTimeout('location.reload()',1000)");
+ }
+ });
+
+ // Support
+ CmsUiUtils.style(cmsPane.getSupportArea(), "support");
+ Label msg = new Label(cmsPane.getSupportArea(), SWT.NONE);
+ CmsUiUtils.style(msg, "support");
+ msg.setText("UNSUPPORTED DEVELOPMENT VERSION");
+ }
+
+ if (ui != null) {
+ ui.createUi(cmsPane.getMainArea(), context);
+ }
+ if (createUi != null) {
+ Invocable invocable = (Invocable) app.getScriptEngine();
+ try {
+ invocable.invokeFunction(createUi, cmsPane.getMainArea(), context);
+
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ if (impl != null) {
+ Invocable invocable = (Invocable) app.getScriptEngine();
+ try {
+ invocable.invokeMethod(impl, "createUi", cmsPane.getMainArea(), context);
+
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ // Invocable invocable = (Invocable) app.getScriptEngine();
+ // try {
+ // invocable.invokeMethod(AppUi.this, "initUi", parent, context);
+ //
+ // } catch (NoSuchMethodException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // } catch (ScriptException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+
+ return null;
+ }
+
+ public void setCreateUi(String createUi) {
+ this.createUi = createUi;
+ }
+
+ public void setImpl(Object impl) {
+ this.impl = impl;
+ }
+
+ public Object getImpl() {
+ return impl;
+ }
+
+ public String getScript() {
+ return script;
+ }
+
+ public void setScript(String script) {
+ this.script = script;
+ }
+
+ // Branding
+ public String getThemeId() {
+ return themeId;
+ }
+
+ public void setThemeId(String themeId) {
+ this.themeId = themeId;
+ }
+
+ public String getAdditionalHeaders() {
+ return additionalHeaders;
+ }
+
+ public void setAdditionalHeaders(String additionalHeaders) {
+ this.additionalHeaders = additionalHeaders;
+ }
+
+ public String getBodyHtml() {
+ return bodyHtml;
+ }
+
+ public void setBodyHtml(String bodyHtml) {
+ this.bodyHtml = bodyHtml;
+ }
+
+ public String getPageTitle() {
+ return pageTitle;
+ }
+
+ public void setPageTitle(String pageTitle) {
+ this.pageTitle = pageTitle;
+ }
+
+ public String getPageOverflow() {
+ return pageOverflow;
+ }
+
+ public void setPageOverflow(String pageOverflow) {
+ this.pageOverflow = pageOverflow;
+ }
+
+ public String getFavicon() {
+ return favicon;
+ }
+
+ public void setFavicon(String favicon) {
+ this.favicon = favicon;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.util.Map;
+
+public interface Branding {
+ public void applyBranding(Map<String, String> properties);
+
+ public String getThemeId();
+
+ public String getAdditionalHeaders();
+
+ public String getBodyHtml();
+
+ public String getPageTitle();
+
+ public String getPageOverflow();
+
+ public String getFavicon();
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.script.ScriptEngine;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsConstants;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.BundleResourceLoader;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.util.SimpleErgonomics;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.Application.OperationMode;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+
+public class CmsScriptApp implements Branding {
+ public final static String CONTEXT_NAME = "contextName";
+
+ ServiceRegistration<ApplicationConfiguration> appConfigReg;
+
+ private ScriptEngine scriptEngine;
+
+ private final static Log log = LogFactory.getLog(CmsScriptApp.class);
+
+ private String webPath;
+ private String repo = "(cn=node)";
+
+ // private Branding branding = new Branding();
+ private Theme theme;
+
+ private List<String> resources = new ArrayList<>();
+
+ private Map<String, AppUi> ui = new HashMap<>();
+
+ private CmsUiProvider header;
+ private Integer headerHeight = null;
+ private CmsUiProvider lead;
+ private CmsUiProvider end;
+ private CmsUiProvider footer;
+
+ // Branding
+ private String themeId;
+ private String additionalHeaders;
+ private String bodyHtml;
+ private String pageTitle;
+ private String pageOverflow;
+ private String favicon;
+
+ public CmsScriptApp(ScriptEngine scriptEngine) {
+ super();
+ this.scriptEngine = scriptEngine;
+ }
+
+ public void apply(BundleContext bundleContext, Repository repository, Application application) {
+ BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
+
+ application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+ // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
+
+ application.setExceptionHandler(new CmsExceptionHandler());
+
+ // loading animated gif
+ application.addResource(CmsConstants.LOADING_IMAGE, createResourceLoader(CmsConstants.LOADING_IMAGE));
+ // empty image
+ application.addResource(CmsConstants.NO_IMAGE, createResourceLoader(CmsConstants.NO_IMAGE));
+
+ for (String resource : resources) {
+ application.addResource(resource, bundleRL);
+ if (log.isTraceEnabled())
+ log.trace("Resource " + resource);
+ }
+
+ if (theme != null) {
+ theme.apply(application);
+ String themeHeaders = theme.getAdditionalHeaders();
+ if (themeHeaders != null) {
+ if (additionalHeaders == null)
+ additionalHeaders = themeHeaders;
+ else
+ additionalHeaders = themeHeaders + "\n" + additionalHeaders;
+ }
+ themeId = theme.getThemeId();
+ }
+
+ // client JavaScript
+ Bundle appBundle = bundleRL.getBundle();
+ BundleContext bc = appBundle.getBundleContext();
+ HttpService httpService = bc.getService(bc.getServiceReference(HttpService.class));
+ HttpContext httpContext = new BundleHttpContext(bc);
+ Enumeration<URL> themeResources = appBundle.findEntries("/js/", "*", true);
+ if (themeResources != null)
+ bundleResources: while (themeResources.hasMoreElements()) {
+ try {
+ String name = themeResources.nextElement().getPath();
+ if (name.endsWith("/"))
+ continue bundleResources;
+ String alias = "/" + getWebPath() + name;
+
+ httpService.registerResources(alias, name, httpContext);
+ if (log.isDebugEnabled())
+ log.debug("Mapped " + name + " to alias " + alias);
+
+ } catch (NamespaceException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ // App UIs
+ for (String appUiName : ui.keySet()) {
+ AppUi appUi = ui.get(appUiName);
+ appUi.apply(repository, application, this, appUiName);
+
+ }
+
+ }
+
+ public void applySides(SimpleErgonomics simpleErgonomics) {
+ simpleErgonomics.setHeader(header);
+ simpleErgonomics.setLead(lead);
+ simpleErgonomics.setEnd(end);
+ simpleErgonomics.setFooter(footer);
+ }
+
+ public void register(BundleContext bundleContext, ApplicationConfiguration appConfig) {
+ Hashtable<String, String> props = new Hashtable<>();
+ props.put(CONTEXT_NAME, webPath);
+ appConfigReg = bundleContext.registerService(ApplicationConfiguration.class, appConfig, props);
+ }
+
+ public void reload() {
+ BundleContext bundleContext = appConfigReg.getReference().getBundle().getBundleContext();
+ ApplicationConfiguration appConfig = bundleContext.getService(appConfigReg.getReference());
+ appConfigReg.unregister();
+ register(bundleContext, appConfig);
+
+ // BundleContext bundleContext = (BundleContext)
+ // getScriptEngine().get("bundleContext");
+ // try {
+ // Bundle bundle = bundleContext.getBundle();
+ // bundle.stop();
+ // bundle.start();
+ // } catch (BundleException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+ }
+
+ private static ResourceLoader createResourceLoader(final String resourceName) {
+ return new ResourceLoader() {
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ return getClass().getClassLoader().getResourceAsStream(resourceName);
+ }
+ };
+ }
+
+ public List<String> getResources() {
+ return resources;
+ }
+
+ public AppUi newUi(String name) {
+ if (ui.containsKey(name))
+ throw new IllegalArgumentException("There is already an UI named " + name);
+ AppUi appUi = new AppUi(this);
+ // appUi.setApp(this);
+ ui.put(name, appUi);
+ return appUi;
+ }
+
+ public void addUi(String name, AppUi appUi) {
+ if (ui.containsKey(name))
+ throw new IllegalArgumentException("There is already an UI named " + name);
+ // appUi.setApp(this);
+ ui.put(name, appUi);
+ }
+
+ public void applyBranding(Map<String, String> properties) {
+ if (themeId != null)
+ properties.put(WebClient.THEME_ID, themeId);
+ if (additionalHeaders != null)
+ properties.put(WebClient.HEAD_HTML, additionalHeaders);
+ if (bodyHtml != null)
+ properties.put(WebClient.BODY_HTML, bodyHtml);
+ if (pageTitle != null)
+ properties.put(WebClient.PAGE_TITLE, pageTitle);
+ if (pageOverflow != null)
+ properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
+ if (favicon != null)
+ properties.put(WebClient.FAVICON, favicon);
+ }
+
+ class CmsExceptionHandler implements ExceptionHandler {
+
+ @Override
+ public void handleException(Throwable throwable) {
+ // TODO be smarter
+ CmsUiUtils.getCmsView().exception(throwable);
+ }
+
+ }
+
+ // public Branding getBranding() {
+ // return branding;
+ // }
+
+ ScriptEngine getScriptEngine() {
+ return scriptEngine;
+ }
+
+ public static String toJson(Node node) {
+ try {
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+ PropertyIterator pit = node.getProperties();
+ int count = 0;
+ while (pit.hasNext()) {
+ Property p = pit.nextProperty();
+ int type = p.getType();
+ if (type == PropertyType.REFERENCE || type == PropertyType.WEAKREFERENCE || type == PropertyType.PATH) {
+ Node ref = p.getNode();
+ if (count != 0)
+ sb.append(',');
+ // TODO limit depth?
+ sb.append(toJson(ref));
+ count++;
+ } else if (!p.isMultiple()) {
+ if (count != 0)
+ sb.append(',');
+ sb.append('\"').append(p.getName()).append("\":\"").append(p.getString()).append('\"');
+ count++;
+ }
+ }
+ sb.append('}');
+ return sb.toString();
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot convert " + node + " to JSON", e);
+ }
+ }
+
+ public void fromJson(Node node, String json) {
+ // TODO
+ }
+
+ public Theme getTheme() {
+ return theme;
+ }
+
+ public void setTheme(Theme theme) {
+ this.theme = theme;
+ }
+
+ public String getWebPath() {
+ return webPath;
+ }
+
+ public void setWebPath(String context) {
+ this.webPath = context;
+ }
+
+ public String getRepo() {
+ return repo;
+ }
+
+ public void setRepo(String repo) {
+ this.repo = repo;
+ }
+
+ public Map<String, AppUi> getUi() {
+ return ui;
+ }
+
+ public void setUi(Map<String, AppUi> ui) {
+ this.ui = ui;
+ }
+
+ // Branding
+ public String getThemeId() {
+ return themeId;
+ }
+
+ public void setThemeId(String themeId) {
+ this.themeId = themeId;
+ }
+
+ public String getAdditionalHeaders() {
+ return additionalHeaders;
+ }
+
+ public void setAdditionalHeaders(String additionalHeaders) {
+ this.additionalHeaders = additionalHeaders;
+ }
+
+ public String getBodyHtml() {
+ return bodyHtml;
+ }
+
+ public void setBodyHtml(String bodyHtml) {
+ this.bodyHtml = bodyHtml;
+ }
+
+ public String getPageTitle() {
+ return pageTitle;
+ }
+
+ public void setPageTitle(String pageTitle) {
+ this.pageTitle = pageTitle;
+ }
+
+ public String getPageOverflow() {
+ return pageOverflow;
+ }
+
+ public void setPageOverflow(String pageOverflow) {
+ this.pageOverflow = pageOverflow;
+ }
+
+ public String getFavicon() {
+ return favicon;
+ }
+
+ public void setFavicon(String favicon) {
+ this.favicon = favicon;
+ }
+
+ public CmsUiProvider getHeader() {
+ return header;
+ }
+
+ public void setHeader(CmsUiProvider header) {
+ this.header = header;
+ }
+
+ public Integer getHeaderHeight() {
+ return headerHeight;
+ }
+
+ public void setHeaderHeight(Integer headerHeight) {
+ this.headerHeight = headerHeight;
+ }
+
+ public CmsUiProvider getLead() {
+ return lead;
+ }
+
+ public void setLead(CmsUiProvider lead) {
+ this.lead = lead;
+ }
+
+ public CmsUiProvider getEnd() {
+ return end;
+ }
+
+ public void setEnd(CmsUiProvider end) {
+ this.end = end;
+ }
+
+ public CmsUiProvider getFooter() {
+ return footer;
+ }
+
+ public void setFooter(CmsUiProvider footer) {
+ this.footer = footer;
+ }
+
+ static class BundleHttpContext implements HttpContext {
+ private BundleContext bundleContext;
+
+ public BundleHttpContext(BundleContext bundleContext) {
+ super();
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ // TODO Auto-generated method stub
+ return true;
+ }
+
+ @Override
+ public URL getResource(String name) {
+
+ return bundleContext.getBundle().getEntry(name);
+ }
+
+ @Override
+ public String getMimeType(String name) {
+ return null;
+ }
+
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+
+import javax.jcr.Repository;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.wiring.BundleWiring;
+
+public class CmsScriptRwtApplication implements ApplicationConfiguration {
+ public final static String APP = "APP";
+ public final static String BC = "BC";
+
+ private final Log log = LogFactory.getLog(CmsScriptRwtApplication.class);
+
+ BundleContext bundleContext;
+ Repository repository;
+
+ ScriptEngine engine;
+
+ public void init(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
+ ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
+ try {
+// Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
+// ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
+// engine = scriptEngineManager.getEngineByName("JavaScript");
+// if (engine == null) {// Nashorn
+// Thread.currentThread().setContextClassLoader(originalCcl);
+// scriptEngineManager = new ScriptEngineManager();
+// Thread.currentThread().setContextClassLoader(bundleCl);
+// engine = scriptEngineManager.getEngineByName("JavaScript");
+// }
+ engine = loadScriptEngine(originalCcl, bundleCl);
+
+ // Load script
+ URL appUrl = bundleContext.getBundle().getEntry("cms/app.js");
+ // System.out.println("Loading " + appUrl);
+ // System.out.println("Loading " + appUrl.getHost());
+ // System.out.println("Loading " + appUrl.getPath());
+
+ CmsScriptApp app = new CmsScriptApp(engine);
+ engine.put(APP, app);
+ engine.put(BC, bundleContext);
+ try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+ engine.eval(reader);
+ } catch (IOException | ScriptException e) {
+ throw new CmsException("Cannot execute " + appUrl, e);
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("CMS script app initialized from " + appUrl);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ Thread.currentThread().setContextClassLoader(originalCcl);
+ }
+ }
+
+ public void destroy(BundleContext bundleContext) {
+ engine = null;
+ }
+
+ @Override
+ public void configure(Application application) {
+ load(application);
+ }
+
+ void load(Application application) {
+ CmsScriptApp app = getApp();
+ app.apply(bundleContext, repository, application);
+ if (log.isDebugEnabled())
+ log.debug("CMS script app loaded to " + app.getWebPath());
+ }
+
+ CmsScriptApp getApp() {
+ if (engine == null)
+ throw new IllegalStateException("CMS script app is not initialized");
+ return (CmsScriptApp) engine.get(APP);
+ }
+
+ void update() {
+
+ try {
+ bundleContext.getBundle().update();
+ } catch (BundleException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ private static ScriptEngine loadScriptEngine(ClassLoader originalCcl, ClassLoader bundleCl) {
+ Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
+ ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
+ ScriptEngine engine = scriptEngineManager.getEngineByName("JavaScript");
+ if (engine == null) {// Nashorn
+ Thread.currentThread().setContextClassLoader(originalCcl);
+ scriptEngineManager = new ScriptEngineManager();
+ Thread.currentThread().setContextClassLoader(bundleCl);
+ engine = scriptEngineManager.getEngineByName("JavaScript");
+ }
+ return engine;
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import javax.jcr.Repository;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class ScriptAppActivator implements BundleActivator {
+ private final static Log log = LogFactory.getLog(ScriptAppActivator.class);
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ try {
+ CmsScriptRwtApplication appConfig = new CmsScriptRwtApplication();
+ appConfig.init(context);
+ CmsScriptApp app = appConfig.getApp();
+ ServiceTracker<Repository, Repository> repoSt = new ServiceTracker<Repository, Repository>(context,
+ FrameworkUtil.createFilter("(&" + app.getRepo() + "(objectClass=javax.jcr.Repository))"), null) {
+
+ @Override
+ public Repository addingService(ServiceReference<Repository> reference) {
+ Repository repository = super.addingService(reference);
+ appConfig.setRepository(repository);
+ CmsScriptApp app = appConfig.getApp();
+ app.register(context, appConfig);
+ return repository;
+ }
+
+ };
+ repoSt.open();
+ } catch (Exception e) {
+ log.error("Cannot initialise script bundle " + context.getBundle().getSymbolicName(), e);
+ throw e;
+ }
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.net.URL;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.BundleContext;
+
+class ScriptUi implements CmsUiProvider {
+ private final static Log log = LogFactory.getLog(ScriptUi.class);
+
+ private boolean development = true;
+ private ScriptEngine scriptEngine;
+
+ private URL appUrl;
+ // private BundleContext bundleContext;
+ // private String path;
+
+ // private Bindings bindings;
+ // private String script;
+
+ public ScriptUi(BundleContext bundleContext,ScriptEngine scriptEngine, String path) {
+ this.scriptEngine = scriptEngine;
+//// ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
+// ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
+// ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
+// try {
+//// Thread.currentThread().setContextClassLoader(bundleCl);
+//// scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
+//// scriptEngine.put(CmsScriptRwtApplication.BC, bundleContext);
+// scriptEngine = CmsScriptRwtApplication.loadScriptEngine(originalCcl, bundleCl);
+//
+// } catch (Exception e) {
+// e.printStackTrace();
+// } finally {
+// Thread.currentThread().setContextClassLoader(originalCcl);
+// }
+ this.appUrl = bundleContext.getBundle().getEntry(path);
+ load();
+ }
+
+ private void load() {
+// try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+// scriptEngine.eval(reader);
+// } catch (IOException | ScriptException e) {
+// log.warn("Cannot execute " + appUrl, e);
+// }
+
+ try {
+ scriptEngine.eval("load('" + appUrl + "')");
+ } catch (ScriptException e) {
+ log.warn("Cannot execute " + appUrl, e);
+ }
+
+ }
+
+ // public ScriptUiProvider(ScriptEngine scriptEngine, String script) throws
+ // ScriptException {
+ // super();
+ // this.scriptEngine = scriptEngine;
+ // this.script = script;
+ // bindings = scriptEngine.createBindings();
+ // scriptEngine.eval(script, bindings);
+ // }
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ long begin = System.currentTimeMillis();
+ // if (bindings == null) {
+ // bindings = scriptEngine.createBindings();
+ // try {
+ // scriptEngine.eval(script, bindings);
+ // } catch (ScriptException e) {
+ // log.warn("Cannot evaluate script", e);
+ // }
+ // }
+ // Bindings bindings = scriptEngine.createBindings();
+ // bindings.put("parent", parent);
+ // bindings.put("context", context);
+ // URL appUrl = bundleContext.getBundle().getEntry(path);
+ // try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+ // scriptEngine.eval(reader,bindings);
+ // } catch (IOException | ScriptException e) {
+ // log.warn("Cannot execute " + appUrl, e);
+ // }
+
+ if (development)
+ load();
+
+ Invocable invocable = (Invocable) scriptEngine;
+ try {
+ invocable.invokeFunction("createUi", parent, context);
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ long duration = System.currentTimeMillis() - begin;
+ if (log.isTraceEnabled())
+ log.trace(appUrl + " UI in " + duration + " ms");
+ return null;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import org.argeo.cms.ui.util.CmsTheme;
+import org.osgi.framework.BundleContext;
+
+/** @deprecated Use <code>CmsTheme</code> instead. */
+@Deprecated
+public class Theme extends CmsTheme {
+
+ public Theme(BundleContext bundleContext, String symbolicName) {
+ super(bundleContext, symbolicName);
+ }
+
+ public Theme(BundleContext bundleContext) {
+ super(bundleContext);
+ }
+
+}
--- /dev/null
+// CMS
+var ScrolledPage = Java.type('org.argeo.cms.ui.widgets.ScrolledPage');
+
+var CmsScriptApp = Java.type('org.argeo.cms.ui.script.CmsScriptApp');
+var AppUi = Java.type('org.argeo.cms.ui.script.AppUi');
+var Theme = Java.type('org.argeo.cms.ui.script.Theme');
+var ScriptUi = Java.type('org.argeo.cms.ui.script.ScriptUi');
+var CmsUtils = Java.type('org.argeo.cms.ui.util.CmsUiUtils');
+var SimpleCmsHeader = Java.type('org.argeo.cms.ui.util.SimpleCmsHeader');
+var CmsLink = Java.type('org.argeo.cms.ui.util.CmsLink');
+var MenuLink = Java.type('org.argeo.cms.ui.util.MenuLink');
+var UserMenuLink = Java.type('org.argeo.cms.ui.util.UserMenuLink');
+
+// SWT
+var SWT = Java.type('org.eclipse.swt.SWT');
+var Composite = Java.type('org.eclipse.swt.widgets.Composite');
+var Label = Java.type('org.eclipse.swt.widgets.Label');
+var Button = Java.type('org.eclipse.swt.widgets.Button');
+var Text = Java.type('org.eclipse.swt.widgets.Text');
+var Browser = Java.type('org.eclipse.swt.browser.Browser');
+
+var FillLayout = Java.type('org.eclipse.swt.layout.FillLayout');
+var GridLayout = Java.type('org.eclipse.swt.layout.GridLayout');
+var RowLayout = Java.type('org.eclipse.swt.layout.RowLayout');
+var FormLayout = Java.type('org.eclipse.swt.layout.FormLayout');
+var GridData = Java.type('org.eclipse.swt.layout.GridData');
+
+function loadNode(node) {
+ var json = CmsScriptApp.toJson(node)
+ var fromJson = JSON.parse(json)
+ return fromJson
+}
+
+function newArea(parent, style, layout) {
+ var control = new Composite(parent, SWT.NONE)
+ control.setLayout(layout)
+ CmsUtils.style(control, style)
+ return control
+}
+
+function newLabel(parent, style, text) {
+ var control = new Label(parent, SWT.WRAP)
+ control.setText(text)
+ CmsUtils.style(control, style)
+ CmsUtils.markup(control)
+ return control
+}
+
+function newButton(parent, style, text) {
+ var control = new Button(parent, SWT.FLAT)
+ control.setText(text)
+ CmsUtils.style(control, style)
+ CmsUtils.markup(control)
+ return control
+}
+
+function newFormLabel(parent, style, text) {
+ return newLabel(parent, style, '<b>' + text + '</b>')
+}
+
+function newText(parent, style, msg) {
+ var control = new Text(parent, SWT.NONE)
+ control.setMessage(msg)
+ CmsUtils.style(control, style)
+ return control
+}
+
+function newScrolledPage(parent) {
+ var scrolled = new ScrolledPage(parent, SWT.NONE)
+ scrolled.setLayoutData(CmsUtils.fillAll())
+ scrolled.setLayout(CmsUtils.noSpaceGridLayout())
+ var page = new Composite(scrolled, SWT.NONE)
+ page.setLayout(CmsUtils.noSpaceGridLayout())
+ page.setBackgroundMode(SWT.INHERIT_NONE)
+ return page
+}
+
+function gridData(control) {
+ var gridData = new GridData()
+ control.setLayoutData(gridData)
+ return gridData
+}
+
+function gridData(control, hAlign, vAlign) {
+ var gridData = new GridData(hAlign, vAlign, false, false)
+ control.setLayoutData(gridData)
+ return gridData
+}
+
+// print(__FILE__, __LINE__, __DIR__)
import java.util.ArrayList;
import java.util.List;
+import org.argeo.api.NodeConstants;
import org.argeo.eclipse.ui.ColumnDefinition;
import org.argeo.eclipse.ui.EclipseUiException;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
import org.argeo.naming.LdapAttrs;
import org.argeo.naming.LdapObjs;
-import org.argeo.node.NodeConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.TrayDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
package org.argeo.cms.ui.useradmin;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.node.NodeConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.swt.SWT;
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.argeo.cms.CmsException;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+
+/** {@link ResourceLoader} implementation wrapping an {@link Bundle}. */
+public class BundleResourceLoader implements ResourceLoader {
+ private final Bundle bundle;
+
+ public BundleResourceLoader(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ URL res = bundle.getEntry(resourceName);
+ if (res == null) {
+ res = bundle.getResource(resourceName);
+ if (res == null)
+ throw new CmsException("Resource " + resourceName + " not found in bundle " + bundle.getSymbolicName());
+ }
+ return res.openStream();
+ }
+
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeUtils;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsStyles;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.service.ResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.ImageData;
+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.osgi.framework.BundleContext;
+
+/** A link to an internal or external location. */
+public class CmsLink implements CmsUiProvider {
+ private final static Log log = LogFactory.getLog(CmsLink.class);
+ private BundleContext bundleContext;
+
+ private String label;
+ private String custom;
+ private String target;
+ private String image;
+ private MouseListener mouseListener;
+
+ private int horizontalAlignment = SWT.CENTER;
+ private int verticalAlignment = SWT.CENTER;
+
+ private String loggedInLabel = null;
+ private String loggedInTarget = null;
+
+ // internal
+ // private Boolean isUrl = false;
+ private Integer imageWidth, imageHeight;
+
+ public CmsLink() {
+ super();
+ }
+
+ public CmsLink(String label, String target) {
+ this(label, target, null);
+ }
+
+ public CmsLink(String label, String target, String custom) {
+ super();
+ this.label = label;
+ this.target = target;
+ this.custom = custom;
+ init();
+ }
+
+ public void init() {
+ if (image != null) {
+ ImageData image = loadImage();
+ if (imageHeight == null && imageWidth == null) {
+ imageWidth = image.width;
+ imageHeight = image.height;
+ } else if (imageHeight == null) {
+ imageHeight = (imageWidth * image.height) / image.width;
+ } else if (imageWidth == null) {
+ imageWidth = (imageHeight * image.width) / image.height;
+ }
+ }
+ }
+
+ /** @return {@link Composite} with a single {@link Label} child. */
+ @Override
+ public Control createUi(final Composite parent, Node context) {
+// if (image != null && (imageWidth == null || imageHeight == null)) {
+// throw new CmsException("Image is not properly configured."
+// + " Make sure bundleContext property is set and init() method has been called.");
+// }
+
+ Composite comp = new Composite(parent, SWT.NONE);
+ comp.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ Label link = new Label(comp, SWT.NONE);
+ link.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
+ GridData layoutData = new GridData(horizontalAlignment, verticalAlignment, false, false);
+ if (image != null) {
+ if (imageHeight != null)
+ layoutData.heightHint = imageHeight;
+ if (label == null)
+ if (imageWidth != null)
+ layoutData.widthHint = imageWidth;
+ }
+
+ link.setLayoutData(layoutData);
+ if (custom != null) {
+ comp.setData(RWT.CUSTOM_VARIANT, custom);
+ link.setData(RWT.CUSTOM_VARIANT, custom);
+ } else {
+ comp.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_LINK);
+ link.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_LINK);
+ }
+
+ // label
+ StringBuilder labelText = new StringBuilder();
+ if (loggedInTarget != null && isLoggedIn()) {
+ labelText.append("<a style='color:inherit;text-decoration:inherit;' href=\"");
+ if (loggedInTarget.equals("")) {
+ try {
+ Node homeNode = NodeUtils.getUserHome(context.getSession());
+ String homePath = homeNode.getPath();
+ labelText.append("/#" + homePath);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot get home path", e);
+ }
+ } else {
+ labelText.append(loggedInTarget);
+ }
+ labelText.append("\">");
+ } else if (target != null) {
+ labelText.append("<a style='color:inherit;text-decoration:inherit;' href=\"");
+ labelText.append(target);
+ labelText.append("\">");
+ }
+ if (image != null) {
+ registerImageIfNeeded();
+ String imageLocation = RWT.getResourceManager().getLocation(image);
+ labelText.append("<img");
+ if (imageWidth != null)
+ labelText.append(" width='").append(imageWidth).append('\'');
+ if (imageHeight != null)
+ labelText.append(" height='").append(imageHeight).append('\'');
+ labelText.append(" src=\"").append(imageLocation).append("\"/>");
+
+ }
+
+ if (loggedInLabel != null && isLoggedIn()) {
+ labelText.append(' ').append(loggedInLabel);
+ } else if (label != null) {
+ labelText.append(' ').append(label);
+ }
+
+ if ((loggedInTarget != null && isLoggedIn()) || target != null)
+ labelText.append("</a>");
+
+ link.setText(labelText.toString());
+
+ if (mouseListener != null)
+ link.addMouseListener(mouseListener);
+
+ return comp;
+ }
+
+ private void registerImageIfNeeded() {
+ ResourceManager resourceManager = RWT.getResourceManager();
+ if (!resourceManager.isRegistered(image)) {
+ URL res = getImageUrl();
+ InputStream inputStream = null;
+ try {
+ IOUtils.closeQuietly(inputStream);
+ inputStream = res.openStream();
+ resourceManager.register(image, inputStream);
+ if (log.isTraceEnabled())
+ log.trace("Registered image " + image);
+ } catch (Exception e) {
+ throw new CmsException("Cannot load image " + image, e);
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+ }
+
+ private ImageData loadImage() {
+ URL url = getImageUrl();
+ ImageData result = null;
+ InputStream inputStream = null;
+ try {
+ inputStream = url.openStream();
+ result = new ImageData(inputStream);
+ if (log.isTraceEnabled())
+ log.trace("Loaded image " + image);
+ } catch (Exception e) {
+ throw new CmsException("Cannot load image " + image, e);
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ }
+ return result;
+ }
+
+ private URL getImageUrl() {
+ URL url;
+ try {
+ // pure URL
+ url = new URL(image);
+ } catch (MalformedURLException e1) {
+ url = bundleContext.getBundle().getResource(image);
+ }
+
+ if (url == null)
+ throw new CmsException("No image " + image + " available.");
+
+ return url;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public void setCustom(String custom) {
+ this.custom = custom;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ // try {
+ // new URL(target);
+ // isUrl = true;
+ // } catch (MalformedURLException e1) {
+ // isUrl = false;
+ // }
+ }
+
+ public void setImage(String image) {
+ this.image = image;
+ }
+
+ public void setLoggedInLabel(String loggedInLabel) {
+ this.loggedInLabel = loggedInLabel;
+ }
+
+ public void setLoggedInTarget(String loggedInTarget) {
+ this.loggedInTarget = loggedInTarget;
+ }
+
+ public void setMouseListener(MouseListener mouseListener) {
+ this.mouseListener = mouseListener;
+ }
+
+ public void setvAlign(String vAlign) {
+ if ("bottom".equals(vAlign)) {
+ verticalAlignment = SWT.BOTTOM;
+ } else if ("top".equals(vAlign)) {
+ verticalAlignment = SWT.TOP;
+ } else if ("center".equals(vAlign)) {
+ verticalAlignment = SWT.CENTER;
+ } else {
+ throw new CmsException("Unsupported vertical allignment " + vAlign + " (must be: top, bottom or center)");
+ }
+ }
+
+ protected boolean isLoggedIn() {
+ return !CurrentUser.isAnonymous();
+ }
+
+ public void setImageWidth(Integer imageWidth) {
+ this.imageWidth = imageWidth;
+ }
+
+ public void setImageHeight(Integer imageHeight) {
+ this.imageHeight = imageHeight;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/** The main pane of a CMS display, with QA and support areas. */
+public class CmsPane {
+
+ private Composite mainArea;
+ private Composite qaArea;
+ private Composite supportArea;
+
+ public CmsPane(Composite parent, int style) {
+ parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+// qaArea = new Composite(parent, SWT.NONE);
+// qaArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+// RowLayout qaLayout = new RowLayout();
+// qaLayout.spacing = 0;
+// qaArea.setLayout(qaLayout);
+
+ mainArea = new Composite(parent, SWT.NONE);
+ mainArea.setLayout(new GridLayout());
+ mainArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+// supportArea = new Composite(parent, SWT.NONE);
+// supportArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+// RowLayout supportLayout = new RowLayout();
+// supportLayout.spacing = 0;
+// supportArea.setLayout(supportLayout);
+ }
+
+ public Composite getMainArea() {
+ return mainArea;
+ }
+
+ public Composite getQaArea() {
+ return qaArea;
+ }
+
+ public Composite getSupportArea() {
+ return supportArea;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Simplifies the theming of an app (only RAP is supported at this stage).<br>
+ *
+ * Additional fonts listed in <code>/fonts.txt</code>.<br>
+ * Additional (standard CSS) header in <code>/header.css</code>.<br>
+ * RAP specific CSS files in <code>/rap/*.css</code>.<br>
+ * All images added as additional resources based on extensions
+ * <code>/ ** /*.{png,gif,jpeg,...}</code>.<br>
+ */
+public class CmsTheme {
+ private final static Log log = LogFactory.getLog(CmsTheme.class);
+
+ private String themeId;
+ private Map<String, ResourceLoader> css = new HashMap<>();
+ private Map<String, ResourceLoader> resources = new HashMap<>();
+
+ private String headerCss;
+ private List<String> fonts = new ArrayList<>();
+
+ private String basePath;
+ private String cssPath;
+
+ public CmsTheme(BundleContext bundleContext) {
+ this(bundleContext, null);
+ }
+
+ public CmsTheme(BundleContext bundleContext, String symbolicName) {
+ Bundle themeBundle;
+ if (symbolicName == null) {
+ themeBundle = bundleContext.getBundle();
+// basePath = "/theme/";
+// cssPath = basePath;
+ } else {
+ themeBundle = ThemeUtils.findThemeBundle(bundleContext, symbolicName);
+ }
+ basePath = "/";
+ cssPath = "/rap/";
+ this.themeId = RWT.DEFAULT_THEME_ID;
+ addStyleSheets(themeBundle, new BundleResourceLoader(themeBundle));
+ BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
+ addResources(themeBRL, "*.png");
+ addResources(themeBRL, "*.gif");
+ addResources(themeBRL, "*.jpg");
+ addResources(themeBRL, "*.jpeg");
+ addResources(themeBRL, "*.svg");
+ addResources(themeBRL, "*.ico");
+
+ // fonts
+ URL fontsUrl = themeBundle.getEntry(basePath + "fonts.txt");
+ if (fontsUrl != null) {
+ loadFontsUrl(fontsUrl);
+ }
+
+ // common CSS header (plain CSS)
+ URL headerCssUrl = themeBundle.getEntry(basePath + "header.css");
+ if (headerCssUrl != null) {
+ try (BufferedReader buffer = new BufferedReader(new InputStreamReader(headerCssUrl.openStream(), UTF_8))) {
+ headerCss = buffer.lines().collect(Collectors.joining("\n"));
+ } catch (IOException e) {
+ throw new CmsException("Cannot read " + headerCssUrl, e);
+ }
+ }
+
+ }
+
+ public void apply(Application application) {
+ resources: for (String name : resources.keySet()) {
+ if (name.startsWith("target/"))
+ continue resources; // skip maven output
+ application.addResource(name, resources.get(name));
+ if (log.isTraceEnabled())
+ log.trace("Added resource " + name);
+ }
+ for (String name : css.keySet()) {
+ application.addStyleSheet(themeId, name, css.get(name));
+ if (log.isDebugEnabled())
+ log.debug("Added RAP CSS " + name);
+ }
+ }
+
+ public String getAdditionalHeaders() {
+ StringBuilder sb = new StringBuilder();
+ if (headerCss != null) {
+ sb.append("<style type='text/css'>\n");
+ sb.append(headerCss);
+ sb.append("\n</style>\n");
+ }
+ for (String link : fonts) {
+ sb.append("<link rel='stylesheet' href='");
+ sb.append(link);
+ sb.append("'/>\n");
+ }
+ if (sb.length() == 0)
+ return null;
+ else
+ return sb.toString();
+ }
+
+ void addStyleSheets(Bundle themeBundle, ResourceLoader ssRL) {
+ Enumeration<URL> themeResources = themeBundle.findEntries(cssPath, "*.css", true);
+ if (themeResources == null)
+ return;
+ while (themeResources.hasMoreElements()) {
+ String resource = themeResources.nextElement().getPath();
+ // remove first '/' so that RWT registers it
+ resource = resource.substring(1);
+ if (!resource.endsWith("/")) {
+ if (css.containsKey(resource))
+ log.warn("Overriding " + resource + " from " + themeBundle.getSymbolicName());
+ css.put(resource, ssRL);
+ }
+
+ }
+
+ }
+
+ void loadFontsUrl(URL url) {
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) {
+ String line = null;
+ while ((line = in.readLine()) != null) {
+ line = line.trim();
+ if (!line.equals("") && !line.startsWith("#")) {
+ fonts.add(line);
+ }
+ }
+ } catch (IOException e) {
+ throw new CmsException("Cannot load URL " + url, e);
+ }
+ }
+
+ void addResources(BundleResourceLoader themeBRL, String pattern) {
+ Bundle themeBundle = themeBRL.getBundle();
+ Enumeration<URL> themeResources = themeBundle.findEntries(basePath, pattern, true);
+ if (themeResources == null)
+ return;
+ while (themeResources.hasMoreElements()) {
+ String resource = themeResources.nextElement().getPath();
+ // remove first '/' so that RWT registers it
+ resource = resource.substring(1);
+ if (!resource.endsWith("/")) {
+ if (resources.containsKey(resource))
+ log.warn("Overriding " + resource + " from " + themeBundle.getSymbolicName());
+ resources.put(resource, themeBRL);
+ }
+
+ }
+
+ }
+
+ public String getThemeId() {
+ return themeId;
+ }
+
+ public void setThemeId(String themeId) {
+ this.themeId = themeId;
+ }
+
+ public String getBasePath() {
+ return basePath;
+ }
+
+ public void setBasePath(String basePath) {
+ this.basePath = basePath;
+ }
+
+ public String getCssPath() {
+ return cssPath;
+ }
+
+ public void setCssPath(String cssPath) {
+ this.cssPath = cssPath;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsConstants;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.service.ResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+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.layout.RowData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+
+/** Static utilities for the CMS framework. */
+public class CmsUiUtils implements CmsConstants {
+ // private final static Log log = LogFactory.getLog(CmsUiUtils.class);
+
+ /**
+ * The CMS view related to this display, or null if none is available from this
+ * call.
+ */
+ public static CmsView getCmsView() {
+ return UiContext.getData(CmsView.KEY);
+ }
+
+ public static StringBuilder getServerBaseUrl(HttpServletRequest request) {
+ try {
+ URL url = new URL(request.getRequestURL().toString());
+ StringBuilder buf = new StringBuilder();
+ buf.append(url.getProtocol()).append("://").append(url.getHost());
+ if (url.getPort() != -1)
+ buf.append(':').append(url.getPort());
+ return buf;
+ } catch (MalformedURLException e) {
+ throw new CmsException("Cannot extract server base URL from " + request.getRequestURL(), e);
+ }
+ }
+
+ //
+ public static String getDataUrl(Node node, HttpServletRequest request) throws RepositoryException {
+ try {
+ StringBuilder buf = getServerBaseUrl(request);
+ buf.append(getDataPath(node));
+ return new URL(buf.toString()).toString();
+ } catch (MalformedURLException e) {
+ throw new CmsException("Cannot build data URL for " + node, e);
+ }
+ }
+
+ /** A path in the node repository */
+ public static String getDataPath(Node node) throws RepositoryException {
+ return getDataPath(NodeConstants.NODE, node);
+ }
+
+ public static String getDataPath(String cn, Node node) throws RepositoryException {
+ return NodeUtils.getDataPath(cn, node);
+ }
+
+ /** @deprecated Use rowData16px() instead. GridData should not be reused. */
+ @Deprecated
+ public static RowData ROW_DATA_16px = new RowData(16, 16);
+
+ public static GridLayout noSpaceGridLayout() {
+ return noSpaceGridLayout(new GridLayout());
+ }
+
+ public static GridLayout noSpaceGridLayout(int columns) {
+ return noSpaceGridLayout(new GridLayout(columns, false));
+ }
+
+ public static GridLayout noSpaceGridLayout(GridLayout layout) {
+ layout.horizontalSpacing = 0;
+ layout.verticalSpacing = 0;
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ return layout;
+ }
+
+ //
+ // GRID DATA
+ //
+ public static GridData fillWidth() {
+ return grabWidth(SWT.FILL, SWT.FILL);
+ }
+
+ public static GridData fillAll() {
+ return new GridData(SWT.FILL, SWT.FILL, true, true);
+ }
+
+ public static GridData grabWidth(int horizontalAlignment, int verticalAlignment) {
+ return new GridData(horizontalAlignment, horizontalAlignment, true, false);
+ }
+
+ public static RowData rowData16px() {
+ return new RowData(16, 16);
+ }
+
+ /** Style widget */
+ public static <T extends Widget> T style(T widget, String style) {
+ widget.setData(CmsConstants.STYLE, style);
+ return widget;
+ }
+
+ /** Enable markups on widget */
+ public static <T extends Widget> T markup(T widget) {
+ widget.setData(CmsConstants.MARKUP, true);
+ return widget;
+ }
+
+ /**
+ * Apply markup and set text on {@link Label}, {@link Button}, {@link Text}.
+ *
+ * @see #markup(Widget)
+ */
+ public static <T extends Widget> T text(T widget, String txt) {
+ markup(widget);
+ if (widget instanceof Label)
+ ((Label) widget).setText(txt);
+ else if (widget instanceof Button)
+ ((Button) widget).setText(txt);
+ else if (widget instanceof Text)
+ ((Text) widget).setText(txt);
+ else
+ throw new IllegalArgumentException("Unsupported widget type " + widget.getClass());
+ return widget;
+ }
+
+ public static void setItemHeight(Table table, int height) {
+ table.setData(CmsConstants.ITEM_HEIGHT, height);
+ }
+
+ /** Dispose all children of a Composite */
+ public static void clear(Composite composite) {
+ for (Control child : composite.getChildren())
+ child.dispose();
+ }
+
+ //
+ // JCR
+ //
+ public static Node getOrAddEmptyFile(Node parent, Enum<?> child) throws RepositoryException {
+ if (has(parent, child))
+ return child(parent, child);
+ return JcrUtils.copyBytesAsFile(parent, child.name(), new byte[0]);
+ }
+
+ public static Node child(Node parent, Enum<?> en) throws RepositoryException {
+ return parent.getNode(en.name());
+ }
+
+ public static Boolean has(Node parent, Enum<?> en) throws RepositoryException {
+ return parent.hasNode(en.name());
+ }
+
+ public static Node getOrAdd(Node parent, Enum<?> en) throws RepositoryException {
+ return getOrAdd(parent, en, null);
+ }
+
+ public static Node getOrAdd(Node parent, Enum<?> en, String primaryType) throws RepositoryException {
+ if (has(parent, en))
+ return child(parent, en);
+ else if (primaryType == null)
+ return parent.addNode(en.name());
+ else
+ return parent.addNode(en.name(), primaryType);
+ }
+
+ // IMAGES
+ public static String img(String src, String width, String height) {
+ return imgBuilder(src, width, height).append("/>").toString();
+ }
+
+ public static String img(String src, Point size) {
+ return img(src, Integer.toString(size.x), Integer.toString(size.y));
+ }
+
+ public static StringBuilder imgBuilder(String src, String width, String height) {
+ return new StringBuilder(64).append("<img width='").append(width).append("' height='").append(height)
+ .append("' src='").append(src).append("'");
+ }
+
+ public static String noImg(Point size) {
+ ResourceManager rm = RWT.getResourceManager();
+ return CmsUiUtils.img(rm.getLocation(NO_IMAGE), size);
+ }
+
+ public static String noImg() {
+ return noImg(NO_IMAGE_SIZE);
+ }
+
+ public static Image noImage(Point size) {
+ ResourceManager rm = RWT.getResourceManager();
+ InputStream in = null;
+ try {
+ in = rm.getRegisteredContent(NO_IMAGE);
+ ImageData id = new ImageData(in);
+ ImageData scaled = id.scaledTo(size.x, size.y);
+ Image image = new Image(Display.getCurrent(), scaled);
+ return image;
+ } finally {
+ try {
+ in.close();
+ } catch (IOException e) {
+ // silent
+ }
+ }
+ }
+
+ /** Lorem ipsum text to be used during development. */
+ public final static String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
+ + " Etiam eleifend hendrerit sem, ac ultricies massa ornare ac."
+ + " Cras aliquam sodales risus, vitae varius lacus molestie quis."
+ + " Vivamus consequat, leo id lacinia volutpat, eros diam efficitur urna, finibus interdum risus turpis at nisi."
+ + " Curabitur vulputate nulla quis scelerisque fringilla. Integer consectetur turpis id lobortis accumsan."
+ + " Pellentesque commodo turpis ac diam ultricies dignissim."
+ + " Curabitur sit amet dolor volutpat lacus aliquam ornare quis sed velit."
+ + " Integer varius quis est et tristique."
+ + " Suspendisse pharetra porttitor purus, eget condimentum magna."
+ + " Duis vitae turpis eros. Sed tincidunt lacinia rutrum."
+ + " Aliquam velit velit, rutrum ut augue sed, condimentum lacinia augue.";
+
+ /** Singleton. */
+ private CmsUiUtils() {
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import static javax.jcr.Node.JCR_CONTENT;
+import static javax.jcr.Property.JCR_DATA;
+import static javax.jcr.nodetype.NodeType.NT_FILE;
+import static javax.jcr.nodetype.NodeType.NT_RESOURCE;
+import static org.argeo.cms.ui.CmsConstants.NO_IMAGE_SIZE;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsImageManager;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.service.ResourceManager;
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+
+/** Manages only public images so far. */
+public class DefaultImageManager implements CmsImageManager {
+ private final static Log log = LogFactory.getLog(DefaultImageManager.class);
+// private MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
+
+ public Boolean load(Node node, Control control, Point preferredSize) throws RepositoryException {
+ Point imageSize = getImageSize(node);
+ Point size;
+ String imgTag = null;
+ if (preferredSize == null || imageSize.x == 0 || imageSize.y == 0
+ || (preferredSize.x == 0 && preferredSize.y == 0)) {
+ if (imageSize.x != 0 && imageSize.y != 0) {
+ // actual image size if completely known
+ size = imageSize;
+ } else {
+ // no image if not completely known
+ size = resizeTo(NO_IMAGE_SIZE, preferredSize != null ? preferredSize : imageSize);
+ imgTag = CmsUiUtils.noImg(size);
+ }
+
+ } else if (preferredSize.x != 0 && preferredSize.y != 0) {
+ // given size if completely provided
+ size = preferredSize;
+ } else {
+ // at this stage :
+ // image is completely known
+ assert imageSize.x != 0 && imageSize.y != 0;
+ // one and only one of the dimension as been specified
+ assert preferredSize.x == 0 || preferredSize.y == 0;
+ size = resizeTo(imageSize, preferredSize);
+ }
+
+ boolean loaded = false;
+ if (control == null)
+ return loaded;
+
+ if (control instanceof Label) {
+ if (imgTag == null) {
+ // IMAGE RETRIEVED HERE
+ imgTag = getImageTag(node, size);
+ //
+ if (imgTag == null)
+ imgTag = CmsUiUtils.noImg(size);
+ else
+ loaded = true;
+ }
+
+ Label lbl = (Label) control;
+ lbl.setText(imgTag);
+ // lbl.setSize(size);
+ } else if (control instanceof FileUpload) {
+ FileUpload lbl = (FileUpload) control;
+ lbl.setImage(CmsUiUtils.noImage(size));
+ lbl.setSize(size);
+ return loaded;
+ } else
+ loaded = false;
+
+ return loaded;
+ }
+
+ private Point resizeTo(Point orig, Point constraints) {
+ if (constraints.x != 0 && constraints.y != 0) {
+ return constraints;
+ } else if (constraints.x == 0 && constraints.y == 0) {
+ return orig;
+ } else if (constraints.y == 0) {// force width
+ return new Point(constraints.x, scale(orig.y, orig.x, constraints.x));
+ } else if (constraints.x == 0) {// force height
+ return new Point(scale(orig.x, orig.y, constraints.y), constraints.y);
+ }
+ throw new CmsException("Cannot resize " + orig + " to " + constraints);
+ }
+
+ private int scale(int origDimension, int otherDimension, int otherConstraint) {
+ return Math.round(origDimension * divide(otherConstraint, otherDimension));
+ }
+
+ private float divide(int a, int b) {
+ return ((float) a) / ((float) b);
+ }
+
+ public Point getImageSize(Node node) throws RepositoryException {
+ // TODO load the SWT image ?
+ return new Point(0, 0);
+ }
+
+ /** @return null if not available */
+ @Override
+ public String getImageTag(Node node) throws RepositoryException {
+ return getImageTag(node, getImageSize(node));
+ }
+
+ private String getImageTag(Node node, Point size) throws RepositoryException {
+ StringBuilder buf = getImageTagBuilder(node, size);
+ if (buf == null)
+ return null;
+ return buf.append("/>").toString();
+ }
+
+ /** @return null if not available */
+ @Override
+ public StringBuilder getImageTagBuilder(Node node, Point size) throws RepositoryException {
+ return getImageTagBuilder(node, Integer.toString(size.x), Integer.toString(size.y));
+ }
+
+ /** @return null if not available */
+ private StringBuilder getImageTagBuilder(Node node, String width, String height) throws RepositoryException {
+ String url = getImageUrl(node);
+ if (url == null)
+ return null;
+ return CmsUiUtils.imgBuilder(url, width, height);
+ }
+
+ /** @return null if not available */
+ @Override
+ public String getImageUrl(Node node) throws RepositoryException {
+ return CmsUiUtils.getDataPath(node);
+ // String name = getResourceName(node);
+ // ResourceManager resourceManager = RWT.getResourceManager();
+ // if (!resourceManager.isRegistered(name)) {
+ // InputStream inputStream = null;
+ // Binary binary = getImageBinary(node);
+ // if (binary == null)
+ // return null;
+ // try {
+ // inputStream = binary.getStream();
+ // resourceManager.register(name, inputStream);
+ // } finally {
+ // IOUtils.closeQuietly(inputStream);
+ // JcrUtils.closeQuietly(binary);
+ // }
+ // if (log.isTraceEnabled())
+ // log.trace("Registered image " + name);
+ // }
+ // return resourceManager.getLocation(name);
+ }
+
+ protected String getResourceName(Node node) throws RepositoryException {
+ String workspace = node.getSession().getWorkspace().getName();
+ if (node.hasNode(JCR_CONTENT))
+ return workspace + '_' + node.getNode(JCR_CONTENT).getIdentifier();
+ else
+ return workspace + '_' + node.getIdentifier();
+ }
+
+ public Binary getImageBinary(Node node) throws RepositoryException {
+ if (node.isNodeType(NT_FILE)) {
+ return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();
+ } else {
+ return null;
+ }
+ }
+
+ public Image getSwtImage(Node node) throws RepositoryException {
+ InputStream inputStream = null;
+ Binary binary = getImageBinary(node);
+ if (binary == null)
+ return null;
+ try {
+ inputStream = binary.getStream();
+ return new Image(Display.getCurrent(), inputStream);
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ JcrUtils.closeQuietly(binary);
+ }
+ }
+
+ @Override
+ public String uploadImage(Node parentNode, String fileName, InputStream in) throws RepositoryException {
+ InputStream inputStream = null;
+ try {
+ String previousResourceName = null;
+ if (parentNode.hasNode(fileName)) {
+ Node node = parentNode.getNode(fileName);
+ previousResourceName = getResourceName(node);
+ if (node.hasNode(JCR_CONTENT)) {
+ node.getNode(JCR_CONTENT).remove();
+ node.addNode(JCR_CONTENT, NT_RESOURCE);
+ }
+ }
+
+ byte[] arr = IOUtils.toByteArray(in);
+ Node fileNode = JcrUtils.copyBytesAsFile(parentNode, fileName, arr);
+ inputStream = new ByteArrayInputStream(arr);
+ ImageData id = new ImageData(inputStream);
+ processNewImageFile(fileNode, id);
+
+ String mime = Files.probeContentType(Paths.get(fileName));
+ fileNode.setProperty(Property.JCR_MIMETYPE, mime);
+ fileNode.getSession().save();
+
+ // reset resource manager
+ ResourceManager resourceManager = RWT.getResourceManager();
+ if (previousResourceName != null && resourceManager.isRegistered(previousResourceName)) {
+ resourceManager.unregister(previousResourceName);
+ if (log.isDebugEnabled())
+ log.debug("Unregistered image " + previousResourceName);
+ }
+ return getImageUrl(fileNode);
+ } catch (IOException e) {
+ throw new CmsException("Cannot upload image " + fileName + " in " + parentNode, e);
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+
+ /** Does nothign by default. */
+ protected void processNewImageFile(Node fileNode, ImageData id) throws RepositoryException, IOException {
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.util.Locale;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsImageManager;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.UxContext;
+import org.argeo.cms.ui.widgets.auth.CmsLogin;
+import org.argeo.cms.ui.widgets.auth.CmsLoginShell;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+
+public class LoginEntryPoint implements EntryPoint, CmsView {
+ protected final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
+ protected final static String HEADER_AUTHORIZATION = "Authorization";
+ private final static Log log = LogFactory.getLog(LoginEntryPoint.class);
+ private LoginContext loginContext;
+ private UxContext uxContext = null;
+
+ @Override
+ public int createUI() {
+ final Display display = createDisplay();
+ UiContext.setData(CmsView.KEY, this);
+ CmsLoginShell loginShell = createCmsLoginShell();
+ try {
+ // try pre-auth
+ loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, loginShell);
+ loginContext.login();
+ } catch (LoginException e) {
+ loginShell.createUi();
+ loginShell.open();
+
+ // HttpServletRequest request = RWT.getRequest();
+ // String authorization = request.getHeader(HEADER_AUTHORIZATION);
+ // if (authorization == null ||
+ // !authorization.startsWith("Negotiate")) {
+ // HttpServletResponse response = RWT.getResponse();
+ // response.setStatus(401);
+ // response.setHeader(HEADER_WWW_AUTHENTICATE, "Negotiate");
+ // response.setDateHeader("Date", System.currentTimeMillis());
+ // response.setDateHeader("Expires", System.currentTimeMillis() +
+ // (24 * 60 * 60 * 1000));
+ // response.setHeader("Accept-Ranges", "bytes");
+ // response.setHeader("Connection", "Keep-Alive");
+ // response.setHeader("Keep-Alive", "timeout=5, max=97");
+ // // response.setContentType("text/html; charset=UTF-8");
+ // }
+
+ while (!loginShell.getShell().isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ }
+
+ if (CurrentUser.getUsername(getSubject()) == null)
+ return -1;
+ uxContext = new SimpleUxContext();
+ return postLogin();
+ }
+
+ protected Display createDisplay() {
+ return new Display();
+ }
+
+ protected int postLogin() {
+ return 0;
+ }
+
+ protected HttpServletRequest getRequest() {
+ return RWT.getRequest();
+ }
+
+ protected CmsLoginShell createCmsLoginShell() {
+ return new CmsLoginShell(this) {
+
+ @Override
+ public void createContents(Composite parent) {
+ LoginEntryPoint.this.createLoginPage(parent, this);
+ }
+
+ @Override
+ protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale,
+ SelectionListener loginSelectionListener) {
+ LoginEntryPoint.this.extendsCredentialsBlock(credentialsBlock, selectedLocale, loginSelectionListener);
+ }
+
+ };
+ }
+
+ /**
+ * To be overridden. CmsLogin#createCredentialsBlock() should be called at
+ * some point in order to create the credentials composite. In order to use
+ * the default layout, call CmsLogin#defaultCreateContents() but <b>not</b>
+ * CmsLogin#createContent(), since it would lead to a stack overflow.
+ */
+ protected void createLoginPage(Composite parent, CmsLogin login) {
+ login.defaultCreateContents(parent);
+ }
+
+ protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale,
+ SelectionListener loginSelectionListener) {
+
+ }
+
+ @Override
+ public void navigateTo(String state) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void authChange(LoginContext loginContext) {
+ if (loginContext == null)
+ throw new CmsException("Login context cannot be null");
+ // logout previous login context
+ if (this.loginContext != null)
+ try {
+ this.loginContext.logout();
+ } catch (LoginException e1) {
+ log.warn("Could not log out: " + e1);
+ }
+ this.loginContext = loginContext;
+ }
+
+ @Override
+ public void logout() {
+ if (loginContext == null)
+ throw new CmsException("Login context should not bet null");
+ try {
+ CurrentUser.logoutCmsSession(loginContext.getSubject());
+ loginContext.logout();
+ } catch (LoginException e) {
+ throw new CmsException("Cannot log out", e);
+ }
+ }
+
+ @Override
+ public void exception(Throwable e) {
+ // TODO Auto-generated method stub
+
+ }
+
+ // @Override
+ // public LoginContext getLoginContext() {
+ // return loginContext;
+ // }
+
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return CurrentUser.isAnonymous(getSubject());
+ }
+
+ @Override
+ public CmsImageManager getImageManager() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public UxContext getUxContext() {
+ return uxContext;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import org.argeo.cms.ui.CmsStyles;
+
+/**
+ * Convenience class setting the custom style {@link CmsStyles#CMS_MENU_LINK} on
+ * a {@link CmsLink} when simple menus are used.
+ */
+public class MenuLink extends CmsLink {
+ public MenuLink() {
+ setCustom(CmsStyles.CMS_MENU_LINK);
+ }
+
+ public MenuLink(String label, String target, String custom) {
+ super(label, target, custom);
+ }
+
+ public MenuLink(String label, String target) {
+ super(label, target, CmsStyles.CMS_MENU_LINK);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+import javax.jcr.version.VersionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsConstants;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.LifeCycleUiProvider;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.Application.OperationMode;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.application.EntryPointFactory;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/** A basic generic app based on {@link SimpleErgonomics}. */
+public class SimpleApp implements CmsConstants, ApplicationConfiguration {
+ private final static Log log = LogFactory.getLog(SimpleApp.class);
+
+ private String contextName = null;
+
+ private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
+ private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
+
+ private List<String> resources = new ArrayList<String>();
+
+ private BundleContext bundleContext;
+
+ private Repository repository;
+ private String workspace = null;
+ private String jcrBasePath = "/";
+ private List<String> roPrincipals = Arrays.asList(NodeConstants.ROLE_ANONYMOUS, NodeConstants.ROLE_USER);
+ private List<String> rwPrincipals = Arrays.asList(NodeConstants.ROLE_USER);
+
+ private CmsUiProvider header;
+ private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
+
+ private Integer headerHeight = 40;
+
+ private ServiceRegistration<ApplicationConfiguration> appReg;
+
+ public void configure(Application application) {
+ try {
+ BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
+
+ application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+ // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
+
+ application.setExceptionHandler(new CmsExceptionHandler());
+
+ // loading animated gif
+ application.addResource(LOADING_IMAGE, createResourceLoader(LOADING_IMAGE));
+ // empty image
+ application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
+
+ for (String resource : resources) {
+ application.addResource(resource, bundleRL);
+ if (log.isTraceEnabled())
+ log.trace("Resource " + resource);
+ }
+
+ Map<String, String> defaultBranding = null;
+ if (branding.containsKey("*"))
+ defaultBranding = branding.get("*");
+ String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
+
+ // entry points
+ for (String page : pages.keySet()) {
+ Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(defaultBranding)
+ : new HashMap<String, String>();
+ if (branding.containsKey(page)) {
+ properties.putAll(branding.get(page));
+ }
+ // favicon
+ if (properties.containsKey(WebClient.FAVICON)) {
+ String themeId = defaultBranding.get(WebClient.THEME_ID);
+ Bundle themeBundle = ThemeUtils.findThemeBundle(bundleContext, themeId);
+ String faviconRelPath = properties.get(WebClient.FAVICON);
+ application.addResource(faviconRelPath,
+ new BundleResourceLoader(themeBundle != null ? themeBundle : bundleContext.getBundle()));
+ if (log.isTraceEnabled())
+ log.trace("Favicon " + faviconRelPath);
+
+ }
+
+ // page title
+ if (!properties.containsKey(WebClient.PAGE_TITLE)) {
+ if (page.length() > 0)
+ properties.put(WebClient.PAGE_TITLE, Character.toUpperCase(page.charAt(0)) + page.substring(1));
+ }
+
+ // default body HTML
+ if (!properties.containsKey(WebClient.BODY_HTML))
+ properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
+
+ //
+ // ADD ENTRY POINT
+ //
+ application.addEntryPoint("/" + page,
+ new CmsEntryPointFactory(pages.get(page), repository, workspace, properties), properties);
+ log.info("Page /" + page);
+ }
+
+ // stylesheets and themes
+ Set<Bundle> themeBundles = new HashSet<>();
+ for (String themeId : styleSheets.keySet()) {
+ Bundle themeBundle = ThemeUtils.findThemeBundle(bundleContext, themeId);
+ StyleSheetResourceLoader styleSheetRL = new StyleSheetResourceLoader(
+ themeBundle != null ? themeBundle : bundleContext.getBundle());
+ if (themeBundle != null)
+ themeBundles.add(themeBundle);
+ List<String> cssLst = styleSheets.get(themeId);
+ if (log.isDebugEnabled())
+ log.debug("Theme " + themeId);
+ for (String css : cssLst) {
+ application.addStyleSheet(themeId, css, styleSheetRL);
+ if (log.isDebugEnabled())
+ log.debug(" CSS " + css);
+ }
+
+ }
+ for (Bundle themeBundle : themeBundles) {
+ BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
+ ThemeUtils.addThemeResources(application, themeBundle, themeBRL, "*.png");
+ ThemeUtils.addThemeResources(application, themeBundle, themeBRL, "*.gif");
+ ThemeUtils.addThemeResources(application, themeBundle, themeBRL, "*.jpg");
+ }
+ } catch (RuntimeException e) {
+ // Easier access to initialisation errors
+ log.error("Unexpected exception when configuring RWT application.", e);
+ throw e;
+ }
+ }
+
+ public void init() throws RepositoryException {
+ Session session = null;
+ try {
+ session = NodeUtils.openDataAdminSession(repository, workspace);
+ // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
+ VersionManager vm = session.getWorkspace().getVersionManager();
+ JcrUtils.mkdirs(session, jcrBasePath);
+ session.save();
+ if (!vm.isCheckedOut(jcrBasePath))
+ vm.checkout(jcrBasePath);
+ for (String principal : rwPrincipals)
+ JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_WRITE);
+ for (String principal : roPrincipals)
+ JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_READ);
+
+ for (String pageName : pages.keySet()) {
+ try {
+ initPage(session, pages.get(pageName));
+ session.save();
+ } catch (Exception e) {
+ throw new CmsException("Cannot initialize page " + pageName, e);
+ }
+ }
+
+ } finally {
+ JcrUtils.logoutQuietly(session);
+ }
+
+ // publish to OSGi
+ register();
+ }
+
+ protected void initPage(Session adminSession, CmsUiProvider page) throws RepositoryException {
+ if (page instanceof LifeCycleUiProvider)
+ ((LifeCycleUiProvider) page).init(adminSession);
+ }
+
+ public void destroy() {
+ for (String pageName : pages.keySet()) {
+ try {
+ CmsUiProvider page = pages.get(pageName);
+ if (page instanceof LifeCycleUiProvider)
+ ((LifeCycleUiProvider) page).destroy();
+ } catch (Exception e) {
+ log.error("Cannot destroy page " + pageName, e);
+ }
+ }
+ }
+
+ protected void register() {
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ if (contextName != null)
+ props.put("contextName", contextName);
+ appReg = bundleContext.registerService(ApplicationConfiguration.class, this, props);
+ if (log.isDebugEnabled())
+ log.debug("Registered " + (contextName == null ? "/" : contextName));
+ }
+
+ protected void unregister() {
+ appReg.unregister();
+ if (log.isDebugEnabled())
+ log.debug("Unregistered " + (contextName == null ? "/" : contextName));
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public void setWorkspace(String workspace) {
+ this.workspace = workspace;
+ }
+
+ public void setHeader(CmsUiProvider header) {
+ this.header = header;
+ }
+
+ public void setPages(Map<String, CmsUiProvider> pages) {
+ this.pages = pages;
+ }
+
+ public void setJcrBasePath(String basePath) {
+ this.jcrBasePath = basePath;
+ }
+
+ public void setRoPrincipals(List<String> roPrincipals) {
+ this.roPrincipals = roPrincipals;
+ }
+
+ public void setRwPrincipals(List<String> rwPrincipals) {
+ this.rwPrincipals = rwPrincipals;
+ }
+
+ public void setHeaderHeight(Integer headerHeight) {
+ this.headerHeight = headerHeight;
+ }
+
+ public void setBranding(Map<String, Map<String, String>> branding) {
+ this.branding = branding;
+ }
+
+ public void setStyleSheets(Map<String, List<String>> styleSheets) {
+ this.styleSheets = styleSheets;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public void setResources(List<String> resources) {
+ this.resources = resources;
+ }
+
+ public void setContextName(String contextName) {
+ this.contextName = contextName;
+ }
+
+ class CmsExceptionHandler implements ExceptionHandler {
+
+ @Override
+ public void handleException(Throwable throwable) {
+ // TODO be smarter
+ CmsUiUtils.getCmsView().exception(throwable);
+ }
+
+ }
+
+ private class CmsEntryPointFactory implements EntryPointFactory {
+ private final CmsUiProvider page;
+ private final Repository repository;
+ private final String workspace;
+ private final Map<String, String> properties;
+
+ public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace,
+ Map<String, String> properties) {
+ this.page = page;
+ this.repository = repository;
+ this.workspace = workspace;
+ this.properties = properties;
+ }
+
+ @Override
+ public EntryPoint create() {
+ SimpleErgonomics entryPoint = new SimpleErgonomics(repository, workspace, jcrBasePath, page, properties) {
+ private static final long serialVersionUID = -637940404865527290L;
+
+ @Override
+ protected void createAdminArea(Composite parent) {
+ Composite adminArea = new Composite(parent, SWT.NONE);
+ adminArea.setLayout(new FillLayout());
+ Button refresh = new Button(adminArea, SWT.PUSH);
+ refresh.setText("Reload App");
+ refresh.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -7671999525536351366L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ long timeBeforeReload = 1000;
+ RWT.getClient().getService(JavaScriptExecutor.class).execute(
+ "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload + ");");
+ reloadApp();
+ }
+ });
+ }
+ };
+ // entryPoint.setState("");
+ entryPoint.setHeader(header);
+ entryPoint.setHeaderHeight(headerHeight);
+ // CmsSession.current.set(entryPoint);
+ return entryPoint;
+ }
+
+ private void reloadApp() {
+ new Thread("Refresh app") {
+ @Override
+ public void run() {
+ unregister();
+ register();
+ }
+ }.start();
+ }
+ }
+
+ private static ResourceLoader createResourceLoader(final String resourceName) {
+ return new ResourceLoader() {
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ return getClass().getClassLoader().getResourceAsStream(resourceName);
+ }
+ };
+ }
+
+ // private static ResourceLoader createUrlResourceLoader(final URL url) {
+ // return new ResourceLoader() {
+ // public InputStream getResourceAsStream(String resourceName)
+ // throws IOException {
+ // return url.openStream();
+ // }
+ // };
+ // }
+
+ /*
+ * TEXTS
+ */
+ private static String DEFAULT_LOADING_BODY = "<div"
+ + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
+ + "<img src=\"./rwt-resources/" + LOADING_IMAGE
+ + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsStyles;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.rap.rwt.RWT;
+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;
+
+/** A header in three parts */
+public class SimpleCmsHeader implements CmsUiProvider {
+ private List<CmsUiProvider> lead = new ArrayList<CmsUiProvider>();
+ private List<CmsUiProvider> center = new ArrayList<CmsUiProvider>();
+ private List<CmsUiProvider> end = new ArrayList<CmsUiProvider>();
+
+ private Boolean subPartsSameWidth = false;
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ Composite header = new Composite(parent, SWT.NONE);
+ header.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_HEADER);
+ header.setBackgroundMode(SWT.INHERIT_DEFAULT);
+ header.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, false)));
+
+ configurePart(context, header, lead);
+ configurePart(context, header, center);
+ configurePart(context, header, end);
+ return header;
+ }
+
+ protected void configurePart(Node context, Composite parent, List<CmsUiProvider> partProviders)
+ throws RepositoryException {
+ final int style;
+ final String custom;
+ if (lead == partProviders) {
+ style = SWT.LEAD;
+ custom = CmsStyles.CMS_HEADER_LEAD;
+ } else if (center == partProviders) {
+ style = SWT.CENTER;
+ custom = CmsStyles.CMS_HEADER_CENTER;
+ } else if (end == partProviders) {
+ style = SWT.END;
+ custom = CmsStyles.CMS_HEADER_END;
+ } else {
+ throw new CmsException("Unsupported part providers " + partProviders);
+ }
+
+ Composite part = new Composite(parent, SWT.NONE);
+ part.setData(RWT.CUSTOM_VARIANT, custom);
+ GridData gridData = new GridData(style, SWT.FILL, true, true);
+ part.setLayoutData(gridData);
+ part.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(partProviders.size(), subPartsSameWidth)));
+ for (CmsUiProvider uiProvider : partProviders) {
+ Control subPart = uiProvider.createUi(part, context);
+ subPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ }
+ }
+
+ public void setLead(List<CmsUiProvider> lead) {
+ this.lead = lead;
+ }
+
+ public void setCenter(List<CmsUiProvider> center) {
+ this.center = center;
+ }
+
+ public void setEnd(List<CmsUiProvider> end) {
+ this.end = end;
+ }
+
+ public void setSubPartsSameWidth(Boolean subPartsSameWidth) {
+ this.subPartsSameWidth = subPartsSameWidth;
+ }
+
+ public List<CmsUiProvider> getLead() {
+ return lead;
+ }
+
+ public List<CmsUiProvider> getCenter() {
+ return center;
+ }
+
+ public List<CmsUiProvider> getEnd() {
+ return end;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+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;
+
+public class SimpleDynamicPages implements CmsUiProvider {
+
+ @Override
+ public Control createUi(Composite parent, Node context)
+ throws RepositoryException {
+ if (context == null)
+ throw new CmsException("Context cannot be null");
+ parent.setLayout(new GridLayout(2, false));
+
+ // parent
+ if (!context.getPath().equals("/")) {
+ new CmsLink("..", context.getParent().getPath()).createUi(parent,
+ context);
+ new Label(parent, SWT.NONE).setText(context.getParent()
+ .getPrimaryNodeType().getName());
+ }
+
+ // context
+ Label contextL = new Label(parent, SWT.NONE);
+ contextL.setData(RWT.MARKUP_ENABLED, true);
+ contextL.setText("<b>" + context.getName() + "</b>");
+ new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType()
+ .getName());
+
+ // children
+ // Label childrenL = new Label(parent, SWT.NONE);
+ // childrenL.setData(RWT.MARKUP_ENABLED, true);
+ // childrenL.setText("<i>Children:</i>");
+ // childrenL.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false,
+ // false, 2, 1));
+
+ for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) {
+ Node child = nIt.nextNode();
+ new CmsLink(child.getName(), child.getPath()).createUi(parent,
+ context);
+
+ new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType()
+ .getName());
+ }
+
+ // properties
+ // Label propsL = new Label(parent, SWT.NONE);
+ // propsL.setData(RWT.MARKUP_ENABLED, true);
+ // propsL.setText("<i>Properties:</i>");
+ // propsL.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false,
+ // 2, 1));
+ for (PropertyIterator pIt = context.getProperties(); pIt.hasNext();) {
+ Property property = pIt.nextProperty();
+
+ Label label = new Label(parent, SWT.NONE);
+ label.setText(property.getName());
+ label.setToolTipText(JcrUtils
+ .getPropertyDefinitionAsString(property));
+
+ new Label(parent, SWT.NONE).setText(getPropAsString(property));
+ }
+
+ return null;
+ }
+
+ private String getPropAsString(Property property)
+ throws RepositoryException {
+ String result = "";
+ DateFormat timeFormatter = new SimpleDateFormat("");
+ if (property.isMultiple()) {
+ result = getMultiAsString(property, ", ");
+ } else {
+ Value value = property.getValue();
+ if (value.getType() == PropertyType.BINARY)
+ result = "<binary>";
+ else if (value.getType() == PropertyType.DATE)
+ result = timeFormatter.format(value.getDate().getTime());
+ else
+ result = value.getString();
+ }
+ return result;
+ }
+
+ private String getMultiAsString(Property property, String separator)
+ throws RepositoryException {
+ if (separator == null)
+ separator = "; ";
+ Value[] values = property.getValues();
+ StringBuilder builder = new StringBuilder();
+ for (Value val : values) {
+ String currStr = val.getString();
+ if (!"".equals(currStr.trim()))
+ builder.append(currStr).append(separator);
+ }
+ if (builder.lastIndexOf(separator) >= 0)
+ return builder.substring(0, builder.length() - separator.length());
+ else
+ return builder.toString();
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.AbstractCmsEntryPoint;
+import org.argeo.cms.ui.CmsImageManager;
+import org.argeo.cms.ui.CmsStyles;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.UxContext;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Simple header/body ergonomics. */
+public class SimpleErgonomics extends AbstractCmsEntryPoint {
+ private static final long serialVersionUID = 8743413921359548523L;
+
+ private final static Log log = LogFactory.getLog(SimpleErgonomics.class);
+
+ private boolean uiInitialized = false;
+ private Composite headerArea;
+ private Composite leftArea;
+ private Composite rightArea;
+ private Composite footerArea;
+ private Composite bodyArea;
+ private final CmsUiProvider uiProvider;
+
+ private CmsUiProvider header;
+ private Integer headerHeight = 0;
+ private Integer footerHeight = 0;
+ private CmsUiProvider lead;
+ private CmsUiProvider end;
+ private CmsUiProvider footer;
+
+ private CmsImageManager imageManager = new DefaultImageManager();
+ private UxContext uxContext = null;
+
+ public SimpleErgonomics(Repository repository, String workspace, String defaultPath, CmsUiProvider uiProvider,
+ Map<String, String> factoryProperties) {
+ super(repository, workspace, defaultPath, factoryProperties);
+ this.uiProvider = uiProvider;
+ }
+
+ @Override
+ protected void initUi(Composite parent) {
+ parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, false)));
+
+ uxContext = new SimpleUxContext();
+ if (!getUxContext().isMasterData())
+ createAdminArea(parent);
+ headerArea = new Composite(parent, SWT.NONE);
+ headerArea.setLayout(new FillLayout());
+ GridData headerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
+ headerData.heightHint = headerHeight;
+ headerArea.setLayoutData(headerData);
+
+ // TODO: bi-directional
+ leftArea = new Composite(parent, SWT.NONE);
+ leftArea.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
+ leftArea.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ bodyArea = new Composite(parent, SWT.NONE);
+ bodyArea.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_BODY);
+ bodyArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ bodyArea.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ // TODO: bi-directional
+ rightArea = new Composite(parent, SWT.NONE);
+ rightArea.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
+ rightArea.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ footerArea = new Composite(parent, SWT.NONE);
+ // footerArea.setLayout(new FillLayout());
+ GridData footerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
+ footerData.heightHint = footerHeight;
+ footerArea.setLayoutData(footerData);
+
+ uiInitialized = true;
+ refresh();
+ }
+
+ @Override
+ protected void refresh() {
+ if (!uiInitialized)
+ return;
+ if (getState() == null)
+ setState("");
+ refreshSides();
+ refreshBody();
+ if (log.isTraceEnabled())
+ log.trace("UI refreshed " + getNode());
+ }
+
+ protected void createAdminArea(Composite parent) {
+ }
+
+ @Deprecated
+ protected void refreshHeader() {
+ if (header == null)
+ return;
+
+ for (Control child : headerArea.getChildren())
+ child.dispose();
+ try {
+ header.createUi(headerArea, getNode());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh header", e);
+ }
+ headerArea.layout(true, true);
+ }
+
+ protected void refreshSides() {
+ refresh(headerArea, header, CmsStyles.CMS_HEADER);
+ refresh(leftArea, lead, CmsStyles.CMS_LEAD);
+ refresh(rightArea, end, CmsStyles.CMS_END);
+ refresh(footerArea, footer, CmsStyles.CMS_FOOTER);
+ }
+
+ private void refresh(Composite area, CmsUiProvider uiProvider, String style) {
+ if (uiProvider == null)
+ return;
+
+ for (Control child : area.getChildren())
+ child.dispose();
+ CmsUiUtils.style(area, style);
+ try {
+ uiProvider.createUi(area, getNode());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh header", e);
+ }
+ area.layout(true, true);
+ }
+
+ protected void refreshBody() {
+ // Exception
+ Throwable exception = getException();
+ if (exception != null) {
+ SystemNotifications systemNotifications = new SystemNotifications(bodyArea);
+ systemNotifications.notifyException(exception);
+ resetException();
+ return;
+ // TODO report
+ }
+
+ // clear
+ for (Control child : bodyArea.getChildren())
+ child.dispose();
+ bodyArea.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ try {
+ Node node = getNode();
+// if (node == null)
+// log.error("Context cannot be null");
+// else
+ uiProvider.createUi(bodyArea, node);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh body", e);
+ }
+
+ bodyArea.layout(true, true);
+ }
+
+ @Override
+ public UxContext getUxContext() {
+ return uxContext;
+ }
+
+ @Override
+ public CmsImageManager getImageManager() {
+ return imageManager;
+ }
+
+ public void setHeader(CmsUiProvider header) {
+ this.header = header;
+ }
+
+ public void setHeaderHeight(Integer headerHeight) {
+ this.headerHeight = headerHeight;
+ }
+
+ public void setImageManager(CmsImageManager imageManager) {
+ this.imageManager = imageManager;
+ }
+
+ public CmsUiProvider getLead() {
+ return lead;
+ }
+
+ public void setLead(CmsUiProvider lead) {
+ this.lead = lead;
+ }
+
+ public CmsUiProvider getEnd() {
+ return end;
+ }
+
+ public void setEnd(CmsUiProvider end) {
+ this.end = end;
+ }
+
+ public CmsUiProvider getFooter() {
+ return footer;
+ }
+
+ public void setFooter(CmsUiProvider footer) {
+ this.footer = footer;
+ }
+
+ public CmsUiProvider getHeader() {
+ return header;
+ }
+
+ public void setFooterHeight(Integer footerHeight) {
+ this.footerHeight = footerHeight;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+public class SimpleImageManager extends DefaultImageManager {
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.CmsStyles;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+public class SimpleStaticPage implements CmsUiProvider {
+ private String text;
+
+ @Override
+ public Control createUi(Composite parent, Node context)
+ throws RepositoryException {
+ Label textC = new Label(parent, SWT.WRAP);
+ textC.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_STATIC_TEXT);
+ textC.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
+ textC.setText(text);
+
+ return textC;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import org.argeo.cms.ui.UxContext;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+
+public class SimpleUxContext implements UxContext {
+ private Point size;
+ private Point small = new Point(400, 400);
+
+ public SimpleUxContext() {
+ this(Display.getCurrent().getBounds());
+ }
+
+ public SimpleUxContext(Rectangle rect) {
+ this.size = new Point(rect.width, rect.height);
+ }
+
+ public SimpleUxContext(Point size) {
+ this.size = size;
+ }
+
+ @Override
+ public boolean isPortrait() {
+ return size.x >= size.y;
+ }
+
+ @Override
+ public boolean isLandscape() {
+ return size.x < size.y;
+ }
+
+ @Override
+ public boolean isSquare() {
+ return size.x == size.y;
+ }
+
+ @Override
+ public boolean isSmall() {
+ return size.x <= small.x || size.y <= small.y;
+ }
+
+ @Override
+ public boolean isMasterData() {
+ // TODO make it configurable
+ return true;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.cms.CmsException;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+
+/** {@link ResourceLoader} caching stylesheets. */
+public class StyleSheetResourceLoader implements ResourceLoader {
+ private Bundle themeBundle;
+ private Map<String, StyleSheet> stylesheets = new LinkedHashMap<String, StyleSheet>();
+
+ public StyleSheetResourceLoader(Bundle themeBundle) {
+ this.themeBundle = themeBundle;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ if (!stylesheets.containsKey(resourceName)) {
+ // TODO deal with other bundles
+ // Bundle bundle = bundleContext.getBundle();
+ // String location =
+ // bundle.getLocation().substring("initial@reference:".length());
+ // if (location.startsWith("file:")) {
+ // Path path = null;
+ // try {
+ // path = Paths.get(new URI(location));
+ // } catch (URISyntaxException e) {
+ // e.printStackTrace();
+ // }
+ // if (path != null) {
+ // Path resourcePath = path.resolve(resourceName);
+ // if (Files.exists(resourcePath))
+ // return Files.newInputStream(resourcePath);
+ // }
+ // }
+
+ URL res = themeBundle.getEntry(resourceName);
+ if (res == null)
+ throw new CmsException(
+ "Entry " + resourceName + " not found in bundle " + themeBundle.getSymbolicName());
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ IOUtils.copy(res.openStream(), out);
+ stylesheets.put(resourceName, new StyleSheet(out.toByteArray()));
+ }
+ return new ByteArrayInputStream(stylesheets.get(resourceName).getData());
+ // return res.openStream();
+ }
+
+ private class StyleSheet {
+ private byte[] data;
+
+ public StyleSheet(byte[] data) {
+ super();
+ this.data = data;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsStyles;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/** Shell displaying system notifications such as exceptions */
+public class SystemNotifications extends Shell implements CmsStyles,
+ MouseListener {
+ private static final long serialVersionUID = -8129377525216022683L;
+
+ private Control source;
+
+ public SystemNotifications(Control source) {
+ super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+ setData(RWT.CUSTOM_VARIANT, CMS_USER_MENU);
+
+ this.source = source;
+
+ // TODO UI
+ // setLocation(source.toDisplay(source.getSize().x - getSize().x,
+ // source.getSize().y));
+ setLayout(new GridLayout());
+ addMouseListener(this);
+
+ addShellListener(new ShellAdapter() {
+ private static final long serialVersionUID = 5178980294808435833L;
+
+ @Override
+ public void shellDeactivated(ShellEvent e) {
+ close();
+ dispose();
+ }
+ });
+
+ }
+
+ public void notifyException(Throwable exception) {
+ Composite pane = this;
+
+ Label lbl = new Label(pane, SWT.NONE);
+ lbl.setText(exception.getLocalizedMessage()
+ + (exception instanceof CmsException ? "" : "("
+ + exception.getClass().getName() + ")") + "\n");
+ lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ lbl.addMouseListener(this);
+ if (exception.getCause() != null)
+ appendCause(pane, exception.getCause());
+
+ StringBuilder mailToUrl = new StringBuilder("mailto:?");
+ try {
+ mailToUrl.append("subject=").append(
+ URLEncoder.encode(
+ "Exception "
+ + new SimpleDateFormat("yyyy-MM-dd hh:mm")
+ .format(new Date()), "UTF-8")
+ .replace("+", "%20"));
+
+ StringWriter sw = new StringWriter();
+ exception.printStackTrace(new PrintWriter(sw));
+ IOUtils.closeQuietly(sw);
+
+ // see
+ // http://stackoverflow.com/questions/4737841/urlencoder-not-able-to-translate-space-character
+ String encoded = URLEncoder.encode(sw.toString(), "UTF-8").replace(
+ "+", "%20");
+ mailToUrl.append("&body=").append(encoded);
+ } catch (UnsupportedEncodingException e) {
+ mailToUrl.append("&body=").append("Could not encode: ")
+ .append(e.getMessage());
+ }
+ Label mailTo = new Label(pane, SWT.NONE);
+ CmsUiUtils.markup(mailTo);
+ mailTo.setText("<a href=\"" + mailToUrl + "\">Send details</a>");
+ mailTo.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+
+ pack();
+ layout();
+
+ setLocation(source.toDisplay(source.getSize().x - getSize().x,
+ source.getSize().y - getSize().y));
+ open();
+ }
+
+ private void appendCause(Composite parent, Throwable e) {
+ Label lbl = new Label(parent, SWT.NONE);
+ lbl.setText(" caused by: " + e.getLocalizedMessage() + " ("
+ + e.getClass().getName() + ")" + "\n");
+ lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ lbl.addMouseListener(this);
+ if (e.getCause() != null)
+ appendCause(parent, e.getCause());
+ }
+
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ close();
+ dispose();
+ }
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.rap.rwt.application.Application;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class ThemeUtils {
+ final static Log log = LogFactory.getLog(ThemeUtils.class);
+
+ public static Bundle findThemeBundle(BundleContext bundleContext, String themeId) {
+ if (themeId == null)
+ return null;
+ // TODO optimize
+ // TODO deal with multiple versions
+ Bundle themeBundle = null;
+ if (themeId != null) {
+ for (Bundle bundle : bundleContext.getBundles())
+ if (themeId.equals(bundle.getSymbolicName())) {
+ themeBundle = bundle;
+ break;
+ }
+ }
+ return themeBundle;
+ }
+
+ public static void addThemeResources(Application application, Bundle themeBundle, BundleResourceLoader themeBRL,
+ String pattern) {
+ Enumeration<URL> themeResources = themeBundle.findEntries("/", pattern, true);
+ if (themeResources == null)
+ return;
+ while (themeResources.hasMoreElements()) {
+ String resource = themeResources.nextElement().getPath();
+ // remove first '/' so that RWT registers it
+ resource = resource.substring(1);
+ if (!resource.endsWith("/")) {
+ application.addResource(resource, themeBRL);
+ if (log.isTraceEnabled())
+ log.trace("Registered " + resource + " from theme " + themeBundle);
+ }
+
+ }
+
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.widgets.auth.CmsLoginShell;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/** The site-related user menu */
+public class UserMenu extends CmsLoginShell {
+ private final Control source;
+ private final Node context;
+
+ public UserMenu(Control source, Node context) {
+ super(CmsUiUtils.getCmsView());
+ this.context = context;
+ createUi();
+ if (source == null)
+ throw new CmsException("Source control cannot be null.");
+ this.source = source;
+ open();
+ }
+
+ @Override
+ protected Shell createShell() {
+ return new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+ }
+
+ @Override
+ public void open() {
+ Shell shell = getShell();
+ shell.pack();
+ shell.layout();
+ shell.setLocation(source.toDisplay(source.getSize().x - shell.getSize().x, source.getSize().y));
+ shell.addShellListener(new ShellAdapter() {
+ private static final long serialVersionUID = 5178980294808435833L;
+
+ @Override
+ public void shellDeactivated(ShellEvent e) {
+ closeShell();
+ }
+ });
+ super.open();
+ }
+
+ protected Node getContext() {
+ return context;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.CmsMsg;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsStyles;
+import org.argeo.cms.ui.widgets.auth.CmsLoginShell;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Open the user menu when clicked */
+public class UserMenuLink extends MenuLink {
+
+ public UserMenuLink() {
+ setCustom(CmsStyles.CMS_USER_MENU_LINK);
+ }
+
+ @Override
+ public Control createUi(Composite parent, Node context) {
+ if (CurrentUser.isAnonymous())
+ setLabel(CmsMsg.login.lead());
+ else {
+ setLabel(CurrentUser.getDisplayName());
+ }
+ Label link = (Label) ((Composite) super.createUi(parent, context)).getChildren()[0];
+ link.addMouseListener(new UserMenuLinkController(context));
+ return link.getParent();
+ }
+
+ protected CmsLoginShell createUserMenu(Control source, Node context) {
+ return new UserMenu(source.getParent(), context);
+ }
+
+ private class UserMenuLinkController implements MouseListener, DisposeListener {
+ private static final long serialVersionUID = 3634864186295639792L;
+
+ private CmsLoginShell userMenu = null;
+ private long lastDisposeTS = 0l;
+
+ private final Node context;
+
+ public UserMenuLinkController(Node context) {
+ this.context = context;
+ }
+
+ //
+ // MOUSE LISTENER
+ //
+ @Override
+ public void mouseDown(MouseEvent e) {
+ if (e.button == 1) {
+ Control source = (Control) e.getSource();
+ if (userMenu == null) {
+ long durationSinceLastDispose = System.currentTimeMillis() - lastDisposeTS;
+ // avoid to reopen the menu, if one has clicked gain
+ if (durationSinceLastDispose > 200) {
+ userMenu = createUserMenu(source, context);
+ userMenu.getShell().addDisposeListener(this);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ }
+
+ @Override
+ public void widgetDisposed(DisposeEvent event) {
+ userMenu = null;
+ lastDisposeTS = System.currentTimeMillis();
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+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;
+
+public class VerticalMenu implements CmsUiProvider {
+ private List<CmsUiProvider> items = new ArrayList<CmsUiProvider>();
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ Composite part = new Composite(parent, SWT.NONE);
+ part.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
+// part.setData(RWT.CUSTOM_VARIANT, custom);
+ part.setLayout(CmsUiUtils.noSpaceGridLayout());
+ for (CmsUiProvider uiProvider : items) {
+ Control subPart = uiProvider.createUi(part, context);
+ subPart.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
+ }
+ return part;
+ }
+
+ public void add(CmsUiProvider uiProvider) {
+ items.add(uiProvider);
+ }
+
+ public List<CmsUiProvider> getItems() {
+ return items;
+ }
+
+ public void setItems(List<CmsUiProvider> items) {
+ this.items = items;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.viewers;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsEditable;
+import org.argeo.cms.ui.widgets.ScrolledPage;
+import org.eclipse.jface.viewers.ContentViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Widget;
+import org.xml.sax.SAXParseException;
+
+/** Base class for viewers related to a page */
+public abstract class AbstractPageViewer extends ContentViewer implements Observer {
+ private static final long serialVersionUID = 5438688173410341485L;
+
+ private final static Log log = LogFactory.getLog(AbstractPageViewer.class);
+
+ private final boolean readOnly;
+ /** The basis for the layouts, typically a ScrolledPage. */
+ private final Composite page;
+ private final CmsEditable cmsEditable;
+
+ private MouseListener mouseListener;
+ private FocusListener focusListener;
+
+ private EditablePart edited;
+ private ISelection selection = StructuredSelection.EMPTY;
+
+ private AccessControlContext accessControlContext;
+
+ protected AbstractPageViewer(Section parent, int style, CmsEditable cmsEditable) {
+ // read only at UI level
+ readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
+
+ this.cmsEditable = cmsEditable == null ? CmsEditable.NON_EDITABLE : cmsEditable;
+ if (this.cmsEditable instanceof Observable)
+ ((Observable) this.cmsEditable).addObserver(this);
+
+ if (cmsEditable.canEdit()) {
+ mouseListener = createMouseListener();
+ focusListener = createFocusListener();
+ }
+ page = findPage(parent);
+ accessControlContext = AccessController.getContext();
+ }
+
+ /**
+ * Can be called to simplify the called to isModelInitialized() and initModel()
+ */
+ protected void initModelIfNeeded(Node node) {
+ try {
+ if (!isModelInitialized(node))
+ if (getCmsEditable().canEdit()) {
+ initModel(node);
+ node.getSession().save();
+ }
+ } catch (Exception e) {
+ throw new CmsException("Cannot initialize model", e);
+ }
+ }
+
+ /** Called if user can edit and model is not initialized */
+ protected Boolean isModelInitialized(Node node) throws RepositoryException {
+ return true;
+ }
+
+ /** Called if user can edit and model is not initialized */
+ protected void initModel(Node node) throws RepositoryException {
+ }
+
+ /** Create (retrieve) the MouseListener to use. */
+ protected MouseListener createMouseListener() {
+ return new MouseAdapter() {
+ private static final long serialVersionUID = 1L;
+ };
+ }
+
+ /** Create (retrieve) the FocusListener to use. */
+ protected FocusListener createFocusListener() {
+ return new FocusListener() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void focusLost(FocusEvent event) {
+ }
+
+ @Override
+ public void focusGained(FocusEvent event) {
+ }
+ };
+ }
+
+ protected Composite findPage(Composite composite) {
+ if (composite instanceof ScrolledPage) {
+ return (ScrolledPage) composite;
+ } else {
+ if (composite.getParent() == null)
+ return composite;
+ return findPage(composite.getParent());
+ }
+ }
+
+ @Override
+ public void update(Observable o, Object arg) {
+ if (o == cmsEditable)
+ editingStateChanged(cmsEditable);
+ }
+
+ /** To be overridden in order to provide the actual refresh */
+ protected void refresh(Control control) throws RepositoryException {
+ }
+
+ /** To be overridden.Save the edited part. */
+ protected void save(EditablePart part) throws RepositoryException {
+ }
+
+ /** Prepare the edited part */
+ protected void prepare(EditablePart part, Object caretPosition) {
+ }
+
+ /** Notified when the editing state changed. Does nothing, to be overridden */
+ protected void editingStateChanged(CmsEditable cmsEditable) {
+ }
+
+ @Override
+ public void refresh() {
+ // TODO check actual context in order to notice a discrepancy
+ Subject viewerSubject = getViewerSubject();
+ Subject.doAs(viewerSubject, (PrivilegedAction<Void>) () -> {
+ try {
+ if (cmsEditable.canEdit() && !readOnly)
+ mouseListener = createMouseListener();
+ else
+ mouseListener = null;
+ refresh(getControl());
+ layout(getControl());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh", e);
+ }
+ return null;
+ });
+ }
+
+ @Override
+ public void setSelection(ISelection selection, boolean reveal) {
+ this.selection = selection;
+ }
+
+ protected void updateContent(EditablePart part) throws RepositoryException {
+ }
+
+ // LOW LEVEL EDITION
+ protected void edit(EditablePart part, Object caretPosition) {
+ try {
+ if (edited == part)
+ return;
+
+ if (edited != null && edited != part) {
+ EditablePart previouslyEdited = edited;
+ try {
+ stopEditing(true);
+ } catch (Exception e) {
+ notifyEditionException(e);
+ edit(previouslyEdited, caretPosition);
+ return;
+ }
+ }
+
+ part.startEditing();
+ updateContent(part);
+ prepare(part, caretPosition);
+ edited = part;
+ layout(part.getControl());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot edit " + part, e);
+ }
+ }
+
+ private void stopEditing(Boolean save) throws RepositoryException {
+ if (edited instanceof Widget && ((Widget) edited).isDisposed()) {
+ edited = null;
+ return;
+ }
+
+ assert edited != null;
+ if (edited == null) {
+ if (log.isTraceEnabled())
+ log.warn("Told to stop editing while not editing anything");
+ return;
+ }
+
+ if (save)
+ save(edited);
+
+ edited.stopEditing();
+ updateContent(edited);
+ layout(((EditablePart) edited).getControl());
+ edited = null;
+ }
+
+ // METHODS AVAILABLE TO EXTENDING CLASSES
+ protected void saveEdit() {
+ try {
+ if (edited != null)
+ stopEditing(true);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot stop editing", e);
+ }
+ }
+
+ protected void cancelEdit() {
+ try {
+ if (edited != null)
+ stopEditing(false);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot cancel editing", e);
+ }
+ }
+
+ /** Layout this controls from the related base page. */
+ public void layout(Control... controls) {
+ page.layout(controls);
+ }
+
+ /**
+ * Find the first {@link EditablePart} in the parents hierarchy of this control
+ */
+ protected EditablePart findDataParent(Control parent) {
+ if (parent instanceof EditablePart) {
+ return (EditablePart) parent;
+ }
+ if (parent.getParent() != null)
+ return findDataParent(parent.getParent());
+ else
+ throw new CmsException("No data parent found");
+ }
+
+ // UTILITIES
+ /** Check whether the edited part is in a proper state */
+ protected void checkEdited() {
+ if (edited == null || (edited instanceof Widget) && ((Widget) edited).isDisposed())
+ throw new CmsException("Edited should not be null or disposed at this stage");
+ }
+
+ /** Persist all changes. */
+ protected void persistChanges(Session session) throws RepositoryException {
+ session.save();
+ session.refresh(false);
+ // TODO notify that changes have been persisted
+ }
+
+ /** Convenience method using a Node in order to save the underlying session. */
+ protected void persistChanges(Node anyNode) throws RepositoryException {
+ persistChanges(anyNode.getSession());
+ }
+
+ /** Notify edition exception */
+ protected void notifyEditionException(Throwable e) {
+ Throwable eToLog = e;
+ if (e instanceof IllegalArgumentException)
+ if (e.getCause() instanceof SAXParseException)
+ eToLog = e.getCause();
+ log.error(eToLog.getMessage(), eToLog);
+// if (log.isTraceEnabled())
+// log.trace("Full stack of " + eToLog.getMessage(), e);
+ // TODO Light error notification popup
+ }
+
+ protected Subject getViewerSubject() {
+ Subject res = null;
+ if (accessControlContext != null) {
+ res = Subject.getSubject(accessControlContext);
+ }
+ if (res == null)
+ throw new CmsException("No subject associated with this viewer");
+ return res;
+ }
+
+ // GETTERS / SETTERS
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ protected EditablePart getEdited() {
+ return edited;
+ }
+
+ public MouseListener getMouseListener() {
+ return mouseListener;
+ }
+
+ public FocusListener getFocusListener() {
+ return focusListener;
+ }
+
+ public CmsEditable getCmsEditable() {
+ return cmsEditable;
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return selection;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.viewers;
+
+import org.eclipse.swt.widgets.Control;
+
+public interface EditablePart {
+ public void startEditing();
+
+ public void stopEditing();
+
+ public Control getControl();
+}
--- /dev/null
+package org.argeo.cms.ui.viewers;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+/** An editable part related to a JCR Item */
+public interface ItemPart<T extends Item> {
+ public Item getItem() throws RepositoryException;
+}
--- /dev/null
+package org.argeo.cms.ui.viewers;
+
+import java.util.Observable;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.version.VersionManager;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsEditable;
+import org.argeo.cms.ui.CmsEditionEvent;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/** Provides the CmsEditable semantic based on JCR versioning. */
+public class JcrVersionCmsEditable extends Observable implements CmsEditable {
+ private final String nodePath;// cache
+ private final VersionManager versionManager;
+ private final Boolean canEdit;
+
+ public JcrVersionCmsEditable(Node node) throws RepositoryException {
+ this.nodePath = node.getPath();
+ if (node.getSession().hasPermission(node.getPath(),
+ Session.ACTION_SET_PROPERTY)) {
+ // was Session.ACTION_ADD_NODE
+ canEdit = true;
+ if (!node.isNodeType(NodeType.MIX_VERSIONABLE)) {
+ node.addMixin(NodeType.MIX_VERSIONABLE);
+ node.getSession().save();
+ }
+ versionManager = node.getSession().getWorkspace()
+ .getVersionManager();
+ } else {
+ canEdit = false;
+ versionManager = null;
+ }
+
+ // bind keys
+ if (canEdit) {
+ Display display = Display.getCurrent();
+ display.setData(RWT.ACTIVE_KEYS, new String[] { "CTRL+RETURN",
+ "CTRL+E" });
+ display.addFilter(SWT.KeyDown, new Listener() {
+ private static final long serialVersionUID = -4378653870463187318L;
+
+ public void handleEvent(Event e) {
+ boolean ctrlPressed = (e.stateMask & SWT.CTRL) != 0;
+ if (ctrlPressed && e.keyCode == '\r')
+ stopEditing();
+ else if (ctrlPressed && e.keyCode == 'E')
+ stopEditing();
+ }
+ });
+ }
+ }
+
+ @Override
+ public Boolean canEdit() {
+ return canEdit;
+ }
+
+ public Boolean isEditing() {
+ try {
+ if (!canEdit())
+ return false;
+ return versionManager.isCheckedOut(nodePath);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot check whether " + nodePath
+ + " is editing", e);
+ }
+ }
+
+ @Override
+ public void startEditing() {
+ try {
+ versionManager.checkout(nodePath);
+ setChanged();
+ } catch (RepositoryException e1) {
+ throw new CmsException("Cannot publish " + nodePath);
+ }
+ notifyObservers(new CmsEditionEvent(nodePath,
+ CmsEditionEvent.START_EDITING));
+ }
+
+ @Override
+ public void stopEditing() {
+ try {
+ versionManager.checkin(nodePath);
+ setChanged();
+ } catch (RepositoryException e1) {
+ throw new CmsException("Cannot publish " + nodePath, e1);
+ }
+ notifyObservers(new CmsEditionEvent(nodePath,
+ CmsEditionEvent.STOP_EDITING));
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.viewers;
+
+import javax.jcr.Node;
+
+/** An editable part related to a node */
+public interface NodePart extends ItemPart<Node> {
+ public Node getNode();
+}
--- /dev/null
+package org.argeo.cms.ui.viewers;
+
+import javax.jcr.Property;
+
+/** An editable part related to a JCR Property */
+public interface PropertyPart extends ItemPart<Property> {
+ public Property getProperty();
+}
--- /dev/null
+package org.argeo.cms.ui.viewers;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.widgets.JcrComposite;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+public class Section extends JcrComposite {
+ private static final long serialVersionUID = -5933796173755739207L;
+
+ private final Section parentSection;
+ private Composite sectionHeader;
+ private final Integer relativeDepth;
+
+ public Section(Composite parent, int style, Node node) throws RepositoryException {
+ this(parent, findSection(parent), style, node);
+ }
+
+ public Section(Section section, int style, Node node) throws RepositoryException {
+ this(section, section, style, node);
+ }
+
+ protected Section(Composite parent, Section parentSection, int style, Node node) throws RepositoryException {
+ super(parent, style, node);
+ this.parentSection = parentSection;
+ if (parentSection != null) {
+ relativeDepth = getNode().getDepth() - parentSection.getNode().getDepth();
+ } else {
+ relativeDepth = 0;
+ }
+ setLayout(CmsUiUtils.noSpaceGridLayout());
+ }
+
+ public Map<String, Section> getSubSections() throws RepositoryException {
+ LinkedHashMap<String, Section> result = new LinkedHashMap<String, Section>();
+ for (Control child : getChildren()) {
+ if (child instanceof Composite) {
+ collectDirectSubSections((Composite) child, result);
+ }
+ }
+ return Collections.unmodifiableMap(result);
+ }
+
+ private void collectDirectSubSections(Composite composite, LinkedHashMap<String, Section> subSections)
+ throws RepositoryException {
+ if (composite == sectionHeader || composite instanceof EditablePart)
+ return;
+ if (composite instanceof Section) {
+ Section section = (Section) composite;
+ subSections.put(section.getNodeId(), section);
+ return;
+ }
+
+ for (Control child : composite.getChildren())
+ if (child instanceof Composite)
+ collectDirectSubSections((Composite) child, subSections);
+ }
+
+ public void createHeader() {
+ if (sectionHeader != null)
+ throw new CmsException("Section header was already created");
+
+ sectionHeader = new Composite(this, SWT.NONE);
+ sectionHeader.setLayoutData(CmsUiUtils.fillWidth());
+ sectionHeader.setLayout(CmsUiUtils.noSpaceGridLayout());
+ // sectionHeader.moveAbove(null);
+ // layout();
+ }
+
+ public Composite getHeader() {
+ if (sectionHeader != null && sectionHeader.isDisposed())
+ sectionHeader = null;
+ return sectionHeader;
+ }
+
+ // SECTION PARTS
+ public SectionPart getSectionPart(String partId) {
+ for (Control child : getChildren()) {
+ if (child instanceof SectionPart) {
+ SectionPart paragraph = (SectionPart) child;
+ if (paragraph.getPartId().equals(partId))
+ return paragraph;
+ }
+ }
+ return null;
+ }
+
+ public SectionPart nextSectionPart(SectionPart sectionPart) {
+ Control[] children = getChildren();
+ for (int i = 0; i < children.length; i++) {
+ if (sectionPart == children[i])
+ if (i + 1 < children.length) {
+ Composite next = (Composite) children[i + 1];
+ return (SectionPart) next;
+ } else {
+ // next section
+ }
+ }
+ return null;
+ }
+
+ public SectionPart previousSectionPart(SectionPart sectionPart) {
+ Control[] children = getChildren();
+ for (int i = 0; i < children.length; i++) {
+ if (sectionPart == children[i])
+ if (i != 0) {
+ Composite previous = (Composite) children[i - 1];
+ return (SectionPart) previous;
+ } else {
+ // previous section
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ if (parentSection == null)
+ return "Main section " + getNode();
+ return "Section " + getNode();
+ }
+
+ public Section getParentSection() {
+ return parentSection;
+ }
+
+ public Integer getRelativeDepth() {
+ return relativeDepth;
+ }
+
+ /** Recursively finds the related section in the parents (can be itself) */
+ public static Section findSection(Control control) {
+ if (control == null)
+ return null;
+ if (control instanceof Section)
+ return (Section) control;
+ else
+ return findSection(control.getParent());
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.viewers;
+
+
+/** An editable part dynamically related to a Section */
+public interface SectionPart extends EditablePart, NodePart {
+ public String getPartId();
+
+ public Section getSection();
+}
--- /dev/null
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** A stylable and editable image. */
+public abstract class EditableImage extends StyledControl {
+ private static final long serialVersionUID = -5689145523114022890L;
+ private final static Log log = LogFactory.getLog(EditableImage.class);
+
+ private Point preferredImageSize;
+ private Boolean loaded = false;
+
+ public EditableImage(Composite parent, int swtStyle) {
+ super(parent, swtStyle);
+ }
+
+ public EditableImage(Composite parent, int swtStyle,
+ Point preferredImageSize) {
+ super(parent, swtStyle);
+ this.preferredImageSize = preferredImageSize;
+ }
+
+ public EditableImage(Composite parent, int style, Node node,
+ boolean cacheImmediately, Point preferredImageSize)
+ throws RepositoryException {
+ super(parent, style, node, cacheImmediately);
+ this.preferredImageSize = preferredImageSize;
+ }
+
+ @Override
+ protected void setContainerLayoutData(Composite composite) {
+ // composite.setLayoutData(fillWidth());
+ }
+
+ @Override
+ protected void setControlLayoutData(Control control) {
+ // control.setLayoutData(fillWidth());
+ }
+
+ /** To be overriden. */
+ protected String createImgTag() throws RepositoryException {
+ return CmsUiUtils.noImg(preferredImageSize != null ? preferredImageSize
+ : getSize());
+ }
+
+ protected Label createLabel(Composite box, String style) {
+ Label lbl = new Label(box, getStyle());
+ // lbl.setLayoutData(CmsUiUtils.fillWidth());
+ CmsUiUtils.markup(lbl);
+ CmsUiUtils.style(lbl, style);
+ if (mouseListener != null)
+ lbl.addMouseListener(mouseListener);
+ load(lbl);
+ return lbl;
+ }
+
+ /** To be overriden. */
+ protected synchronized Boolean load(Control control) {
+ String imgTag;
+ try {
+ imgTag = createImgTag();
+ } catch (Exception e) {
+ // throw new CmsException("Cannot retrieve image", e);
+ log.error("Cannot retrieve image", e);
+ imgTag = CmsUiUtils.noImg(preferredImageSize);
+ loaded = false;
+ }
+
+ if (imgTag == null) {
+ loaded = false;
+ imgTag = CmsUiUtils.noImg(preferredImageSize);
+ } else
+ loaded = true;
+ if (control != null) {
+ ((Label) control).setText(imgTag);
+ control.setSize(preferredImageSize != null ? preferredImageSize
+ : getSize());
+ } else {
+ loaded = false;
+ }
+ getParent().layout();
+ return loaded;
+ }
+
+ public void setPreferredSize(Point size) {
+ this.preferredImageSize = size;
+ if (!loaded) {
+ load((Label) getControl());
+ }
+ }
+
+ protected Text createText(Composite box, String style) {
+ Text text = new Text(box, getStyle());
+ CmsUiUtils.style(text, style);
+ return text;
+ }
+
+ public Point getPreferredImageSize() {
+ return preferredImageSize;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+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.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Editable text part displaying styled text. */
+public class EditableText extends StyledControl {
+ private static final long serialVersionUID = -6372283442330912755L;
+
+ public EditableText(Composite parent, int swtStyle) {
+ super(parent, swtStyle);
+ }
+
+ public EditableText(Composite parent, int style, Item item)
+ throws RepositoryException {
+ this(parent, style, item, false);
+ }
+
+ public EditableText(Composite parent, int style, Item item,
+ boolean cacheImmediately) throws RepositoryException {
+ super(parent, style, item, cacheImmediately);
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ if (isEditing())
+ return createText(box, style);
+ else
+ return createLabel(box, style);
+ }
+
+ protected Label createLabel(Composite box, String style) {
+ Label lbl = new Label(box, getStyle() | SWT.WRAP);
+ lbl.setLayoutData(CmsUiUtils.fillWidth());
+ CmsUiUtils.style(lbl, style);
+ CmsUiUtils.markup(lbl);
+ if (mouseListener != null)
+ lbl.addMouseListener(mouseListener);
+ return lbl;
+ }
+
+ protected Text createText(Composite box, String style) {
+ final Text text = new Text(box, getStyle() | SWT.MULTI | SWT.WRAP);
+ GridData textLayoutData = CmsUiUtils.fillWidth();
+ // textLayoutData.heightHint = preferredHeight;
+ text.setLayoutData(textLayoutData);
+ CmsUiUtils.style(text, style);
+ text.setFocus();
+ return text;
+ }
+
+ public void setText(String text) {
+ Control child = getControl();
+ if (child instanceof Label)
+ ((Label) child).setText(text);
+ else if (child instanceof Text)
+ ((Text) child).setText(text);
+ }
+
+ public Text getAsText() {
+ return (Text) getControl();
+ }
+
+ public Label getAsLabel() {
+ return (Label) getControl();
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsImageManager;
+import org.argeo.cms.ui.internal.JcrFileUploadReceiver;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.NodePart;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.cms.ui.viewers.SectionPart;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadListener;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+import org.eclipse.rap.rwt.service.ServerPushSession;
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** An image within the Argeo Text framework */
+public class Img extends EditableImage implements SectionPart, NodePart {
+ private static final long serialVersionUID = 6233572783968188476L;
+
+ private final Section section;
+
+ private final CmsImageManager imageManager;
+ private FileUploadHandler currentUploadHandler = null;
+ private FileUploadListener fileUploadListener;
+
+ public Img(Composite parent, int swtStyle, Node imgNode,
+ Point preferredImageSize) throws RepositoryException {
+ this(Section.findSection(parent), parent, swtStyle, imgNode,
+ preferredImageSize);
+ setStyle(TextStyles.TEXT_IMAGE);
+ }
+
+ public Img(Composite parent, int swtStyle, Node imgNode)
+ throws RepositoryException {
+ this(Section.findSection(parent), parent, swtStyle, imgNode, null);
+ setStyle(TextStyles.TEXT_IMAGE);
+ }
+
+ Img(Section section, Composite parent, int swtStyle, Node imgNode,
+ Point preferredImageSize) throws RepositoryException {
+ super(parent, swtStyle, imgNode, false, preferredImageSize);
+ this.section = section;
+ imageManager = CmsUiUtils.getCmsView().getImageManager();
+ CmsUiUtils.style(this, TextStyles.TEXT_IMG);
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ if (isEditing()) {
+ try {
+ return createImageChooser(box, style);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot create image chooser", e);
+ }
+ } else {
+ return createLabel(box, style);
+ }
+ }
+
+ @Override
+ public synchronized void stopEditing() {
+ super.stopEditing();
+ fileUploadListener = null;
+ }
+
+ @Override
+ protected synchronized Boolean load(Control lbl) {
+ try {
+ Node imgNode = getNode();
+ boolean loaded = imageManager.load(imgNode, lbl,
+ getPreferredImageSize());
+ // getParent().layout();
+ return loaded;
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot load " + getNodeId()
+ + " from image manager", e);
+ }
+ }
+
+ protected Control createImageChooser(Composite box, String style)
+ throws RepositoryException {
+ // FileDialog fileDialog = new FileDialog(getShell());
+ // fileDialog.open();
+ // String fileName = fileDialog.getFileName();
+ CmsImageManager imageManager = CmsUiUtils.getCmsView().getImageManager();
+ Node node = getNode();
+ JcrFileUploadReceiver receiver = new JcrFileUploadReceiver(
+ node.getParent(), node.getName() + '[' + node.getIndex() + ']',
+ imageManager);
+ if (currentUploadHandler != null)
+ currentUploadHandler.dispose();
+ currentUploadHandler = prepareUpload(receiver);
+ final ServerPushSession pushSession = new ServerPushSession();
+ final FileUpload fileUpload = new FileUpload(box, SWT.NONE);
+ CmsUiUtils.style(fileUpload, style);
+ fileUpload.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -9158471843941668562L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ pushSession.start();
+ fileUpload.submit(currentUploadHandler.getUploadUrl());
+ }
+ });
+ return fileUpload;
+ }
+
+ protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) {
+ final FileUploadHandler uploadHandler = new FileUploadHandler(receiver);
+ if (fileUploadListener != null)
+ uploadHandler.addUploadListener(fileUploadListener);
+ return uploadHandler;
+ }
+
+ @Override
+ public Section getSection() {
+ return section;
+ }
+
+ public void setFileUploadListener(FileUploadListener fileUploadListener) {
+ this.fileUploadListener = fileUploadListener;
+ if (currentUploadHandler != null)
+ currentUploadHandler.addUploadListener(fileUploadListener);
+ }
+
+ @Override
+ public Node getItem() throws RepositoryException {
+ return getNode();
+ }
+
+ @Override
+ public String getPartId() {
+ return getNodeId();
+ }
+
+ @Override
+ public String toString() {
+ return "Img #" + getPartId();
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+
+/** A composite which can (optionally) manage a JCR Item. */
+public class JcrComposite extends Composite {
+ private static final long serialVersionUID = -1447009015451153367L;
+
+ private final Session session;
+
+ private String nodeId;
+ private String property = null;
+ private Node cache;
+
+ /** Regular composite constructor. No layout is set. */
+ public JcrComposite(Composite parent, int style) {
+ super(parent, style);
+ session = null;
+ nodeId = null;
+ }
+
+ public JcrComposite(Composite parent, int style, Item item)
+ throws RepositoryException {
+ this(parent, style, item, false);
+ }
+
+ public JcrComposite(Composite parent, int style, Item item,
+ boolean cacheImmediately) throws RepositoryException {
+ super(parent, style);
+ this.session = item.getSession();
+ if (!cacheImmediately && (SWT.READ_ONLY == (style & SWT.READ_ONLY))) {
+ // (useless?) optimization: we only save a pointer to the session,
+ // not even a reference to the item
+ this.nodeId = null;
+ } else {
+ Node node;
+ Property property = null;
+ if (item instanceof Node) {
+ node = (Node) item;
+ } else {// Property
+ property = (Property) item;
+ if (property.isMultiple())// TODO manage property index
+ throw new CmsException(
+ "Multiple properties not supported yet.");
+ this.property = property.getName();
+ node = property.getParent();
+ }
+ this.nodeId = node.getIdentifier();
+ if (cacheImmediately)
+ this.cache = node;
+ }
+ setLayout(CmsUiUtils.noSpaceGridLayout());
+ }
+
+ public synchronized Node getNode() {
+ try {
+ if (!itemIsNode())
+ throw new CmsException("Item is not a Node");
+ return getNodeInternal();
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot get node " + nodeId, e);
+ }
+ }
+
+ private synchronized Node getNodeInternal() throws RepositoryException {
+ if (cache != null)
+ return cache;
+ else if (session != null)
+ if (nodeId != null)
+ return session.getNodeByIdentifier(nodeId);
+ else
+ return null;
+ else
+ return null;
+ }
+
+ public synchronized Property getProperty() {
+ try {
+ if (itemIsNode())
+ throw new CmsException("Item is not a Property");
+ Node node = getNodeInternal();
+ if (!node.hasProperty(property))
+ throw new CmsException("Property " + property
+ + " is not set on " + node);
+ return node.getProperty(property);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot get property " + property
+ + " from node " + nodeId, e);
+ }
+ }
+
+ public synchronized Boolean itemIsNode() {
+ return property == null;
+ }
+
+ /** Set/update the cache or change the node */
+ public synchronized void setNode(Node node) throws RepositoryException {
+ if (!itemIsNode())
+ throw new CmsException("Cannot set a Node on a Property");
+
+ if (node == null) {// clear cache
+ this.cache = null;
+ return;
+ }
+
+ if (session == null || session != node.getSession())// check session
+ throw new CmsException("Uncompatible session");
+
+ if (nodeId == null || !nodeId.equals(node.getIdentifier())) {
+ nodeId = node.getIdentifier();
+ cache = node;
+ itemUpdated();
+ } else {
+ cache = node;// set/update cache
+ }
+ }
+
+ /** Set/update the cache or change the property */
+ public synchronized void setProperty(Property prop)
+ throws RepositoryException {
+ if (itemIsNode())
+ throw new CmsException("Cannot set a Property on a Node");
+
+ if (prop == null) {// clear cache
+ this.cache = null;
+ return;
+ }
+
+ if (session == null || session != prop.getSession())// check session
+ throw new CmsException("Uncompatible session");
+
+ Node node = prop.getNode();
+ if (nodeId == null || !nodeId.equals(node.getIdentifier())
+ || !property.equals(prop.getName())) {
+ nodeId = node.getIdentifier();
+ property = prop.getName();
+ cache = node;
+ itemUpdated();
+ } else {
+ cache = node;// set/update cache
+ }
+ }
+
+ public synchronized String getNodeId() {
+ return nodeId;
+ }
+
+ /** Change the node, does nothing if same. */
+ public synchronized void setNodeId(String nodeId)
+ throws RepositoryException {
+ if (this.nodeId != null && this.nodeId.equals(nodeId))
+ return;
+ this.nodeId = nodeId;
+ if (cache != null)
+ cache = session.getNodeByIdentifier(this.nodeId);
+ itemUpdated();
+ }
+
+ protected synchronized void itemUpdated() {
+ layout();
+ }
+
+ public Session getSession() {
+ return session;
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * A composite that can be scrolled vertically. It wraps a
+ * {@link ScrolledComposite} (and is being wrapped by it), simplifying its
+ * configuration.
+ */
+public class ScrolledPage extends Composite {
+ private static final long serialVersionUID = 1593536965663574437L;
+
+ private ScrolledComposite scrolledComposite;
+
+ public ScrolledPage(Composite parent, int style) {
+ super(new ScrolledComposite(parent, SWT.V_SCROLL), style);
+ scrolledComposite = (ScrolledComposite) getParent();
+ scrolledComposite.setContent(this);
+
+ scrolledComposite.setExpandVertical(true);
+ scrolledComposite.setExpandHorizontal(true);
+ scrolledComposite.addControlListener(new ScrollControlListener());
+ }
+
+ @Override
+ public void layout(boolean changed, boolean all) {
+ updateScroll();
+ super.layout(changed, all);
+ }
+
+ protected void updateScroll() {
+ Rectangle r = scrolledComposite.getClientArea();
+ Point preferredSize = computeSize(r.width, SWT.DEFAULT);
+ scrolledComposite.setMinHeight(preferredSize.y);
+ }
+
+ // public ScrolledComposite getScrolledComposite() {
+ // return this.scrolledComposite;
+ // }
+
+ /** Set it on the wrapping scrolled composite */
+ @Override
+ public void setLayoutData(Object layoutData) {
+ scrolledComposite.setLayoutData(layoutData);
+ }
+
+ private class ScrollControlListener extends
+ org.eclipse.swt.events.ControlAdapter {
+ private static final long serialVersionUID = -3586986238567483316L;
+
+ public void controlResized(ControlEvent e) {
+ updateScroll();
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.CmsConstants;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Editable text part displaying styled text. */
+public abstract class StyledControl extends JcrComposite implements CmsConstants {
+ private static final long serialVersionUID = -6372283442330912755L;
+ private Control control;
+
+ private Composite container;
+ private Composite box;
+
+ protected MouseListener mouseListener;
+ protected FocusListener focusListener;
+
+ private Boolean editing = Boolean.FALSE;
+
+ public StyledControl(Composite parent, int swtStyle) {
+ super(parent, swtStyle);
+ setLayout(CmsUiUtils.noSpaceGridLayout());
+ }
+
+ public StyledControl(Composite parent, int style, Item item) throws RepositoryException {
+ super(parent, style, item);
+ }
+
+ public StyledControl(Composite parent, int style, Item item, boolean cacheImmediately) throws RepositoryException {
+ super(parent, style, item, cacheImmediately);
+ }
+
+ protected abstract Control createControl(Composite box, String style);
+
+ protected Composite createBox(Composite parent) {
+ Composite box = new Composite(parent, SWT.INHERIT_DEFAULT);
+ setContainerLayoutData(box);
+ box.setLayout(CmsUiUtils.noSpaceGridLayout());
+ // new Label(box, SWT.NONE).setText("BOX");
+ return box;
+ }
+
+ public Control getControl() {
+ return control;
+ }
+
+ protected synchronized Boolean isEditing() {
+ return editing;
+ }
+
+ public synchronized void startEditing() {
+ assert !isEditing();
+ editing = true;
+ // int height = control.getSize().y;
+ String style = (String) control.getData(STYLE);
+ clear(false);
+ control = createControl(box, style);
+ setControlLayoutData(control);
+
+ // add the focus listener to the newly created edition control
+ if (focusListener != null)
+ control.addFocusListener(focusListener);
+ }
+
+ public synchronized void stopEditing() {
+ assert isEditing();
+ editing = false;
+ String style = (String) control.getData(STYLE);
+ clear(false);
+ control = createControl(box, style);
+ setControlLayoutData(control);
+ }
+
+ public void setStyle(String style) {
+ Object currentStyle = null;
+ if (control != null)
+ currentStyle = control.getData(STYLE);
+ if (currentStyle != null && currentStyle.equals(style))
+ return;
+
+ // Integer preferredHeight = control != null ? control.getSize().y :
+ // null;
+ clear(true);
+ control = createControl(box, style);
+ setControlLayoutData(control);
+
+ control.getParent().setData(STYLE, style + "_box");
+ control.getParent().getParent().setData(STYLE, style + "_container");
+ }
+
+ /** To be overridden */
+ protected void setControlLayoutData(Control control) {
+ control.setLayoutData(CmsUiUtils.fillWidth());
+ }
+
+ /** To be overridden */
+ protected void setContainerLayoutData(Composite composite) {
+ composite.setLayoutData(CmsUiUtils.fillWidth());
+ }
+
+ protected void clear(boolean deep) {
+ if (deep) {
+ for (Control control : getChildren())
+ control.dispose();
+ container = createBox(this);
+ box = createBox(container);
+ } else {
+ control.dispose();
+ }
+ }
+
+ public void setMouseListener(MouseListener mouseListener) {
+ if (this.mouseListener != null && control != null)
+ control.removeMouseListener(this.mouseListener);
+ this.mouseListener = mouseListener;
+ if (control != null && this.mouseListener != null)
+ control.addMouseListener(mouseListener);
+ }
+
+ public void setFocusListener(FocusListener focusListener) {
+ if (this.focusListener != null && control != null)
+ control.removeFocusListener(this.focusListener);
+ this.focusListener = focusListener;
+ if (control != null && this.focusListener != null)
+ control.addFocusListener(focusListener);
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.widgets;
+
+/** Styles references in the CSS. */
+public interface TextStyles {
+ /** The whole page area */
+ public final static String TEXT_AREA = "text_area";
+ /** Area providing controls for editing text */
+ public final static String TEXT_EDITOR_HEADER = "text_editor_header";
+ /** The styled composite for editing the text */
+ public final static String TEXT_STYLED_COMPOSITE = "text_styled_composite";
+ /** A section */
+ public final static String TEXT_SECTION = "text_section";
+ /** A paragraph */
+ public final static String TEXT_PARAGRAPH = "text_paragraph";
+ /** An image */
+ public final static String TEXT_IMG = "text_img";
+ /** The dialog to edit styled paragraph */
+ public final static String TEXT_STYLED_TOOLS_DIALOG = "text_styled_tools_dialog";
+
+ /*
+ * DEFAULT TEXT STYLES
+ */
+ /** Default style for text body */
+ public final static String TEXT_DEFAULT = "text_default";
+ /** Fixed-width, typically code */
+ public final static String TEXT_PRE = "text_pre";
+ /** Quote */
+ public final static String TEXT_QUOTE = "text_quote";
+ /** Title */
+ public final static String TEXT_TITLE = "text_title";
+ /** Header (to be dynamically completed with the depth, e.g. text_h1) */
+ public final static String TEXT_H = "text_h";
+
+ /** Default style for images */
+ public final static String TEXT_IMAGE = "text_image";
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.cms.ui.widgets.auth;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.operation.ModalContext;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.osgi.framework.FrameworkUtil;
+
+/** Base for login dialogs */
+public abstract class AbstractLoginDialog extends TrayDialog implements CallbackHandler {
+ private static final long serialVersionUID = -8046708963512717709L;
+
+ private final static Log log = LogFactory.getLog(AbstractLoginDialog.class);
+
+ private Thread modalContextThread = null;
+ boolean processCallbacks = false;
+ boolean isCancelled = false;
+ Callback[] callbackArray;
+
+ protected final Callback[] getCallbacks() {
+ return this.callbackArray;
+ }
+
+ public abstract void internalHandle();
+
+ public boolean isCancelled() {
+ return isCancelled;
+ }
+
+ protected AbstractLoginDialog(Shell parentShell) {
+ super(parentShell);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth
+ * .callback.Callback[])
+ */
+ public void handle(final Callback[] callbacks) throws IOException {
+ // clean previous usage
+ if (processCallbacks) {
+ // this handler was already used
+ processCallbacks = false;
+ }
+
+ if (modalContextThread != null) {
+ try {
+ modalContextThread.join(1000);
+ } catch (InterruptedException e) {
+ // silent
+ }
+ modalContextThread = null;
+ }
+
+ // initialize
+ this.callbackArray = callbacks;
+ final Display display = Display.getDefault();
+ display.syncExec(new Runnable() {
+
+ public void run() {
+ isCancelled = false;
+ setBlockOnOpen(false);
+ open();
+
+ final Button okButton = getButton(IDialogConstants.OK_ID);
+ okButton.setText("Login");
+ okButton.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = -200281625679096775L;
+
+ public void widgetSelected(final SelectionEvent event) {
+ processCallbacks = true;
+ }
+
+ public void widgetDefaultSelected(final SelectionEvent event) {
+ // nothing to do
+ }
+ });
+ final Button cancel = getButton(IDialogConstants.CANCEL_ID);
+ cancel.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = -3826030278084915815L;
+
+ public void widgetSelected(final SelectionEvent event) {
+ isCancelled = true;
+ processCallbacks = true;
+ }
+
+ public void widgetDefaultSelected(final SelectionEvent event) {
+ // nothing to do
+ }
+ });
+ }
+ });
+ try {
+ ModalContext.setAllowReadAndDispatch(true); // Works for now.
+ ModalContext.run(new IRunnableWithProgress() {
+
+ public void run(final IProgressMonitor monitor) {
+ modalContextThread = Thread.currentThread();
+ // Wait here until OK or cancel is pressed, then let it rip.
+ // The event
+ // listener
+ // is responsible for closing the dialog (in the
+ // loginSucceeded
+ // event).
+ while (!processCallbacks && (modalContextThread != null)
+ && (modalContextThread == Thread.currentThread())
+ && FrameworkUtil.getBundle(AbstractLoginDialog.class).getBundleContext() != null) {
+ // Note: SecurityUiPlugin.getDefault() != null is false
+ // when the OSGi runtime is shut down
+ try {
+ Thread.sleep(100);
+ // if (display.isDisposed()) {
+ // log.warn("Display is disposed, killing login
+ // dialog thread");
+ // throw new ThreadDeath();
+ // }
+ } catch (final Exception e) {
+ // do nothing
+ }
+ }
+ processCallbacks = false;
+ // Call the adapter to handle the callbacks
+ if (!isCancelled())
+ internalHandle();
+ else
+ // clear callbacks are when cancelling
+ for (Callback callback : callbacks)
+ if (callback instanceof PasswordCallback) {
+ char[] arr = ((PasswordCallback) callback).getPassword();
+ if (arr != null) {
+ Arrays.fill(arr, '*');
+ ((PasswordCallback) callback).setPassword(null);
+ }
+ } else if (callback instanceof NameCallback)
+ ((NameCallback) callback).setName(null);
+ }
+ }, true, new NullProgressMonitor(), Display.getDefault());
+ } catch (ThreadDeath e) {
+ isCancelled = true;
+ log.debug("Thread " + Thread.currentThread().getId() + " died");
+ throw e;
+ } catch (Exception e) {
+ isCancelled = true;
+ IOException ioe = new IOException("Unexpected issue in login dialog, see root cause for more details");
+ ioe.initCause(e);
+ throw ioe;
+ } finally {
+ // so that the modal thread dies
+ processCallbacks = true;
+ // try {
+ // // wait for the modal context thread to gracefully exit
+ // modalContextThread.join();
+ // } catch (InterruptedException ie) {
+ // // silent
+ // }
+ modalContextThread = null;
+ }
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText("Authentication");
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.widgets.auth;
+
+import static org.argeo.cms.CmsMsg.password;
+import static org.argeo.cms.CmsMsg.username;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeState;
+import org.argeo.cms.CmsMsg;
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.auth.HttpRequestCallback;
+import org.argeo.cms.ui.CmsStyles;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.internal.Activator;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+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.Shell;
+import org.eclipse.swt.widgets.Text;
+
+public class CmsLogin implements CmsStyles, CallbackHandler {
+ private final static Log log = LogFactory.getLog(CmsLogin.class);
+
+ private Composite parent;
+ private Text usernameT, passwordT;
+ private Composite credentialsBlock;
+ private final SelectionListener loginSelectionListener;
+
+ private final Locale defaultLocale;
+ private LocaleChoice localeChoice = null;
+
+ private final CmsView cmsView;
+
+ // optional subject to be set explicitly
+ private Subject subject = null;
+
+ public CmsLogin(CmsView cmsView) {
+ this.cmsView = cmsView;
+ NodeState nodeState = Activator.getNodeState();
+ if (nodeState != null) {
+ defaultLocale = nodeState.getDefaultLocale();
+ List<Locale> locales = nodeState.getLocales();
+ if (locales != null)
+ localeChoice = new LocaleChoice(locales, defaultLocale);
+ } else {
+ defaultLocale = Locale.getDefault();
+ }
+ loginSelectionListener = new SelectionListener() {
+ private static final long serialVersionUID = -8832133363830973578L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ login();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ };
+ }
+
+ protected boolean isAnonymous() {
+ return cmsView.isAnonymous();
+ }
+
+ public final void createUi(Composite parent) {
+ this.parent = parent;
+ createContents(parent);
+ }
+
+ protected void createContents(Composite parent) {
+ defaultCreateContents(parent);
+ }
+
+ public final void defaultCreateContents(Composite parent) {
+ parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+ Composite credentialsBlock = createCredentialsBlock(parent);
+ if (parent instanceof Shell) {
+ credentialsBlock.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+ }
+ }
+
+ public final Composite createCredentialsBlock(Composite parent) {
+ if (isAnonymous()) {
+ return anonymousUi(parent);
+ } else {
+ return userUi(parent);
+ }
+ }
+
+ protected Composite getCredentialsBlock() {
+ return credentialsBlock;
+ }
+
+ protected Composite userUi(Composite parent) {
+ Locale locale = localeChoice == null ? this.defaultLocale : localeChoice.getSelectedLocale();
+ credentialsBlock = new Composite(parent, SWT.NONE);
+ credentialsBlock.setLayout(new GridLayout());
+ // credentialsBlock.setLayoutData(CmsUiUtils.fillAll());
+
+ specificUserUi(credentialsBlock);
+
+ Label l = new Label(credentialsBlock, SWT.NONE);
+ CmsUiUtils.style(l, CMS_USER_MENU_ITEM);
+ l.setText(CmsMsg.logout.lead(locale));
+ GridData lData = CmsUiUtils.fillWidth();
+ lData.widthHint = 120;
+ l.setLayoutData(lData);
+
+ l.addMouseListener(new MouseAdapter() {
+ private static final long serialVersionUID = 6444395812777413116L;
+
+ public void mouseDown(MouseEvent e) {
+ logout();
+ }
+ });
+ return credentialsBlock;
+ }
+
+ /** To be overridden */
+ protected void specificUserUi(Composite parent) {
+
+ }
+
+ protected Composite anonymousUi(Composite parent) {
+ Locale locale = localeChoice == null ? this.defaultLocale : localeChoice.getSelectedLocale();
+ // We need a composite for the traversal
+ credentialsBlock = new Composite(parent, SWT.NONE);
+ credentialsBlock.setLayout(new GridLayout());
+ // credentialsBlock.setLayoutData(CmsUiUtils.fillAll());
+ CmsUiUtils.style(credentialsBlock, CMS_LOGIN_DIALOG);
+
+ Integer textWidth = 120;
+ if (parent instanceof Shell)
+ CmsUiUtils.style(parent, CMS_USER_MENU);
+ // new Label(this, SWT.NONE).setText(CmsMsg.username.lead());
+ usernameT = new Text(credentialsBlock, SWT.BORDER);
+ usernameT.setMessage(username.lead(locale));
+ CmsUiUtils.style(usernameT, CMS_LOGIN_DIALOG_USERNAME);
+ GridData gd = CmsUiUtils.fillWidth();
+ gd.widthHint = textWidth;
+ usernameT.setLayoutData(gd);
+
+ // new Label(this, SWT.NONE).setText(CmsMsg.password.lead());
+ passwordT = new Text(credentialsBlock, SWT.BORDER | SWT.PASSWORD);
+ passwordT.setMessage(password.lead(locale));
+ CmsUiUtils.style(passwordT, CMS_LOGIN_DIALOG_PASSWORD);
+ gd = CmsUiUtils.fillWidth();
+ gd.widthHint = textWidth;
+ passwordT.setLayoutData(gd);
+
+ TraverseListener tl = new TraverseListener() {
+ private static final long serialVersionUID = -1158892811534971856L;
+
+ public void keyTraversed(TraverseEvent e) {
+ if (e.detail == SWT.TRAVERSE_RETURN)
+ login();
+ }
+ };
+ credentialsBlock.addTraverseListener(tl);
+ usernameT.addTraverseListener(tl);
+ passwordT.addTraverseListener(tl);
+ parent.setTabList(new Control[] { credentialsBlock });
+ credentialsBlock.setTabList(new Control[] { usernameT, passwordT });
+
+ // Button
+ Button loginButton = new Button(credentialsBlock, SWT.PUSH);
+ loginButton.setText(CmsMsg.login.lead(locale));
+ loginButton.setLayoutData(CmsUiUtils.fillWidth());
+ loginButton.addSelectionListener(loginSelectionListener);
+
+ extendsCredentialsBlock(credentialsBlock, locale, loginSelectionListener);
+ if (localeChoice != null)
+ createLocalesBlock(credentialsBlock);
+ return credentialsBlock;
+ }
+
+ /**
+ * To be overridden in order to provide custom login button and other links.
+ */
+ protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale,
+ SelectionListener loginSelectionListener) {
+
+ }
+
+ protected void updateLocale(Locale selectedLocale) {
+ // save already entered values
+ String usernameStr = usernameT.getText();
+ char[] pwd = passwordT.getTextChars();
+
+ for (Control child : parent.getChildren())
+ child.dispose();
+ createContents(parent);
+ if (parent.getParent() != null)
+ parent.getParent().layout();
+ else
+ parent.layout();
+ usernameT.setText(usernameStr);
+ passwordT.setTextChars(pwd);
+ }
+
+ protected Composite createLocalesBlock(final Composite parent) {
+ Composite c = new Composite(parent, SWT.NONE);
+ CmsUiUtils.style(c, CMS_USER_MENU_ITEM);
+ c.setLayout(CmsUiUtils.noSpaceGridLayout());
+ c.setLayoutData(CmsUiUtils.fillAll());
+
+ SelectionListener selectionListener = new SelectionAdapter() {
+ private static final long serialVersionUID = 4891637813567806762L;
+
+ public void widgetSelected(SelectionEvent event) {
+ Button button = (Button) event.widget;
+ if (button.getSelection()) {
+ localeChoice.setSelectedIndex((Integer) event.widget.getData());
+ updateLocale(localeChoice.getSelectedLocale());
+ }
+ };
+ };
+
+ List<Locale> locales = localeChoice.getLocales();
+ for (Integer i = 0; i < locales.size(); i++) {
+ Locale locale = locales.get(i);
+ Button button = new Button(c, SWT.RADIO);
+ CmsUiUtils.style(button, CMS_USER_MENU_ITEM);
+ button.setData(i);
+ button.setText(LocaleUtils.lead(locale.getDisplayName(locale), locale) + " (" + locale + ")");
+ // button.addListener(SWT.Selection, listener);
+ button.addSelectionListener(selectionListener);
+ if (i == localeChoice.getSelectedIndex())
+ button.setSelection(true);
+ }
+ return c;
+ }
+
+ protected boolean login() {
+ // TODO use CmsVie in order to retrieve subject?
+ // Subject subject = cmsView.getLoginContext().getSubject();
+ // LoginContext loginContext = cmsView.getLoginContext();
+ try {
+ //
+ // LOGIN
+ //
+ // loginContext.logout();
+ LoginContext loginContext;
+ if (subject == null)
+ loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, this);
+ else
+ loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, subject, this);
+ loginContext.login();
+ cmsView.authChange(loginContext);
+ return true;
+ } catch (LoginException e) {
+ if (log.isTraceEnabled())
+ log.warn("Login failed: " + e.getMessage(), e);
+ else
+ log.warn("Login failed: " + e.getMessage());
+
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e2) {
+ // silent
+ }
+ // ErrorFeedback.show("Login failed", e);
+ return false;
+ }
+ // catch (LoginException e) {
+ // log.error("Cannot login", e);
+ // return false;
+ // }
+ }
+
+ protected void logout() {
+ cmsView.logout();
+ cmsView.navigateTo("~");
+ }
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ for (Callback callback : callbacks) {
+ if (callback instanceof NameCallback && usernameT != null)
+ ((NameCallback) callback).setName(usernameT.getText());
+ else if (callback instanceof PasswordCallback && passwordT != null)
+ ((PasswordCallback) callback).setPassword(passwordT.getTextChars());
+ else if (callback instanceof HttpRequestCallback) {
+ ((HttpRequestCallback) callback).setRequest(UiContext.getHttpRequest());
+ ((HttpRequestCallback) callback).setResponse(UiContext.getHttpResponse());
+ } else if (callback instanceof LanguageCallback) {
+ Locale toUse = null;
+ if (localeChoice != null)
+ toUse = localeChoice.getSelectedLocale();
+ else if (defaultLocale != null)
+ toUse = defaultLocale;
+
+ if (toUse != null) {
+ ((LanguageCallback) callback).setLocale(toUse);
+ UiContext.setLocale(toUse);
+ }
+
+ }
+ }
+ }
+
+ public void setSubject(Subject subject) {
+ this.subject = subject;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.widgets.auth;
+
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/** The site-related user menu */
+public class CmsLoginShell extends CmsLogin {
+ private final Shell shell;
+
+ public CmsLoginShell(CmsView cmsView) {
+ super(cmsView);
+ shell = createShell();
+ CmsUiUtils.style(shell, CMS_USER_MENU);
+// createUi(shell);
+ }
+
+ /** To be overridden. */
+ protected Shell createShell() {
+ Shell shell = new Shell(Display.getCurrent(), SWT.NO_TRIM);
+ shell.setMaximized(true);
+ return shell;
+ }
+
+ /** To be overridden. */
+ public void open() {
+ shell.open();
+ }
+
+ @Override
+ protected boolean login() {
+ boolean success = false;
+ try {
+ success = super.login();
+ return success;
+ } finally {
+ if (success)
+ closeShell();
+ else {
+ for (Control child : shell.getChildren())
+ child.dispose();
+ createUi(shell);
+ shell.layout();
+ // TODO error message
+ }
+ }
+ }
+
+ @Override
+ protected void logout() {
+ closeShell();
+ super.logout();
+ }
+
+ protected void closeShell() {
+ if (!shell.isDisposed()) {
+ shell.close();
+ shell.dispose();
+ }
+ }
+
+ public Shell getShell() {
+ return shell;
+ }
+
+ public void createUi(){
+ createUi(shell);
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.widgets.auth;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * A composite that can populate itself based on {@link Callback}s. It can be
+ * used directly as a {@link CallbackHandler} or be used by one by calling the
+ * {@link #createCallbackHandlers(Callback[])}. Supported standard
+ * {@link Callback}s are:<br>
+ * <ul>
+ * <li>{@link PasswordCallback}</li>
+ * <li>{@link NameCallback}</li>
+ * <li>{@link TextOutputCallback}</li>
+ * </ul>
+ * Supported Argeo {@link Callback}s are:<br>
+ * <ul>
+ * <li>{@link LocaleChoice}</li>
+ * </ul>
+ */
+public class CompositeCallbackHandler extends Composite implements CallbackHandler {
+ private static final long serialVersionUID = -928223893722723777L;
+
+ private boolean wasUsedAlready = false;
+ private boolean isSubmitted = false;
+ private boolean isCanceled = false;
+
+ public CompositeCallbackHandler(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ public synchronized void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ // reset
+ if (wasUsedAlready && !isSubmitted() && !isCanceled()) {
+ cancel();
+ for (Control control : getChildren())
+ control.dispose();
+ isSubmitted = false;
+ isCanceled = false;
+ }
+
+ for (Callback callback : callbacks)
+ checkCallbackSupported(callback);
+ // create controls synchronously in the UI thread
+ getDisplay().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ createCallbackHandlers(callbacks);
+ }
+ });
+
+ if (!wasUsedAlready)
+ wasUsedAlready = true;
+
+ // while (!isSubmitted() && !isCanceled()) {
+ // try {
+ // wait(1000l);
+ // } catch (InterruptedException e) {
+ // // silent
+ // }
+ // }
+
+ // cleanCallbacksAfterCancel(callbacks);
+ }
+
+ public void checkCallbackSupported(Callback callback) throws UnsupportedCallbackException {
+ if (callback instanceof TextOutputCallback || callback instanceof NameCallback
+ || callback instanceof PasswordCallback || callback instanceof LocaleChoice) {
+ return;
+ } else {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+
+ /**
+ * Set writable callbacks to null if the handle is canceled (check is done
+ * by the method)
+ */
+ public void cleanCallbacksAfterCancel(Callback[] callbacks) {
+ if (isCanceled()) {
+ for (Callback callback : callbacks) {
+ if (callback instanceof NameCallback) {
+ ((NameCallback) callback).setName(null);
+ } else if (callback instanceof PasswordCallback) {
+ PasswordCallback pCallback = (PasswordCallback) callback;
+ char[] arr = pCallback.getPassword();
+ if (arr != null) {
+ Arrays.fill(arr, '*');
+ pCallback.setPassword(null);
+ }
+ }
+ }
+ }
+ }
+
+ public void createCallbackHandlers(Callback[] callbacks) {
+ Composite composite = this;
+ for (int i = 0; i < callbacks.length; i++) {
+ Callback callback = callbacks[i];
+ if (callback instanceof TextOutputCallback) {
+ createLabelTextoutputHandler(composite, (TextOutputCallback) callback);
+ } else if (callback instanceof NameCallback) {
+ createNameHandler(composite, (NameCallback) callback);
+ } else if (callback instanceof PasswordCallback) {
+ createPasswordHandler(composite, (PasswordCallback) callback);
+ } else if (callback instanceof LocaleChoice) {
+ createLocaleHandler(composite, (LocaleChoice) callback);
+ }
+ }
+ }
+
+ protected Text createNameHandler(Composite composite, final NameCallback callback) {
+ Label label = new Label(composite, SWT.NONE);
+ label.setText(callback.getPrompt());
+ final Text text = new Text(composite, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
+ if (callback.getDefaultName() != null) {
+ // set default value, if provided
+ text.setText(callback.getDefaultName());
+ callback.setName(callback.getDefaultName());
+ }
+ text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ text.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = 7300032545287292973L;
+
+ public void modifyText(ModifyEvent event) {
+ callback.setName(text.getText());
+ }
+ });
+ text.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = 1820530045857665111L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ submit();
+ }
+ });
+
+ text.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -8698107785092095713L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ }
+ });
+ return text;
+ }
+
+ protected Text createPasswordHandler(Composite composite, final PasswordCallback callback) {
+ Label label = new Label(composite, SWT.NONE);
+ label.setText(callback.getPrompt());
+ final Text passwordText = new Text(composite, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD | SWT.BORDER);
+ passwordText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ passwordText.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = -7099363995047686732L;
+
+ public void modifyText(ModifyEvent event) {
+ callback.setPassword(passwordText.getTextChars());
+ }
+ });
+ passwordText.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = 1820530045857665111L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ submit();
+ }
+ });
+ return passwordText;
+ }
+
+ protected Combo createLocaleHandler(Composite composite, final LocaleChoice callback) {
+ String[] labels = callback.getSupportedLocalesLabels();
+ if (labels.length == 0)
+ return null;
+ Label label = new Label(composite, SWT.NONE);
+ label.setText("Language");
+
+ final Combo combo = new Combo(composite, SWT.READ_ONLY);
+ combo.setItems(labels);
+ combo.select(callback.getDefaultIndex());
+ combo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ combo.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = 38678989091946277L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ callback.setSelectedIndex(combo.getSelectionIndex());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ return combo;
+ }
+
+ protected Label createLabelTextoutputHandler(Composite composite, final TextOutputCallback callback) {
+ Label label = new Label(composite, SWT.NONE);
+ label.setText(callback.getMessage());
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.horizontalSpan = 2;
+ label.setLayoutData(data);
+ return label;
+ // TODO: find a way to pass this information
+ // int messageType = callback.getMessageType();
+ // int dialogMessageType = IMessageProvider.NONE;
+ // switch (messageType) {
+ // case TextOutputCallback.INFORMATION:
+ // dialogMessageType = IMessageProvider.INFORMATION;
+ // break;
+ // case TextOutputCallback.WARNING:
+ // dialogMessageType = IMessageProvider.WARNING;
+ // break;
+ // case TextOutputCallback.ERROR:
+ // dialogMessageType = IMessageProvider.ERROR;
+ // break;
+ // }
+ // setMessage(callback.getMessage(), dialogMessageType);
+ }
+
+ synchronized boolean isSubmitted() {
+ return isSubmitted;
+ }
+
+ synchronized boolean isCanceled() {
+ return isCanceled;
+ }
+
+ protected synchronized void submit() {
+ isSubmitted = true;
+ notifyAll();
+ }
+
+ protected synchronized void cancel() {
+ isCanceled = true;
+ notifyAll();
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.cms.ui.widgets.auth;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+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.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/** Default authentication dialog, to be used as {@link CallbackHandler}. */
+public class DefaultLoginDialog extends AbstractLoginDialog {
+ private static final long serialVersionUID = -8551827590693035734L;
+
+ public DefaultLoginDialog() {
+ this(Display.getCurrent().getActiveShell());
+ }
+
+ public DefaultLoginDialog(Shell parentShell) {
+ super(parentShell);
+ }
+
+ protected Point getInitialSize() {
+ return new Point(350, 180);
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ Control control = super.createContents(parent);
+ parent.pack();
+
+ // Move the dialog to the center of the top level shell.
+ Rectangle shellBounds;
+ if (Display.getCurrent().getActiveShell() != null) // RCP
+ shellBounds = Display.getCurrent().getActiveShell().getBounds();
+ else
+ shellBounds = Display.getCurrent().getBounds();// RAP
+ Point dialogSize = parent.getSize();
+ int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2;
+ int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2;
+ parent.setLocation(x, y);
+ return control;
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite dialogarea = (Composite) super.createDialogArea(parent);
+ CompositeCallbackHandler composite = new CompositeCallbackHandler(
+ dialogarea, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ composite.createCallbackHandlers(getCallbacks());
+ return composite;
+ }
+
+ public void internalHandle() {
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.widgets.auth;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.argeo.eclipse.ui.dialogs.LightweightDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class DynamicCallbackHandler implements CallbackHandler {
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ Shell activeShell = Display.getCurrent().getActiveShell();
+ LightweightDialog dialog = new LightweightDialog(activeShell) {
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ CompositeCallbackHandler cch = new CompositeCallbackHandler(parent, SWT.NONE);
+ cch.createCallbackHandlers(callbacks);
+ return cch;
+ }
+ };
+ dialog.setBlockOnOpen(true);
+ dialog.open();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.cms.ui.widgets.auth;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import javax.security.auth.callback.LanguageCallback;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.LocaleUtils;
+
+/** Choose in a list of locales. TODO: replace with {@link LanguageCallback} */
+public class LocaleChoice {
+ private final List<Locale> locales;
+
+ private Integer selectedIndex = null;
+ private final Integer defaultIndex;
+
+ public LocaleChoice(List<Locale> locales, Locale defaultLocale) {
+ Integer defaultIndex = null;
+ this.locales = Collections.unmodifiableList(locales);
+ for (int i = 0; i < locales.size(); i++)
+ if (locales.get(i).equals(defaultLocale))
+ defaultIndex = i;
+
+ // based on language only
+ if (defaultIndex == null)
+ for (int i = 0; i < locales.size(); i++)
+ if (locales.get(i).getLanguage().equals(defaultLocale.getLanguage()))
+ defaultIndex = i;
+
+ if (defaultIndex == null)
+ throw new CmsException("Default locale " + defaultLocale + " is not in available locales " + locales);
+ this.defaultIndex = defaultIndex;
+
+ this.selectedIndex = defaultIndex;
+ }
+
+ /**
+ * Convenience constructor based on a comma separated list of iso codes (en,
+ * en_US, fr_CA, etc.). Default selection is default locale.
+ */
+ public LocaleChoice(String locales, Locale defaultLocale) {
+ this(LocaleUtils.asLocaleList(locales), defaultLocale);
+ }
+
+ public String[] getSupportedLocalesLabels() {
+ String[] labels = new String[locales.size()];
+ for (int i = 0; i < locales.size(); i++) {
+ Locale locale = locales.get(i);
+ if (locale.getCountry().equals(""))
+ labels[i] = locale.getDisplayLanguage(locale) + " [" + locale.getLanguage() + "]";
+ else
+ labels[i] = locale.getDisplayLanguage(locale) + " (" + locale.getDisplayCountry(locale) + ") ["
+ + locale.getLanguage() + "_" + locale.getCountry() + "]";
+
+ }
+ return labels;
+ }
+
+ public Locale getSelectedLocale() {
+ if (selectedIndex == null)
+ return null;
+ return locales.get(selectedIndex);
+ }
+
+ public void setSelectedIndex(Integer selectedIndex) {
+ this.selectedIndex = selectedIndex;
+ }
+
+ public Integer getSelectedIndex() {
+ return selectedIndex;
+ }
+
+ public Integer getDefaultIndex() {
+ return defaultIndex;
+ }
+
+ public List<Locale> getLocales() {
+ return locales;
+ }
+
+ public Locale getDefaultLocale() {
+ return locales.get(getDefaultIndex());
+ }
+}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import org.argeo.cms.CmsException;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-
-/** {@link ResourceLoader} implementation wrapping an {@link Bundle}. */
-public class BundleResourceLoader implements ResourceLoader {
- private final Bundle bundle;
-
- public BundleResourceLoader(Bundle bundle) {
- this.bundle = bundle;
- }
-
- @Override
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- URL res = bundle.getEntry(resourceName);
- if (res == null) {
- res = bundle.getResource(resourceName);
- if (res == null)
- throw new CmsException("Resource " + resourceName + " not found in bundle " + bundle.getSymbolicName());
- }
- return res.openStream();
- }
-
- public Bundle getBundle() {
- return bundle;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsStyles;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.node.NodeUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.service.ResourceManager;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.graphics.ImageData;
-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.osgi.framework.BundleContext;
-
-/** A link to an internal or external location. */
-public class CmsLink implements CmsUiProvider {
- private final static Log log = LogFactory.getLog(CmsLink.class);
- private BundleContext bundleContext;
-
- private String label;
- private String custom;
- private String target;
- private String image;
- private MouseListener mouseListener;
-
- private int horizontalAlignment = SWT.CENTER;
- private int verticalAlignment = SWT.CENTER;
-
- private String loggedInLabel = null;
- private String loggedInTarget = null;
-
- // internal
- // private Boolean isUrl = false;
- private Integer imageWidth, imageHeight;
-
- public CmsLink() {
- super();
- }
-
- public CmsLink(String label, String target) {
- this(label, target, null);
- }
-
- public CmsLink(String label, String target, String custom) {
- super();
- this.label = label;
- this.target = target;
- this.custom = custom;
- init();
- }
-
- public void init() {
- if (image != null) {
- ImageData image = loadImage();
- if (imageHeight == null && imageWidth == null) {
- imageWidth = image.width;
- imageHeight = image.height;
- } else if (imageHeight == null) {
- imageHeight = (imageWidth * image.height) / image.width;
- } else if (imageWidth == null) {
- imageWidth = (imageHeight * image.width) / image.height;
- }
- }
- }
-
- /** @return {@link Composite} with a single {@link Label} child. */
- @Override
- public Control createUi(final Composite parent, Node context) {
-// if (image != null && (imageWidth == null || imageHeight == null)) {
-// throw new CmsException("Image is not properly configured."
-// + " Make sure bundleContext property is set and init() method has been called.");
-// }
-
- Composite comp = new Composite(parent, SWT.NONE);
- comp.setLayout(CmsUtils.noSpaceGridLayout());
-
- Label link = new Label(comp, SWT.NONE);
- link.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
- GridData layoutData = new GridData(horizontalAlignment, verticalAlignment, false, false);
- if (image != null) {
- if (imageHeight != null)
- layoutData.heightHint = imageHeight;
- if (label == null)
- if (imageWidth != null)
- layoutData.widthHint = imageWidth;
- }
-
- link.setLayoutData(layoutData);
- if (custom != null) {
- comp.setData(RWT.CUSTOM_VARIANT, custom);
- link.setData(RWT.CUSTOM_VARIANT, custom);
- } else {
- comp.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_LINK);
- link.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_LINK);
- }
-
- // label
- StringBuilder labelText = new StringBuilder();
- if (loggedInTarget != null && isLoggedIn()) {
- labelText.append("<a style='color:inherit;text-decoration:inherit;' href=\"");
- if (loggedInTarget.equals("")) {
- try {
- Node homeNode = NodeUtils.getUserHome(context.getSession());
- String homePath = homeNode.getPath();
- labelText.append("/#" + homePath);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot get home path", e);
- }
- } else {
- labelText.append(loggedInTarget);
- }
- labelText.append("\">");
- } else if (target != null) {
- labelText.append("<a style='color:inherit;text-decoration:inherit;' href=\"");
- labelText.append(target);
- labelText.append("\">");
- }
- if (image != null) {
- registerImageIfNeeded();
- String imageLocation = RWT.getResourceManager().getLocation(image);
- labelText.append("<img");
- if (imageWidth != null)
- labelText.append(" width='").append(imageWidth).append('\'');
- if (imageHeight != null)
- labelText.append(" height='").append(imageHeight).append('\'');
- labelText.append(" src=\"").append(imageLocation).append("\"/>");
-
- }
-
- if (loggedInLabel != null && isLoggedIn()) {
- labelText.append(' ').append(loggedInLabel);
- } else if (label != null) {
- labelText.append(' ').append(label);
- }
-
- if ((loggedInTarget != null && isLoggedIn()) || target != null)
- labelText.append("</a>");
-
- link.setText(labelText.toString());
-
- if (mouseListener != null)
- link.addMouseListener(mouseListener);
-
- return comp;
- }
-
- private void registerImageIfNeeded() {
- ResourceManager resourceManager = RWT.getResourceManager();
- if (!resourceManager.isRegistered(image)) {
- URL res = getImageUrl();
- InputStream inputStream = null;
- try {
- IOUtils.closeQuietly(inputStream);
- inputStream = res.openStream();
- resourceManager.register(image, inputStream);
- if (log.isTraceEnabled())
- log.trace("Registered image " + image);
- } catch (Exception e) {
- throw new CmsException("Cannot load image " + image, e);
- } finally {
- IOUtils.closeQuietly(inputStream);
- }
- }
- }
-
- private ImageData loadImage() {
- URL url = getImageUrl();
- ImageData result = null;
- InputStream inputStream = null;
- try {
- inputStream = url.openStream();
- result = new ImageData(inputStream);
- if (log.isTraceEnabled())
- log.trace("Loaded image " + image);
- } catch (Exception e) {
- throw new CmsException("Cannot load image " + image, e);
- } finally {
- IOUtils.closeQuietly(inputStream);
- }
- return result;
- }
-
- private URL getImageUrl() {
- URL url;
- try {
- // pure URL
- url = new URL(image);
- } catch (MalformedURLException e1) {
- url = bundleContext.getBundle().getResource(image);
- }
-
- if (url == null)
- throw new CmsException("No image " + image + " available.");
-
- return url;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- public void setLabel(String label) {
- this.label = label;
- }
-
- public void setCustom(String custom) {
- this.custom = custom;
- }
-
- public void setTarget(String target) {
- this.target = target;
- // try {
- // new URL(target);
- // isUrl = true;
- // } catch (MalformedURLException e1) {
- // isUrl = false;
- // }
- }
-
- public void setImage(String image) {
- this.image = image;
- }
-
- public void setLoggedInLabel(String loggedInLabel) {
- this.loggedInLabel = loggedInLabel;
- }
-
- public void setLoggedInTarget(String loggedInTarget) {
- this.loggedInTarget = loggedInTarget;
- }
-
- public void setMouseListener(MouseListener mouseListener) {
- this.mouseListener = mouseListener;
- }
-
- public void setvAlign(String vAlign) {
- if ("bottom".equals(vAlign)) {
- verticalAlignment = SWT.BOTTOM;
- } else if ("top".equals(vAlign)) {
- verticalAlignment = SWT.TOP;
- } else if ("center".equals(vAlign)) {
- verticalAlignment = SWT.CENTER;
- } else {
- throw new CmsException("Unsupported vertical allignment " + vAlign + " (must be: top, bottom or center)");
- }
- }
-
- protected boolean isLoggedIn() {
- return !CurrentUser.isAnonymous();
- }
-
- public void setImageWidth(Integer imageWidth) {
- this.imageWidth = imageWidth;
- }
-
- public void setImageHeight(Integer imageHeight) {
- this.imageHeight = imageHeight;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** The main pane of a CMS display, with QA and support areas. */
-public class CmsPane {
-
- private Composite mainArea;
- private Composite qaArea;
- private Composite supportArea;
-
- public CmsPane(Composite parent, int style) {
- parent.setLayout(CmsUtils.noSpaceGridLayout());
-
-// qaArea = new Composite(parent, SWT.NONE);
-// qaArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-// RowLayout qaLayout = new RowLayout();
-// qaLayout.spacing = 0;
-// qaArea.setLayout(qaLayout);
-
- mainArea = new Composite(parent, SWT.NONE);
- mainArea.setLayout(new GridLayout());
- mainArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
-// supportArea = new Composite(parent, SWT.NONE);
-// supportArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-// RowLayout supportLayout = new RowLayout();
-// supportLayout.spacing = 0;
-// supportArea.setLayout(supportLayout);
- }
-
- public Composite getMainArea() {
- return mainArea;
- }
-
- public Composite getQaArea() {
- return qaArea;
- }
-
- public Composite getSupportArea() {
- return supportArea;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-
-/**
- * Simplifies the theming of an app (only RAP is supported at this stage).<br>
- *
- * Additional fonts listed in <code>/fonts.txt</code>.<br>
- * Additional (standard CSS) header in <code>/header.css</code>.<br>
- * RAP specific CSS files in <code>/rap/*.css</code>.<br>
- * All images added as additional resources based on extensions
- * <code>/ ** /*.{png,gif,jpeg,...}</code>.<br>
- */
-public class CmsTheme {
- private final static Log log = LogFactory.getLog(CmsTheme.class);
-
- private String themeId;
- private Map<String, ResourceLoader> css = new HashMap<>();
- private Map<String, ResourceLoader> resources = new HashMap<>();
-
- private String headerCss;
- private List<String> fonts = new ArrayList<>();
-
- private String basePath;
- private String cssPath;
-
- public CmsTheme(BundleContext bundleContext) {
- this(bundleContext, null);
- }
-
- public CmsTheme(BundleContext bundleContext, String symbolicName) {
- Bundle themeBundle;
- if (symbolicName == null) {
- themeBundle = bundleContext.getBundle();
-// basePath = "/theme/";
-// cssPath = basePath;
- } else {
- themeBundle = ThemeUtils.findThemeBundle(bundleContext, symbolicName);
- }
- basePath = "/";
- cssPath = "/rap/";
- this.themeId = RWT.DEFAULT_THEME_ID;
- addStyleSheets(themeBundle, new BundleResourceLoader(themeBundle));
- BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
- addResources(themeBRL, "*.png");
- addResources(themeBRL, "*.gif");
- addResources(themeBRL, "*.jpg");
- addResources(themeBRL, "*.jpeg");
- addResources(themeBRL, "*.svg");
- addResources(themeBRL, "*.ico");
-
- // fonts
- URL fontsUrl = themeBundle.getEntry(basePath + "fonts.txt");
- if (fontsUrl != null) {
- loadFontsUrl(fontsUrl);
- }
-
- // common CSS header (plain CSS)
- URL headerCssUrl = themeBundle.getEntry(basePath + "header.css");
- if (headerCssUrl != null) {
- try (BufferedReader buffer = new BufferedReader(new InputStreamReader(headerCssUrl.openStream(), UTF_8))) {
- headerCss = buffer.lines().collect(Collectors.joining("\n"));
- } catch (IOException e) {
- throw new CmsException("Cannot read " + headerCssUrl, e);
- }
- }
-
- }
-
- public void apply(Application application) {
- resources: for (String name : resources.keySet()) {
- if (name.startsWith("target/"))
- continue resources; // skip maven output
- application.addResource(name, resources.get(name));
- if (log.isTraceEnabled())
- log.trace("Added resource " + name);
- }
- for (String name : css.keySet()) {
- application.addStyleSheet(themeId, name, css.get(name));
- if (log.isDebugEnabled())
- log.debug("Added RAP CSS " + name);
- }
- }
-
- public String getAdditionalHeaders() {
- StringBuilder sb = new StringBuilder();
- if (headerCss != null) {
- sb.append("<style type='text/css'>\n");
- sb.append(headerCss);
- sb.append("\n</style>\n");
- }
- for (String link : fonts) {
- sb.append("<link rel='stylesheet' href='");
- sb.append(link);
- sb.append("'/>\n");
- }
- if (sb.length() == 0)
- return null;
- else
- return sb.toString();
- }
-
- void addStyleSheets(Bundle themeBundle, ResourceLoader ssRL) {
- Enumeration<URL> themeResources = themeBundle.findEntries(cssPath, "*.css", true);
- if (themeResources == null)
- return;
- while (themeResources.hasMoreElements()) {
- String resource = themeResources.nextElement().getPath();
- // remove first '/' so that RWT registers it
- resource = resource.substring(1);
- if (!resource.endsWith("/")) {
- if (css.containsKey(resource))
- log.warn("Overriding " + resource + " from " + themeBundle.getSymbolicName());
- css.put(resource, ssRL);
- }
-
- }
-
- }
-
- void loadFontsUrl(URL url) {
- try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) {
- String line = null;
- while ((line = in.readLine()) != null) {
- line = line.trim();
- if (!line.equals("") && !line.startsWith("#")) {
- fonts.add(line);
- }
- }
- } catch (IOException e) {
- throw new CmsException("Cannot load URL " + url, e);
- }
- }
-
- void addResources(BundleResourceLoader themeBRL, String pattern) {
- Bundle themeBundle = themeBRL.getBundle();
- Enumeration<URL> themeResources = themeBundle.findEntries(basePath, pattern, true);
- if (themeResources == null)
- return;
- while (themeResources.hasMoreElements()) {
- String resource = themeResources.nextElement().getPath();
- // remove first '/' so that RWT registers it
- resource = resource.substring(1);
- if (!resource.endsWith("/")) {
- if (resources.containsKey(resource))
- log.warn("Overriding " + resource + " from " + themeBundle.getSymbolicName());
- resources.put(resource, themeBRL);
- }
-
- }
-
- }
-
- public String getThemeId() {
- return themeId;
- }
-
- public void setThemeId(String themeId) {
- this.themeId = themeId;
- }
-
- public String getBasePath() {
- return basePath;
- }
-
- public void setBasePath(String basePath) {
- this.basePath = basePath;
- }
-
- public String getCssPath() {
- return cssPath;
- }
-
- public void setCssPath(String cssPath) {
- this.cssPath = cssPath;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.servlet.http.HttpServletRequest;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsConstants;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.service.ResourceManager;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Image;
-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.layout.RowData;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.Widget;
-
-/** Static utilities for the CMS framework. */
-public class CmsUtils implements CmsConstants {
- // private final static Log log = LogFactory.getLog(CmsUtils.class);
-
- /**
- * The CMS view related to this display, or null if none is available from this
- * call.
- */
- public static CmsView getCmsView() {
- return UiContext.getData(CmsView.KEY);
- }
-
- public static StringBuilder getServerBaseUrl(HttpServletRequest request) {
- try {
- URL url = new URL(request.getRequestURL().toString());
- StringBuilder buf = new StringBuilder();
- buf.append(url.getProtocol()).append("://").append(url.getHost());
- if (url.getPort() != -1)
- buf.append(':').append(url.getPort());
- return buf;
- } catch (MalformedURLException e) {
- throw new CmsException("Cannot extract server base URL from " + request.getRequestURL(), e);
- }
- }
-
- //
- public static String getDataUrl(Node node, HttpServletRequest request) throws RepositoryException {
- try {
- StringBuilder buf = getServerBaseUrl(request);
- buf.append(getDataPath(node));
- return new URL(buf.toString()).toString();
- } catch (MalformedURLException e) {
- throw new CmsException("Cannot build data URL for " + node, e);
- }
- }
-
- /** A path in the node repository */
- public static String getDataPath(Node node) throws RepositoryException {
- return getDataPath(NodeConstants.NODE, node);
- }
-
- public static String getDataPath(String cn, Node node) throws RepositoryException {
- return NodeUtils.getDataPath(cn, node);
- }
-
- /** @deprecated Use rowData16px() instead. GridData should not be reused. */
- @Deprecated
- public static RowData ROW_DATA_16px = new RowData(16, 16);
-
- public static GridLayout noSpaceGridLayout() {
- return noSpaceGridLayout(new GridLayout());
- }
-
- public static GridLayout noSpaceGridLayout(int columns) {
- return noSpaceGridLayout(new GridLayout(columns, false));
- }
-
- public static GridLayout noSpaceGridLayout(GridLayout layout) {
- layout.horizontalSpacing = 0;
- layout.verticalSpacing = 0;
- layout.marginWidth = 0;
- layout.marginHeight = 0;
- return layout;
- }
-
- //
- // GRID DATA
- //
- public static GridData fillWidth() {
- return grabWidth(SWT.FILL, SWT.FILL);
- }
-
- public static GridData fillAll() {
- return new GridData(SWT.FILL, SWT.FILL, true, true);
- }
-
- public static GridData grabWidth(int horizontalAlignment, int verticalAlignment) {
- return new GridData(horizontalAlignment, horizontalAlignment, true, false);
- }
-
- public static RowData rowData16px() {
- return new RowData(16, 16);
- }
-
- /** Style widget */
- public static <T extends Widget> T style(T widget, String style) {
- widget.setData(CmsConstants.STYLE, style);
- return widget;
- }
-
- /** Enable markups on widget */
- public static <T extends Widget> T markup(T widget) {
- widget.setData(CmsConstants.MARKUP, true);
- return widget;
- }
-
- /**
- * Apply markup and set text on {@link Label}, {@link Button}, {@link Text}.
- *
- * @see #markup(Widget)
- */
- public static <T extends Widget> T text(T widget, String txt) {
- markup(widget);
- if (widget instanceof Label)
- ((Label) widget).setText(txt);
- else if (widget instanceof Button)
- ((Button) widget).setText(txt);
- else if (widget instanceof Text)
- ((Text) widget).setText(txt);
- else
- throw new IllegalArgumentException("Unsupported widget type " + widget.getClass());
- return widget;
- }
-
- public static void setItemHeight(Table table, int height) {
- table.setData(CmsConstants.ITEM_HEIGHT, height);
- }
-
- /** Dispose all children of a Composite */
- public static void clear(Composite composite) {
- for (Control child : composite.getChildren())
- child.dispose();
- }
-
- //
- // JCR
- //
- public static Node getOrAddEmptyFile(Node parent, Enum<?> child) throws RepositoryException {
- if (has(parent, child))
- return child(parent, child);
- return JcrUtils.copyBytesAsFile(parent, child.name(), new byte[0]);
- }
-
- public static Node child(Node parent, Enum<?> en) throws RepositoryException {
- return parent.getNode(en.name());
- }
-
- public static Boolean has(Node parent, Enum<?> en) throws RepositoryException {
- return parent.hasNode(en.name());
- }
-
- public static Node getOrAdd(Node parent, Enum<?> en) throws RepositoryException {
- return getOrAdd(parent, en, null);
- }
-
- public static Node getOrAdd(Node parent, Enum<?> en, String primaryType) throws RepositoryException {
- if (has(parent, en))
- return child(parent, en);
- else if (primaryType == null)
- return parent.addNode(en.name());
- else
- return parent.addNode(en.name(), primaryType);
- }
-
- // IMAGES
- public static String img(String src, String width, String height) {
- return imgBuilder(src, width, height).append("/>").toString();
- }
-
- public static String img(String src, Point size) {
- return img(src, Integer.toString(size.x), Integer.toString(size.y));
- }
-
- public static StringBuilder imgBuilder(String src, String width, String height) {
- return new StringBuilder(64).append("<img width='").append(width).append("' height='").append(height)
- .append("' src='").append(src).append("'");
- }
-
- public static String noImg(Point size) {
- ResourceManager rm = RWT.getResourceManager();
- return CmsUtils.img(rm.getLocation(NO_IMAGE), size);
- }
-
- public static String noImg() {
- return noImg(NO_IMAGE_SIZE);
- }
-
- public static Image noImage(Point size) {
- ResourceManager rm = RWT.getResourceManager();
- InputStream in = null;
- try {
- in = rm.getRegisteredContent(NO_IMAGE);
- ImageData id = new ImageData(in);
- ImageData scaled = id.scaledTo(size.x, size.y);
- Image image = new Image(Display.getCurrent(), scaled);
- return image;
- } finally {
- try {
- in.close();
- } catch (IOException e) {
- // silent
- }
- }
- }
-
- /** Lorem ipsum text to be used during development. */
- public final static String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
- + " Etiam eleifend hendrerit sem, ac ultricies massa ornare ac."
- + " Cras aliquam sodales risus, vitae varius lacus molestie quis."
- + " Vivamus consequat, leo id lacinia volutpat, eros diam efficitur urna, finibus interdum risus turpis at nisi."
- + " Curabitur vulputate nulla quis scelerisque fringilla. Integer consectetur turpis id lobortis accumsan."
- + " Pellentesque commodo turpis ac diam ultricies dignissim."
- + " Curabitur sit amet dolor volutpat lacus aliquam ornare quis sed velit."
- + " Integer varius quis est et tristique."
- + " Suspendisse pharetra porttitor purus, eget condimentum magna."
- + " Duis vitae turpis eros. Sed tincidunt lacinia rutrum."
- + " Aliquam velit velit, rutrum ut augue sed, condimentum lacinia augue.";
-
- /** Singleton. */
- private CmsUtils() {
- }
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import static javax.jcr.Node.JCR_CONTENT;
-import static javax.jcr.Property.JCR_DATA;
-import static javax.jcr.nodetype.NodeType.NT_FILE;
-import static javax.jcr.nodetype.NodeType.NT_RESOURCE;
-import static org.argeo.cms.ui.CmsConstants.NO_IMAGE_SIZE;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-
-import javax.jcr.Binary;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsImageManager;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.service.ResourceManager;
-import org.eclipse.rap.rwt.widgets.FileUpload;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-
-/** Manages only public images so far. */
-public class DefaultImageManager implements CmsImageManager {
- private final static Log log = LogFactory.getLog(DefaultImageManager.class);
-// private MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
-
- public Boolean load(Node node, Control control, Point preferredSize) throws RepositoryException {
- Point imageSize = getImageSize(node);
- Point size;
- String imgTag = null;
- if (preferredSize == null || imageSize.x == 0 || imageSize.y == 0
- || (preferredSize.x == 0 && preferredSize.y == 0)) {
- if (imageSize.x != 0 && imageSize.y != 0) {
- // actual image size if completely known
- size = imageSize;
- } else {
- // no image if not completely known
- size = resizeTo(NO_IMAGE_SIZE, preferredSize != null ? preferredSize : imageSize);
- imgTag = CmsUtils.noImg(size);
- }
-
- } else if (preferredSize.x != 0 && preferredSize.y != 0) {
- // given size if completely provided
- size = preferredSize;
- } else {
- // at this stage :
- // image is completely known
- assert imageSize.x != 0 && imageSize.y != 0;
- // one and only one of the dimension as been specified
- assert preferredSize.x == 0 || preferredSize.y == 0;
- size = resizeTo(imageSize, preferredSize);
- }
-
- boolean loaded = false;
- if (control == null)
- return loaded;
-
- if (control instanceof Label) {
- if (imgTag == null) {
- // IMAGE RETRIEVED HERE
- imgTag = getImageTag(node, size);
- //
- if (imgTag == null)
- imgTag = CmsUtils.noImg(size);
- else
- loaded = true;
- }
-
- Label lbl = (Label) control;
- lbl.setText(imgTag);
- // lbl.setSize(size);
- } else if (control instanceof FileUpload) {
- FileUpload lbl = (FileUpload) control;
- lbl.setImage(CmsUtils.noImage(size));
- lbl.setSize(size);
- return loaded;
- } else
- loaded = false;
-
- return loaded;
- }
-
- private Point resizeTo(Point orig, Point constraints) {
- if (constraints.x != 0 && constraints.y != 0) {
- return constraints;
- } else if (constraints.x == 0 && constraints.y == 0) {
- return orig;
- } else if (constraints.y == 0) {// force width
- return new Point(constraints.x, scale(orig.y, orig.x, constraints.x));
- } else if (constraints.x == 0) {// force height
- return new Point(scale(orig.x, orig.y, constraints.y), constraints.y);
- }
- throw new CmsException("Cannot resize " + orig + " to " + constraints);
- }
-
- private int scale(int origDimension, int otherDimension, int otherConstraint) {
- return Math.round(origDimension * divide(otherConstraint, otherDimension));
- }
-
- private float divide(int a, int b) {
- return ((float) a) / ((float) b);
- }
-
- public Point getImageSize(Node node) throws RepositoryException {
- // TODO load the SWT image ?
- return new Point(0, 0);
- }
-
- /** @return null if not available */
- @Override
- public String getImageTag(Node node) throws RepositoryException {
- return getImageTag(node, getImageSize(node));
- }
-
- private String getImageTag(Node node, Point size) throws RepositoryException {
- StringBuilder buf = getImageTagBuilder(node, size);
- if (buf == null)
- return null;
- return buf.append("/>").toString();
- }
-
- /** @return null if not available */
- @Override
- public StringBuilder getImageTagBuilder(Node node, Point size) throws RepositoryException {
- return getImageTagBuilder(node, Integer.toString(size.x), Integer.toString(size.y));
- }
-
- /** @return null if not available */
- private StringBuilder getImageTagBuilder(Node node, String width, String height) throws RepositoryException {
- String url = getImageUrl(node);
- if (url == null)
- return null;
- return CmsUtils.imgBuilder(url, width, height);
- }
-
- /** @return null if not available */
- @Override
- public String getImageUrl(Node node) throws RepositoryException {
- return CmsUtils.getDataPath(node);
- // String name = getResourceName(node);
- // ResourceManager resourceManager = RWT.getResourceManager();
- // if (!resourceManager.isRegistered(name)) {
- // InputStream inputStream = null;
- // Binary binary = getImageBinary(node);
- // if (binary == null)
- // return null;
- // try {
- // inputStream = binary.getStream();
- // resourceManager.register(name, inputStream);
- // } finally {
- // IOUtils.closeQuietly(inputStream);
- // JcrUtils.closeQuietly(binary);
- // }
- // if (log.isTraceEnabled())
- // log.trace("Registered image " + name);
- // }
- // return resourceManager.getLocation(name);
- }
-
- protected String getResourceName(Node node) throws RepositoryException {
- String workspace = node.getSession().getWorkspace().getName();
- if (node.hasNode(JCR_CONTENT))
- return workspace + '_' + node.getNode(JCR_CONTENT).getIdentifier();
- else
- return workspace + '_' + node.getIdentifier();
- }
-
- public Binary getImageBinary(Node node) throws RepositoryException {
- if (node.isNodeType(NT_FILE)) {
- return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();
- } else {
- return null;
- }
- }
-
- public Image getSwtImage(Node node) throws RepositoryException {
- InputStream inputStream = null;
- Binary binary = getImageBinary(node);
- if (binary == null)
- return null;
- try {
- inputStream = binary.getStream();
- return new Image(Display.getCurrent(), inputStream);
- } finally {
- IOUtils.closeQuietly(inputStream);
- JcrUtils.closeQuietly(binary);
- }
- }
-
- @Override
- public String uploadImage(Node parentNode, String fileName, InputStream in) throws RepositoryException {
- InputStream inputStream = null;
- try {
- String previousResourceName = null;
- if (parentNode.hasNode(fileName)) {
- Node node = parentNode.getNode(fileName);
- previousResourceName = getResourceName(node);
- if (node.hasNode(JCR_CONTENT)) {
- node.getNode(JCR_CONTENT).remove();
- node.addNode(JCR_CONTENT, NT_RESOURCE);
- }
- }
-
- byte[] arr = IOUtils.toByteArray(in);
- Node fileNode = JcrUtils.copyBytesAsFile(parentNode, fileName, arr);
- inputStream = new ByteArrayInputStream(arr);
- ImageData id = new ImageData(inputStream);
- processNewImageFile(fileNode, id);
-
- String mime = Files.probeContentType(Paths.get(fileName));
- fileNode.setProperty(Property.JCR_MIMETYPE, mime);
- fileNode.getSession().save();
-
- // reset resource manager
- ResourceManager resourceManager = RWT.getResourceManager();
- if (previousResourceName != null && resourceManager.isRegistered(previousResourceName)) {
- resourceManager.unregister(previousResourceName);
- if (log.isDebugEnabled())
- log.debug("Unregistered image " + previousResourceName);
- }
- return getImageUrl(fileNode);
- } catch (IOException e) {
- throw new CmsException("Cannot upload image " + fileName + " in " + parentNode, e);
- } finally {
- IOUtils.closeQuietly(inputStream);
- }
- }
-
- /** Does nothign by default. */
- protected void processNewImageFile(Node fileNode, ImageData id) throws RepositoryException, IOException {
- }
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.util.Locale;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsImageManager;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.UxContext;
-import org.argeo.cms.widgets.auth.CmsLogin;
-import org.argeo.cms.widgets.auth.CmsLoginShell;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.node.NodeConstants;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-
-public class LoginEntryPoint implements EntryPoint, CmsView {
- protected final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
- protected final static String HEADER_AUTHORIZATION = "Authorization";
- private final static Log log = LogFactory.getLog(LoginEntryPoint.class);
- private LoginContext loginContext;
- private UxContext uxContext = null;
-
- @Override
- public int createUI() {
- final Display display = createDisplay();
- UiContext.setData(CmsView.KEY, this);
- CmsLoginShell loginShell = createCmsLoginShell();
- try {
- // try pre-auth
- loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, loginShell);
- loginContext.login();
- } catch (LoginException e) {
- loginShell.createUi();
- loginShell.open();
-
- // HttpServletRequest request = RWT.getRequest();
- // String authorization = request.getHeader(HEADER_AUTHORIZATION);
- // if (authorization == null ||
- // !authorization.startsWith("Negotiate")) {
- // HttpServletResponse response = RWT.getResponse();
- // response.setStatus(401);
- // response.setHeader(HEADER_WWW_AUTHENTICATE, "Negotiate");
- // response.setDateHeader("Date", System.currentTimeMillis());
- // response.setDateHeader("Expires", System.currentTimeMillis() +
- // (24 * 60 * 60 * 1000));
- // response.setHeader("Accept-Ranges", "bytes");
- // response.setHeader("Connection", "Keep-Alive");
- // response.setHeader("Keep-Alive", "timeout=5, max=97");
- // // response.setContentType("text/html; charset=UTF-8");
- // }
-
- while (!loginShell.getShell().isDisposed()) {
- if (!display.readAndDispatch())
- display.sleep();
- }
- }
-
- if (CurrentUser.getUsername(getSubject()) == null)
- return -1;
- uxContext = new SimpleUxContext();
- return postLogin();
- }
-
- protected Display createDisplay() {
- return new Display();
- }
-
- protected int postLogin() {
- return 0;
- }
-
- protected HttpServletRequest getRequest() {
- return RWT.getRequest();
- }
-
- protected CmsLoginShell createCmsLoginShell() {
- return new CmsLoginShell(this) {
-
- @Override
- public void createContents(Composite parent) {
- LoginEntryPoint.this.createLoginPage(parent, this);
- }
-
- @Override
- protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale,
- SelectionListener loginSelectionListener) {
- LoginEntryPoint.this.extendsCredentialsBlock(credentialsBlock, selectedLocale, loginSelectionListener);
- }
-
- };
- }
-
- /**
- * To be overridden. CmsLogin#createCredentialsBlock() should be called at
- * some point in order to create the credentials composite. In order to use
- * the default layout, call CmsLogin#defaultCreateContents() but <b>not</b>
- * CmsLogin#createContent(), since it would lead to a stack overflow.
- */
- protected void createLoginPage(Composite parent, CmsLogin login) {
- login.defaultCreateContents(parent);
- }
-
- protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale,
- SelectionListener loginSelectionListener) {
-
- }
-
- @Override
- public void navigateTo(String state) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void authChange(LoginContext loginContext) {
- if (loginContext == null)
- throw new CmsException("Login context cannot be null");
- // logout previous login context
- if (this.loginContext != null)
- try {
- this.loginContext.logout();
- } catch (LoginException e1) {
- log.warn("Could not log out: " + e1);
- }
- this.loginContext = loginContext;
- }
-
- @Override
- public void logout() {
- if (loginContext == null)
- throw new CmsException("Login context should not bet null");
- try {
- CurrentUser.logoutCmsSession(loginContext.getSubject());
- loginContext.logout();
- } catch (LoginException e) {
- throw new CmsException("Cannot log out", e);
- }
- }
-
- @Override
- public void exception(Throwable e) {
- // TODO Auto-generated method stub
-
- }
-
- // @Override
- // public LoginContext getLoginContext() {
- // return loginContext;
- // }
-
- protected Subject getSubject() {
- return loginContext.getSubject();
- }
-
- @Override
- public boolean isAnonymous() {
- return CurrentUser.isAnonymous(getSubject());
- }
-
- @Override
- public CmsImageManager getImageManager() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public UxContext getUxContext() {
- return uxContext;
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.util;
-
-import org.argeo.cms.ui.CmsStyles;
-
-/**
- * Convenience class setting the custom style {@link CmsStyles#CMS_MENU_LINK} on
- * a {@link CmsLink} when simple menus are used.
- */
-public class MenuLink extends CmsLink {
- public MenuLink() {
- setCustom(CmsStyles.CMS_MENU_LINK);
- }
-
- public MenuLink(String label, String target, String custom) {
- super(label, target, custom);
- }
-
- public MenuLink(String label, String target) {
- super(label, target, CmsStyles.CMS_MENU_LINK);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.security.Privilege;
-import javax.jcr.version.VersionManager;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsConstants;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.LifeCycleUiProvider;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.Application.OperationMode;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.application.EntryPointFactory;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-/** A basic generic app based on {@link SimpleErgonomics}. */
-public class SimpleApp implements CmsConstants, ApplicationConfiguration {
- private final static Log log = LogFactory.getLog(SimpleApp.class);
-
- private String contextName = null;
-
- private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
- private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
-
- private List<String> resources = new ArrayList<String>();
-
- private BundleContext bundleContext;
-
- private Repository repository;
- private String workspace = null;
- private String jcrBasePath = "/";
- private List<String> roPrincipals = Arrays.asList(NodeConstants.ROLE_ANONYMOUS, NodeConstants.ROLE_USER);
- private List<String> rwPrincipals = Arrays.asList(NodeConstants.ROLE_USER);
-
- private CmsUiProvider header;
- private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
-
- private Integer headerHeight = 40;
-
- private ServiceRegistration<ApplicationConfiguration> appReg;
-
- public void configure(Application application) {
- try {
- BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
-
- application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
- // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
-
- application.setExceptionHandler(new CmsExceptionHandler());
-
- // loading animated gif
- application.addResource(LOADING_IMAGE, createResourceLoader(LOADING_IMAGE));
- // empty image
- application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
-
- for (String resource : resources) {
- application.addResource(resource, bundleRL);
- if (log.isTraceEnabled())
- log.trace("Resource " + resource);
- }
-
- Map<String, String> defaultBranding = null;
- if (branding.containsKey("*"))
- defaultBranding = branding.get("*");
- String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
-
- // entry points
- for (String page : pages.keySet()) {
- Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(defaultBranding)
- : new HashMap<String, String>();
- if (branding.containsKey(page)) {
- properties.putAll(branding.get(page));
- }
- // favicon
- if (properties.containsKey(WebClient.FAVICON)) {
- String themeId = defaultBranding.get(WebClient.THEME_ID);
- Bundle themeBundle = ThemeUtils.findThemeBundle(bundleContext, themeId);
- String faviconRelPath = properties.get(WebClient.FAVICON);
- application.addResource(faviconRelPath,
- new BundleResourceLoader(themeBundle != null ? themeBundle : bundleContext.getBundle()));
- if (log.isTraceEnabled())
- log.trace("Favicon " + faviconRelPath);
-
- }
-
- // page title
- if (!properties.containsKey(WebClient.PAGE_TITLE)) {
- if (page.length() > 0)
- properties.put(WebClient.PAGE_TITLE, Character.toUpperCase(page.charAt(0)) + page.substring(1));
- }
-
- // default body HTML
- if (!properties.containsKey(WebClient.BODY_HTML))
- properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
-
- //
- // ADD ENTRY POINT
- //
- application.addEntryPoint("/" + page,
- new CmsEntryPointFactory(pages.get(page), repository, workspace, properties), properties);
- log.info("Page /" + page);
- }
-
- // stylesheets and themes
- Set<Bundle> themeBundles = new HashSet<>();
- for (String themeId : styleSheets.keySet()) {
- Bundle themeBundle = ThemeUtils.findThemeBundle(bundleContext, themeId);
- StyleSheetResourceLoader styleSheetRL = new StyleSheetResourceLoader(
- themeBundle != null ? themeBundle : bundleContext.getBundle());
- if (themeBundle != null)
- themeBundles.add(themeBundle);
- List<String> cssLst = styleSheets.get(themeId);
- if (log.isDebugEnabled())
- log.debug("Theme " + themeId);
- for (String css : cssLst) {
- application.addStyleSheet(themeId, css, styleSheetRL);
- if (log.isDebugEnabled())
- log.debug(" CSS " + css);
- }
-
- }
- for (Bundle themeBundle : themeBundles) {
- BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
- ThemeUtils.addThemeResources(application, themeBundle, themeBRL, "*.png");
- ThemeUtils.addThemeResources(application, themeBundle, themeBRL, "*.gif");
- ThemeUtils.addThemeResources(application, themeBundle, themeBRL, "*.jpg");
- }
- } catch (RuntimeException e) {
- // Easier access to initialisation errors
- log.error("Unexpected exception when configuring RWT application.", e);
- throw e;
- }
- }
-
- public void init() throws RepositoryException {
- Session session = null;
- try {
- session = NodeUtils.openDataAdminSession(repository, workspace);
- // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
- VersionManager vm = session.getWorkspace().getVersionManager();
- JcrUtils.mkdirs(session, jcrBasePath);
- session.save();
- if (!vm.isCheckedOut(jcrBasePath))
- vm.checkout(jcrBasePath);
- for (String principal : rwPrincipals)
- JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_WRITE);
- for (String principal : roPrincipals)
- JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_READ);
-
- for (String pageName : pages.keySet()) {
- try {
- initPage(session, pages.get(pageName));
- session.save();
- } catch (Exception e) {
- throw new CmsException("Cannot initialize page " + pageName, e);
- }
- }
-
- } finally {
- JcrUtils.logoutQuietly(session);
- }
-
- // publish to OSGi
- register();
- }
-
- protected void initPage(Session adminSession, CmsUiProvider page) throws RepositoryException {
- if (page instanceof LifeCycleUiProvider)
- ((LifeCycleUiProvider) page).init(adminSession);
- }
-
- public void destroy() {
- for (String pageName : pages.keySet()) {
- try {
- CmsUiProvider page = pages.get(pageName);
- if (page instanceof LifeCycleUiProvider)
- ((LifeCycleUiProvider) page).destroy();
- } catch (Exception e) {
- log.error("Cannot destroy page " + pageName, e);
- }
- }
- }
-
- protected void register() {
- Hashtable<String, String> props = new Hashtable<String, String>();
- if (contextName != null)
- props.put("contextName", contextName);
- appReg = bundleContext.registerService(ApplicationConfiguration.class, this, props);
- if (log.isDebugEnabled())
- log.debug("Registered " + (contextName == null ? "/" : contextName));
- }
-
- protected void unregister() {
- appReg.unregister();
- if (log.isDebugEnabled())
- log.debug("Unregistered " + (contextName == null ? "/" : contextName));
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public void setWorkspace(String workspace) {
- this.workspace = workspace;
- }
-
- public void setHeader(CmsUiProvider header) {
- this.header = header;
- }
-
- public void setPages(Map<String, CmsUiProvider> pages) {
- this.pages = pages;
- }
-
- public void setJcrBasePath(String basePath) {
- this.jcrBasePath = basePath;
- }
-
- public void setRoPrincipals(List<String> roPrincipals) {
- this.roPrincipals = roPrincipals;
- }
-
- public void setRwPrincipals(List<String> rwPrincipals) {
- this.rwPrincipals = rwPrincipals;
- }
-
- public void setHeaderHeight(Integer headerHeight) {
- this.headerHeight = headerHeight;
- }
-
- public void setBranding(Map<String, Map<String, String>> branding) {
- this.branding = branding;
- }
-
- public void setStyleSheets(Map<String, List<String>> styleSheets) {
- this.styleSheets = styleSheets;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- public void setResources(List<String> resources) {
- this.resources = resources;
- }
-
- public void setContextName(String contextName) {
- this.contextName = contextName;
- }
-
- class CmsExceptionHandler implements ExceptionHandler {
-
- @Override
- public void handleException(Throwable throwable) {
- // TODO be smarter
- CmsUtils.getCmsView().exception(throwable);
- }
-
- }
-
- private class CmsEntryPointFactory implements EntryPointFactory {
- private final CmsUiProvider page;
- private final Repository repository;
- private final String workspace;
- private final Map<String, String> properties;
-
- public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace,
- Map<String, String> properties) {
- this.page = page;
- this.repository = repository;
- this.workspace = workspace;
- this.properties = properties;
- }
-
- @Override
- public EntryPoint create() {
- SimpleErgonomics entryPoint = new SimpleErgonomics(repository, workspace, jcrBasePath, page, properties) {
- private static final long serialVersionUID = -637940404865527290L;
-
- @Override
- protected void createAdminArea(Composite parent) {
- Composite adminArea = new Composite(parent, SWT.NONE);
- adminArea.setLayout(new FillLayout());
- Button refresh = new Button(adminArea, SWT.PUSH);
- refresh.setText("Reload App");
- refresh.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -7671999525536351366L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- long timeBeforeReload = 1000;
- RWT.getClient().getService(JavaScriptExecutor.class).execute(
- "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload + ");");
- reloadApp();
- }
- });
- }
- };
- // entryPoint.setState("");
- entryPoint.setHeader(header);
- entryPoint.setHeaderHeight(headerHeight);
- // CmsSession.current.set(entryPoint);
- return entryPoint;
- }
-
- private void reloadApp() {
- new Thread("Refresh app") {
- @Override
- public void run() {
- unregister();
- register();
- }
- }.start();
- }
- }
-
- private static ResourceLoader createResourceLoader(final String resourceName) {
- return new ResourceLoader() {
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- return getClass().getClassLoader().getResourceAsStream(resourceName);
- }
- };
- }
-
- // private static ResourceLoader createUrlResourceLoader(final URL url) {
- // return new ResourceLoader() {
- // public InputStream getResourceAsStream(String resourceName)
- // throws IOException {
- // return url.openStream();
- // }
- // };
- // }
-
- /*
- * TEXTS
- */
- private static String DEFAULT_LOADING_BODY = "<div"
- + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
- + "<img src=\"./rwt-resources/" + LOADING_IMAGE
- + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsStyles;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.rap.rwt.RWT;
-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;
-
-/** A header in three parts */
-public class SimpleCmsHeader implements CmsUiProvider {
- private List<CmsUiProvider> lead = new ArrayList<CmsUiProvider>();
- private List<CmsUiProvider> center = new ArrayList<CmsUiProvider>();
- private List<CmsUiProvider> end = new ArrayList<CmsUiProvider>();
-
- private Boolean subPartsSameWidth = false;
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- Composite header = new Composite(parent, SWT.NONE);
- header.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_HEADER);
- header.setBackgroundMode(SWT.INHERIT_DEFAULT);
- header.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(3, false)));
-
- configurePart(context, header, lead);
- configurePart(context, header, center);
- configurePart(context, header, end);
- return header;
- }
-
- protected void configurePart(Node context, Composite parent, List<CmsUiProvider> partProviders)
- throws RepositoryException {
- final int style;
- final String custom;
- if (lead == partProviders) {
- style = SWT.LEAD;
- custom = CmsStyles.CMS_HEADER_LEAD;
- } else if (center == partProviders) {
- style = SWT.CENTER;
- custom = CmsStyles.CMS_HEADER_CENTER;
- } else if (end == partProviders) {
- style = SWT.END;
- custom = CmsStyles.CMS_HEADER_END;
- } else {
- throw new CmsException("Unsupported part providers " + partProviders);
- }
-
- Composite part = new Composite(parent, SWT.NONE);
- part.setData(RWT.CUSTOM_VARIANT, custom);
- GridData gridData = new GridData(style, SWT.FILL, true, true);
- part.setLayoutData(gridData);
- part.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(partProviders.size(), subPartsSameWidth)));
- for (CmsUiProvider uiProvider : partProviders) {
- Control subPart = uiProvider.createUi(part, context);
- subPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- }
- }
-
- public void setLead(List<CmsUiProvider> lead) {
- this.lead = lead;
- }
-
- public void setCenter(List<CmsUiProvider> center) {
- this.center = center;
- }
-
- public void setEnd(List<CmsUiProvider> end) {
- this.end = end;
- }
-
- public void setSubPartsSameWidth(Boolean subPartsSameWidth) {
- this.subPartsSameWidth = subPartsSameWidth;
- }
-
- public List<CmsUiProvider> getLead() {
- return lead;
- }
-
- public List<CmsUiProvider> getCenter() {
- return center;
- }
-
- public List<CmsUiProvider> getEnd() {
- return end;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.rwt.RWT;
-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;
-
-public class SimpleDynamicPages implements CmsUiProvider {
-
- @Override
- public Control createUi(Composite parent, Node context)
- throws RepositoryException {
- if (context == null)
- throw new CmsException("Context cannot be null");
- parent.setLayout(new GridLayout(2, false));
-
- // parent
- if (!context.getPath().equals("/")) {
- new CmsLink("..", context.getParent().getPath()).createUi(parent,
- context);
- new Label(parent, SWT.NONE).setText(context.getParent()
- .getPrimaryNodeType().getName());
- }
-
- // context
- Label contextL = new Label(parent, SWT.NONE);
- contextL.setData(RWT.MARKUP_ENABLED, true);
- contextL.setText("<b>" + context.getName() + "</b>");
- new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType()
- .getName());
-
- // children
- // Label childrenL = new Label(parent, SWT.NONE);
- // childrenL.setData(RWT.MARKUP_ENABLED, true);
- // childrenL.setText("<i>Children:</i>");
- // childrenL.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false,
- // false, 2, 1));
-
- for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) {
- Node child = nIt.nextNode();
- new CmsLink(child.getName(), child.getPath()).createUi(parent,
- context);
-
- new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType()
- .getName());
- }
-
- // properties
- // Label propsL = new Label(parent, SWT.NONE);
- // propsL.setData(RWT.MARKUP_ENABLED, true);
- // propsL.setText("<i>Properties:</i>");
- // propsL.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false,
- // 2, 1));
- for (PropertyIterator pIt = context.getProperties(); pIt.hasNext();) {
- Property property = pIt.nextProperty();
-
- Label label = new Label(parent, SWT.NONE);
- label.setText(property.getName());
- label.setToolTipText(JcrUtils
- .getPropertyDefinitionAsString(property));
-
- new Label(parent, SWT.NONE).setText(getPropAsString(property));
- }
-
- return null;
- }
-
- private String getPropAsString(Property property)
- throws RepositoryException {
- String result = "";
- DateFormat timeFormatter = new SimpleDateFormat("");
- if (property.isMultiple()) {
- result = getMultiAsString(property, ", ");
- } else {
- Value value = property.getValue();
- if (value.getType() == PropertyType.BINARY)
- result = "<binary>";
- else if (value.getType() == PropertyType.DATE)
- result = timeFormatter.format(value.getDate().getTime());
- else
- result = value.getString();
- }
- return result;
- }
-
- private String getMultiAsString(Property property, String separator)
- throws RepositoryException {
- if (separator == null)
- separator = "; ";
- Value[] values = property.getValues();
- StringBuilder builder = new StringBuilder();
- for (Value val : values) {
- String currStr = val.getString();
- if (!"".equals(currStr.trim()))
- builder.append(currStr).append(separator);
- }
- if (builder.lastIndexOf(separator) >= 0)
- return builder.substring(0, builder.length() - separator.length());
- else
- return builder.toString();
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.AbstractCmsEntryPoint;
-import org.argeo.cms.ui.CmsImageManager;
-import org.argeo.cms.ui.CmsStyles;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.UxContext;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Simple header/body ergonomics. */
-public class SimpleErgonomics extends AbstractCmsEntryPoint {
- private static final long serialVersionUID = 8743413921359548523L;
-
- private final static Log log = LogFactory.getLog(SimpleErgonomics.class);
-
- private boolean uiInitialized = false;
- private Composite headerArea;
- private Composite leftArea;
- private Composite rightArea;
- private Composite footerArea;
- private Composite bodyArea;
- private final CmsUiProvider uiProvider;
-
- private CmsUiProvider header;
- private Integer headerHeight = 0;
- private Integer footerHeight = 0;
- private CmsUiProvider lead;
- private CmsUiProvider end;
- private CmsUiProvider footer;
-
- private CmsImageManager imageManager = new DefaultImageManager();
- private UxContext uxContext = null;
-
- public SimpleErgonomics(Repository repository, String workspace, String defaultPath, CmsUiProvider uiProvider,
- Map<String, String> factoryProperties) {
- super(repository, workspace, defaultPath, factoryProperties);
- this.uiProvider = uiProvider;
- }
-
- @Override
- protected void initUi(Composite parent) {
- parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- parent.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(3, false)));
-
- uxContext = new SimpleUxContext();
- if (!getUxContext().isMasterData())
- createAdminArea(parent);
- headerArea = new Composite(parent, SWT.NONE);
- headerArea.setLayout(new FillLayout());
- GridData headerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
- headerData.heightHint = headerHeight;
- headerArea.setLayoutData(headerData);
-
- // TODO: bi-directional
- leftArea = new Composite(parent, SWT.NONE);
- leftArea.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
- leftArea.setLayout(CmsUtils.noSpaceGridLayout());
-
- bodyArea = new Composite(parent, SWT.NONE);
- bodyArea.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_BODY);
- bodyArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- bodyArea.setLayout(CmsUtils.noSpaceGridLayout());
-
- // TODO: bi-directional
- rightArea = new Composite(parent, SWT.NONE);
- rightArea.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
- rightArea.setLayout(CmsUtils.noSpaceGridLayout());
-
- footerArea = new Composite(parent, SWT.NONE);
- // footerArea.setLayout(new FillLayout());
- GridData footerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
- footerData.heightHint = footerHeight;
- footerArea.setLayoutData(footerData);
-
- uiInitialized = true;
- refresh();
- }
-
- @Override
- protected void refresh() {
- if (!uiInitialized)
- return;
- if (getState() == null)
- setState("");
- refreshSides();
- refreshBody();
- if (log.isTraceEnabled())
- log.trace("UI refreshed " + getNode());
- }
-
- protected void createAdminArea(Composite parent) {
- }
-
- @Deprecated
- protected void refreshHeader() {
- if (header == null)
- return;
-
- for (Control child : headerArea.getChildren())
- child.dispose();
- try {
- header.createUi(headerArea, getNode());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh header", e);
- }
- headerArea.layout(true, true);
- }
-
- protected void refreshSides() {
- refresh(headerArea, header, CmsStyles.CMS_HEADER);
- refresh(leftArea, lead, CmsStyles.CMS_LEAD);
- refresh(rightArea, end, CmsStyles.CMS_END);
- refresh(footerArea, footer, CmsStyles.CMS_FOOTER);
- }
-
- private void refresh(Composite area, CmsUiProvider uiProvider, String style) {
- if (uiProvider == null)
- return;
-
- for (Control child : area.getChildren())
- child.dispose();
- CmsUtils.style(area, style);
- try {
- uiProvider.createUi(area, getNode());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh header", e);
- }
- area.layout(true, true);
- }
-
- protected void refreshBody() {
- // Exception
- Throwable exception = getException();
- if (exception != null) {
- SystemNotifications systemNotifications = new SystemNotifications(bodyArea);
- systemNotifications.notifyException(exception);
- resetException();
- return;
- // TODO report
- }
-
- // clear
- for (Control child : bodyArea.getChildren())
- child.dispose();
- bodyArea.setLayout(CmsUtils.noSpaceGridLayout());
-
- try {
- Node node = getNode();
-// if (node == null)
-// log.error("Context cannot be null");
-// else
- uiProvider.createUi(bodyArea, node);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh body", e);
- }
-
- bodyArea.layout(true, true);
- }
-
- @Override
- public UxContext getUxContext() {
- return uxContext;
- }
-
- @Override
- public CmsImageManager getImageManager() {
- return imageManager;
- }
-
- public void setHeader(CmsUiProvider header) {
- this.header = header;
- }
-
- public void setHeaderHeight(Integer headerHeight) {
- this.headerHeight = headerHeight;
- }
-
- public void setImageManager(CmsImageManager imageManager) {
- this.imageManager = imageManager;
- }
-
- public CmsUiProvider getLead() {
- return lead;
- }
-
- public void setLead(CmsUiProvider lead) {
- this.lead = lead;
- }
-
- public CmsUiProvider getEnd() {
- return end;
- }
-
- public void setEnd(CmsUiProvider end) {
- this.end = end;
- }
-
- public CmsUiProvider getFooter() {
- return footer;
- }
-
- public void setFooter(CmsUiProvider footer) {
- this.footer = footer;
- }
-
- public CmsUiProvider getHeader() {
- return header;
- }
-
- public void setFooterHeight(Integer footerHeight) {
- this.footerHeight = footerHeight;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-public class SimpleImageManager extends DefaultImageManager {
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.CmsStyles;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-public class SimpleStaticPage implements CmsUiProvider {
- private String text;
-
- @Override
- public Control createUi(Composite parent, Node context)
- throws RepositoryException {
- Label textC = new Label(parent, SWT.WRAP);
- textC.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_STATIC_TEXT);
- textC.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
- textC.setText(text);
-
- return textC;
- }
-
- public void setText(String text) {
- this.text = text;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import org.argeo.cms.ui.UxContext;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Display;
-
-public class SimpleUxContext implements UxContext {
- private Point size;
- private Point small = new Point(400, 400);
-
- public SimpleUxContext() {
- this(Display.getCurrent().getBounds());
- }
-
- public SimpleUxContext(Rectangle rect) {
- this.size = new Point(rect.width, rect.height);
- }
-
- public SimpleUxContext(Point size) {
- this.size = size;
- }
-
- @Override
- public boolean isPortrait() {
- return size.x >= size.y;
- }
-
- @Override
- public boolean isLandscape() {
- return size.x < size.y;
- }
-
- @Override
- public boolean isSquare() {
- return size.x == size.y;
- }
-
- @Override
- public boolean isSmall() {
- return size.x <= small.x || size.y <= small.y;
- }
-
- @Override
- public boolean isMasterData() {
- // TODO make it configurable
- return true;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.cms.CmsException;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-
-/** {@link ResourceLoader} caching stylesheets. */
-public class StyleSheetResourceLoader implements ResourceLoader {
- private Bundle themeBundle;
- private Map<String, StyleSheet> stylesheets = new LinkedHashMap<String, StyleSheet>();
-
- public StyleSheetResourceLoader(Bundle themeBundle) {
- this.themeBundle = themeBundle;
- }
-
- @Override
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- if (!stylesheets.containsKey(resourceName)) {
- // TODO deal with other bundles
- // Bundle bundle = bundleContext.getBundle();
- // String location =
- // bundle.getLocation().substring("initial@reference:".length());
- // if (location.startsWith("file:")) {
- // Path path = null;
- // try {
- // path = Paths.get(new URI(location));
- // } catch (URISyntaxException e) {
- // e.printStackTrace();
- // }
- // if (path != null) {
- // Path resourcePath = path.resolve(resourceName);
- // if (Files.exists(resourcePath))
- // return Files.newInputStream(resourcePath);
- // }
- // }
-
- URL res = themeBundle.getEntry(resourceName);
- if (res == null)
- throw new CmsException(
- "Entry " + resourceName + " not found in bundle " + themeBundle.getSymbolicName());
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- IOUtils.copy(res.openStream(), out);
- stylesheets.put(resourceName, new StyleSheet(out.toByteArray()));
- }
- return new ByteArrayInputStream(stylesheets.get(resourceName).getData());
- // return res.openStream();
- }
-
- private class StyleSheet {
- private byte[] data;
-
- public StyleSheet(byte[] data) {
- super();
- this.data = data;
- }
-
- public byte[] getData() {
- return data;
- }
-
- }
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsStyles;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-
-/** Shell displaying system notifications such as exceptions */
-public class SystemNotifications extends Shell implements CmsStyles,
- MouseListener {
- private static final long serialVersionUID = -8129377525216022683L;
-
- private Control source;
-
- public SystemNotifications(Control source) {
- super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
- setData(RWT.CUSTOM_VARIANT, CMS_USER_MENU);
-
- this.source = source;
-
- // TODO UI
- // setLocation(source.toDisplay(source.getSize().x - getSize().x,
- // source.getSize().y));
- setLayout(new GridLayout());
- addMouseListener(this);
-
- addShellListener(new ShellAdapter() {
- private static final long serialVersionUID = 5178980294808435833L;
-
- @Override
- public void shellDeactivated(ShellEvent e) {
- close();
- dispose();
- }
- });
-
- }
-
- public void notifyException(Throwable exception) {
- Composite pane = this;
-
- Label lbl = new Label(pane, SWT.NONE);
- lbl.setText(exception.getLocalizedMessage()
- + (exception instanceof CmsException ? "" : "("
- + exception.getClass().getName() + ")") + "\n");
- lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- lbl.addMouseListener(this);
- if (exception.getCause() != null)
- appendCause(pane, exception.getCause());
-
- StringBuilder mailToUrl = new StringBuilder("mailto:?");
- try {
- mailToUrl.append("subject=").append(
- URLEncoder.encode(
- "Exception "
- + new SimpleDateFormat("yyyy-MM-dd hh:mm")
- .format(new Date()), "UTF-8")
- .replace("+", "%20"));
-
- StringWriter sw = new StringWriter();
- exception.printStackTrace(new PrintWriter(sw));
- IOUtils.closeQuietly(sw);
-
- // see
- // http://stackoverflow.com/questions/4737841/urlencoder-not-able-to-translate-space-character
- String encoded = URLEncoder.encode(sw.toString(), "UTF-8").replace(
- "+", "%20");
- mailToUrl.append("&body=").append(encoded);
- } catch (UnsupportedEncodingException e) {
- mailToUrl.append("&body=").append("Could not encode: ")
- .append(e.getMessage());
- }
- Label mailTo = new Label(pane, SWT.NONE);
- CmsUtils.markup(mailTo);
- mailTo.setText("<a href=\"" + mailToUrl + "\">Send details</a>");
- mailTo.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
-
- pack();
- layout();
-
- setLocation(source.toDisplay(source.getSize().x - getSize().x,
- source.getSize().y - getSize().y));
- open();
- }
-
- private void appendCause(Composite parent, Throwable e) {
- Label lbl = new Label(parent, SWT.NONE);
- lbl.setText(" caused by: " + e.getLocalizedMessage() + " ("
- + e.getClass().getName() + ")" + "\n");
- lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- lbl.addMouseListener(this);
- if (e.getCause() != null)
- appendCause(parent, e.getCause());
- }
-
- @Override
- public void mouseDoubleClick(MouseEvent e) {
- }
-
- @Override
- public void mouseDown(MouseEvent e) {
- close();
- dispose();
- }
-
- @Override
- public void mouseUp(MouseEvent e) {
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.net.URL;
-import java.util.Enumeration;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.eclipse.rap.rwt.application.Application;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-
-public class ThemeUtils {
- final static Log log = LogFactory.getLog(ThemeUtils.class);
-
- public static Bundle findThemeBundle(BundleContext bundleContext, String themeId) {
- if (themeId == null)
- return null;
- // TODO optimize
- // TODO deal with multiple versions
- Bundle themeBundle = null;
- if (themeId != null) {
- for (Bundle bundle : bundleContext.getBundles())
- if (themeId.equals(bundle.getSymbolicName())) {
- themeBundle = bundle;
- break;
- }
- }
- return themeBundle;
- }
-
- public static void addThemeResources(Application application, Bundle themeBundle, BundleResourceLoader themeBRL,
- String pattern) {
- Enumeration<URL> themeResources = themeBundle.findEntries("/", pattern, true);
- if (themeResources == null)
- return;
- while (themeResources.hasMoreElements()) {
- String resource = themeResources.nextElement().getPath();
- // remove first '/' so that RWT registers it
- resource = resource.substring(1);
- if (!resource.endsWith("/")) {
- application.addResource(resource, themeBRL);
- if (log.isTraceEnabled())
- log.trace("Registered " + resource + " from theme " + themeBundle);
- }
-
- }
-
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.widgets.auth.CmsLoginShell;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-/** The site-related user menu */
-public class UserMenu extends CmsLoginShell {
- private final Control source;
- private final Node context;
-
- public UserMenu(Control source, Node context) {
- super(CmsUtils.getCmsView());
- this.context = context;
- createUi();
- if (source == null)
- throw new CmsException("Source control cannot be null.");
- this.source = source;
- open();
- }
-
- @Override
- protected Shell createShell() {
- return new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
- }
-
- @Override
- public void open() {
- Shell shell = getShell();
- shell.pack();
- shell.layout();
- shell.setLocation(source.toDisplay(source.getSize().x - shell.getSize().x, source.getSize().y));
- shell.addShellListener(new ShellAdapter() {
- private static final long serialVersionUID = 5178980294808435833L;
-
- @Override
- public void shellDeactivated(ShellEvent e) {
- closeShell();
- }
- });
- super.open();
- }
-
- protected Node getContext() {
- return context;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.CmsMsg;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsStyles;
-import org.argeo.cms.widgets.auth.CmsLoginShell;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** Open the user menu when clicked */
-public class UserMenuLink extends MenuLink {
-
- public UserMenuLink() {
- setCustom(CmsStyles.CMS_USER_MENU_LINK);
- }
-
- @Override
- public Control createUi(Composite parent, Node context) {
- if (CurrentUser.isAnonymous())
- setLabel(CmsMsg.login.lead());
- else {
- setLabel(CurrentUser.getDisplayName());
- }
- Label link = (Label) ((Composite) super.createUi(parent, context)).getChildren()[0];
- link.addMouseListener(new UserMenuLinkController(context));
- return link.getParent();
- }
-
- protected CmsLoginShell createUserMenu(Control source, Node context) {
- return new UserMenu(source.getParent(), context);
- }
-
- private class UserMenuLinkController implements MouseListener, DisposeListener {
- private static final long serialVersionUID = 3634864186295639792L;
-
- private CmsLoginShell userMenu = null;
- private long lastDisposeTS = 0l;
-
- private final Node context;
-
- public UserMenuLinkController(Node context) {
- this.context = context;
- }
-
- //
- // MOUSE LISTENER
- //
- @Override
- public void mouseDown(MouseEvent e) {
- if (e.button == 1) {
- Control source = (Control) e.getSource();
- if (userMenu == null) {
- long durationSinceLastDispose = System.currentTimeMillis() - lastDisposeTS;
- // avoid to reopen the menu, if one has clicked gain
- if (durationSinceLastDispose > 200) {
- userMenu = createUserMenu(source, context);
- userMenu.getShell().addDisposeListener(this);
- }
- }
- }
- }
-
- @Override
- public void mouseDoubleClick(MouseEvent e) {
- }
-
- @Override
- public void mouseUp(MouseEvent e) {
- }
-
- @Override
- public void widgetDisposed(DisposeEvent event) {
- userMenu = null;
- lastDisposeTS = System.currentTimeMillis();
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-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;
-
-public class VerticalMenu implements CmsUiProvider {
- private List<CmsUiProvider> items = new ArrayList<CmsUiProvider>();
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- Composite part = new Composite(parent, SWT.NONE);
- part.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
-// part.setData(RWT.CUSTOM_VARIANT, custom);
- part.setLayout(CmsUtils.noSpaceGridLayout());
- for (CmsUiProvider uiProvider : items) {
- Control subPart = uiProvider.createUi(part, context);
- subPart.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
- }
- return part;
- }
-
- public void add(CmsUiProvider uiProvider) {
- items.add(uiProvider);
- }
-
- public List<CmsUiProvider> getItems() {
- return items;
- }
-
- public void setItems(List<CmsUiProvider> items) {
- this.items = items;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.viewers;
-
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Observable;
-import java.util.Observer;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.security.auth.Subject;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsEditable;
-import org.argeo.cms.widgets.ScrolledPage;
-import org.eclipse.jface.viewers.ContentViewer;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Widget;
-import org.xml.sax.SAXParseException;
-
-/** Base class for viewers related to a page */
-public abstract class AbstractPageViewer extends ContentViewer implements Observer {
- private static final long serialVersionUID = 5438688173410341485L;
-
- private final static Log log = LogFactory.getLog(AbstractPageViewer.class);
-
- private final boolean readOnly;
- /** The basis for the layouts, typically a ScrolledPage. */
- private final Composite page;
- private final CmsEditable cmsEditable;
-
- private MouseListener mouseListener;
- private FocusListener focusListener;
-
- private EditablePart edited;
- private ISelection selection = StructuredSelection.EMPTY;
-
- private AccessControlContext accessControlContext;
-
- protected AbstractPageViewer(Section parent, int style, CmsEditable cmsEditable) {
- // read only at UI level
- readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
-
- this.cmsEditable = cmsEditable == null ? CmsEditable.NON_EDITABLE : cmsEditable;
- if (this.cmsEditable instanceof Observable)
- ((Observable) this.cmsEditable).addObserver(this);
-
- if (cmsEditable.canEdit()) {
- mouseListener = createMouseListener();
- focusListener = createFocusListener();
- }
- page = findPage(parent);
- accessControlContext = AccessController.getContext();
- }
-
- /**
- * Can be called to simplify the called to isModelInitialized() and initModel()
- */
- protected void initModelIfNeeded(Node node) {
- try {
- if (!isModelInitialized(node))
- if (getCmsEditable().canEdit()) {
- initModel(node);
- node.getSession().save();
- }
- } catch (Exception e) {
- throw new CmsException("Cannot initialize model", e);
- }
- }
-
- /** Called if user can edit and model is not initialized */
- protected Boolean isModelInitialized(Node node) throws RepositoryException {
- return true;
- }
-
- /** Called if user can edit and model is not initialized */
- protected void initModel(Node node) throws RepositoryException {
- }
-
- /** Create (retrieve) the MouseListener to use. */
- protected MouseListener createMouseListener() {
- return new MouseAdapter() {
- private static final long serialVersionUID = 1L;
- };
- }
-
- /** Create (retrieve) the FocusListener to use. */
- protected FocusListener createFocusListener() {
- return new FocusListener() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void focusLost(FocusEvent event) {
- }
-
- @Override
- public void focusGained(FocusEvent event) {
- }
- };
- }
-
- protected Composite findPage(Composite composite) {
- if (composite instanceof ScrolledPage) {
- return (ScrolledPage) composite;
- } else {
- if (composite.getParent() == null)
- return composite;
- return findPage(composite.getParent());
- }
- }
-
- @Override
- public void update(Observable o, Object arg) {
- if (o == cmsEditable)
- editingStateChanged(cmsEditable);
- }
-
- /** To be overridden in order to provide the actual refresh */
- protected void refresh(Control control) throws RepositoryException {
- }
-
- /** To be overridden.Save the edited part. */
- protected void save(EditablePart part) throws RepositoryException {
- }
-
- /** Prepare the edited part */
- protected void prepare(EditablePart part, Object caretPosition) {
- }
-
- /** Notified when the editing state changed. Does nothing, to be overridden */
- protected void editingStateChanged(CmsEditable cmsEditable) {
- }
-
- @Override
- public void refresh() {
- // TODO check actual context in order to notice a discrepancy
- Subject viewerSubject = getViewerSubject();
- Subject.doAs(viewerSubject, (PrivilegedAction<Void>) () -> {
- try {
- if (cmsEditable.canEdit() && !readOnly)
- mouseListener = createMouseListener();
- else
- mouseListener = null;
- refresh(getControl());
- layout(getControl());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh", e);
- }
- return null;
- });
- }
-
- @Override
- public void setSelection(ISelection selection, boolean reveal) {
- this.selection = selection;
- }
-
- protected void updateContent(EditablePart part) throws RepositoryException {
- }
-
- // LOW LEVEL EDITION
- protected void edit(EditablePart part, Object caretPosition) {
- try {
- if (edited == part)
- return;
-
- if (edited != null && edited != part) {
- EditablePart previouslyEdited = edited;
- try {
- stopEditing(true);
- } catch (Exception e) {
- notifyEditionException(e);
- edit(previouslyEdited, caretPosition);
- return;
- }
- }
-
- part.startEditing();
- updateContent(part);
- prepare(part, caretPosition);
- edited = part;
- layout(part.getControl());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot edit " + part, e);
- }
- }
-
- private void stopEditing(Boolean save) throws RepositoryException {
- if (edited instanceof Widget && ((Widget) edited).isDisposed()) {
- edited = null;
- return;
- }
-
- assert edited != null;
- if (edited == null) {
- if (log.isTraceEnabled())
- log.warn("Told to stop editing while not editing anything");
- return;
- }
-
- if (save)
- save(edited);
-
- edited.stopEditing();
- updateContent(edited);
- layout(((EditablePart) edited).getControl());
- edited = null;
- }
-
- // METHODS AVAILABLE TO EXTENDING CLASSES
- protected void saveEdit() {
- try {
- if (edited != null)
- stopEditing(true);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot stop editing", e);
- }
- }
-
- protected void cancelEdit() {
- try {
- if (edited != null)
- stopEditing(false);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot cancel editing", e);
- }
- }
-
- /** Layout this controls from the related base page. */
- public void layout(Control... controls) {
- page.layout(controls);
- }
-
- /**
- * Find the first {@link EditablePart} in the parents hierarchy of this control
- */
- protected EditablePart findDataParent(Control parent) {
- if (parent instanceof EditablePart) {
- return (EditablePart) parent;
- }
- if (parent.getParent() != null)
- return findDataParent(parent.getParent());
- else
- throw new CmsException("No data parent found");
- }
-
- // UTILITIES
- /** Check whether the edited part is in a proper state */
- protected void checkEdited() {
- if (edited == null || (edited instanceof Widget) && ((Widget) edited).isDisposed())
- throw new CmsException("Edited should not be null or disposed at this stage");
- }
-
- /** Persist all changes. */
- protected void persistChanges(Session session) throws RepositoryException {
- session.save();
- session.refresh(false);
- // TODO notify that changes have been persisted
- }
-
- /** Convenience method using a Node in order to save the underlying session. */
- protected void persistChanges(Node anyNode) throws RepositoryException {
- persistChanges(anyNode.getSession());
- }
-
- /** Notify edition exception */
- protected void notifyEditionException(Throwable e) {
- Throwable eToLog = e;
- if (e instanceof IllegalArgumentException)
- if (e.getCause() instanceof SAXParseException)
- eToLog = e.getCause();
- log.error(eToLog.getMessage(), eToLog);
-// if (log.isTraceEnabled())
-// log.trace("Full stack of " + eToLog.getMessage(), e);
- // TODO Light error notification popup
- }
-
- protected Subject getViewerSubject() {
- Subject res = null;
- if (accessControlContext != null) {
- res = Subject.getSubject(accessControlContext);
- }
- if (res == null)
- throw new CmsException("No subject associated with this viewer");
- return res;
- }
-
- // GETTERS / SETTERS
- public boolean isReadOnly() {
- return readOnly;
- }
-
- protected EditablePart getEdited() {
- return edited;
- }
-
- public MouseListener getMouseListener() {
- return mouseListener;
- }
-
- public FocusListener getFocusListener() {
- return focusListener;
- }
-
- public CmsEditable getCmsEditable() {
- return cmsEditable;
- }
-
- @Override
- public ISelection getSelection() {
- return selection;
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.viewers;
-
-import org.eclipse.swt.widgets.Control;
-
-public interface EditablePart {
- public void startEditing();
-
- public void stopEditing();
-
- public Control getControl();
-}
+++ /dev/null
-package org.argeo.cms.viewers;
-
-import javax.jcr.Item;
-import javax.jcr.RepositoryException;
-
-/** An editable part related to a JCR Item */
-public interface ItemPart<T extends Item> {
- public Item getItem() throws RepositoryException;
-}
+++ /dev/null
-package org.argeo.cms.viewers;
-
-import java.util.Observable;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.version.VersionManager;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsEditable;
-import org.argeo.cms.ui.CmsEditionEvent;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-
-/** Provides the CmsEditable semantic based on JCR versioning. */
-public class JcrVersionCmsEditable extends Observable implements CmsEditable {
- private final String nodePath;// cache
- private final VersionManager versionManager;
- private final Boolean canEdit;
-
- public JcrVersionCmsEditable(Node node) throws RepositoryException {
- this.nodePath = node.getPath();
- if (node.getSession().hasPermission(node.getPath(),
- Session.ACTION_SET_PROPERTY)) {
- // was Session.ACTION_ADD_NODE
- canEdit = true;
- if (!node.isNodeType(NodeType.MIX_VERSIONABLE)) {
- node.addMixin(NodeType.MIX_VERSIONABLE);
- node.getSession().save();
- }
- versionManager = node.getSession().getWorkspace()
- .getVersionManager();
- } else {
- canEdit = false;
- versionManager = null;
- }
-
- // bind keys
- if (canEdit) {
- Display display = Display.getCurrent();
- display.setData(RWT.ACTIVE_KEYS, new String[] { "CTRL+RETURN",
- "CTRL+E" });
- display.addFilter(SWT.KeyDown, new Listener() {
- private static final long serialVersionUID = -4378653870463187318L;
-
- public void handleEvent(Event e) {
- boolean ctrlPressed = (e.stateMask & SWT.CTRL) != 0;
- if (ctrlPressed && e.keyCode == '\r')
- stopEditing();
- else if (ctrlPressed && e.keyCode == 'E')
- stopEditing();
- }
- });
- }
- }
-
- @Override
- public Boolean canEdit() {
- return canEdit;
- }
-
- public Boolean isEditing() {
- try {
- if (!canEdit())
- return false;
- return versionManager.isCheckedOut(nodePath);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot check whether " + nodePath
- + " is editing", e);
- }
- }
-
- @Override
- public void startEditing() {
- try {
- versionManager.checkout(nodePath);
- setChanged();
- } catch (RepositoryException e1) {
- throw new CmsException("Cannot publish " + nodePath);
- }
- notifyObservers(new CmsEditionEvent(nodePath,
- CmsEditionEvent.START_EDITING));
- }
-
- @Override
- public void stopEditing() {
- try {
- versionManager.checkin(nodePath);
- setChanged();
- } catch (RepositoryException e1) {
- throw new CmsException("Cannot publish " + nodePath, e1);
- }
- notifyObservers(new CmsEditionEvent(nodePath,
- CmsEditionEvent.STOP_EDITING));
- }
-}
+++ /dev/null
-package org.argeo.cms.viewers;
-
-import javax.jcr.Node;
-
-/** An editable part related to a node */
-public interface NodePart extends ItemPart<Node> {
- public Node getNode();
-}
+++ /dev/null
-package org.argeo.cms.viewers;
-
-import javax.jcr.Property;
-
-/** An editable part related to a JCR Property */
-public interface PropertyPart extends ItemPart<Property> {
- public Property getProperty();
-}
+++ /dev/null
-package org.argeo.cms.viewers;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.widgets.JcrComposite;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-public class Section extends JcrComposite {
- private static final long serialVersionUID = -5933796173755739207L;
-
- private final Section parentSection;
- private Composite sectionHeader;
- private final Integer relativeDepth;
-
- public Section(Composite parent, int style, Node node) throws RepositoryException {
- this(parent, findSection(parent), style, node);
- }
-
- public Section(Section section, int style, Node node) throws RepositoryException {
- this(section, section, style, node);
- }
-
- protected Section(Composite parent, Section parentSection, int style, Node node) throws RepositoryException {
- super(parent, style, node);
- this.parentSection = parentSection;
- if (parentSection != null) {
- relativeDepth = getNode().getDepth() - parentSection.getNode().getDepth();
- } else {
- relativeDepth = 0;
- }
- setLayout(CmsUtils.noSpaceGridLayout());
- }
-
- public Map<String, Section> getSubSections() throws RepositoryException {
- LinkedHashMap<String, Section> result = new LinkedHashMap<String, Section>();
- for (Control child : getChildren()) {
- if (child instanceof Composite) {
- collectDirectSubSections((Composite) child, result);
- }
- }
- return Collections.unmodifiableMap(result);
- }
-
- private void collectDirectSubSections(Composite composite, LinkedHashMap<String, Section> subSections)
- throws RepositoryException {
- if (composite == sectionHeader || composite instanceof EditablePart)
- return;
- if (composite instanceof Section) {
- Section section = (Section) composite;
- subSections.put(section.getNodeId(), section);
- return;
- }
-
- for (Control child : composite.getChildren())
- if (child instanceof Composite)
- collectDirectSubSections((Composite) child, subSections);
- }
-
- public void createHeader() {
- if (sectionHeader != null)
- throw new CmsException("Section header was already created");
-
- sectionHeader = new Composite(this, SWT.NONE);
- sectionHeader.setLayoutData(CmsUtils.fillWidth());
- sectionHeader.setLayout(CmsUtils.noSpaceGridLayout());
- // sectionHeader.moveAbove(null);
- // layout();
- }
-
- public Composite getHeader() {
- if (sectionHeader != null && sectionHeader.isDisposed())
- sectionHeader = null;
- return sectionHeader;
- }
-
- // SECTION PARTS
- public SectionPart getSectionPart(String partId) {
- for (Control child : getChildren()) {
- if (child instanceof SectionPart) {
- SectionPart paragraph = (SectionPart) child;
- if (paragraph.getPartId().equals(partId))
- return paragraph;
- }
- }
- return null;
- }
-
- public SectionPart nextSectionPart(SectionPart sectionPart) {
- Control[] children = getChildren();
- for (int i = 0; i < children.length; i++) {
- if (sectionPart == children[i])
- if (i + 1 < children.length) {
- Composite next = (Composite) children[i + 1];
- return (SectionPart) next;
- } else {
- // next section
- }
- }
- return null;
- }
-
- public SectionPart previousSectionPart(SectionPart sectionPart) {
- Control[] children = getChildren();
- for (int i = 0; i < children.length; i++) {
- if (sectionPart == children[i])
- if (i != 0) {
- Composite previous = (Composite) children[i - 1];
- return (SectionPart) previous;
- } else {
- // previous section
- }
- }
- return null;
- }
-
- @Override
- public String toString() {
- if (parentSection == null)
- return "Main section " + getNode();
- return "Section " + getNode();
- }
-
- public Section getParentSection() {
- return parentSection;
- }
-
- public Integer getRelativeDepth() {
- return relativeDepth;
- }
-
- /** Recursively finds the related section in the parents (can be itself) */
- public static Section findSection(Control control) {
- if (control == null)
- return null;
- if (control instanceof Section)
- return (Section) control;
- else
- return findSection(control.getParent());
- }
-}
+++ /dev/null
-package org.argeo.cms.viewers;
-
-
-/** An editable part dynamically related to a Section */
-public interface SectionPart extends EditablePart, NodePart {
- public String getPartId();
-
- public Section getSection();
-}
+++ /dev/null
-package org.argeo.cms.widgets;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** A stylable and editable image. */
-public abstract class EditableImage extends StyledControl {
- private static final long serialVersionUID = -5689145523114022890L;
- private final static Log log = LogFactory.getLog(EditableImage.class);
-
- private Point preferredImageSize;
- private Boolean loaded = false;
-
- public EditableImage(Composite parent, int swtStyle) {
- super(parent, swtStyle);
- }
-
- public EditableImage(Composite parent, int swtStyle,
- Point preferredImageSize) {
- super(parent, swtStyle);
- this.preferredImageSize = preferredImageSize;
- }
-
- public EditableImage(Composite parent, int style, Node node,
- boolean cacheImmediately, Point preferredImageSize)
- throws RepositoryException {
- super(parent, style, node, cacheImmediately);
- this.preferredImageSize = preferredImageSize;
- }
-
- @Override
- protected void setContainerLayoutData(Composite composite) {
- // composite.setLayoutData(fillWidth());
- }
-
- @Override
- protected void setControlLayoutData(Control control) {
- // control.setLayoutData(fillWidth());
- }
-
- /** To be overriden. */
- protected String createImgTag() throws RepositoryException {
- return CmsUtils.noImg(preferredImageSize != null ? preferredImageSize
- : getSize());
- }
-
- protected Label createLabel(Composite box, String style) {
- Label lbl = new Label(box, getStyle());
- // lbl.setLayoutData(CmsUtils.fillWidth());
- CmsUtils.markup(lbl);
- CmsUtils.style(lbl, style);
- if (mouseListener != null)
- lbl.addMouseListener(mouseListener);
- load(lbl);
- return lbl;
- }
-
- /** To be overriden. */
- protected synchronized Boolean load(Control control) {
- String imgTag;
- try {
- imgTag = createImgTag();
- } catch (Exception e) {
- // throw new CmsException("Cannot retrieve image", e);
- log.error("Cannot retrieve image", e);
- imgTag = CmsUtils.noImg(preferredImageSize);
- loaded = false;
- }
-
- if (imgTag == null) {
- loaded = false;
- imgTag = CmsUtils.noImg(preferredImageSize);
- } else
- loaded = true;
- if (control != null) {
- ((Label) control).setText(imgTag);
- control.setSize(preferredImageSize != null ? preferredImageSize
- : getSize());
- } else {
- loaded = false;
- }
- getParent().layout();
- return loaded;
- }
-
- public void setPreferredSize(Point size) {
- this.preferredImageSize = size;
- if (!loaded) {
- load((Label) getControl());
- }
- }
-
- protected Text createText(Composite box, String style) {
- Text text = new Text(box, getStyle());
- CmsUtils.style(text, style);
- return text;
- }
-
- public Point getPreferredImageSize() {
- return preferredImageSize;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.widgets;
-
-import javax.jcr.Item;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.util.CmsUtils;
-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.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Editable text part displaying styled text. */
-public class EditableText extends StyledControl {
- private static final long serialVersionUID = -6372283442330912755L;
-
- public EditableText(Composite parent, int swtStyle) {
- super(parent, swtStyle);
- }
-
- public EditableText(Composite parent, int style, Item item)
- throws RepositoryException {
- this(parent, style, item, false);
- }
-
- public EditableText(Composite parent, int style, Item item,
- boolean cacheImmediately) throws RepositoryException {
- super(parent, style, item, cacheImmediately);
- }
-
- @Override
- protected Control createControl(Composite box, String style) {
- if (isEditing())
- return createText(box, style);
- else
- return createLabel(box, style);
- }
-
- protected Label createLabel(Composite box, String style) {
- Label lbl = new Label(box, getStyle() | SWT.WRAP);
- lbl.setLayoutData(CmsUtils.fillWidth());
- CmsUtils.style(lbl, style);
- CmsUtils.markup(lbl);
- if (mouseListener != null)
- lbl.addMouseListener(mouseListener);
- return lbl;
- }
-
- protected Text createText(Composite box, String style) {
- final Text text = new Text(box, getStyle() | SWT.MULTI | SWT.WRAP);
- GridData textLayoutData = CmsUtils.fillWidth();
- // textLayoutData.heightHint = preferredHeight;
- text.setLayoutData(textLayoutData);
- CmsUtils.style(text, style);
- text.setFocus();
- return text;
- }
-
- public void setText(String text) {
- Control child = getControl();
- if (child instanceof Label)
- ((Label) child).setText(text);
- else if (child instanceof Text)
- ((Text) child).setText(text);
- }
-
- public Text getAsText() {
- return (Text) getControl();
- }
-
- public Label getAsLabel() {
- return (Label) getControl();
- }
-
-}
+++ /dev/null
-package org.argeo.cms.widgets;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsImageManager;
-import org.argeo.cms.ui.internal.JcrFileUploadReceiver;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.viewers.NodePart;
-import org.argeo.cms.viewers.Section;
-import org.argeo.cms.viewers.SectionPart;
-import org.eclipse.rap.fileupload.FileUploadHandler;
-import org.eclipse.rap.fileupload.FileUploadListener;
-import org.eclipse.rap.fileupload.FileUploadReceiver;
-import org.eclipse.rap.rwt.service.ServerPushSession;
-import org.eclipse.rap.rwt.widgets.FileUpload;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** An image within the Argeo Text framework */
-public class Img extends EditableImage implements SectionPart, NodePart {
- private static final long serialVersionUID = 6233572783968188476L;
-
- private final Section section;
-
- private final CmsImageManager imageManager;
- private FileUploadHandler currentUploadHandler = null;
- private FileUploadListener fileUploadListener;
-
- public Img(Composite parent, int swtStyle, Node imgNode,
- Point preferredImageSize) throws RepositoryException {
- this(Section.findSection(parent), parent, swtStyle, imgNode,
- preferredImageSize);
- setStyle(TextStyles.TEXT_IMAGE);
- }
-
- public Img(Composite parent, int swtStyle, Node imgNode)
- throws RepositoryException {
- this(Section.findSection(parent), parent, swtStyle, imgNode, null);
- setStyle(TextStyles.TEXT_IMAGE);
- }
-
- Img(Section section, Composite parent, int swtStyle, Node imgNode,
- Point preferredImageSize) throws RepositoryException {
- super(parent, swtStyle, imgNode, false, preferredImageSize);
- this.section = section;
- imageManager = CmsUtils.getCmsView().getImageManager();
- CmsUtils.style(this, TextStyles.TEXT_IMG);
- }
-
- @Override
- protected Control createControl(Composite box, String style) {
- if (isEditing()) {
- try {
- return createImageChooser(box, style);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot create image chooser", e);
- }
- } else {
- return createLabel(box, style);
- }
- }
-
- @Override
- public synchronized void stopEditing() {
- super.stopEditing();
- fileUploadListener = null;
- }
-
- @Override
- protected synchronized Boolean load(Control lbl) {
- try {
- Node imgNode = getNode();
- boolean loaded = imageManager.load(imgNode, lbl,
- getPreferredImageSize());
- // getParent().layout();
- return loaded;
- } catch (RepositoryException e) {
- throw new CmsException("Cannot load " + getNodeId()
- + " from image manager", e);
- }
- }
-
- protected Control createImageChooser(Composite box, String style)
- throws RepositoryException {
- // FileDialog fileDialog = new FileDialog(getShell());
- // fileDialog.open();
- // String fileName = fileDialog.getFileName();
- CmsImageManager imageManager = CmsUtils.getCmsView().getImageManager();
- Node node = getNode();
- JcrFileUploadReceiver receiver = new JcrFileUploadReceiver(
- node.getParent(), node.getName() + '[' + node.getIndex() + ']',
- imageManager);
- if (currentUploadHandler != null)
- currentUploadHandler.dispose();
- currentUploadHandler = prepareUpload(receiver);
- final ServerPushSession pushSession = new ServerPushSession();
- final FileUpload fileUpload = new FileUpload(box, SWT.NONE);
- CmsUtils.style(fileUpload, style);
- fileUpload.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -9158471843941668562L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- pushSession.start();
- fileUpload.submit(currentUploadHandler.getUploadUrl());
- }
- });
- return fileUpload;
- }
-
- protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) {
- final FileUploadHandler uploadHandler = new FileUploadHandler(receiver);
- if (fileUploadListener != null)
- uploadHandler.addUploadListener(fileUploadListener);
- return uploadHandler;
- }
-
- @Override
- public Section getSection() {
- return section;
- }
-
- public void setFileUploadListener(FileUploadListener fileUploadListener) {
- this.fileUploadListener = fileUploadListener;
- if (currentUploadHandler != null)
- currentUploadHandler.addUploadListener(fileUploadListener);
- }
-
- @Override
- public Node getItem() throws RepositoryException {
- return getNode();
- }
-
- @Override
- public String getPartId() {
- return getNodeId();
- }
-
- @Override
- public String toString() {
- return "Img #" + getPartId();
- }
-
-}
+++ /dev/null
-package org.argeo.cms.widgets;
-
-import javax.jcr.Item;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-
-/** A composite which can (optionally) manage a JCR Item. */
-public class JcrComposite extends Composite {
- private static final long serialVersionUID = -1447009015451153367L;
-
- private final Session session;
-
- private String nodeId;
- private String property = null;
- private Node cache;
-
- /** Regular composite constructor. No layout is set. */
- public JcrComposite(Composite parent, int style) {
- super(parent, style);
- session = null;
- nodeId = null;
- }
-
- public JcrComposite(Composite parent, int style, Item item)
- throws RepositoryException {
- this(parent, style, item, false);
- }
-
- public JcrComposite(Composite parent, int style, Item item,
- boolean cacheImmediately) throws RepositoryException {
- super(parent, style);
- this.session = item.getSession();
- if (!cacheImmediately && (SWT.READ_ONLY == (style & SWT.READ_ONLY))) {
- // (useless?) optimization: we only save a pointer to the session,
- // not even a reference to the item
- this.nodeId = null;
- } else {
- Node node;
- Property property = null;
- if (item instanceof Node) {
- node = (Node) item;
- } else {// Property
- property = (Property) item;
- if (property.isMultiple())// TODO manage property index
- throw new CmsException(
- "Multiple properties not supported yet.");
- this.property = property.getName();
- node = property.getParent();
- }
- this.nodeId = node.getIdentifier();
- if (cacheImmediately)
- this.cache = node;
- }
- setLayout(CmsUtils.noSpaceGridLayout());
- }
-
- public synchronized Node getNode() {
- try {
- if (!itemIsNode())
- throw new CmsException("Item is not a Node");
- return getNodeInternal();
- } catch (RepositoryException e) {
- throw new CmsException("Cannot get node " + nodeId, e);
- }
- }
-
- private synchronized Node getNodeInternal() throws RepositoryException {
- if (cache != null)
- return cache;
- else if (session != null)
- if (nodeId != null)
- return session.getNodeByIdentifier(nodeId);
- else
- return null;
- else
- return null;
- }
-
- public synchronized Property getProperty() {
- try {
- if (itemIsNode())
- throw new CmsException("Item is not a Property");
- Node node = getNodeInternal();
- if (!node.hasProperty(property))
- throw new CmsException("Property " + property
- + " is not set on " + node);
- return node.getProperty(property);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot get property " + property
- + " from node " + nodeId, e);
- }
- }
-
- public synchronized Boolean itemIsNode() {
- return property == null;
- }
-
- /** Set/update the cache or change the node */
- public synchronized void setNode(Node node) throws RepositoryException {
- if (!itemIsNode())
- throw new CmsException("Cannot set a Node on a Property");
-
- if (node == null) {// clear cache
- this.cache = null;
- return;
- }
-
- if (session == null || session != node.getSession())// check session
- throw new CmsException("Uncompatible session");
-
- if (nodeId == null || !nodeId.equals(node.getIdentifier())) {
- nodeId = node.getIdentifier();
- cache = node;
- itemUpdated();
- } else {
- cache = node;// set/update cache
- }
- }
-
- /** Set/update the cache or change the property */
- public synchronized void setProperty(Property prop)
- throws RepositoryException {
- if (itemIsNode())
- throw new CmsException("Cannot set a Property on a Node");
-
- if (prop == null) {// clear cache
- this.cache = null;
- return;
- }
-
- if (session == null || session != prop.getSession())// check session
- throw new CmsException("Uncompatible session");
-
- Node node = prop.getNode();
- if (nodeId == null || !nodeId.equals(node.getIdentifier())
- || !property.equals(prop.getName())) {
- nodeId = node.getIdentifier();
- property = prop.getName();
- cache = node;
- itemUpdated();
- } else {
- cache = node;// set/update cache
- }
- }
-
- public synchronized String getNodeId() {
- return nodeId;
- }
-
- /** Change the node, does nothing if same. */
- public synchronized void setNodeId(String nodeId)
- throws RepositoryException {
- if (this.nodeId != null && this.nodeId.equals(nodeId))
- return;
- this.nodeId = nodeId;
- if (cache != null)
- cache = session.getNodeByIdentifier(this.nodeId);
- itemUpdated();
- }
-
- protected synchronized void itemUpdated() {
- layout();
- }
-
- public Session getSession() {
- return session;
- }
-}
+++ /dev/null
-package org.argeo.cms.widgets;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Composite;
-
-/**
- * A composite that can be scrolled vertically. It wraps a
- * {@link ScrolledComposite} (and is being wrapped by it), simplifying its
- * configuration.
- */
-public class ScrolledPage extends Composite {
- private static final long serialVersionUID = 1593536965663574437L;
-
- private ScrolledComposite scrolledComposite;
-
- public ScrolledPage(Composite parent, int style) {
- super(new ScrolledComposite(parent, SWT.V_SCROLL), style);
- scrolledComposite = (ScrolledComposite) getParent();
- scrolledComposite.setContent(this);
-
- scrolledComposite.setExpandVertical(true);
- scrolledComposite.setExpandHorizontal(true);
- scrolledComposite.addControlListener(new ScrollControlListener());
- }
-
- @Override
- public void layout(boolean changed, boolean all) {
- updateScroll();
- super.layout(changed, all);
- }
-
- protected void updateScroll() {
- Rectangle r = scrolledComposite.getClientArea();
- Point preferredSize = computeSize(r.width, SWT.DEFAULT);
- scrolledComposite.setMinHeight(preferredSize.y);
- }
-
- // public ScrolledComposite getScrolledComposite() {
- // return this.scrolledComposite;
- // }
-
- /** Set it on the wrapping scrolled composite */
- @Override
- public void setLayoutData(Object layoutData) {
- scrolledComposite.setLayoutData(layoutData);
- }
-
- private class ScrollControlListener extends
- org.eclipse.swt.events.ControlAdapter {
- private static final long serialVersionUID = -3586986238567483316L;
-
- public void controlResized(ControlEvent e) {
- updateScroll();
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.widgets;
-
-import javax.jcr.Item;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.CmsConstants;
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Editable text part displaying styled text. */
-public abstract class StyledControl extends JcrComposite implements CmsConstants {
- private static final long serialVersionUID = -6372283442330912755L;
- private Control control;
-
- private Composite container;
- private Composite box;
-
- protected MouseListener mouseListener;
- protected FocusListener focusListener;
-
- private Boolean editing = Boolean.FALSE;
-
- public StyledControl(Composite parent, int swtStyle) {
- super(parent, swtStyle);
- setLayout(CmsUtils.noSpaceGridLayout());
- }
-
- public StyledControl(Composite parent, int style, Item item) throws RepositoryException {
- super(parent, style, item);
- }
-
- public StyledControl(Composite parent, int style, Item item, boolean cacheImmediately) throws RepositoryException {
- super(parent, style, item, cacheImmediately);
- }
-
- protected abstract Control createControl(Composite box, String style);
-
- protected Composite createBox(Composite parent) {
- Composite box = new Composite(parent, SWT.INHERIT_DEFAULT);
- setContainerLayoutData(box);
- box.setLayout(CmsUtils.noSpaceGridLayout());
- // new Label(box, SWT.NONE).setText("BOX");
- return box;
- }
-
- public Control getControl() {
- return control;
- }
-
- protected synchronized Boolean isEditing() {
- return editing;
- }
-
- public synchronized void startEditing() {
- assert !isEditing();
- editing = true;
- // int height = control.getSize().y;
- String style = (String) control.getData(STYLE);
- clear(false);
- control = createControl(box, style);
- setControlLayoutData(control);
-
- // add the focus listener to the newly created edition control
- if (focusListener != null)
- control.addFocusListener(focusListener);
- }
-
- public synchronized void stopEditing() {
- assert isEditing();
- editing = false;
- String style = (String) control.getData(STYLE);
- clear(false);
- control = createControl(box, style);
- setControlLayoutData(control);
- }
-
- public void setStyle(String style) {
- Object currentStyle = null;
- if (control != null)
- currentStyle = control.getData(STYLE);
- if (currentStyle != null && currentStyle.equals(style))
- return;
-
- // Integer preferredHeight = control != null ? control.getSize().y :
- // null;
- clear(true);
- control = createControl(box, style);
- setControlLayoutData(control);
-
- control.getParent().setData(STYLE, style + "_box");
- control.getParent().getParent().setData(STYLE, style + "_container");
- }
-
- /** To be overridden */
- protected void setControlLayoutData(Control control) {
- control.setLayoutData(CmsUtils.fillWidth());
- }
-
- /** To be overridden */
- protected void setContainerLayoutData(Composite composite) {
- composite.setLayoutData(CmsUtils.fillWidth());
- }
-
- protected void clear(boolean deep) {
- if (deep) {
- for (Control control : getChildren())
- control.dispose();
- container = createBox(this);
- box = createBox(container);
- } else {
- control.dispose();
- }
- }
-
- public void setMouseListener(MouseListener mouseListener) {
- if (this.mouseListener != null && control != null)
- control.removeMouseListener(this.mouseListener);
- this.mouseListener = mouseListener;
- if (control != null && this.mouseListener != null)
- control.addMouseListener(mouseListener);
- }
-
- public void setFocusListener(FocusListener focusListener) {
- if (this.focusListener != null && control != null)
- control.removeFocusListener(this.focusListener);
- this.focusListener = focusListener;
- if (control != null && this.focusListener != null)
- control.addFocusListener(focusListener);
- }
-}
+++ /dev/null
-package org.argeo.cms.widgets;
-
-/** Styles references in the CSS. */
-public interface TextStyles {
- /** The whole page area */
- public final static String TEXT_AREA = "text_area";
- /** Area providing controls for editing text */
- public final static String TEXT_EDITOR_HEADER = "text_editor_header";
- /** The styled composite for editing the text */
- public final static String TEXT_STYLED_COMPOSITE = "text_styled_composite";
- /** A section */
- public final static String TEXT_SECTION = "text_section";
- /** A paragraph */
- public final static String TEXT_PARAGRAPH = "text_paragraph";
- /** An image */
- public final static String TEXT_IMG = "text_img";
- /** The dialog to edit styled paragraph */
- public final static String TEXT_STYLED_TOOLS_DIALOG = "text_styled_tools_dialog";
-
- /*
- * DEFAULT TEXT STYLES
- */
- /** Default style for text body */
- public final static String TEXT_DEFAULT = "text_default";
- /** Fixed-width, typically code */
- public final static String TEXT_PRE = "text_pre";
- /** Quote */
- public final static String TEXT_QUOTE = "text_quote";
- /** Title */
- public final static String TEXT_TITLE = "text_title";
- /** Header (to be dynamically completed with the depth, e.g. text_h1) */
- public final static String TEXT_H = "text_h";
-
- /** Default style for images */
- public final static String TEXT_IMAGE = "text_image";
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.cms.widgets.auth;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.jface.dialogs.TrayDialog;
-import org.eclipse.jface.operation.IRunnableWithProgress;
-import org.eclipse.jface.operation.ModalContext;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.osgi.framework.FrameworkUtil;
-
-/** Base for login dialogs */
-public abstract class AbstractLoginDialog extends TrayDialog implements CallbackHandler {
- private static final long serialVersionUID = -8046708963512717709L;
-
- private final static Log log = LogFactory.getLog(AbstractLoginDialog.class);
-
- private Thread modalContextThread = null;
- boolean processCallbacks = false;
- boolean isCancelled = false;
- Callback[] callbackArray;
-
- protected final Callback[] getCallbacks() {
- return this.callbackArray;
- }
-
- public abstract void internalHandle();
-
- public boolean isCancelled() {
- return isCancelled;
- }
-
- protected AbstractLoginDialog(Shell parentShell) {
- super(parentShell);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth
- * .callback.Callback[])
- */
- public void handle(final Callback[] callbacks) throws IOException {
- // clean previous usage
- if (processCallbacks) {
- // this handler was already used
- processCallbacks = false;
- }
-
- if (modalContextThread != null) {
- try {
- modalContextThread.join(1000);
- } catch (InterruptedException e) {
- // silent
- }
- modalContextThread = null;
- }
-
- // initialize
- this.callbackArray = callbacks;
- final Display display = Display.getDefault();
- display.syncExec(new Runnable() {
-
- public void run() {
- isCancelled = false;
- setBlockOnOpen(false);
- open();
-
- final Button okButton = getButton(IDialogConstants.OK_ID);
- okButton.setText("Login");
- okButton.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = -200281625679096775L;
-
- public void widgetSelected(final SelectionEvent event) {
- processCallbacks = true;
- }
-
- public void widgetDefaultSelected(final SelectionEvent event) {
- // nothing to do
- }
- });
- final Button cancel = getButton(IDialogConstants.CANCEL_ID);
- cancel.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = -3826030278084915815L;
-
- public void widgetSelected(final SelectionEvent event) {
- isCancelled = true;
- processCallbacks = true;
- }
-
- public void widgetDefaultSelected(final SelectionEvent event) {
- // nothing to do
- }
- });
- }
- });
- try {
- ModalContext.setAllowReadAndDispatch(true); // Works for now.
- ModalContext.run(new IRunnableWithProgress() {
-
- public void run(final IProgressMonitor monitor) {
- modalContextThread = Thread.currentThread();
- // Wait here until OK or cancel is pressed, then let it rip.
- // The event
- // listener
- // is responsible for closing the dialog (in the
- // loginSucceeded
- // event).
- while (!processCallbacks && (modalContextThread != null)
- && (modalContextThread == Thread.currentThread())
- && FrameworkUtil.getBundle(AbstractLoginDialog.class).getBundleContext() != null) {
- // Note: SecurityUiPlugin.getDefault() != null is false
- // when the OSGi runtime is shut down
- try {
- Thread.sleep(100);
- // if (display.isDisposed()) {
- // log.warn("Display is disposed, killing login
- // dialog thread");
- // throw new ThreadDeath();
- // }
- } catch (final Exception e) {
- // do nothing
- }
- }
- processCallbacks = false;
- // Call the adapter to handle the callbacks
- if (!isCancelled())
- internalHandle();
- else
- // clear callbacks are when cancelling
- for (Callback callback : callbacks)
- if (callback instanceof PasswordCallback) {
- char[] arr = ((PasswordCallback) callback).getPassword();
- if (arr != null) {
- Arrays.fill(arr, '*');
- ((PasswordCallback) callback).setPassword(null);
- }
- } else if (callback instanceof NameCallback)
- ((NameCallback) callback).setName(null);
- }
- }, true, new NullProgressMonitor(), Display.getDefault());
- } catch (ThreadDeath e) {
- isCancelled = true;
- log.debug("Thread " + Thread.currentThread().getId() + " died");
- throw e;
- } catch (Exception e) {
- isCancelled = true;
- IOException ioe = new IOException("Unexpected issue in login dialog, see root cause for more details");
- ioe.initCause(e);
- throw ioe;
- } finally {
- // so that the modal thread dies
- processCallbacks = true;
- // try {
- // // wait for the modal context thread to gracefully exit
- // modalContextThread.join();
- // } catch (InterruptedException ie) {
- // // silent
- // }
- modalContextThread = null;
- }
- }
-
- protected void configureShell(Shell shell) {
- super.configureShell(shell);
- shell.setText("Authentication");
- }
-}
+++ /dev/null
-package org.argeo.cms.widgets.auth;
-
-import static org.argeo.cms.CmsMsg.password;
-import static org.argeo.cms.CmsMsg.username;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Locale;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.LanguageCallback;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsMsg;
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.auth.HttpRequestCallback;
-import org.argeo.cms.ui.CmsStyles;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.internal.Activator;
-import org.argeo.cms.util.CmsUtils;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeState;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.events.TraverseEvent;
-import org.eclipse.swt.events.TraverseListener;
-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.Shell;
-import org.eclipse.swt.widgets.Text;
-
-public class CmsLogin implements CmsStyles, CallbackHandler {
- private final static Log log = LogFactory.getLog(CmsLogin.class);
-
- private Composite parent;
- private Text usernameT, passwordT;
- private Composite credentialsBlock;
- private final SelectionListener loginSelectionListener;
-
- private final Locale defaultLocale;
- private LocaleChoice localeChoice = null;
-
- private final CmsView cmsView;
-
- // optional subject to be set explicitly
- private Subject subject = null;
-
- public CmsLogin(CmsView cmsView) {
- this.cmsView = cmsView;
- NodeState nodeState = Activator.getNodeState();
- if (nodeState != null) {
- defaultLocale = nodeState.getDefaultLocale();
- List<Locale> locales = nodeState.getLocales();
- if (locales != null)
- localeChoice = new LocaleChoice(locales, defaultLocale);
- } else {
- defaultLocale = Locale.getDefault();
- }
- loginSelectionListener = new SelectionListener() {
- private static final long serialVersionUID = -8832133363830973578L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- login();
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- }
- };
- }
-
- protected boolean isAnonymous() {
- return cmsView.isAnonymous();
- }
-
- public final void createUi(Composite parent) {
- this.parent = parent;
- createContents(parent);
- }
-
- protected void createContents(Composite parent) {
- defaultCreateContents(parent);
- }
-
- public final void defaultCreateContents(Composite parent) {
- parent.setLayout(CmsUtils.noSpaceGridLayout());
- Composite credentialsBlock = createCredentialsBlock(parent);
- if (parent instanceof Shell) {
- credentialsBlock.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
- }
- }
-
- public final Composite createCredentialsBlock(Composite parent) {
- if (isAnonymous()) {
- return anonymousUi(parent);
- } else {
- return userUi(parent);
- }
- }
-
- protected Composite getCredentialsBlock() {
- return credentialsBlock;
- }
-
- protected Composite userUi(Composite parent) {
- Locale locale = localeChoice == null ? this.defaultLocale : localeChoice.getSelectedLocale();
- credentialsBlock = new Composite(parent, SWT.NONE);
- credentialsBlock.setLayout(new GridLayout());
- // credentialsBlock.setLayoutData(CmsUtils.fillAll());
-
- specificUserUi(credentialsBlock);
-
- Label l = new Label(credentialsBlock, SWT.NONE);
- CmsUtils.style(l, CMS_USER_MENU_ITEM);
- l.setText(CmsMsg.logout.lead(locale));
- GridData lData = CmsUtils.fillWidth();
- lData.widthHint = 120;
- l.setLayoutData(lData);
-
- l.addMouseListener(new MouseAdapter() {
- private static final long serialVersionUID = 6444395812777413116L;
-
- public void mouseDown(MouseEvent e) {
- logout();
- }
- });
- return credentialsBlock;
- }
-
- /** To be overridden */
- protected void specificUserUi(Composite parent) {
-
- }
-
- protected Composite anonymousUi(Composite parent) {
- Locale locale = localeChoice == null ? this.defaultLocale : localeChoice.getSelectedLocale();
- // We need a composite for the traversal
- credentialsBlock = new Composite(parent, SWT.NONE);
- credentialsBlock.setLayout(new GridLayout());
- // credentialsBlock.setLayoutData(CmsUtils.fillAll());
- CmsUtils.style(credentialsBlock, CMS_LOGIN_DIALOG);
-
- Integer textWidth = 120;
- if (parent instanceof Shell)
- CmsUtils.style(parent, CMS_USER_MENU);
- // new Label(this, SWT.NONE).setText(CmsMsg.username.lead());
- usernameT = new Text(credentialsBlock, SWT.BORDER);
- usernameT.setMessage(username.lead(locale));
- CmsUtils.style(usernameT, CMS_LOGIN_DIALOG_USERNAME);
- GridData gd = CmsUtils.fillWidth();
- gd.widthHint = textWidth;
- usernameT.setLayoutData(gd);
-
- // new Label(this, SWT.NONE).setText(CmsMsg.password.lead());
- passwordT = new Text(credentialsBlock, SWT.BORDER | SWT.PASSWORD);
- passwordT.setMessage(password.lead(locale));
- CmsUtils.style(passwordT, CMS_LOGIN_DIALOG_PASSWORD);
- gd = CmsUtils.fillWidth();
- gd.widthHint = textWidth;
- passwordT.setLayoutData(gd);
-
- TraverseListener tl = new TraverseListener() {
- private static final long serialVersionUID = -1158892811534971856L;
-
- public void keyTraversed(TraverseEvent e) {
- if (e.detail == SWT.TRAVERSE_RETURN)
- login();
- }
- };
- credentialsBlock.addTraverseListener(tl);
- usernameT.addTraverseListener(tl);
- passwordT.addTraverseListener(tl);
- parent.setTabList(new Control[] { credentialsBlock });
- credentialsBlock.setTabList(new Control[] { usernameT, passwordT });
-
- // Button
- Button loginButton = new Button(credentialsBlock, SWT.PUSH);
- loginButton.setText(CmsMsg.login.lead(locale));
- loginButton.setLayoutData(CmsUtils.fillWidth());
- loginButton.addSelectionListener(loginSelectionListener);
-
- extendsCredentialsBlock(credentialsBlock, locale, loginSelectionListener);
- if (localeChoice != null)
- createLocalesBlock(credentialsBlock);
- return credentialsBlock;
- }
-
- /**
- * To be overridden in order to provide custom login button and other links.
- */
- protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale,
- SelectionListener loginSelectionListener) {
-
- }
-
- protected void updateLocale(Locale selectedLocale) {
- // save already entered values
- String usernameStr = usernameT.getText();
- char[] pwd = passwordT.getTextChars();
-
- for (Control child : parent.getChildren())
- child.dispose();
- createContents(parent);
- if (parent.getParent() != null)
- parent.getParent().layout();
- else
- parent.layout();
- usernameT.setText(usernameStr);
- passwordT.setTextChars(pwd);
- }
-
- protected Composite createLocalesBlock(final Composite parent) {
- Composite c = new Composite(parent, SWT.NONE);
- CmsUtils.style(c, CMS_USER_MENU_ITEM);
- c.setLayout(CmsUtils.noSpaceGridLayout());
- c.setLayoutData(CmsUtils.fillAll());
-
- SelectionListener selectionListener = new SelectionAdapter() {
- private static final long serialVersionUID = 4891637813567806762L;
-
- public void widgetSelected(SelectionEvent event) {
- Button button = (Button) event.widget;
- if (button.getSelection()) {
- localeChoice.setSelectedIndex((Integer) event.widget.getData());
- updateLocale(localeChoice.getSelectedLocale());
- }
- };
- };
-
- List<Locale> locales = localeChoice.getLocales();
- for (Integer i = 0; i < locales.size(); i++) {
- Locale locale = locales.get(i);
- Button button = new Button(c, SWT.RADIO);
- CmsUtils.style(button, CMS_USER_MENU_ITEM);
- button.setData(i);
- button.setText(LocaleUtils.lead(locale.getDisplayName(locale), locale) + " (" + locale + ")");
- // button.addListener(SWT.Selection, listener);
- button.addSelectionListener(selectionListener);
- if (i == localeChoice.getSelectedIndex())
- button.setSelection(true);
- }
- return c;
- }
-
- protected boolean login() {
- // TODO use CmsVie in order to retrieve subject?
- // Subject subject = cmsView.getLoginContext().getSubject();
- // LoginContext loginContext = cmsView.getLoginContext();
- try {
- //
- // LOGIN
- //
- // loginContext.logout();
- LoginContext loginContext;
- if (subject == null)
- loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, this);
- else
- loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, subject, this);
- loginContext.login();
- cmsView.authChange(loginContext);
- return true;
- } catch (LoginException e) {
- if (log.isTraceEnabled())
- log.warn("Login failed: " + e.getMessage(), e);
- else
- log.warn("Login failed: " + e.getMessage());
-
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e2) {
- // silent
- }
- // ErrorFeedback.show("Login failed", e);
- return false;
- }
- // catch (LoginException e) {
- // log.error("Cannot login", e);
- // return false;
- // }
- }
-
- protected void logout() {
- cmsView.logout();
- cmsView.navigateTo("~");
- }
-
- @Override
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- for (Callback callback : callbacks) {
- if (callback instanceof NameCallback && usernameT != null)
- ((NameCallback) callback).setName(usernameT.getText());
- else if (callback instanceof PasswordCallback && passwordT != null)
- ((PasswordCallback) callback).setPassword(passwordT.getTextChars());
- else if (callback instanceof HttpRequestCallback) {
- ((HttpRequestCallback) callback).setRequest(UiContext.getHttpRequest());
- ((HttpRequestCallback) callback).setResponse(UiContext.getHttpResponse());
- } else if (callback instanceof LanguageCallback) {
- Locale toUse = null;
- if (localeChoice != null)
- toUse = localeChoice.getSelectedLocale();
- else if (defaultLocale != null)
- toUse = defaultLocale;
-
- if (toUse != null) {
- ((LanguageCallback) callback).setLocale(toUse);
- UiContext.setLocale(toUse);
- }
-
- }
- }
- }
-
- public void setSubject(Subject subject) {
- this.subject = subject;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.widgets.auth;
-
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.util.CmsUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-/** The site-related user menu */
-public class CmsLoginShell extends CmsLogin {
- private final Shell shell;
-
- public CmsLoginShell(CmsView cmsView) {
- super(cmsView);
- shell = createShell();
- CmsUtils.style(shell, CMS_USER_MENU);
-// createUi(shell);
- }
-
- /** To be overridden. */
- protected Shell createShell() {
- Shell shell = new Shell(Display.getCurrent(), SWT.NO_TRIM);
- shell.setMaximized(true);
- return shell;
- }
-
- /** To be overridden. */
- public void open() {
- shell.open();
- }
-
- @Override
- protected boolean login() {
- boolean success = false;
- try {
- success = super.login();
- return success;
- } finally {
- if (success)
- closeShell();
- else {
- for (Control child : shell.getChildren())
- child.dispose();
- createUi(shell);
- shell.layout();
- // TODO error message
- }
- }
- }
-
- @Override
- protected void logout() {
- closeShell();
- super.logout();
- }
-
- protected void closeShell() {
- if (!shell.isDisposed()) {
- shell.close();
- shell.dispose();
- }
- }
-
- public Shell getShell() {
- return shell;
- }
-
- public void createUi(){
- createUi(shell);
- }
-}
+++ /dev/null
-package org.argeo.cms.widgets.auth;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.TextOutputCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * A composite that can populate itself based on {@link Callback}s. It can be
- * used directly as a {@link CallbackHandler} or be used by one by calling the
- * {@link #createCallbackHandlers(Callback[])}. Supported standard
- * {@link Callback}s are:<br>
- * <ul>
- * <li>{@link PasswordCallback}</li>
- * <li>{@link NameCallback}</li>
- * <li>{@link TextOutputCallback}</li>
- * </ul>
- * Supported Argeo {@link Callback}s are:<br>
- * <ul>
- * <li>{@link LocaleChoice}</li>
- * </ul>
- */
-public class CompositeCallbackHandler extends Composite implements CallbackHandler {
- private static final long serialVersionUID = -928223893722723777L;
-
- private boolean wasUsedAlready = false;
- private boolean isSubmitted = false;
- private boolean isCanceled = false;
-
- public CompositeCallbackHandler(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- public synchronized void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- // reset
- if (wasUsedAlready && !isSubmitted() && !isCanceled()) {
- cancel();
- for (Control control : getChildren())
- control.dispose();
- isSubmitted = false;
- isCanceled = false;
- }
-
- for (Callback callback : callbacks)
- checkCallbackSupported(callback);
- // create controls synchronously in the UI thread
- getDisplay().syncExec(new Runnable() {
-
- @Override
- public void run() {
- createCallbackHandlers(callbacks);
- }
- });
-
- if (!wasUsedAlready)
- wasUsedAlready = true;
-
- // while (!isSubmitted() && !isCanceled()) {
- // try {
- // wait(1000l);
- // } catch (InterruptedException e) {
- // // silent
- // }
- // }
-
- // cleanCallbacksAfterCancel(callbacks);
- }
-
- public void checkCallbackSupported(Callback callback) throws UnsupportedCallbackException {
- if (callback instanceof TextOutputCallback || callback instanceof NameCallback
- || callback instanceof PasswordCallback || callback instanceof LocaleChoice) {
- return;
- } else {
- throw new UnsupportedCallbackException(callback);
- }
- }
-
- /**
- * Set writable callbacks to null if the handle is canceled (check is done
- * by the method)
- */
- public void cleanCallbacksAfterCancel(Callback[] callbacks) {
- if (isCanceled()) {
- for (Callback callback : callbacks) {
- if (callback instanceof NameCallback) {
- ((NameCallback) callback).setName(null);
- } else if (callback instanceof PasswordCallback) {
- PasswordCallback pCallback = (PasswordCallback) callback;
- char[] arr = pCallback.getPassword();
- if (arr != null) {
- Arrays.fill(arr, '*');
- pCallback.setPassword(null);
- }
- }
- }
- }
- }
-
- public void createCallbackHandlers(Callback[] callbacks) {
- Composite composite = this;
- for (int i = 0; i < callbacks.length; i++) {
- Callback callback = callbacks[i];
- if (callback instanceof TextOutputCallback) {
- createLabelTextoutputHandler(composite, (TextOutputCallback) callback);
- } else if (callback instanceof NameCallback) {
- createNameHandler(composite, (NameCallback) callback);
- } else if (callback instanceof PasswordCallback) {
- createPasswordHandler(composite, (PasswordCallback) callback);
- } else if (callback instanceof LocaleChoice) {
- createLocaleHandler(composite, (LocaleChoice) callback);
- }
- }
- }
-
- protected Text createNameHandler(Composite composite, final NameCallback callback) {
- Label label = new Label(composite, SWT.NONE);
- label.setText(callback.getPrompt());
- final Text text = new Text(composite, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
- if (callback.getDefaultName() != null) {
- // set default value, if provided
- text.setText(callback.getDefaultName());
- callback.setName(callback.getDefaultName());
- }
- text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- text.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = 7300032545287292973L;
-
- public void modifyText(ModifyEvent event) {
- callback.setName(text.getText());
- }
- });
- text.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = 1820530045857665111L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- submit();
- }
- });
-
- text.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -8698107785092095713L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- }
- });
- return text;
- }
-
- protected Text createPasswordHandler(Composite composite, final PasswordCallback callback) {
- Label label = new Label(composite, SWT.NONE);
- label.setText(callback.getPrompt());
- final Text passwordText = new Text(composite, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD | SWT.BORDER);
- passwordText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- passwordText.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = -7099363995047686732L;
-
- public void modifyText(ModifyEvent event) {
- callback.setPassword(passwordText.getTextChars());
- }
- });
- passwordText.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = 1820530045857665111L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- submit();
- }
- });
- return passwordText;
- }
-
- protected Combo createLocaleHandler(Composite composite, final LocaleChoice callback) {
- String[] labels = callback.getSupportedLocalesLabels();
- if (labels.length == 0)
- return null;
- Label label = new Label(composite, SWT.NONE);
- label.setText("Language");
-
- final Combo combo = new Combo(composite, SWT.READ_ONLY);
- combo.setItems(labels);
- combo.select(callback.getDefaultIndex());
- combo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- combo.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = 38678989091946277L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- callback.setSelectedIndex(combo.getSelectionIndex());
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- }
- });
- return combo;
- }
-
- protected Label createLabelTextoutputHandler(Composite composite, final TextOutputCallback callback) {
- Label label = new Label(composite, SWT.NONE);
- label.setText(callback.getMessage());
- GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
- data.horizontalSpan = 2;
- label.setLayoutData(data);
- return label;
- // TODO: find a way to pass this information
- // int messageType = callback.getMessageType();
- // int dialogMessageType = IMessageProvider.NONE;
- // switch (messageType) {
- // case TextOutputCallback.INFORMATION:
- // dialogMessageType = IMessageProvider.INFORMATION;
- // break;
- // case TextOutputCallback.WARNING:
- // dialogMessageType = IMessageProvider.WARNING;
- // break;
- // case TextOutputCallback.ERROR:
- // dialogMessageType = IMessageProvider.ERROR;
- // break;
- // }
- // setMessage(callback.getMessage(), dialogMessageType);
- }
-
- synchronized boolean isSubmitted() {
- return isSubmitted;
- }
-
- synchronized boolean isCanceled() {
- return isCanceled;
- }
-
- protected synchronized void submit() {
- isSubmitted = true;
- notifyAll();
- }
-
- protected synchronized void cancel() {
- isCanceled = true;
- notifyAll();
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.cms.widgets.auth;
-
-import javax.security.auth.callback.CallbackHandler;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-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.Display;
-import org.eclipse.swt.widgets.Shell;
-
-/** Default authentication dialog, to be used as {@link CallbackHandler}. */
-public class DefaultLoginDialog extends AbstractLoginDialog {
- private static final long serialVersionUID = -8551827590693035734L;
-
- public DefaultLoginDialog() {
- this(Display.getCurrent().getActiveShell());
- }
-
- public DefaultLoginDialog(Shell parentShell) {
- super(parentShell);
- }
-
- protected Point getInitialSize() {
- return new Point(350, 180);
- }
-
- @Override
- protected Control createContents(Composite parent) {
- Control control = super.createContents(parent);
- parent.pack();
-
- // Move the dialog to the center of the top level shell.
- Rectangle shellBounds;
- if (Display.getCurrent().getActiveShell() != null) // RCP
- shellBounds = Display.getCurrent().getActiveShell().getBounds();
- else
- shellBounds = Display.getCurrent().getBounds();// RAP
- Point dialogSize = parent.getSize();
- int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2;
- int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2;
- parent.setLocation(x, y);
- return control;
- }
-
- protected Control createDialogArea(Composite parent) {
- Composite dialogarea = (Composite) super.createDialogArea(parent);
- CompositeCallbackHandler composite = new CompositeCallbackHandler(
- dialogarea, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
- composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- composite.createCallbackHandlers(getCallbacks());
- return composite;
- }
-
- public void internalHandle() {
- }
-}
+++ /dev/null
-package org.argeo.cms.widgets.auth;
-
-import java.io.IOException;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-import org.argeo.eclipse.ui.dialogs.LightweightDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-public class DynamicCallbackHandler implements CallbackHandler {
-
- @Override
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- Shell activeShell = Display.getCurrent().getActiveShell();
- LightweightDialog dialog = new LightweightDialog(activeShell) {
-
- @Override
- protected Control createDialogArea(Composite parent) {
- CompositeCallbackHandler cch = new CompositeCallbackHandler(parent, SWT.NONE);
- cch.createCallbackHandlers(callbacks);
- return cch;
- }
- };
- dialog.setBlockOnOpen(true);
- dialog.open();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.cms.widgets.auth;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-
-import javax.security.auth.callback.LanguageCallback;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.LocaleUtils;
-
-/** Choose in a list of locales. TODO: replace with {@link LanguageCallback} */
-public class LocaleChoice {
- private final List<Locale> locales;
-
- private Integer selectedIndex = null;
- private final Integer defaultIndex;
-
- public LocaleChoice(List<Locale> locales, Locale defaultLocale) {
- Integer defaultIndex = null;
- this.locales = Collections.unmodifiableList(locales);
- for (int i = 0; i < locales.size(); i++)
- if (locales.get(i).equals(defaultLocale))
- defaultIndex = i;
-
- // based on language only
- if (defaultIndex == null)
- for (int i = 0; i < locales.size(); i++)
- if (locales.get(i).getLanguage().equals(defaultLocale.getLanguage()))
- defaultIndex = i;
-
- if (defaultIndex == null)
- throw new CmsException("Default locale " + defaultLocale + " is not in available locales " + locales);
- this.defaultIndex = defaultIndex;
-
- this.selectedIndex = defaultIndex;
- }
-
- /**
- * Convenience constructor based on a comma separated list of iso codes (en,
- * en_US, fr_CA, etc.). Default selection is default locale.
- */
- public LocaleChoice(String locales, Locale defaultLocale) {
- this(LocaleUtils.asLocaleList(locales), defaultLocale);
- }
-
- public String[] getSupportedLocalesLabels() {
- String[] labels = new String[locales.size()];
- for (int i = 0; i < locales.size(); i++) {
- Locale locale = locales.get(i);
- if (locale.getCountry().equals(""))
- labels[i] = locale.getDisplayLanguage(locale) + " [" + locale.getLanguage() + "]";
- else
- labels[i] = locale.getDisplayLanguage(locale) + " (" + locale.getDisplayCountry(locale) + ") ["
- + locale.getLanguage() + "_" + locale.getCountry() + "]";
-
- }
- return labels;
- }
-
- public Locale getSelectedLocale() {
- if (selectedIndex == null)
- return null;
- return locales.get(selectedIndex);
- }
-
- public void setSelectedIndex(Integer selectedIndex) {
- this.selectedIndex = selectedIndex;
- }
-
- public Integer getSelectedIndex() {
- return selectedIndex;
- }
-
- public Integer getDefaultIndex() {
- return defaultIndex;
- }
-
- public List<Locale> getLocales() {
- return locales;
- }
-
- public Locale getDefaultLocale() {
- return locales.get(getDefaultIndex());
- }
-}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.commons.cnd.CndImporter;
+import org.argeo.api.tabular.TabularColumn;
+import org.argeo.api.tabular.TabularRow;
+import org.argeo.api.tabular.TabularRowIterator;
+import org.argeo.api.tabular.TabularWriter;
import org.argeo.cms.ArgeoTypes;
import org.argeo.jackrabbit.unit.AbstractJackrabbitTestCase;
-import org.argeo.node.tabular.TabularColumn;
-import org.argeo.node.tabular.TabularRow;
-import org.argeo.node.tabular.TabularRowIterator;
-import org.argeo.node.tabular.TabularWriter;
public class JcrTabularTest extends AbstractJackrabbitTestCase {
private final static Log log = LogFactory.getLog(JcrTabularTest.class);
public void testWriteReadCsv() throws Exception {
// session().setNamespacePrefix("argeo", ArgeoNames.ARGEO_NAMESPACE);
- InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/argeo/node/ldap.cnd"));
+ InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/argeo/api/ldap.cnd"));
CndImporter.registerNodeTypes(reader, session());
reader.close();
reader = new InputStreamReader(getClass().getResourceAsStream("/org/argeo/cms/argeo.cnd"));
<dependencies>
<dependency>
<groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.node.api</artifactId>
+ <artifactId>org.argeo.api</artifactId>
<version>2.1.88-SNAPSHOT</version>
</dependency>
<dependency>
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.security.AnonymousPrincipal;
+import org.argeo.api.security.DataAdminPrincipal;
+import org.argeo.api.security.NodeSecurityUtils;
//import org.apache.jackrabbit.core.security.AnonymousPrincipal;
//import org.apache.jackrabbit.core.security.SecurityConstants;
//import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
import org.argeo.cms.internal.auth.ImpliedByPrincipal;
import org.argeo.cms.internal.http.WebCmsSessionImpl;
import org.argeo.cms.internal.kernel.Activator;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.security.AnonymousPrincipal;
-import org.argeo.node.security.DataAdminPrincipal;
-import org.argeo.node.security.NodeSecurityUtils;
import org.argeo.osgi.useradmin.AuthenticatingUser;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.auth.CmsSessionImpl;
import org.argeo.cms.internal.auth.ImpliedByPrincipal;
import org.argeo.cms.internal.kernel.Activator;
-import org.argeo.node.NodeConstants;
import org.osgi.service.useradmin.Authorization;
/**
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
-import org.argeo.node.security.PBEKeySpecCallback;
+import org.argeo.api.security.PBEKeySpecCallback;
import org.argeo.util.PasswordEncryption;
/** Adds a secret key to the private credentials */
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.security.DataAdminPrincipal;
import org.argeo.cms.internal.auth.ImpliedByPrincipal;
import org.argeo.naming.LdapAttrs;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.security.DataAdminPrincipal;
import org.argeo.osgi.useradmin.IpaUtils;
public class SingleUserLoginModule implements LoginModule {
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.security.CryptoKeyring;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.kernel.Activator;
import org.argeo.naming.LdapAttrs;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.security.CryptoKeyring;
import org.argeo.osgi.useradmin.AuthenticatingUser;
import org.argeo.osgi.useradmin.IpaUtils;
import org.argeo.osgi.useradmin.OsUserUtils;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.naming.LdapAttrs;
-import org.argeo.node.NodeConstants;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
import org.osgi.service.useradmin.UserAdmin;
+++ /dev/null
-package org.argeo.cms.i18n;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Enumeration;
-import java.util.ResourceBundle;
-import java.util.Vector;
-
-import org.argeo.cms.CmsException;
-
-/** Expose the default values as a {@link ResourceBundle} */
-@Deprecated
-public class DefaultsResourceBundle extends ResourceBundle {
-
- @Override
- protected Object handleGetObject(String key) {
- Object obj;
- try {
- Field field = getClass().getField(key);
- obj = field.getType().getMethod("getDefault")
- .invoke(field.get(null));
- } catch (Exception e) {
- throw new CmsException("Cannot get default for " + key, e);
- }
- return obj;
- }
-
- @Override
- public Enumeration<String> getKeys() {
- Vector<String> res = new Vector<String>();
- final Field[] fieldArray = getClass().getDeclaredFields();
-
- for (Field field : fieldArray) {
- if (Modifier.isStatic(field.getModifiers())
- && field.getType().isAssignableFrom(LocaleUtils.class)) {
- res.add(field.getName());
- }
- }
- return res.elements();
- }
-
-}
+++ /dev/null
-package org.argeo.cms.i18n;
-
-import java.util.List;
-import java.util.Locale;
-
-import org.argeo.cms.auth.CurrentUser;
-
-/**
- * Utilities simplifying the development of localization enums.
- *
- * @deprecated Use {@link org.argeo.cms.LocaleUtils}
- */
-@Deprecated
-public class LocaleUtils {
- public static Object local(Enum<?> en) {
- return org.argeo.cms.LocaleUtils.local(en);
- }
-
- public static Object local(Enum<?> en, Locale locale) {
- return org.argeo.cms.LocaleUtils.local(en, locale);
- }
-
- public static Object local(Enum<?> en, Locale locale, String resource) {
- return org.argeo.cms.LocaleUtils.local(en, locale, resource);
- }
-
- public static Object local(Enum<?> en, Locale locale, String resource, ClassLoader classLoader) {
- return org.argeo.cms.LocaleUtils.local(en, locale, resource, classLoader);
- }
-
- public static String lead(String raw, Locale locale) {
- return org.argeo.cms.LocaleUtils.lead(raw, locale);
- }
-
- public static String lead(Localized localized) {
- return org.argeo.cms.LocaleUtils.lead(localized);
- }
-
- public static String lead(Localized localized, Locale locale) {
- return org.argeo.cms.LocaleUtils.lead(localized, locale);
- }
-
- static Locale getCurrentLocale() {
- return CurrentUser.locale();
- // return UiContext.getLocale();
- // FIXME look into Subject or settings
- // return Locale.getDefault();
- }
-
- /** Returns null if argument is null. */
- public static List<Locale> asLocaleList(Object locales) {
- return org.argeo.cms.LocaleUtils.asLocaleList(locales);
- }
-}
+++ /dev/null
-package org.argeo.cms.i18n;
-
-/**
- * Localized object.
- *
- * @deprecated Use {@link org.argeo.cms.Localized} instead.
- */
-@Deprecated
-public interface Localized extends org.argeo.cms.Localized {
-}
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.auth.CmsSessionId;
import org.argeo.cms.auth.HttpRequestCallback;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
-import org.argeo.node.NodeConstants;
import org.osgi.service.useradmin.Authorization;
import com.fasterxml.jackson.core.JsonGenerator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.auth.CmsSessionId;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.HttpRequestCallback;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
-import org.argeo.node.NodeConstants;
/** Externally authenticate an http session. */
public class CmsLogoutServlet extends HttpServlet {
package org.argeo.cms.integration;
-import static org.argeo.node.NodeConstants.LOGIN_CONTEXT_USER;
+import static org.argeo.api.NodeConstants.LOGIN_CONTEXT_USER;
import java.io.IOException;
import java.security.AccessControlContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsUserManager;
import org.argeo.cms.auth.HttpRequestCallback;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
import org.argeo.naming.NamingUtils;
-import org.argeo.node.NodeConstants;
import org.osgi.service.useradmin.Authorization;
import com.fasterxml.jackson.core.JsonGenerator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.security.NodeSecurityUtils;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CmsSession;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.security.NodeSecurityUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsUserManager;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.naming.LdapAttrs;
import org.argeo.naming.NamingUtils;
import org.argeo.naming.SharedSecret;
-import org.argeo.node.NodeConstants;
import org.argeo.osgi.useradmin.TokenUtils;
import org.argeo.osgi.useradmin.UserAdminConf;
import org.osgi.framework.InvalidSyntaxException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
-import org.argeo.node.NodeConstants;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.http.HttpContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
import org.argeo.cms.CmsException;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.apache.jackrabbit.core.cache.CacheManager;
import org.apache.jackrabbit.core.config.RepositoryConfig;
import org.apache.jackrabbit.core.config.RepositoryConfigurationParser;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.kernel.CmsPaths;
import org.argeo.jcr.ArgeoJcrException;
-import org.argeo.node.NodeConstants;
import org.xml.sax.InputSource;
/** Can interpret properties in order to create an actual JCR repository. */
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.ArgeoLogger;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeDeployment;
+import org.argeo.api.NodeInstance;
+import org.argeo.api.NodeState;
import org.argeo.cms.CmsException;
import org.argeo.ident.IdentClient;
-import org.argeo.node.ArgeoLogger;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeDeployment;
-import org.argeo.node.NodeInstance;
-import org.argeo.node.NodeState;
import org.argeo.util.LangUtils;
import org.ietf.jgss.GSSCredential;
import org.osgi.framework.BundleActivator;
package org.argeo.cms.internal.kernel;
-import static org.argeo.node.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
+import static org.argeo.api.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
import java.io.File;
import java.io.InputStreamReader;
import org.apache.jackrabbit.commons.cnd.CndImporter;
import org.apache.jackrabbit.core.RepositoryContext;
import org.apache.jackrabbit.core.RepositoryImpl;
+import org.argeo.api.DataModelNamespace;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeDeployment;
+import org.argeo.api.NodeState;
+import org.argeo.api.security.CryptoKeyring;
+import org.argeo.api.security.Keyring;
import org.argeo.cms.ArgeoNames;
import org.argeo.cms.CmsException;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.DataModelNamespace;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeDeployment;
-import org.argeo.node.NodeState;
-import org.argeo.node.security.CryptoKeyring;
-import org.argeo.node.security.Keyring;
import org.argeo.osgi.useradmin.UserAdminConf;
import org.argeo.util.LangUtils;
import org.eclipse.equinox.http.jetty.JettyConfigurator;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.jackrabbit.fs.AbstractJackrabbitFsProvider;
import org.argeo.jcr.fs.JcrFileSystem;
import org.argeo.jcr.fs.JcrFileSystemProvider;
import org.argeo.jcr.fs.JcrFsException;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeInstance;
import org.argeo.cms.CmsException;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeInstance;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeState;
import org.argeo.cms.CmsException;
import org.argeo.cms.LocaleUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeState;
import org.argeo.transaction.simple.SimpleTransactionManager;
import org.argeo.util.LangUtils;
import org.osgi.framework.BundleContext;
package org.argeo.cms.internal.kernel;
-import static org.argeo.node.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
+import static org.argeo.api.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
import java.util.ArrayList;
import java.util.Collections;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.DataModelNamespace;
import org.argeo.cms.CmsException;
-import org.argeo.node.DataModelNamespace;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.http.InternalHttpConstants;
import org.argeo.cms.websocket.CmsWebSocketConfigurator;
import org.argeo.naming.AttributesDictionary;
import org.argeo.naming.LdifParser;
import org.argeo.naming.LdifWriter;
-import org.argeo.node.NodeConstants;
import org.argeo.osgi.useradmin.UserAdminConf;
import org.eclipse.equinox.http.jetty.JettyConfigurator;
import org.osgi.framework.BundleContext;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
import org.argeo.cms.CmsException;
import org.argeo.jcr.JcrRepositoryWrapper;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeUtils;
/**
* Make sure each user has a home directory available.
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.http.InternalHttpConstants;
import org.argeo.cms.internal.jcr.RepoConf;
-import org.argeo.node.NodeConstants;
import org.argeo.osgi.useradmin.UserAdminConf;
/**
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.core.RepositoryImpl;
-import org.argeo.node.NodeConstants;
+import org.argeo.api.NodeConstants;
class JackrabbitLocalRepository extends LocalRepository {
private final static Log log = LogFactory.getLog(JackrabbitLocalRepository.class);
package org.argeo.cms.internal.kernel;
-import org.argeo.node.NodeConstants;
+import org.argeo.api.NodeConstants;
public interface KernelConstants {
String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" };
import javax.security.auth.login.LoginException;
import org.apache.commons.logging.Log;
+import org.argeo.api.DataModelNamespace;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
-import org.argeo.node.DataModelNamespace;
-import org.argeo.node.NodeConstants;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import javax.jcr.Repository;
+import org.argeo.api.NodeConstants;
import org.argeo.jcr.JcrRepositoryWrapper;
-import org.argeo.node.NodeConstants;
class LocalRepository extends JcrRepositoryWrapper {
private final String cn;
import org.apache.jackrabbit.server.SessionProvider;
import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.http.CmsSessionProvider;
import org.argeo.cms.internal.http.DataHttpContext;
import org.argeo.cms.internal.http.LinkServlet;
import org.argeo.cms.internal.http.PrivateHttpContext;
import org.argeo.cms.internal.http.RobotServlet;
-import org.argeo.node.NodeConstants;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.spi.LoggingEvent;
+import org.argeo.api.ArgeoLogListener;
+import org.argeo.api.ArgeoLogger;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
-import org.argeo.node.ArgeoLogListener;
-import org.argeo.node.ArgeoLogger;
-import org.argeo.node.NodeConstants;
import org.argeo.osgi.useradmin.UserAdminConf;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.internal.jcr.RepoConf;
import org.argeo.jcr.ArgeoJcrException;
-import org.argeo.node.NodeConstants;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.apache.commons.httpclient.params.HttpParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.http.client.HttpCredentialProvider;
import org.argeo.cms.internal.http.client.SpnegoAuthScheme;
import org.argeo.naming.DnsBrowser;
-import org.argeo.node.NodeConstants;
import org.argeo.osgi.useradmin.AbstractUserDirectory;
import org.argeo.osgi.useradmin.AggregatingUserAdmin;
import org.argeo.osgi.useradmin.LdapUserAdmin;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.core.RepositoryContext;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.jcr.RepoConf;
import org.argeo.cms.internal.jcr.RepositoryBuilder;
-import org.argeo.node.NodeConstants;
import org.argeo.util.LangUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import javax.security.auth.AuthPermission;
-import org.argeo.node.NodeUtils;
+import org.argeo.api.NodeUtils;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
};
DATA_ADMIN {
- org.argeo.node.DataAdminLoginModule requisite;
+ org.argeo.api.DataAdminLoginModule requisite;
};
NODE {
keyTab="${osgi.instance.area}node/krb5.keytab"
useKeyTab=true
storeKey=true;
- org.argeo.node.DataAdminLoginModule requisite;
+ org.argeo.api.DataAdminLoginModule requisite;
};
KEYRING {
};
DATA_ADMIN {
- org.argeo.node.DataAdminLoginModule requisite;
+ org.argeo.api.DataAdminLoginModule requisite;
};
NODE {
- org.argeo.node.DataAdminLoginModule requisite;
+ org.argeo.api.DataAdminLoginModule requisite;
};
KEYRING {
import javax.security.auth.login.LoginException;
import org.apache.commons.io.IOUtils;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.security.CryptoKeyring;
+import org.argeo.api.security.Keyring;
+import org.argeo.api.security.PBEKeySpecCallback;
import org.argeo.cms.CmsException;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.security.CryptoKeyring;
-import org.argeo.node.security.Keyring;
-import org.argeo.node.security.PBEKeySpecCallback;
/** username / password based keyring. TODO internationalize */
public abstract class AbstractKeyring implements Keyring, CryptoKeyring {
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.api.security.PBEKeySpecCallback;
import org.argeo.cms.ArgeoNames;
import org.argeo.cms.ArgeoTypes;
import org.argeo.cms.CmsException;
import org.argeo.jcr.ArgeoJcrException;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeUtils;
-import org.argeo.node.security.PBEKeySpecCallback;
/** JCR based implementation of a keyring */
public class JcrKeyring extends AbstractKeyring implements ArgeoNames {
import java.io.OutputStream;
-import org.argeo.node.tabular.TabularWriter;
+import org.argeo.api.tabular.TabularWriter;
import org.argeo.util.CsvWriter;
/** Write tabular content in a stream as CSV. Wraps a {@link CsvWriter}. */
import javax.jcr.RepositoryException;
import org.apache.commons.io.IOUtils;
+import org.argeo.api.tabular.ArrayTabularRow;
+import org.argeo.api.tabular.TabularColumn;
+import org.argeo.api.tabular.TabularRow;
+import org.argeo.api.tabular.TabularRowIterator;
import org.argeo.cms.ArgeoTypes;
import org.argeo.jcr.ArgeoJcrException;
-import org.argeo.node.tabular.ArrayTabularRow;
-import org.argeo.node.tabular.TabularColumn;
-import org.argeo.node.tabular.TabularRow;
-import org.argeo.node.tabular.TabularRowIterator;
import org.argeo.util.CsvParser;
/** Iterates over the rows of a {@link ArgeoTypes#ARGEO_TABLE} node. */
import javax.jcr.RepositoryException;
import org.apache.commons.io.IOUtils;
+import org.argeo.api.tabular.TabularColumn;
+import org.argeo.api.tabular.TabularWriter;
import org.argeo.cms.ArgeoTypes;
import org.argeo.jcr.ArgeoJcrException;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.tabular.TabularColumn;
-import org.argeo.node.tabular.TabularWriter;
import org.argeo.util.CsvWriter;
/** Write / reference tabular content in a JCR repository. */
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
-import org.argeo.node.NodeConstants;
import org.osgi.service.http.context.ServletContextHelper;
/** Customises the initialisation of a new web socket. */
Import-Package: org.eclipse.swt,\
org.eclipse.jface.dialogs,\
-org.argeo.eclipse.ui.utils,\
+org.argeo.eclipse.ui.util,\
org.eclipse.swt.events,\
*
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.utils.SingleSourcingConstants;
+import org.argeo.eclipse.ui.util.SingleSourcingConstants;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.rap.rwt.RWT;
*/
package org.argeo.eclipse.ui.specific;
-import static org.argeo.eclipse.ui.utils.SingleSourcingConstants.FILE_SCHEME;
-import static org.argeo.eclipse.ui.utils.SingleSourcingConstants.SCHEME_HOST_SEPARATOR;
+import static org.argeo.eclipse.ui.util.SingleSourcingConstants.FILE_SCHEME;
+import static org.argeo.eclipse.ui.util.SingleSourcingConstants.SCHEME_HOST_SEPARATOR;
import java.io.IOException;
import java.nio.file.Files;
import javax.servlet.http.HttpServletResponse;
import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.utils.SingleSourcingConstants;
+import org.argeo.eclipse.ui.util.SingleSourcingConstants;
import org.eclipse.rap.rwt.service.ServiceHandler;
/**
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.eclipse.ui.jcr.util;
+
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.FileProvider;
+
+/**
+ * Implements a FileProvider for UI purposes. Note that it might not be very
+ * reliable as long as we have not fixed login and multi repository issues that
+ * will be addressed in the next version.
+ *
+ * NOTE: id used here is the real id of the JCR Node, not the JCR Path
+ *
+ * Relies on common approach for JCR file handling implementation.
+ *
+ */
+@SuppressWarnings("deprecation")
+public class JcrFileProvider implements FileProvider {
+
+ // private Object[] rootNodes;
+ private Node refNode;
+
+ /**
+ * Must be set in order for the provider to be able to get current session
+ * and thus have the ability to get the file node corresponding to a given
+ * file ID
+ *
+ * @param refNode
+ */
+ public void setReferenceNode(Node refNode) {
+ // FIXME : this introduces some concurrency ISSUES.
+ this.refNode = refNode;
+ }
+
+ public byte[] getByteArrayFileFromId(String fileId) {
+ InputStream fis = null;
+ byte[] ba = null;
+ Node child = getFileNodeFromId(fileId);
+ try {
+ fis = (InputStream) child.getProperty(Property.JCR_DATA).getBinary().getStream();
+ ba = IOUtils.toByteArray(fis);
+
+ } catch (Exception e) {
+ throw new EclipseUiException("Stream error while opening file", e);
+ } finally {
+ IOUtils.closeQuietly(fis);
+ }
+ return ba;
+ }
+
+ public InputStream getInputStreamFromFileId(String fileId) {
+ try {
+ InputStream fis = null;
+
+ Node child = getFileNodeFromId(fileId);
+ fis = (InputStream) child.getProperty(Property.JCR_DATA).getBinary().getStream();
+ return fis;
+ } catch (RepositoryException re) {
+ throw new EclipseUiException("Cannot get stream from file node for Id " + fileId, re);
+ }
+ }
+
+ /**
+ * Throws an exception if the node is not found in the current repository (a
+ * bit like a FileNotFoundException)
+ *
+ * @param fileId
+ * @return Returns the child node of the nt:file node. It is the child node
+ * that have the jcr:data property where actual file is stored.
+ * never null
+ */
+ private Node getFileNodeFromId(String fileId) {
+ try {
+ Node result = refNode.getSession().getNodeByIdentifier(fileId);
+
+ // rootNodes: for (int j = 0; j < rootNodes.length; j++) {
+ // // in case we have a classic JCR Node
+ // if (rootNodes[j] instanceof Node) {
+ // Node curNode = (Node) rootNodes[j];
+ // if (result != null)
+ // break rootNodes;
+ // } // Case of a repository Node
+ // else if (rootNodes[j] instanceof RepositoryNode) {
+ // Object[] nodes = ((RepositoryNode) rootNodes[j])
+ // .getChildren();
+ // for (int i = 0; i < nodes.length; i++) {
+ // Node node = (Node) nodes[i];
+ // result = node.getSession().getNodeByIdentifier(fileId);
+ // if (result != null)
+ // break rootNodes;
+ // }
+ // }
+ // }
+
+ // Sanity checks
+ if (result == null)
+ throw new EclipseUiException("File node not found for ID" + fileId);
+
+ Node child = null;
+
+ boolean isValid = true;
+ if (!result.isNodeType(NodeType.NT_FILE))
+ // useless: mandatory child node
+ // || !result.hasNode(Property.JCR_CONTENT))
+ isValid = false;
+ else {
+ child = result.getNode(Property.JCR_CONTENT);
+ if (!(child.isNodeType(NodeType.NT_RESOURCE) || child.hasProperty(Property.JCR_DATA)))
+ isValid = false;
+ }
+
+ if (!isValid)
+ throw new EclipseUiException("ERROR: In the current implemented model, '" + NodeType.NT_FILE
+ + "' file node must have a child node named jcr:content "
+ + "that has a BINARY Property named jcr:data " + "where the actual data is stored");
+ return child;
+
+ } catch (RepositoryException re) {
+ throw new EclipseUiException("Erreur while getting file node of ID " + fileId, re);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.eclipse.ui.jcr.util;
+
+import java.util.Comparator;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+
+/** Compares two JCR items (node or properties) based on their names. */
+public class JcrItemsComparator implements Comparator<Item> {
+ public int compare(Item o1, Item o2) {
+ try {
+ // TODO: put folder before files
+ return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
+ } catch (RepositoryException e) {
+ throw new EclipseUiException("Cannot compare " + o1 + " and " + o2, e);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.eclipse.ui.jcr.util;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.IElementComparer;
+
+/** Compare JCR nodes based on their JCR identifiers, for use in JFace viewers. */
+public class NodeViewerComparer implements IElementComparer {
+
+ // force comparison on Node IDs only.
+ public boolean equals(Object elementA, Object elementB) {
+ if (!(elementA instanceof Node) || !(elementB instanceof Node)) {
+ return elementA == null ? elementB == null : elementA
+ .equals(elementB);
+ } else {
+
+ boolean result = false;
+ try {
+ String idA = ((Node) elementA).getIdentifier();
+ String idB = ((Node) elementB).getIdentifier();
+ result = idA == null ? idB == null : idA.equals(idB);
+ } catch (RepositoryException re) {
+ throw new EclipseUiException("cannot compare nodes", re);
+ }
+
+ return result;
+ }
+ }
+
+ public int hashCode(Object element) {
+ // TODO enhanced this method.
+ return element.getClass().toString().hashCode();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.eclipse.ui.jcr.util;
+
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.FileProvider;
+
+/**
+ * Implements a FileProvider for UI purposes. Unlike the
+ * <code> JcrFileProvider </code>, it relies on a single session and manages
+ * nodes with path only.
+ *
+ * Note that considered id is the JCR path
+ *
+ * Relies on common approach for JCR file handling implementation.
+ */
+@SuppressWarnings("deprecation")
+public class SingleSessionFileProvider implements FileProvider {
+
+ private Session session;
+
+ public SingleSessionFileProvider(Session session) {
+ this.session = session;
+ }
+
+ public byte[] getByteArrayFileFromId(String fileId) {
+ InputStream fis = null;
+ byte[] ba = null;
+ Node child = getFileNodeFromId(fileId);
+ try {
+ fis = (InputStream) child.getProperty(Property.JCR_DATA)
+ .getBinary().getStream();
+ ba = IOUtils.toByteArray(fis);
+
+ } catch (Exception e) {
+ throw new EclipseUiException("Stream error while opening file", e);
+ } finally {
+ IOUtils.closeQuietly(fis);
+ }
+ return ba;
+ }
+
+ public InputStream getInputStreamFromFileId(String fileId) {
+ try {
+ InputStream fis = null;
+
+ Node child = getFileNodeFromId(fileId);
+ fis = (InputStream) child.getProperty(Property.JCR_DATA)
+ .getBinary().getStream();
+ return fis;
+ } catch (RepositoryException re) {
+ throw new EclipseUiException("Cannot get stream from file node for Id "
+ + fileId, re);
+ }
+ }
+
+ /**
+ *
+ * @param fileId
+ * @return Returns the child node of the nt:file node. It is the child node
+ * that have the jcr:data property where actual file is stored.
+ * never null
+ */
+ private Node getFileNodeFromId(String fileId) {
+ try {
+ Node result = null;
+ result = session.getNode(fileId);
+
+ // Sanity checks
+ if (result == null)
+ throw new EclipseUiException("File node not found for ID" + fileId);
+
+ // Ensure that the node have the correct type.
+ if (!result.isNodeType(NodeType.NT_FILE))
+ throw new EclipseUiException(
+ "Cannot open file children Node that are not of "
+ + NodeType.NT_RESOURCE + " type.");
+
+ Node child = result.getNodes().nextNode();
+ if (child == null || !child.isNodeType(NodeType.NT_RESOURCE))
+ throw new EclipseUiException(
+ "ERROR: IN the current implemented model, "
+ + NodeType.NT_FILE
+ + " file node must have one and only one child of the nt:ressource, where actual data is stored");
+ return child;
+ } catch (RepositoryException re) {
+ throw new EclipseUiException("Erreur while getting file node of ID "
+ + fileId, re);
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.eclipse.ui.jcr.utils;
-
-import java.io.InputStream;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.FileProvider;
-
-/**
- * Implements a FileProvider for UI purposes. Note that it might not be very
- * reliable as long as we have not fixed login and multi repository issues that
- * will be addressed in the next version.
- *
- * NOTE: id used here is the real id of the JCR Node, not the JCR Path
- *
- * Relies on common approach for JCR file handling implementation.
- *
- */
-@SuppressWarnings("deprecation")
-public class JcrFileProvider implements FileProvider {
-
- // private Object[] rootNodes;
- private Node refNode;
-
- /**
- * Must be set in order for the provider to be able to get current session
- * and thus have the ability to get the file node corresponding to a given
- * file ID
- *
- * @param refNode
- */
- public void setReferenceNode(Node refNode) {
- // FIXME : this introduces some concurrency ISSUES.
- this.refNode = refNode;
- }
-
- public byte[] getByteArrayFileFromId(String fileId) {
- InputStream fis = null;
- byte[] ba = null;
- Node child = getFileNodeFromId(fileId);
- try {
- fis = (InputStream) child.getProperty(Property.JCR_DATA).getBinary().getStream();
- ba = IOUtils.toByteArray(fis);
-
- } catch (Exception e) {
- throw new EclipseUiException("Stream error while opening file", e);
- } finally {
- IOUtils.closeQuietly(fis);
- }
- return ba;
- }
-
- public InputStream getInputStreamFromFileId(String fileId) {
- try {
- InputStream fis = null;
-
- Node child = getFileNodeFromId(fileId);
- fis = (InputStream) child.getProperty(Property.JCR_DATA).getBinary().getStream();
- return fis;
- } catch (RepositoryException re) {
- throw new EclipseUiException("Cannot get stream from file node for Id " + fileId, re);
- }
- }
-
- /**
- * Throws an exception if the node is not found in the current repository (a
- * bit like a FileNotFoundException)
- *
- * @param fileId
- * @return Returns the child node of the nt:file node. It is the child node
- * that have the jcr:data property where actual file is stored.
- * never null
- */
- private Node getFileNodeFromId(String fileId) {
- try {
- Node result = refNode.getSession().getNodeByIdentifier(fileId);
-
- // rootNodes: for (int j = 0; j < rootNodes.length; j++) {
- // // in case we have a classic JCR Node
- // if (rootNodes[j] instanceof Node) {
- // Node curNode = (Node) rootNodes[j];
- // if (result != null)
- // break rootNodes;
- // } // Case of a repository Node
- // else if (rootNodes[j] instanceof RepositoryNode) {
- // Object[] nodes = ((RepositoryNode) rootNodes[j])
- // .getChildren();
- // for (int i = 0; i < nodes.length; i++) {
- // Node node = (Node) nodes[i];
- // result = node.getSession().getNodeByIdentifier(fileId);
- // if (result != null)
- // break rootNodes;
- // }
- // }
- // }
-
- // Sanity checks
- if (result == null)
- throw new EclipseUiException("File node not found for ID" + fileId);
-
- Node child = null;
-
- boolean isValid = true;
- if (!result.isNodeType(NodeType.NT_FILE))
- // useless: mandatory child node
- // || !result.hasNode(Property.JCR_CONTENT))
- isValid = false;
- else {
- child = result.getNode(Property.JCR_CONTENT);
- if (!(child.isNodeType(NodeType.NT_RESOURCE) || child.hasProperty(Property.JCR_DATA)))
- isValid = false;
- }
-
- if (!isValid)
- throw new EclipseUiException("ERROR: In the current implemented model, '" + NodeType.NT_FILE
- + "' file node must have a child node named jcr:content "
- + "that has a BINARY Property named jcr:data " + "where the actual data is stored");
- return child;
-
- } catch (RepositoryException re) {
- throw new EclipseUiException("Erreur while getting file node of ID " + fileId, re);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.eclipse.ui.jcr.utils;
-
-import java.util.Comparator;
-
-import javax.jcr.Item;
-import javax.jcr.RepositoryException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-
-/** Compares two JCR items (node or properties) based on their names. */
-public class JcrItemsComparator implements Comparator<Item> {
- public int compare(Item o1, Item o2) {
- try {
- // TODO: put folder before files
- return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
- } catch (RepositoryException e) {
- throw new EclipseUiException("Cannot compare " + o1 + " and " + o2, e);
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.eclipse.ui.jcr.utils;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.IElementComparer;
-
-/** Compare JCR nodes based on their JCR identifiers, for use in JFace viewers. */
-public class NodeViewerComparer implements IElementComparer {
-
- // force comparison on Node IDs only.
- public boolean equals(Object elementA, Object elementB) {
- if (!(elementA instanceof Node) || !(elementB instanceof Node)) {
- return elementA == null ? elementB == null : elementA
- .equals(elementB);
- } else {
-
- boolean result = false;
- try {
- String idA = ((Node) elementA).getIdentifier();
- String idB = ((Node) elementB).getIdentifier();
- result = idA == null ? idB == null : idA.equals(idB);
- } catch (RepositoryException re) {
- throw new EclipseUiException("cannot compare nodes", re);
- }
-
- return result;
- }
- }
-
- public int hashCode(Object element) {
- // TODO enhanced this method.
- return element.getClass().toString().hashCode();
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.eclipse.ui.jcr.utils;
-
-import java.io.InputStream;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.FileProvider;
-
-/**
- * Implements a FileProvider for UI purposes. Unlike the
- * <code> JcrFileProvider </code>, it relies on a single session and manages
- * nodes with path only.
- *
- * Note that considered id is the JCR path
- *
- * Relies on common approach for JCR file handling implementation.
- */
-@SuppressWarnings("deprecation")
-public class SingleSessionFileProvider implements FileProvider {
-
- private Session session;
-
- public SingleSessionFileProvider(Session session) {
- this.session = session;
- }
-
- public byte[] getByteArrayFileFromId(String fileId) {
- InputStream fis = null;
- byte[] ba = null;
- Node child = getFileNodeFromId(fileId);
- try {
- fis = (InputStream) child.getProperty(Property.JCR_DATA)
- .getBinary().getStream();
- ba = IOUtils.toByteArray(fis);
-
- } catch (Exception e) {
- throw new EclipseUiException("Stream error while opening file", e);
- } finally {
- IOUtils.closeQuietly(fis);
- }
- return ba;
- }
-
- public InputStream getInputStreamFromFileId(String fileId) {
- try {
- InputStream fis = null;
-
- Node child = getFileNodeFromId(fileId);
- fis = (InputStream) child.getProperty(Property.JCR_DATA)
- .getBinary().getStream();
- return fis;
- } catch (RepositoryException re) {
- throw new EclipseUiException("Cannot get stream from file node for Id "
- + fileId, re);
- }
- }
-
- /**
- *
- * @param fileId
- * @return Returns the child node of the nt:file node. It is the child node
- * that have the jcr:data property where actual file is stored.
- * never null
- */
- private Node getFileNodeFromId(String fileId) {
- try {
- Node result = null;
- result = session.getNode(fileId);
-
- // Sanity checks
- if (result == null)
- throw new EclipseUiException("File node not found for ID" + fileId);
-
- // Ensure that the node have the correct type.
- if (!result.isNodeType(NodeType.NT_FILE))
- throw new EclipseUiException(
- "Cannot open file children Node that are not of "
- + NodeType.NT_RESOURCE + " type.");
-
- Node child = result.getNodes().nextNode();
- if (child == null || !child.isNodeType(NodeType.NT_RESOURCE))
- throw new EclipseUiException(
- "ERROR: IN the current implemented model, "
- + NodeType.NT_FILE
- + " file node must have one and only one child of the nt:ressource, where actual data is stored");
- return child;
- } catch (RepositoryException re) {
- throw new EclipseUiException("Erreur while getting file node of ID "
- + fileId, re);
- }
- }
-}
import org.argeo.eclipse.ui.ColumnDefinition;
import org.argeo.eclipse.ui.EclipseUiException;
import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.utils.ViewerUtils;
+import org.argeo.eclipse.ui.util.ViewerUtils;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ColumnLabelProvider;
--- /dev/null
+package org.argeo.eclipse.ui.util;
+
+/**
+ * Centralise constants that are used in both RAP and RCP specific code to avoid
+ * duplicated declaration
+ */
+public interface SingleSourcingConstants {
+
+ // Single sourced open file command
+ String OPEN_FILE_CMD_ID = "org.argeo.cms.ui.workbench.openFile";
+ String PARAM_FILE_NAME = "param.fileName";
+ String PARAM_FILE_URI = "param.fileURI";
+
+ String SCHEME_HOST_SEPARATOR = "://";
+ String FILE_SCHEME = "file";
+ String JCR_SCHEME = "jcr";
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.eclipse.ui.util;
+
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ * Centralise useful methods to manage JFace Table, Tree and TreeColumn viewers.
+ */
+public class ViewerUtils {
+
+ /**
+ * Creates a basic column for the given table. For the time being, we do not
+ * support movable columns.
+ */
+ public static TableColumn createColumn(Table parent, String name, int style, int width) {
+ TableColumn result = new TableColumn(parent, style);
+ result.setText(name);
+ result.setWidth(width);
+ result.setResizable(true);
+ return result;
+ }
+
+ /**
+ * Creates a TableViewerColumn for the given viewer. For the time being, we do
+ * not support movable columns.
+ */
+ public static TableViewerColumn createTableViewerColumn(TableViewer parent, String name, int style, int width) {
+ TableViewerColumn tvc = new TableViewerColumn(parent, style);
+ TableColumn column = tvc.getColumn();
+ column.setText(name);
+ column.setWidth(width);
+ column.setResizable(true);
+ return tvc;
+ }
+
+ // public static TableViewerColumn createTableViewerColumn(TableViewer parent,
+ // Localized name, int style, int width) {
+ // return createTableViewerColumn(parent, name.lead(), style, width);
+ // }
+
+ /**
+ * Creates a TreeViewerColumn for the given viewer. For the time being, we do
+ * not support movable columns.
+ */
+ public static TreeViewerColumn createTreeViewerColumn(TreeViewer parent, String name, int style, int width) {
+ TreeViewerColumn tvc = new TreeViewerColumn(parent, style);
+ TreeColumn column = tvc.getColumn();
+ column.setText(name);
+ column.setWidth(width);
+ column.setResizable(true);
+ return tvc;
+ }
+}
+++ /dev/null
-package org.argeo.eclipse.ui.utils;
-
-/**
- * Centralise constants that are used in both RAP and RCP specific code to avoid
- * duplicated declaration
- */
-public interface SingleSourcingConstants {
-
- // Single sourced open file command
- String OPEN_FILE_CMD_ID = "org.argeo.cms.ui.workbench.openFile";
- String PARAM_FILE_NAME = "param.fileName";
- String PARAM_FILE_URI = "param.fileURI";
-
- String SCHEME_HOST_SEPARATOR = "://";
- String FILE_SCHEME = "file";
- String JCR_SCHEME = "jcr";
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.eclipse.ui.utils;
-
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.TreeViewerColumn;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.TreeColumn;
-
-/**
- * Centralise useful methods to manage JFace Table, Tree and TreeColumn viewers.
- */
-public class ViewerUtils {
-
- /**
- * Creates a basic column for the given table. For the time being, we do not
- * support movable columns.
- */
- public static TableColumn createColumn(Table parent, String name, int style, int width) {
- TableColumn result = new TableColumn(parent, style);
- result.setText(name);
- result.setWidth(width);
- result.setResizable(true);
- return result;
- }
-
- /**
- * Creates a TableViewerColumn for the given viewer. For the time being, we do
- * not support movable columns.
- */
- public static TableViewerColumn createTableViewerColumn(TableViewer parent, String name, int style, int width) {
- TableViewerColumn tvc = new TableViewerColumn(parent, style);
- TableColumn column = tvc.getColumn();
- column.setText(name);
- column.setWidth(width);
- column.setResizable(true);
- return tvc;
- }
-
- // public static TableViewerColumn createTableViewerColumn(TableViewer parent,
- // Localized name, int style, int width) {
- // return createTableViewerColumn(parent, name.lead(), style, width);
- // }
-
- /**
- * Creates a TreeViewerColumn for the given viewer. For the time being, we do
- * not support movable columns.
- */
- public static TreeViewerColumn createTreeViewerColumn(TreeViewer parent, String name, int style, int width) {
- TreeViewerColumn tvc = new TreeViewerColumn(parent, style);
- TreeColumn column = tvc.getColumn();
- column.setText(name);
- column.setWidth(width);
- column.setResizable(true);
- return tvc;
- }
-}
org.eclipse.jetty.websocket.common,\
org.osgi.service.http,\
org.argeo.cms.auth,\
-org.argeo.node,\
+org.argeo.api,\
*
\ No newline at end of file
Fragment-Host: org.apache.jackrabbit.core
-Import-Package: org.argeo.node,\
+Import-Package: org.argeo.api,\
*
<dependencies>
<dependency>
<groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.node.api</artifactId>
+ <artifactId>org.argeo.api</artifactId>
<version>2.1.88-SNAPSHOT</version>
</dependency>
<dependency>
import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
import org.apache.jackrabbit.core.security.principal.PrincipalProvider;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.security.AnonymousPrincipal;
+import org.argeo.api.security.DataAdminPrincipal;
import org.argeo.cms.auth.CmsSession;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.security.AnonymousPrincipal;
-import org.argeo.node.security.DataAdminPrincipal;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.apache.jackrabbit.core.security.AnonymousPrincipal;
import org.apache.jackrabbit.core.security.SecurityConstants;
import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
-import org.argeo.node.security.DataAdminPrincipal;
+import org.argeo.api.security.DataAdminPrincipal;
public class SystemJackrabbitLoginModule implements LoginModule {
private Subject subject;
@Override
public boolean commit() throws LoginException {
- Set<org.argeo.node.security.AnonymousPrincipal> anonPrincipal = subject.getPrincipals(org.argeo.node.security.AnonymousPrincipal.class);
+ Set<org.argeo.api.security.AnonymousPrincipal> anonPrincipal = subject.getPrincipals(org.argeo.api.security.AnonymousPrincipal.class);
if (!anonPrincipal.isEmpty()) {
subject.getPrincipals().add(new AnonymousPrincipal());
return true;
</dependency>
<dependency>
<groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.node.api</artifactId>
+ <artifactId>org.argeo.api</artifactId>
<version>2.1.88-SNAPSHOT</version>
</dependency>
</dependencies>
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeUtils;
import org.argeo.jcr.Jcr;
import org.argeo.jcr.JcrUtils;
import org.argeo.naming.Distinguished;
-import org.argeo.node.NodeUtils;
import org.osgi.service.useradmin.Group;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.UserAdmin;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeUtils;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.xml.sax.SAXException;
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.node.api</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-Provide-Capability: cms.datamodel;name=ldap;cnd=/org/argeo/node/ldap.cnd;abstract=true
+++ /dev/null
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
- .
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.commons</groupId>
- <artifactId>argeo-commons</artifactId>
- <version>2.1.88-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.node.api</artifactId>
- <name>Argeo Node API</name>
- <packaging>jar</packaging>
- <dependencies>
- </dependencies>
-</project>
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node;
-
-/** Framework agnostic interface for log notifications */
-public interface ArgeoLogListener {
- /**
- * Appends a log
- *
- * @param username
- * authentified user, null for anonymous
- * @param level
- * INFO, DEBUG, WARN, etc. (logging framework specific)
- * @param category
- * hierarchy (logging framework specific)
- * @param thread
- * name of the thread which logged this message
- * @param msg
- * any object as long as its toString() method returns the
- * message
- * @param exception
- * exception in log4j ThrowableStrRep format
- */
- public void appendLog(String username, Long timestamp, String level,
- String category, String thread, Object msg, String[] exception);
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node;
-
-/**
- * Logging framework agnostic identifying a logging service, to which one can
- * register
- */
-public interface ArgeoLogger {
- /**
- * Register for events by threads with the same authentication (or all
- * threads if admin)
- */
- public void register(ArgeoLogListener listener,
- Integer numberOfPreviousEvents);
-
- /**
- * For admin use only: register for all users
- *
- * @param listener
- * the log listener
- * @param numberOfPreviousEvents
- * the number of previous events to notify
- * @param everything
- * if true even anonymous is logged
- */
- public void registerForAll(ArgeoLogListener listener,
- Integer numberOfPreviousEvents, boolean everything);
-
- public void unregister(ArgeoLogListener listener);
-
- public void unregisterForAll(ArgeoLogListener listener);
-}
+++ /dev/null
-package org.argeo.node;
-
-import java.util.Map;
-
-import javax.security.auth.AuthPermission;
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-
-import org.argeo.node.security.DataAdminPrincipal;
-
-/**
- * Log-in a system process as data admin. Protection is via
- * {@link AuthPermission} on this login module, so if it can be accessed it will
- * always succeed.
- */
-public class DataAdminLoginModule implements LoginModule {
- private Subject subject;
-
- @Override
- public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
- Map<String, ?> options) {
- this.subject = subject;
- }
-
- @Override
- public boolean login() throws LoginException {
- return true;
- }
-
- @Override
- public boolean commit() throws LoginException {
- subject.getPrincipals().add(new DataAdminPrincipal());
- return true;
- }
-
- @Override
- public boolean abort() throws LoginException {
- return true;
- }
-
- @Override
- public boolean logout() throws LoginException {
- subject.getPrincipals().removeAll(subject.getPrincipals(DataAdminPrincipal.class));
- return true;
- }
-}
+++ /dev/null
-package org.argeo.node;
-
-import org.osgi.resource.Namespace;
-
-/** CMS Data Model capability namespace. */
-public class DataModelNamespace extends Namespace {
-
- public static final String CMS_DATA_MODEL_NAMESPACE = "cms.datamodel";
- public static final String NAME = "name";
- public static final String CND = "cnd";
- /** If 'true', indicates that no repository should be published */
- public static final String ABSTRACT = "abstract";
-
- private DataModelNamespace() {
- // empty
- }
-
-}
+++ /dev/null
-package org.argeo.node;
-
-import java.util.function.BiFunction;
-
-/**
- * Stateless UI part creator. Takes a parent view (V) and a model context (M) in
- * order to create a view part (W) which can then be further configured. Such
- * object can be used as services and reference other part of the model which
- * are relevant for all created UI part.
- */
-@FunctionalInterface
-public interface MvcProvider<V, M, W> extends BiFunction<V, M, W> {
- /**
- * Whether this parent view is supported.
- *
- * @return true by default.
- */
- default boolean isViewSupported(V parent) {
- return true;
- }
-
- /**
- * Whether this context is supported.
- *
- * @return true by default.
- */
- default boolean isModelSupported(M context) {
- return true;
- }
-
- default W createUiPart(V parent, M context) {
- if (!isViewSupported(parent))
- throw new IllegalArgumentException("Parent view " + parent + "is not supported.");
- if (!isModelSupported(context))
- throw new IllegalArgumentException("Model context " + context + "is not supported.");
- return apply(parent, context);
- }
-}
+++ /dev/null
-package org.argeo.node;
-
-public interface NodeConstants {
- /*
- * DN ATTRIBUTES (RFC 4514)
- */
- String CN = "cn";
- String L = "l";
- String ST = "st";
- String O = "o";
- String OU = "ou";
- String C = "c";
- String STREET = "street";
- String DC = "dc";
- String UID = "uid";
-
- /*
- * STANDARD ATTRIBUTES
- */
- String LABELED_URI = "labeledUri";
-
- /*
- * COMMON NAMES
- */
- String NODE = "node";
- String EGO = "ego";
- String HOME = "home";
- String SRV = "srv";
- String GUESTS = "guests";
- String PUBLIC = "public";
-
- /*
- * BASE DNs
- */
- String DEPLOY_BASEDN = "ou=deploy,ou=node";
-
- /*
- * STANDARD VALUES
- */
- String DEFAULT = "default";
-
- /*
- * RESERVED ROLES
- */
- String ROLES_BASEDN = "ou=roles,ou=node";
- String TOKENS_BASEDN = "ou=tokens,ou=node";
- String ROLE_ADMIN = "cn=admin," + ROLES_BASEDN;
- String ROLE_USER_ADMIN = "cn=userAdmin," + ROLES_BASEDN;
- String ROLE_DATA_ADMIN = "cn=dataAdmin," + ROLES_BASEDN;
- // Special system groups that cannot be edited:
- // user U anonymous = everyone
- String ROLE_USER = "cn=user," + ROLES_BASEDN;
- String ROLE_ANONYMOUS = "cn=anonymous," + ROLES_BASEDN;
- // Account lifecycle
- String ROLE_REGISTERING = "cn=registering," + ROLES_BASEDN;
-
- /*
- * LOGIN CONTEXTS
- */
- String LOGIN_CONTEXT_NODE = "NODE";
- String LOGIN_CONTEXT_USER = "USER";
- String LOGIN_CONTEXT_ANONYMOUS = "ANONYMOUS";
- String LOGIN_CONTEXT_DATA_ADMIN = "DATA_ADMIN";
- String LOGIN_CONTEXT_SINGLE_USER = "SINGLE_USER";
- String LOGIN_CONTEXT_KEYRING = "KEYRING";
-
- /*
- * PATHS
- */
- String PATH_DATA = "/data";
- String PATH_JCR = "/jcr";
- String PATH_FILES = "/files";
- // String PATH_JCR_PUB = "/pub";
-
- /*
- * FILE SYSTEMS
- */
- String SCHEME_NODE = NODE;
-
- /*
- * KERBEROS
- */
- String NODE_SERVICE = NODE;
-
- /*
- * INIT FRAMEWORK PROPERTIES
- */
- String NODE_INIT = "argeo.node.init";
- String I18N_DEFAULT_LOCALE = "argeo.i18n.defaultLocale";
- String I18N_LOCALES = "argeo.i18n.locales";
- // Node Security
- String ROLES_URI = "argeo.node.roles.uri";
- String TOKENS_URI = "argeo.node.tokens.uri";
- /** URI to an LDIF file or LDAP server used as initialization or backend */
- String USERADMIN_URIS = "argeo.node.useradmin.uris";
- // Transaction manager
- String TRANSACTION_MANAGER = "argeo.node.transaction.manager";
- String TRANSACTION_MANAGER_SIMPLE = "simple";
- String TRANSACTION_MANAGER_BITRONIX = "bitronix";
- // Node
- /** Properties configuring the node repository */
- String NODE_REPO_PROP_PREFIX = "argeo.node.repo.";
- /** Additional standalone repositories, related to data models. */
- String NODE_REPOS_PROP_PREFIX = "argeo.node.repos.";
- // HTTP
- String HTTP_PORT = "org.osgi.service.http.port";
- String HTTP_PORT_SECURE = "org.osgi.service.http.port.secure";
- /**
- * The HTTP header used to convey the DN of a client verified by a reverse
- * proxy. Typically SSL_CLIENT_S_DN for Apache.
- */
- String HTTP_PROXY_SSL_DN = "argeo.http.proxy.ssl.dn";
-
- /*
- * PIDs
- */
- String NODE_STATE_PID = "org.argeo.node.state";
- String NODE_DEPLOYMENT_PID = "org.argeo.node.deployment";
- String NODE_INSTANCE_PID = "org.argeo.node.instance";
-
- String NODE_KEYRING_PID = "org.argeo.node.keyring";
- String NODE_FS_PROVIDER_PID = "org.argeo.node.fsProvider";
-
- /*
- * FACTORY PIDs
- */
- String NODE_REPOS_FACTORY_PID = "org.argeo.node.repos";
- String NODE_USER_ADMIN_PID = "org.argeo.node.userAdmin";
-}
+++ /dev/null
-package org.argeo.node;
-
-public interface NodeDeployment {
- Long getAvailableSince();
-}
+++ /dev/null
-package org.argeo.node;
-
-import javax.naming.ldap.LdapName;
-
-/** The structured data */
-public interface NodeInstance {
- /**
- * To be used as an identifier of a workgroup, typically as a value for the
- * 'businessCategory' attribute in LDAP.
- */
- public final static String WORKGROUP = "workgroup";
-
- /** Mark this group as a workgroup */
- void createWorkgroup(LdapName groupDn);
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node;
-
-/** JCR types in the http://www.argeo.org/node namespace */
-@Deprecated
-public interface NodeNames {
- String LDAP_UID = "ldap:"+NodeConstants.UID;
- String LDAP_CN = "ldap:"+NodeConstants.CN;
-}
+++ /dev/null
-package org.argeo.node;
-
-interface NodeOID {
- String BASE = "1.3.6.1.4.1" + ".48308" + ".1";
-
- // ATTRIBUTE TYPES
- String ATTRIBUTE_TYPES = BASE + ".4";
-
- // OBJECT CLASSES
- String OBJECT_CLASSES = BASE + ".6";
-}
+++ /dev/null
-package org.argeo.node;
-
-import java.util.List;
-import java.util.Locale;
-
-public interface NodeState {
- Locale getDefaultLocale();
-
- List<Locale> getLocales();
-
- String getHostname();
-
- boolean isClean();
-
- Long getAvailableSince();
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node;
-
-/** JCR types in the http://www.argeo.org/node namespace */
-@Deprecated
-public interface NodeTypes {
- String NODE_USER_HOME = "node:userHome";
- String NODE_GROUP_HOME = "node:groupHome";
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node;
-
-import java.security.PrivilegedAction;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.NoSuchWorkspaceException;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.RepositoryFactory;
-import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.security.auth.AuthPermission;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-/** Utilities related to Argeo model in JCR */
-public class NodeUtils {
- /**
- * Wraps the call to the repository factory based on parameter
- * {@link NodeConstants#CN} in order to simplify it and protect against future
- * API changes.
- */
- public static Repository getRepositoryByAlias(RepositoryFactory repositoryFactory, String alias) {
- try {
- Map<String, String> parameters = new HashMap<String, String>();
- parameters.put(NodeConstants.CN, alias);
- return repositoryFactory.getRepository(parameters);
- } catch (RepositoryException e) {
- throw new RuntimeException("Unexpected exception when trying to retrieve repository with alias " + alias,
- e);
- }
- }
-
- /**
- * Wraps the call to the repository factory based on parameter
- * {@link NodeConstants#LABELED_URI} in order to simplify it and protect against
- * future API changes.
- */
- public static Repository getRepositoryByUri(RepositoryFactory repositoryFactory, String uri) {
- return getRepositoryByUri(repositoryFactory, uri, null);
- }
-
- /**
- * Wraps the call to the repository factory based on parameter
- * {@link NodeConstants#LABELED_URI} in order to simplify it and protect against
- * future API changes.
- */
- public static Repository getRepositoryByUri(RepositoryFactory repositoryFactory, String uri, String alias) {
- try {
- Map<String, String> parameters = new HashMap<String, String>();
- parameters.put(NodeConstants.LABELED_URI, uri);
- if (alias != null)
- parameters.put(NodeConstants.CN, alias);
- return repositoryFactory.getRepository(parameters);
- } catch (RepositoryException e) {
- throw new RuntimeException("Unexpected exception when trying to retrieve repository with uri " + uri, e);
- }
- }
-
- /**
- * Returns the home node of the user or null if none was found.
- *
- * @param session the session to use in order to perform the search, this can
- * be a session with a different user ID than the one searched,
- * typically when a system or admin session is used.
- * @param username the username of the user
- */
- public static Node getUserHome(Session session, String username) {
-// try {
-// QueryObjectModelFactory qomf = session.getWorkspace().getQueryManager().getQOMFactory();
-// Selector sel = qomf.selector(NodeTypes.NODE_USER_HOME, "sel");
-// DynamicOperand dop = qomf.propertyValue(sel.getSelectorName(), NodeNames.LDAP_UID);
-// StaticOperand sop = qomf.literal(session.getValueFactory().createValue(username));
-// Constraint constraint = qomf.comparison(dop, QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, sop);
-// Query query = qomf.createQuery(sel, constraint, null, null);
-// return querySingleNode(query);
-// } catch (RepositoryException e) {
-// throw new RuntimeException("Cannot find home for user " + username, e);
-// }
-
- try {
- checkUserWorkspace(session, username);
- String homePath = getHomePath(username);
- if (session.itemExists(homePath))
- return session.getNode(homePath);
- // legacy
- homePath = "/home/" + username;
- if (session.itemExists(homePath))
- return session.getNode(homePath);
- return null;
- } catch (RepositoryException e) {
- throw new RuntimeException("Cannot find home for user " + username, e);
- }
- }
-
- private static String getHomePath(String username) {
- LdapName dn;
- try {
- dn = new LdapName(username);
- } catch (InvalidNameException e) {
- throw new IllegalArgumentException("Invalid name " + username, e);
- }
- String userId = dn.getRdn(dn.size() - 1).getValue().toString();
- return '/' + userId;
- }
-
- private static void checkUserWorkspace(Session session, String username) {
- String workspaceName = session.getWorkspace().getName();
- if (!NodeConstants.HOME.equals(workspaceName))
- throw new IllegalArgumentException(workspaceName + " is not the home workspace for user " + username);
- }
-
- /**
- * Returns the home node of the user or null if none was found.
- *
- * @param session the session to use in order to perform the search, this can
- * be a session with a different user ID than the one searched,
- * typically when a system or admin session is used.
- * @param groupname the name of the group
- */
- public static Node getGroupHome(Session session, String groupname) {
-// try {
-// QueryObjectModelFactory qomf = session.getWorkspace().getQueryManager().getQOMFactory();
-// Selector sel = qomf.selector(NodeTypes.NODE_GROUP_HOME, "sel");
-// DynamicOperand dop = qomf.propertyValue(sel.getSelectorName(), NodeNames.LDAP_CN);
-// StaticOperand sop = qomf.literal(session.getValueFactory().createValue(cn));
-// Constraint constraint = qomf.comparison(dop, QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, sop);
-// Query query = qomf.createQuery(sel, constraint, null, null);
-// return querySingleNode(query);
-// } catch (RepositoryException e) {
-// throw new RuntimeException("Cannot find home for group " + cn, e);
-// }
-
- try {
- checkGroupWorkspace(session, groupname);
- String homePath = getGroupPath(groupname);
- if (session.itemExists(homePath))
- return session.getNode(homePath);
- // legacy
- homePath = "/groups/" + groupname;
- if (session.itemExists(homePath))
- return session.getNode(homePath);
- return null;
- } catch (RepositoryException e) {
- throw new RuntimeException("Cannot find home for group " + groupname, e);
- }
-
- }
-
- private static String getGroupPath(String groupname) {
- String cn;
- try {
- LdapName dn = new LdapName(groupname);
- cn = dn.getRdn(dn.size() - 1).getValue().toString();
- } catch (InvalidNameException e) {
- cn = groupname;
- }
- return '/' + cn;
- }
-
- private static void checkGroupWorkspace(Session session, String groupname) {
- String workspaceName = session.getWorkspace().getName();
- if (!NodeConstants.SRV.equals(workspaceName))
- throw new IllegalArgumentException(workspaceName + " is not the group workspace for group " + groupname);
- }
-
- /**
- * Queries one single node.
- *
- * @return one single node or null if none was found
- * @throws ArgeoJcrException if more than one node was found
- */
- private static Node querySingleNode(Query query) {
- NodeIterator nodeIterator;
- try {
- QueryResult queryResult = query.execute();
- nodeIterator = queryResult.getNodes();
- } catch (RepositoryException e) {
- throw new RuntimeException("Cannot execute query " + query, e);
- }
- Node node;
- if (nodeIterator.hasNext())
- node = nodeIterator.nextNode();
- else
- return null;
-
- if (nodeIterator.hasNext())
- throw new RuntimeException("Query returned more than one node.");
- return node;
- }
-
- /** Returns the home node of the session user or null if none was found. */
- public static Node getUserHome(Session session) {
- String userID = session.getUserID();
- return getUserHome(session, userID);
- }
-
- /**
- * Translate the path to this node into a path containing the name of the
- * repository and the name of the workspace.
- */
- public static String getDataPath(String cn, Node node) throws RepositoryException {
- assert node != null;
- StringBuilder buf = new StringBuilder(NodeConstants.PATH_DATA);
- return buf.append('/').append(cn).append('/').append(node.getSession().getWorkspace().getName())
- .append(node.getPath()).toString();
- }
-
- /**
- * Open a JCR session with full read/write rights on the data, as
- * {@link NodeConstants#ROLE_USER_ADMIN}, using the
- * {@link NodeConstants#LOGIN_CONTEXT_DATA_ADMIN} login context. For security
- * hardened deployement, use {@link AuthPermission} on this login context.
- */
- public static Session openDataAdminSession(Repository repository, String workspaceName) {
- ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
- LoginContext loginContext;
- try {
- loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN);
- loginContext.login();
- } catch (LoginException e1) {
- throw new RuntimeException("Could not login as data admin", e1);
- } finally {
- Thread.currentThread().setContextClassLoader(currentCl);
- }
- return Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Session>() {
-
- @Override
- public Session run() {
- try {
- return repository.login(workspaceName);
- } catch (NoSuchWorkspaceException e) {
- throw new IllegalArgumentException("No workspace " + workspaceName + " available", e);
- } catch (RepositoryException e) {
- throw new RuntimeException("Cannot open data admin session", e);
- }
- }
-
- });
- }
-
- /** Singleton. */
- private NodeUtils() {
- }
-
-}
+++ /dev/null
-<ldap = 'http://www.argeo.org/ns/ldap'>
+++ /dev/null
-<node = 'http://www.argeo.org/ns/node'>
-
-[node:userHome]
-mixin
-- ldap:uid (STRING) m
-
-[node:groupHome]
-mixin
-- ldap:cn (STRING) m
+++ /dev/null
-/**
- * Abstractions or constants related to an Argeo Node, an active repository of
- * linked data.
- */
-package org.argeo.node;
\ No newline at end of file
+++ /dev/null
-package org.argeo.node.security;
-
-import java.security.Principal;
-
-import javax.naming.ldap.LdapName;
-
-import org.argeo.node.NodeConstants;
-
-/** Marker for anonymous users. */
-public final class AnonymousPrincipal implements Principal {
- private final String name = NodeConstants.ROLE_ANONYMOUS;
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public int hashCode() {
- return name.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return this == obj;
- }
-
- @Override
- public String toString() {
- return name.toString();
- }
-
- public LdapName getLdapName(){
- return NodeSecurityUtils.ROLE_ANONYMOUS_NAME;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.security;
-
-/**
- * Marker interface for an advanced keyring based on cryptography.
- */
-public interface CryptoKeyring extends Keyring {
- public void changePassword(char[] oldPassword, char[] newPassword);
-
- public void unlock(char[] password);
-}
+++ /dev/null
-package org.argeo.node.security;
-
-import java.security.Principal;
-
-import org.argeo.node.NodeConstants;
-
-/** Allows to modify any data. */
-public final class DataAdminPrincipal implements Principal {
- private final String name = NodeConstants.ROLE_DATA_ADMIN;
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public int hashCode() {
- return name.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof DataAdminPrincipal;
- }
-
- @Override
- public String toString() {
- return name.toString();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.security;
-
-import java.io.InputStream;
-
-/**
- * Access to private (typically encrypted) data. The keyring is responsible for
- * retrieving the necessary credentials. <b>Experimental. This API may
- * change.</b>
- */
-public interface Keyring {
- /**
- * Returns the confidential information as chars. Must ask for it if it is
- * not stored.
- */
- public char[] getAsChars(String path);
-
- /**
- * Returns the confidential information as a stream. Must ask for it if it
- * is not stored.
- */
- public InputStream getAsStream(String path);
-
- public void set(String path, char[] arr);
-
- public void set(String path, InputStream in);
-}
+++ /dev/null
-package org.argeo.node.security;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.node.NodeConstants;
-
-public class NodeSecurityUtils {
- public final static LdapName ROLE_ADMIN_NAME, ROLE_DATA_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME,
- ROLE_USER_ADMIN_NAME;
- public final static List<LdapName> RESERVED_ROLES;
- static {
- try {
- ROLE_ADMIN_NAME = new LdapName(NodeConstants.ROLE_ADMIN);
- ROLE_DATA_ADMIN_NAME = new LdapName(NodeConstants.ROLE_DATA_ADMIN);
- ROLE_USER_NAME = new LdapName(NodeConstants.ROLE_USER);
- ROLE_USER_ADMIN_NAME = new LdapName(NodeConstants.ROLE_USER_ADMIN);
- ROLE_ANONYMOUS_NAME = new LdapName(NodeConstants.ROLE_ANONYMOUS);
- RESERVED_ROLES = Collections.unmodifiableList(Arrays.asList(
- new LdapName[] { ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME, ROLE_USER_ADMIN_NAME }));
- } catch (InvalidNameException e) {
- throw new Error("Cannot initialize login module class", e);
- }
- }
-
- public static void checkUserName(LdapName name) throws IllegalArgumentException {
- if (RESERVED_ROLES.contains(name))
- throw new IllegalArgumentException(name + " is a reserved name");
- }
-
- public static void checkImpliedPrincipalName(LdapName roleName) throws IllegalArgumentException {
-// if (ROLE_USER_NAME.equals(roleName) || ROLE_ANONYMOUS_NAME.equals(roleName))
-// throw new IllegalArgumentException(roleName + " cannot be listed as role");
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.security;
-
-import javax.crypto.spec.PBEKeySpec;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.PasswordCallback;
-
-/**
- * All information required to set up a {@link PBEKeySpec} bar the password
- * itself (use a {@link PasswordCallback})
- */
-public class PBEKeySpecCallback implements Callback {
- private String secretKeyFactory;
- private byte[] salt;
- private Integer iterationCount;
- /** Can be null for some algorithms */
- private Integer keyLength;
- /** Can be null, will trigger secret key encryption if not */
- private String secretKeyEncryption;
-
- private String encryptedPasswordHashCipher;
- private byte[] encryptedPasswordHash;
-
- public void set(String secretKeyFactory, byte[] salt,
- Integer iterationCount, Integer keyLength,
- String secretKeyEncryption) {
- this.secretKeyFactory = secretKeyFactory;
- this.salt = salt;
- this.iterationCount = iterationCount;
- this.keyLength = keyLength;
- this.secretKeyEncryption = secretKeyEncryption;
-// this.encryptedPasswordHashCipher = encryptedPasswordHashCipher;
-// this.encryptedPasswordHash = encryptedPasswordHash;
- }
-
- public String getSecretKeyFactory() {
- return secretKeyFactory;
- }
-
- public byte[] getSalt() {
- return salt;
- }
-
- public Integer getIterationCount() {
- return iterationCount;
- }
-
- public Integer getKeyLength() {
- return keyLength;
- }
-
- public String getSecretKeyEncryption() {
- return secretKeyEncryption;
- }
-
- public String getEncryptedPasswordHashCipher() {
- return encryptedPasswordHashCipher;
- }
-
- public byte[] getEncryptedPasswordHash() {
- return encryptedPasswordHash;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.tabular;
-
-import java.util.List;
-
-/** Minimal tabular row wrapping an {@link Object} array */
-public class ArrayTabularRow implements TabularRow {
- private final Object[] arr;
-
- public ArrayTabularRow(List<?> objs) {
- this.arr = objs.toArray();
- }
-
- public Object get(Integer col) {
- return arr[col];
- }
-
- public int size() {
- return arr.length;
- }
-
- public Object[] toArray() {
- return arr;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.tabular;
-
-/** The column in a tabular content */
-public class TabularColumn {
- private String name;
- /**
- * JCR types, see
- * http://www.day.com/maven/javax.jcr/javadocs/jcr-2.0/index.html
- * ?javax/jcr/PropertyType.html
- */
- private Integer type;
-
- /** column with default type */
- public TabularColumn(String name) {
- super();
- this.name = name;
- }
-
- public TabularColumn(String name, Integer type) {
- super();
- this.name = name;
- this.type = type;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public Integer getType() {
- return type;
- }
-
- public void setType(Integer type) {
- this.type = type;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.tabular;
-
-import java.util.List;
-
-/**
- * Content organized as a table, possibly with headers. Only JCR types are
- * supported even though there is not direct dependency on JCR.
- */
-public interface TabularContent {
- /** The headers of this table or <code>null</code> is none available. */
- public List<TabularColumn> getColumns();
-
- public TabularRowIterator read();
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.tabular;
-
-/** A row of tabular data */
-public interface TabularRow {
- /** The value at this column index */
- public Object get(Integer col);
-
- /** The raw objects (direct references) */
- public Object[] toArray();
-
- /** Number of columns */
- public int size();
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.tabular;
-
-import java.util.Iterator;
-
-/** Navigation of rows */
-public interface TabularRowIterator extends Iterator<TabularRow> {
- /**
- * Current row number, has to be incremented by each call to next() ; starts at 0, will
- * therefore be 1 for the first row returned.
- */
- public Long getCurrentRowNumber();
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.node.tabular;
-
-
-/** Write to a tabular content */
-public interface TabularWriter {
- /** Append a new row of data */
- public void appendRow(Object[] row);
-
- /** Finish persisting data and release resources */
- public void close();
-}
--- /dev/null
+package org.argeo.util;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/** A generic tester based on Java assertions and functional programming. */
+public class Tester {
+ private Map<String, TesterStatus> results = Collections.synchronizedSortedMap(new TreeMap<>());
+
+ private ClassLoader classLoader;
+
+ /** Use {@link Thread#getContextClassLoader()} by default. */
+ public Tester() {
+ this(Thread.currentThread().getContextClassLoader());
+ }
+
+ public Tester(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ public void execute(String className) {
+ Class<?> clss;
+ try {
+ clss = classLoader.loadClass(className);
+ boolean assertionsEnabled = clss.desiredAssertionStatus();
+ if (!assertionsEnabled)
+ throw new IllegalStateException("Test runner " + getClass().getName()
+ + " requires Java assertions to be enabled. Call the JVM with the -ea argument.");
+ } catch (Exception e1) {
+ throw new IllegalArgumentException("Cannot initalise test for " + className, e1);
+
+ }
+ List<Method> methods = findMethods(clss);
+ if (methods.size() == 0)
+ throw new IllegalArgumentException("No test method found in " + clss);
+ // TODO make order more predictable?
+ for (Method method : methods) {
+ String uid = method.getDeclaringClass().getName() + "#" + method.getName();
+ TesterStatus testStatus = new TesterStatus(uid);
+ Object obj = null;
+ try {
+ beforeTest(uid, method);
+ obj = clss.getDeclaredConstructor().newInstance();
+ method.invoke(obj);
+ testStatus.setPassed();
+ afterTestPassed(uid, method, obj);
+ } catch (Exception e) {
+ testStatus.setFailed(e);
+ afterTestFailed(uid, method, obj, e);
+ } finally {
+ results.put(uid, testStatus);
+ }
+ }
+ }
+
+ protected void beforeTest(String uid, Method method) {
+ // System.out.println(uid + ": STARTING");
+ }
+
+ protected void afterTestPassed(String uid, Method method, Object obj) {
+ System.out.println(uid + ": PASSED");
+ }
+
+ protected void afterTestFailed(String uid, Method method, Object obj, Throwable e) {
+ System.out.println(uid + ": FAILED");
+ e.printStackTrace();
+ }
+
+ protected List<Method> findMethods(Class<?> clss) {
+ List<Method> methods = new ArrayList<Method>();
+// Method call = getMethod(clss, "call");
+// if (call != null)
+// methods.add(call);
+//
+ for (Method method : clss.getMethods()) {
+ if (method.getName().startsWith("test")) {
+ methods.add(method);
+ }
+ }
+ return methods;
+ }
+
+ protected Method getMethod(Class<?> clss, String name, Class<?>... parameterTypes) {
+ try {
+ return clss.getMethod(name, parameterTypes);
+ } catch (NoSuchMethodException e) {
+ return null;
+ } catch (SecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static void main(String[] args) {
+ // deal with arguments
+ String className;
+ if (args.length < 1) {
+ System.err.println(usage());
+ System.exit(1);
+ throw new IllegalArgumentException();
+ } else {
+ className = args[0];
+ }
+
+ Tester test = new Tester();
+ try {
+ test.execute(className);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ Map<String, TesterStatus> r = test.results;
+ for (String uid : r.keySet()) {
+ TesterStatus testStatus = r.get(uid);
+ System.out.println(testStatus);
+ }
+ }
+
+ public static String usage() {
+ return "java " + Tester.class.getName() + " [test class name]";
+
+ }
+}
--- /dev/null
+package org.argeo.util;
+
+import java.io.Serializable;
+
+/** The status of a test. */
+public class TesterStatus implements Serializable {
+ private static final long serialVersionUID = 6272975746885487000L;
+
+ private Boolean passed = null;
+ private final String uid;
+ private Throwable throwable = null;
+
+ public TesterStatus(String uid) {
+ this.uid = uid;
+ }
+
+ /** For cloning. */
+ public TesterStatus(String uid, Boolean passed, Throwable throwable) {
+ this(uid);
+ this.passed = passed;
+ this.throwable = throwable;
+ }
+
+ public synchronized Boolean isRunning() {
+ return passed == null;
+ }
+
+ public synchronized Boolean isPassed() {
+ assert passed != null;
+ return passed;
+ }
+
+ public synchronized Boolean isFailed() {
+ assert passed != null;
+ return !passed;
+ }
+
+ public synchronized void setPassed() {
+ setStatus(true);
+ }
+
+ public synchronized void setFailed() {
+ setStatus(false);
+ }
+
+ public synchronized void setFailed(Throwable throwable) {
+ setStatus(false);
+ setThrowable(throwable);
+ }
+
+ protected void setStatus(Boolean passed) {
+ if (this.passed != null)
+ throw new IllegalStateException("Passed status of test " + uid + " is already set (to " + passed + ")");
+ this.passed = passed;
+ }
+
+ protected void setThrowable(Throwable throwable) {
+ if (this.throwable != null)
+ throw new IllegalStateException("Throwable of test " + uid + " is already set (to " + passed + ")");
+ this.throwable = throwable;
+ }
+
+ public String getUid() {
+ return uid;
+ }
+
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ // TODO Auto-generated method stub
+ return super.clone();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof TesterStatus) {
+ TesterStatus other = (TesterStatus) o;
+ // we don't check consistency for performance purposes
+ // this equals() is supposed to be used in collections or for transfer
+ return other.uid.equals(uid);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return uid.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return uid + "\t" + (passed ? "passed" : "failed");
+ }
+
+}
+++ /dev/null
-package org.argeo.util.test;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/** A generic tester based on Java assertions and functional programming. */
-public class Tester {
- private Map<String, TesterStatus> results = Collections.synchronizedSortedMap(new TreeMap<>());
-
- private ClassLoader classLoader;
-
- /** Use {@link Thread#getContextClassLoader()} by default. */
- public Tester() {
- this(Thread.currentThread().getContextClassLoader());
- }
-
- public Tester(ClassLoader classLoader) {
- this.classLoader = classLoader;
- }
-
- public void execute(String className) {
- Class<?> clss;
- try {
- clss = classLoader.loadClass(className);
- boolean assertionsEnabled = clss.desiredAssertionStatus();
- if (!assertionsEnabled)
- throw new IllegalStateException("Test runner " + getClass().getName()
- + " requires Java assertions to be enabled. Call the JVM with the -ea argument.");
- } catch (Exception e1) {
- throw new IllegalArgumentException("Cannot initalise test for " + className, e1);
-
- }
- List<Method> methods = findMethods(clss);
- if (methods.size() == 0)
- throw new IllegalArgumentException("No test method found in " + clss);
- // TODO make order more predictable?
- for (Method method : methods) {
- String uid = method.getDeclaringClass().getName() + "#" + method.getName();
- TesterStatus testStatus = new TesterStatus(uid);
- Object obj = null;
- try {
- beforeTest(uid, method);
- obj = clss.getDeclaredConstructor().newInstance();
- method.invoke(obj);
- testStatus.setPassed();
- afterTestPassed(uid, method, obj);
- } catch (Exception e) {
- testStatus.setFailed(e);
- afterTestFailed(uid, method, obj, e);
- } finally {
- results.put(uid, testStatus);
- }
- }
- }
-
- protected void beforeTest(String uid, Method method) {
- // System.out.println(uid + ": STARTING");
- }
-
- protected void afterTestPassed(String uid, Method method, Object obj) {
- System.out.println(uid + ": PASSED");
- }
-
- protected void afterTestFailed(String uid, Method method, Object obj, Throwable e) {
- System.out.println(uid + ": FAILED");
- e.printStackTrace();
- }
-
- protected List<Method> findMethods(Class<?> clss) {
- List<Method> methods = new ArrayList<Method>();
-// Method call = getMethod(clss, "call");
-// if (call != null)
-// methods.add(call);
-//
- for (Method method : clss.getMethods()) {
- if (method.getName().startsWith("test")) {
- methods.add(method);
- }
- }
- return methods;
- }
-
- protected Method getMethod(Class<?> clss, String name, Class<?>... parameterTypes) {
- try {
- return clss.getMethod(name, parameterTypes);
- } catch (NoSuchMethodException e) {
- return null;
- } catch (SecurityException e) {
- throw new IllegalStateException(e);
- }
- }
-
- public static void main(String[] args) {
- // deal with arguments
- String className;
- if (args.length < 1) {
- System.err.println(usage());
- System.exit(1);
- throw new IllegalArgumentException();
- } else {
- className = args[0];
- }
-
- Tester test = new Tester();
- try {
- test.execute(className);
- } catch (Throwable e) {
- e.printStackTrace();
- }
-
- Map<String, TesterStatus> r = test.results;
- for (String uid : r.keySet()) {
- TesterStatus testStatus = r.get(uid);
- System.out.println(testStatus);
- }
- }
-
- public static String usage() {
- return "java " + Tester.class.getName() + " [test class name]";
-
- }
-}
+++ /dev/null
-package org.argeo.util.test;
-
-import java.io.Serializable;
-
-/** The status of a test. */
-public class TesterStatus implements Serializable {
- private static final long serialVersionUID = 6272975746885487000L;
-
- private Boolean passed = null;
- private final String uid;
- private Throwable throwable = null;
-
- public TesterStatus(String uid) {
- this.uid = uid;
- }
-
- /** For cloning. */
- public TesterStatus(String uid, Boolean passed, Throwable throwable) {
- this(uid);
- this.passed = passed;
- this.throwable = throwable;
- }
-
- public synchronized Boolean isRunning() {
- return passed == null;
- }
-
- public synchronized Boolean isPassed() {
- assert passed != null;
- return passed;
- }
-
- public synchronized Boolean isFailed() {
- assert passed != null;
- return !passed;
- }
-
- public synchronized void setPassed() {
- setStatus(true);
- }
-
- public synchronized void setFailed() {
- setStatus(false);
- }
-
- public synchronized void setFailed(Throwable throwable) {
- setStatus(false);
- setThrowable(throwable);
- }
-
- protected void setStatus(Boolean passed) {
- if (this.passed != null)
- throw new IllegalStateException("Passed status of test " + uid + " is already set (to " + passed + ")");
- this.passed = passed;
- }
-
- protected void setThrowable(Throwable throwable) {
- if (this.throwable != null)
- throw new IllegalStateException("Throwable of test " + uid + " is already set (to " + passed + ")");
- this.throwable = throwable;
- }
-
- public String getUid() {
- return uid;
- }
-
- public Throwable getThrowable() {
- return throwable;
- }
-
- @Override
- protected Object clone() throws CloneNotSupportedException {
- // TODO Auto-generated method stub
- return super.clone();
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof TesterStatus) {
- TesterStatus other = (TesterStatus) o;
- // we don't check consistency for performance purposes
- // this equals() is supposed to be used in collections or for transfer
- return other.uid.equals(uid);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return uid.hashCode();
- }
-
- @Override
- public String toString() {
- return uid + "\t" + (passed ? "passed" : "failed");
- }
-
-}
<module>org.argeo.eclipse.ui</module>
<module>org.argeo.eclipse.ui.rap</module>
<!-- CMS -->
- <module>org.argeo.node.api</module>
+ <module>org.argeo.api</module>
<module>org.argeo.maintenance</module>
<module>org.argeo.cms</module>
<module>org.argeo.cms.ui.theme</module>
<configuration>
<failOnError>false</failOnError>
<additionalJOption>-Xdoclint:none</additionalJOption>
- <excludePackageNames>*.internal.*,org.eclipse.*</excludePackageNames>
+ <excludePackageNames>*.internal.*,org.eclipse.*,org.argeo.cms.ui.eclipse.forms.*</excludePackageNames>
<encoding>UTF-8</encoding>
<detectLinks>true</detectLinks>
<links>