From: Mathieu Baudier Date: Fri, 10 Dec 2021 10:43:43 +0000 (+0100) Subject: Major refactoring of Argeo CMS UI X-Git-Tag: argeo-commons-2.3.5~128 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=b7683883512d924a039a43c2e1102290aa49f64d;p=lgpl%2Fargeo-commons.git Major refactoring of Argeo CMS UI --- diff --git a/org.argeo.api/bnd.bnd b/org.argeo.api/bnd.bnd index e69de29bb..6f9826d27 100644 --- a/org.argeo.api/bnd.bnd +++ b/org.argeo.api/bnd.bnd @@ -0,0 +1,2 @@ +Import-Package: javax.naming.*,\ +javax.security.* \ No newline at end of file diff --git a/org.argeo.api/src/org/argeo/api/DataModelNamespace.java b/org.argeo.api/src/org/argeo/api/DataModelNamespace.java deleted file mode 100644 index 421b11a4a..000000000 --- a/org.argeo.api/src/org/argeo/api/DataModelNamespace.java +++ /dev/null @@ -1,18 +0,0 @@ -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 - } - -} diff --git a/org.argeo.api/src/org/argeo/api/PublishNamespace.java b/org.argeo.api/src/org/argeo/api/PublishNamespace.java deleted file mode 100644 index ff9575486..000000000 --- a/org.argeo.api/src/org/argeo/api/PublishNamespace.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.argeo.api; - -import org.osgi.resource.Namespace; - -/** Namespace defining which resources can be published. Typically use to expose icon of scripts to the web. */ -public class PublishNamespace extends Namespace { - - public static final String CMS_PUBLISH_NAMESPACE = "cms.publish"; - public static final String PKG = "pkg"; - public static final String FILE = "file"; - - private PublishNamespace() { - // empty - } - -} diff --git a/org.argeo.api/src/org/argeo/api/cms/Cms2DSize.java b/org.argeo.api/src/org/argeo/api/cms/Cms2DSize.java new file mode 100644 index 000000000..30b3d8100 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/Cms2DSize.java @@ -0,0 +1,34 @@ +package org.argeo.api.cms; + +/** A 2D size. */ +public class Cms2DSize { + private Integer width; + private Integer height; + + public Cms2DSize() { + + } + + public Cms2DSize(Integer width, Integer height) { + super(); + this.width = width; + this.height = height; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } + + public Integer getHeight() { + return height; + } + + public void setHeight(Integer height) { + this.height = height; + } + +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsApp.java b/org.argeo.api/src/org/argeo/api/cms/CmsApp.java new file mode 100644 index 000000000..761191e5d --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsApp.java @@ -0,0 +1,31 @@ +package org.argeo.api.cms; + +import java.util.Set; + +/** An extensible user interface base on the CMS backend. */ +public interface CmsApp { + /** + * If {@link CmsUi#setData(String, Object)} is set with this property, it + * indicates a different UI (typically with another theming. The {@link CmsApp} + * can use this information, but it doesn't have to be set, in which case a + * default UI must be provided. The provided value must belong to the values + * returned by {@link CmsApp#getUiNames()}. + */ + final static String UI_NAME_PROPERTY = CmsApp.class.getName() + ".ui.name"; + + Set getUiNames(); + + CmsUi initUi(Object uiParent); + + void refreshUi(CmsUi cmsUi, String state); + + void setState(CmsUi cmsUi, String state); + + CmsTheme getTheme(String uiName); + + boolean allThemesAvailable(); + + void addCmsAppListener(CmsAppListener listener); + + void removeCmsAppListener(CmsAppListener listener); +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsAppListener.java b/org.argeo.api/src/org/argeo/api/cms/CmsAppListener.java new file mode 100644 index 000000000..55fcec56b --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsAppListener.java @@ -0,0 +1,7 @@ +package org.argeo.api.cms; + +/** Notifies important events in a CMS App life cycle. */ +public interface CmsAppListener { + /** Theming has been updated and should be reloaded. */ + void themingUpdated(); +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsEditable.java b/org.argeo.api/src/org/argeo/api/cms/CmsEditable.java new file mode 100644 index 000000000..2deca018e --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsEditable.java @@ -0,0 +1,57 @@ +package org.argeo.api.cms; + +/** Abstraction of a simple edition life cycle. */ +public interface CmsEditable { + + /** Whether the calling thread can edit, the value is immutable */ + public Boolean canEdit(); + + public Boolean isEditing(); + + public void startEditing(); + + public void stopEditing(); + + public static CmsEditable NON_EDITABLE = new CmsEditable() { + + @Override + public void stopEditing() { + } + + @Override + public void startEditing() { + } + + @Override + public Boolean isEditing() { + return false; + } + + @Override + public Boolean canEdit() { + return false; + } + }; + + public static CmsEditable ALWAYS_EDITING = new CmsEditable() { + + @Override + public void stopEditing() { + } + + @Override + public void startEditing() { + } + + @Override + public Boolean isEditing() { + return true; + } + + @Override + public Boolean canEdit() { + return true; + } + }; + +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsEvent.java b/org.argeo.api/src/org/argeo/api/cms/CmsEvent.java new file mode 100644 index 000000000..b5dccbe9c --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsEvent.java @@ -0,0 +1,19 @@ +package org.argeo.api.cms; + +/** + * Can be applied to {@link Enum}s in order to define events used by + * {@link CmsView#sendEvent(String, java.util.Map)}. + */ +public interface CmsEvent { + String name(); + + default String topic() { + return getTopicBase() + "/" + name(); + } + + default String getTopicBase() { + return "argeo/cms"; + } + + +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsImageManager.java b/org.argeo.api/src/org/argeo/api/cms/CmsImageManager.java new file mode 100644 index 000000000..8c637b8cb --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsImageManager.java @@ -0,0 +1,46 @@ +package org.argeo.api.cms; + +import java.io.InputStream; + +/** Read and write access to images. */ +public interface CmsImageManager { + /** Load image in control */ + public Boolean load(M node, V control, Cms2DSize size); + + /** @return (0,0) if not available */ + public Cms2DSize getImageSize(M node); + + /** + * The related <img> tag, with src, width and height set. + * + * @return null if not available + */ + public String getImageTag(M node); + + /** + * The related <img> tag, with url, width and height set. Caller must + * close the tag (or add additional attributes). + * + * @return null if not available + */ + public StringBuilder getImageTagBuilder(M node, Cms2DSize size); + + /** + * Returns the remotely accessible URL of the image (registering it if + * needed) @return null if not available + */ + public String getImageUrl(M node); + +// public Binary getImageBinary(Node node) throws RepositoryException; + +// public Image getSwtImage(Node node) throws RepositoryException; + + /** @return URL */ + public String uploadImage(M context, M uploadFolder, String fileName, InputStream in, String contentType); + + @Deprecated + default String uploadImage(M uploadFolder, String fileName, InputStream in) { + System.err.println("Context must be provided to " + CmsImageManager.class.getName()); + return uploadImage(null, uploadFolder, fileName, in, null); + } +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsSession.java b/org.argeo.api/src/org/argeo/api/cms/CmsSession.java new file mode 100644 index 000000000..18d53cee8 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsSession.java @@ -0,0 +1,40 @@ +package org.argeo.api.cms; + +import java.time.ZonedDateTime; +import java.util.Locale; +import java.util.UUID; + +import javax.naming.ldap.LdapName; +import javax.security.auth.Subject; + +/** An authenticated user session. */ +public interface CmsSession { + final static String USER_DN = "DN"; + final static String SESSION_UUID = "entryUUID"; + final static String SESSION_LOCAL_ID = "uniqueIdentifier"; + + UUID getUuid(); + + String getUserRole(); + + LdapName getUserDn(); + + String getLocalId(); + + String getDisplayName(); +// Authorization getAuthorization(); + + Subject getSubject(); + + boolean isAnonymous(); + + ZonedDateTime getCreationTime(); + + ZonedDateTime getEnd(); + + Locale getLocale(); + + boolean isValid(); + + void registerView(String uid, Object view); +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsSessionId.java b/org.argeo.api/src/org/argeo/api/cms/CmsSessionId.java new file mode 100644 index 000000000..0e4778953 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsSessionId.java @@ -0,0 +1,39 @@ +package org.argeo.api.cms; + +import java.util.UUID; + +import javax.security.auth.Subject; + +/** + * The ID of a {@link CmsSession}, which must be available in the private + * credentials of an authenticated {@link Subject}. + */ +public class CmsSessionId { + private final UUID uuid; + + public CmsSessionId(UUID value) { + if (value == null) + throw new IllegalArgumentException("Value cannot be null"); + this.uuid = value; + } + + public UUID getUuid() { + return uuid; + } + + @Override + public int hashCode() { + return uuid.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof CmsSessionId && ((CmsSessionId) obj).getUuid().equals(uuid); + } + + @Override + public String toString() { + return "Node Session " + uuid; + } + +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsStyle.java b/org.argeo.api/src/org/argeo/api/cms/CmsStyle.java new file mode 100644 index 000000000..8444e2fc5 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsStyle.java @@ -0,0 +1,22 @@ +package org.argeo.api.cms; + +/** Can be applied to {@link Enum}s in order to generate (CSS) class names. */ +public interface CmsStyle { + String name(); + + /** @deprecated use {@link #style()} instead. */ + @Deprecated + default String toStyleClass() { + return style(); + } + + default String style() { + String classPrefix = getClassPrefix(); + return "".equals(classPrefix) ? name() : classPrefix + "-" + name(); + } + + default String getClassPrefix() { + return ""; + } + +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsTheme.java b/org.argeo.api/src/org/argeo/api/cms/CmsTheme.java new file mode 100644 index 000000000..50c3b1f25 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsTheme.java @@ -0,0 +1,45 @@ +package org.argeo.api.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Set; + +/** A CMS theme which can be applied to web apps as well as desktop apps. */ +public interface CmsTheme { + /** Unique ID of this theme. */ + String getThemeId(); + + /** + * Load a resource as an input stream, base don its relative path, or + * null if not found + */ + InputStream getResourceAsStream(String resourceName) throws IOException; + + /** Relative paths to standard web CSS. */ + Set getWebCssPaths(); + + /** Relative paths to RAP specific CSS. */ + Set getRapCssPaths(); + + /** Relative paths to SWT specific CSS. */ + Set getSwtCssPaths(); + + /** Relative paths to images such as icons. */ + Set getImagesPaths(); + + /** Relative paths to fonts. */ + Set getFontsPaths(); + + /** Tags to be added to the header section of the HTML page. */ + String getHtmlHeaders(); + + /** The HTML body to use. */ + String getBodyHtml(); + + /** The default icon size (typically the smallest). */ + Integer getDefaultIconSize(); + + /** Loads one of the relative path provided by the other methods. */ + InputStream loadPath(String path) throws IOException; + +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsUi.java b/org.argeo.api/src/org/argeo/api/cms/CmsUi.java new file mode 100644 index 000000000..fd91c6e34 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsUi.java @@ -0,0 +1,7 @@ +package org.argeo.api.cms; + +public interface CmsUi { + Object getData(String key); + void setData(String key, Object value); + +} diff --git a/org.argeo.api/src/org/argeo/api/cms/CmsView.java b/org.argeo.api/src/org/argeo/api/cms/CmsView.java new file mode 100644 index 000000000..c7ca1e90c --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/CmsView.java @@ -0,0 +1,97 @@ +package org.argeo.api.cms; + +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.login.LoginContext; + +/** Provides interaction with the CMS system. */ +public interface CmsView { + final static String CMS_VIEW_UID_PROPERTY = "argeo.cms.view.uid"; + // String KEY = "org.argeo.cms.ui.view"; + + String getUid(); + + UxContext getUxContext(); + + // NAVIGATION + void navigateTo(String state); + + // SECURITY + void authChange(LoginContext loginContext); + + void logout(); + + // void registerCallbackHandler(CallbackHandler callbackHandler); + + // SERVICES + void exception(Throwable e); + + CmsImageManager getImageManager(); + + boolean isAnonymous(); + + /** + * Send an event to this topic. Does nothing by default., but if implemented it + * MUST set the {@link #CMS_VIEW_UID_PROPERTY} in the properties. + */ + default void sendEvent(String topic, Map properties) { + + } + + /** + * Convenience methods for when {@link #sendEvent(String, Map)} only requires + * one single parameter. + */ + default void sendEvent(String topic, String param, Object value) { + Map properties = new HashMap<>(); + properties.put(param, value); + sendEvent(topic, properties); + } + + default void applyStyles(Object widget) { + + } + + default T doAs(PrivilegedAction action) { + throw new UnsupportedOperationException(); + } + + default Void runAs(Runnable runnable) { + return doAs(new PrivilegedAction() { + + @Override + public Void run() { + if (runnable != null) + runnable.run(); + return null; + } + }); + } + + default void stateChanged(String state, String title) { + } + + default CmsSession getCmsSession() { + throw new UnsupportedOperationException(); + } + + default Object getData(String key) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + default T getUiContext(Class clss) { + return (T) getData(clss.getName()); + } + + default void setUiContext(Class clss, T instance) { + setData(clss.getName(), instance); + } + + default void setData(String key, Object value) { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.argeo.api/src/org/argeo/api/cms/MvcProvider.java b/org.argeo.api/src/org/argeo/api/cms/MvcProvider.java new file mode 100644 index 000000000..c1aa6006c --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/MvcProvider.java @@ -0,0 +1,44 @@ +package org.argeo.api.cms; + +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 extends BiFunction { + W createUiPart(V parent, M context); + + /** + * 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 apply(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 createUiPart(parent, context); + } + + default W createUiPart(V parent) { + return createUiPart(parent, null); + } +} diff --git a/org.argeo.api/src/org/argeo/api/cms/UxContext.java b/org.argeo.api/src/org/argeo/api/cms/UxContext.java new file mode 100644 index 000000000..fb99178ee --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/cms/UxContext.java @@ -0,0 +1,18 @@ +package org.argeo.api.cms; + +public interface UxContext { + boolean isPortrait(); + + boolean isLandscape(); + + boolean isSquare(); + + boolean isSmall(); + + /** + * Is a production environment (must be false by default, and be explicitly + * set during the CMS deployment). When false, it can activate additional UI + * capabilities in order to facilitate QA. + */ + boolean isMasterData(); +} diff --git a/org.argeo.api/src/org/argeo/api/gcr/ContentRepository.java b/org.argeo.api/src/org/argeo/api/gcr/ContentRepository.java new file mode 100644 index 000000000..3349b30a1 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/gcr/ContentRepository.java @@ -0,0 +1,6 @@ +package org.argeo.api.gcr; + +import java.util.function.Supplier; + +public interface ContentRepository extends Supplier { +} diff --git a/org.argeo.api/src/org/argeo/api/gcr/ContentSession.java b/org.argeo.api/src/org/argeo/api/gcr/ContentSession.java new file mode 100644 index 000000000..cd2543f8e --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/gcr/ContentSession.java @@ -0,0 +1,5 @@ +package org.argeo.api.gcr; + +public interface ContentSession { + +} diff --git a/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/AbstractRapE4App.java b/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/AbstractRapE4App.java index 8c43a8089..5fe22ae33 100644 --- a/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/AbstractRapE4App.java +++ b/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/AbstractRapE4App.java @@ -3,7 +3,7 @@ package org.argeo.cms.e4.rap; import java.util.HashMap; import java.util.Map; -import org.argeo.cms.ui.dialogs.CmsFeedback; +import org.argeo.cms.swt.dialogs.CmsFeedback; import org.eclipse.rap.e4.E4ApplicationConfig; import org.eclipse.rap.rwt.application.Application; import org.eclipse.rap.rwt.application.Application.OperationMode; diff --git a/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java b/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java index 12ee3c55e..3ee8df1ef 100644 --- a/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java +++ b/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java @@ -10,14 +10,15 @@ 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.cms.CmsImageManager; +import org.argeo.api.cms.CmsView; +import org.argeo.api.cms.UxContext; 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.swt.CmsSwtUtils; +import org.argeo.cms.swt.SimpleSwtUxContext; +import org.argeo.cms.swt.auth.CmsLoginShell; +import org.argeo.cms.swt.dialogs.CmsFeedback; import org.argeo.cms.ui.util.SimpleImageManager; -import org.argeo.cms.ui.util.SimpleUxContext; -import org.argeo.cms.ui.widgets.auth.CmsLoginShell; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.ui.workbench.UIEvents; import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate; @@ -63,7 +64,7 @@ public class CmsLoginLifecycle implements CmsView { Display display = Display.getCurrent(); // UiContext.setData(CmsView.KEY, this); CmsLoginShell loginShell = new CmsLoginShell(this); - CmsView.registerCmsView(loginShell.getShell(), this); + CmsSwtUtils.registerCmsView(loginShell.getShell(), this); loginShell.setSubject(subject); try { // try pre-auth @@ -80,7 +81,7 @@ public class CmsLoginLifecycle implements CmsView { } if (CurrentUser.getUsername(getSubject()) == null) return false; - uxContext = new SimpleUxContext(); + uxContext = new SimpleSwtUxContext(); imageManager = new SimpleImageManager(); eventBroker.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE, new EventHandler() { diff --git a/org.argeo.cms.e4/OSGI-INF/defaultCallbackHandler.xml b/org.argeo.cms.e4/OSGI-INF/defaultCallbackHandler.xml index 3fd7fdafb..fcd3ae5cb 100644 --- a/org.argeo.cms.e4/OSGI-INF/defaultCallbackHandler.xml +++ b/org.argeo.cms.e4/OSGI-INF/defaultCallbackHandler.xml @@ -1,6 +1,6 @@ - + diff --git a/org.argeo.cms.e4/bnd.bnd b/org.argeo.cms.e4/bnd.bnd index 8714dab79..e4a4519f0 100644 --- a/org.argeo.cms.e4/bnd.bnd +++ b/org.argeo.cms.e4/bnd.bnd @@ -11,5 +11,5 @@ javax.jcr.nodetype,\ org.argeo.cms,\ org.eclipse.core.commands.common,\ org.eclipse.jface.window,\ -org.argeo.cms.ui.widgets.auth,\ +org.argeo.cms.swt.auth,\ * diff --git a/org.argeo.cms.e4/e4xmi/cms-devops.e4xmi b/org.argeo.cms.e4/e4xmi/cms-devops.e4xmi index dc8044587..89bcc376d 100644 --- a/org.argeo.cms.e4/e4xmi/cms-devops.e4xmi +++ b/org.argeo.cms.e4/e4xmi/cms-devops.e4xmi @@ -5,16 +5,16 @@ shellMaximized auth.cn=admin,ou=roles,ou=node - + auth.cn=admin,ou=roles,ou=node - + - - + + @@ -22,34 +22,34 @@ usersEditorArea - + - - + + - + - + - - - - + + + + ViewMenu - - - - - + + + + + @@ -58,18 +58,18 @@ - + - - - - + + + + - + - + @@ -78,21 +78,21 @@ - + auth.cn=admin,ou=roles,ou=node - + - + - + - + @@ -102,9 +102,9 @@ - - - + + + diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java index fe05253c1..1d3bab9f8 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java @@ -15,7 +15,7 @@ import javax.naming.ldap.LdapName; import org.argeo.api.security.CryptoKeyring; import org.argeo.cms.CmsException; import org.argeo.cms.auth.CurrentUser; -import org.argeo.cms.ui.dialogs.CmsMessageDialog; +import org.argeo.cms.swt.dialogs.CmsMessageDialog; import org.argeo.eclipse.ui.dialogs.ErrorFeedback; import org.argeo.osgi.transaction.WorkTransaction; import org.eclipse.e4.core.di.annotations.Execute; diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java index 4fc1d983c..f352f91aa 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java @@ -20,13 +20,13 @@ 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.swt.CmsSwtUtils; import org.argeo.cms.ui.jcr.JcrBrowserUtils; import org.argeo.cms.ui.jcr.NodeContentProvider; import org.argeo.cms.ui.jcr.NodeLabelProvider; 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.ui.util.CmsUiUtils; import org.argeo.eclipse.ui.EclipseUiException; import org.argeo.eclipse.ui.TreeParent; import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; @@ -97,7 +97,7 @@ public class JcrBrowserView { // Create the tree on top of the view Composite top = new Composite(sashForm, SWT.NONE); // GridLayout gl = new GridLayout(1, false); - top.setLayout(CmsUiUtils.noSpaceGridLayout()); + top.setLayout(CmsSwtUtils.noSpaceGridLayout()); try { this.userSession = this.nodeRepository.login(NodeConstants.HOME_WORKSPACE); @@ -121,7 +121,7 @@ public class JcrBrowserView { // Create the property viewer on the bottom Composite bottom = new Composite(sashForm, SWT.NONE); - bottom.setLayout(CmsUiUtils.noSpaceGridLayout()); + bottom.setLayout(CmsSwtUtils.noSpaceGridLayout()); propertiesViewer = createPropertiesViewer(bottom); sashForm.setWeights(getWeights()); diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/AbstractOsgiComposite.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/AbstractOsgiComposite.java index c83183130..c9c18e9df 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/AbstractOsgiComposite.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/AbstractOsgiComposite.java @@ -4,7 +4,7 @@ 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.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; @@ -20,8 +20,8 @@ abstract class AbstractOsgiComposite extends Composite { public AbstractOsgiComposite(Composite parent, int style) { super(parent, style); - parent.setLayout(CmsUiUtils.noSpaceGridLayout()); - setLayout(CmsUiUtils.noSpaceGridLayout()); + parent.setLayout(CmsSwtUtils.noSpaceGridLayout()); + setLayout(CmsSwtUtils.noSpaceGridLayout()); setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); initUi(style); } diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/Browse.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/Browse.java index 2212b7b05..260a114cd 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/Browse.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/Browse.java @@ -15,10 +15,11 @@ import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; +import org.argeo.api.cms.Cms2DSize; import org.argeo.cms.CmsException; +import org.argeo.cms.swt.CmsSwtUtils; 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; @@ -75,13 +76,13 @@ public class Browse implements CmsUiProvider { if (context == null) // return null; throw new CmsException("Context cannot be null"); - GridLayout layout = CmsUiUtils.noSpaceGridLayout(); + GridLayout layout = CmsSwtUtils.noSpaceGridLayout(); layout.numColumns = 2; parent.setLayout(layout); // Left Composite leftCmp = new Composite(parent, SWT.NO_FOCUS); - leftCmp.setLayoutData(CmsUiUtils.fillAll()); + leftCmp.setLayoutData(CmsSwtUtils.fillAll()); createBrowserPart(leftCmp, context); // Right @@ -102,17 +103,17 @@ public class Browse implements CmsUiProvider { } private void createBrowserPart(Composite parent, Node context) throws RepositoryException { - GridLayout layout = CmsUiUtils.noSpaceGridLayout(); + GridLayout layout = CmsSwtUtils.noSpaceGridLayout(); parent.setLayout(layout); Composite filterCmp = new Composite(parent, SWT.NO_FOCUS); - filterCmp.setLayoutData(CmsUiUtils.fillWidth()); + filterCmp.setLayoutData(CmsSwtUtils.fillWidth()); // top filter addFilterPanel(filterCmp); // scrolled composite scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER | SWT.NO_FOCUS); - scrolledCmp.setLayoutData(CmsUiUtils.fillAll()); + scrolledCmp.setLayoutData(CmsSwtUtils.fillAll()); scrolledCmp.setExpandVertical(true); scrolledCmp.setExpandHorizontal(true); scrolledCmp.setShowFocusedControl(true); @@ -132,7 +133,7 @@ public class Browse implements CmsUiProvider { } private Control initExplorer(Composite parent, Node context) throws RepositoryException { - parent.setLayout(CmsUiUtils.noSpaceGridLayout()); + parent.setLayout(CmsSwtUtils.noSpaceGridLayout()); createBrowserColumn(parent, context); return null; } @@ -149,14 +150,14 @@ public class Browse implements CmsUiProvider { public void addFilterPanel(Composite parent) { - parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(2, false))); + parent.setLayout(CmsSwtUtils.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.setLayoutData(CmsSwtUtils.fillWidth()); filterTxt.addModifyListener(new ModifyListener() { private static final long serialVersionUID = 7709303319740056286L; @@ -212,7 +213,7 @@ public class Browse implements CmsUiProvider { private void setEdited(Node node) { try { currEdited = node; - CmsUiUtils.clear(nodeDisplayParent); + CmsSwtUtils.clear(nodeDisplayParent); createNodeView(nodeDisplayParent, currEdited); nodeDisplayParent.layout(); refreshFilters(node); @@ -282,7 +283,7 @@ public class Browse implements CmsUiProvider { if (!browserCols.containsKey(currNodePath)) createBrowserColumn(colViewer, node); - colViewer.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false))); + colViewer.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false))); // colViewer.pack(); colViewer.layout(); // also resize the scrolled composite @@ -313,7 +314,7 @@ public class Browse implements CmsUiProvider { } } - private Point imageWidth = new Point(250, 0); + private Cms2DSize imageWidth = new Cms2DSize(250, 0); /** * Recreates the content of the box that displays information about the current @@ -330,7 +331,7 @@ public class Browse implements CmsUiProvider { // Name and primary type Label contextL = new Label(parent, SWT.NONE); - CmsUiUtils.markup(contextL); + CmsSwtUtils.markup(contextL); contextL.setText("" + context.getName() + ""); new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType().getName()); @@ -437,7 +438,7 @@ public class Browse implements CmsUiProvider { protected void populate() { Composite parent = this; - GridLayout layout = CmsUiUtils.noSpaceGridLayout(); + GridLayout layout = CmsSwtUtils.noSpaceGridLayout(); this.setLayout(layout); createTableViewer(parent); @@ -452,17 +453,17 @@ public class Browse implements CmsUiProvider { GridData gd = new GridData(SWT.LEFT, SWT.FILL, false, true); gd.widthHint = COLUMN_WIDTH; listCmp.setLayoutData(gd); - listCmp.setLayout(CmsUiUtils.noSpaceGridLayout()); + listCmp.setLayout(CmsSwtUtils.noSpaceGridLayout()); entityViewer = new TableViewer(listCmp, SWT.VIRTUAL | SWT.SINGLE); Table table = entityViewer.getTable(); - table.setLayoutData(CmsUiUtils.fillAll()); + table.setLayoutData(CmsSwtUtils.fillAll()); table.setLinesVisible(true); table.setHeaderVisible(false); - CmsUiUtils.markup(table); + CmsSwtUtils.markup(table); - CmsUiUtils.style(table, MaintenanceStyles.BROWSER_COLUMN); + CmsSwtUtils.style(table, MaintenanceStyles.BROWSER_COLUMN); // first column TableViewerColumn column = new TableViewerColumn(entityViewer, SWT.NONE); diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/ConnectivityDeploymentUi.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/ConnectivityDeploymentUi.java index 7e8a99196..97f3e6713 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/ConnectivityDeploymentUi.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/ConnectivityDeploymentUi.java @@ -1,6 +1,6 @@ package org.argeo.cms.e4.maintenance; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; @@ -38,7 +38,7 @@ class ConnectivityDeploymentUi extends AbstractOsgiComposite { Label label = new Label(this, SWT.NONE); label.setData(new GridData(SWT.FILL, SWT.FILL, false, false)); - CmsUiUtils.markup(label); + CmsSwtUtils.markup(label); label.setText(text.toString()); } diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DataDeploymentUi.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DataDeploymentUi.java index a750e9541..22e80069d 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DataDeploymentUi.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DataDeploymentUi.java @@ -10,7 +10,7 @@ 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.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -106,7 +106,7 @@ class DataDeploymentUi extends AbstractOsgiComposite { } Label label = new Label(parent, SWT.NONE); label.setData(new GridData(SWT.FILL, SWT.FILL, false, false)); - CmsUiUtils.markup(label); + CmsSwtUtils.markup(label); label.setText("" + text.toString() + ""); } diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DeploymentEntryPoint.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DeploymentEntryPoint.java index a746b3c46..505f67d81 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DeploymentEntryPoint.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DeploymentEntryPoint.java @@ -6,7 +6,7 @@ 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.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; @@ -68,7 +68,7 @@ class DeploymentEntryPoint { NodeState nodeState = bc.getService(nodeStateRef); ServiceReference nodeDeploymentRef = bc.getServiceReference(NodeDeployment.class); Label label = new Label(composite, SWT.WRAP); - CmsUiUtils.markup(label); + CmsSwtUtils.markup(label); if (nodeDeploymentRef == null) { label.setText("Not yet deployed on
" + nodeState.getHostname() + "
, please configure below."); } else { @@ -85,7 +85,7 @@ class DeploymentEntryPoint { private static Group createHighLevelGroup(Composite parent, String text) { Group group = new Group(parent, SWT.NONE); group.setText(text); - CmsUiUtils.markup(group); + CmsSwtUtils.markup(group); return group; } diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/LogDeploymentUi.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/LogDeploymentUi.java index 05923fb47..fa5d3dae3 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/LogDeploymentUi.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/LogDeploymentUi.java @@ -6,7 +6,7 @@ import java.util.Enumeration; import java.util.GregorianCalendar; import java.util.TimeZone; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; @@ -37,7 +37,7 @@ class LogDeploymentUi extends AbstractOsgiComposite implements LogListener { 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); + CmsSwtUtils.markup(logDisplay); Enumeration logEntries = (Enumeration) logReader.getLog(); while (logEntries.hasMoreElements()) logDisplay.append(printEntry(logEntries.nextElement())); diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/NonAdminPage.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/NonAdminPage.java index 122f5cfaa..cb38ce899 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/NonAdminPage.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/NonAdminPage.java @@ -3,8 +3,8 @@ package org.argeo.cms.e4.maintenance; import javax.jcr.Node; import javax.jcr.RepositoryException; +import org.argeo.cms.swt.CmsSwtUtils; 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; @@ -18,7 +18,7 @@ public class NonAdminPage implements CmsUiProvider{ public Control createUi(Composite parent, Node context) throws RepositoryException { Composite body = new Composite(parent, SWT.NO_FOCUS); - body.setLayoutData(CmsUiUtils.fillAll()); + body.setLayoutData(CmsSwtUtils.fillAll()); body.setLayout(new GridLayout()); Label label = new Label(body, SWT.NONE); label.setText("You should be an admin to perform maintenance operations. " diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/SecurityDeploymentUi.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/SecurityDeploymentUi.java index 4edbf565a..3492c5499 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/SecurityDeploymentUi.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/SecurityDeploymentUi.java @@ -2,7 +2,7 @@ package org.argeo.cms.e4.maintenance; import java.net.URI; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; @@ -75,7 +75,7 @@ class SecurityDeploymentUi extends AbstractOsgiComposite { } Label label = new Label(parent, SWT.NONE); label.setData(new GridData(SWT.FILL, SWT.FILL, false, false)); - CmsUiUtils.markup(label); + CmsSwtUtils.markup(label); label.setText(text.toString()); } diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/CmsSessionsView.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/CmsSessionsView.java index 0c73fd7ce..8a3605095 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/CmsSessionsView.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/CmsSessionsView.java @@ -10,8 +10,7 @@ import java.util.List; import javax.annotation.PostConstruct; import javax.naming.ldap.LdapName; -import org.argeo.cms.CmsException; -import org.argeo.cms.auth.CmsSession; +import org.argeo.api.cms.CmsSession; import org.argeo.eclipse.ui.ColumnViewerComparator; import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils; import org.argeo.util.LangUtils; @@ -55,7 +54,7 @@ public class CmsSessionsView { private static final long serialVersionUID = -5234573509093747505L; public String getText(Object element) { - return ((CmsSession) element).getAuthorization().toString(); + return ((CmsSession) element).getDisplayName(); } public String getToolTipText(Object element) { @@ -154,7 +153,7 @@ public class CmsSessionsView { try { srs = bc.getServiceReferences(CmsSession.class, null); } catch (InvalidSyntaxException e) { - throw new CmsException("Cannot retrieve CMS sessions", e); + throw new IllegalArgumentException("Cannot retrieve CMS sessions", e); } List res = new ArrayList<>(); for (ServiceReference sr : srs) { diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/EgoDashboard.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/EgoDashboard.java index 8499356dc..5a805d1e9 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/EgoDashboard.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/EgoDashboard.java @@ -1,16 +1,15 @@ package org.argeo.cms.e4.parts; -import static org.argeo.cms.ui.util.CmsUiUtils.lbl; -import static org.argeo.cms.ui.util.CmsUiUtils.txt; - import java.security.AccessController; import java.time.ZonedDateTime; import javax.annotation.PostConstruct; import javax.security.auth.Subject; -import org.argeo.cms.auth.CmsSession; +import org.argeo.api.cms.CmsSession; import org.argeo.cms.auth.CurrentUser; +import org.argeo.cms.osgi.CmsOsgiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.osgi.framework.BundleContext; @@ -25,23 +24,23 @@ public class EgoDashboard { p.setLayout(new GridLayout()); String username = CurrentUser.getUsername(); - lbl(p, "" + CurrentUser.getDisplayName() + ""); - txt(p, username); - lbl(p, "Roles:"); + CmsSwtUtils.lbl(p, "" + CurrentUser.getDisplayName() + ""); + CmsSwtUtils.txt(p, username); + CmsSwtUtils.lbl(p, "Roles:"); roles: for (String role : CurrentUser.roles()) { if (username.equals(role)) continue roles; - txt(p, role); + CmsSwtUtils.txt(p, role); } Subject subject = Subject.getSubject(AccessController.getContext()); if (subject != null) { - CmsSession cmsSession = CmsSession.getCmsSession(bc, subject); + CmsSession cmsSession = CmsOsgiUtils.getCmsSession(bc, subject); ZonedDateTime loggedIndSince = cmsSession.getCreationTime(); - lbl(p, "Session:"); - txt(p, cmsSession.getUuid().toString()); - lbl(p, "Logged in since:"); - txt(p, loggedIndSince.toString()); + CmsSwtUtils.lbl(p, "Session:"); + CmsSwtUtils.txt(p, cmsSession.getUuid().toString()); + CmsSwtUtils.lbl(p, "Logged in since:"); + CmsSwtUtils.txt(p, loggedIndSince.toString()); } } } diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java index 708a65315..2521612c7 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java @@ -27,9 +27,9 @@ import org.argeo.cms.e4.users.providers.MailLP; import org.argeo.cms.e4.users.providers.RoleIconLP; import org.argeo.cms.e4.users.providers.UserFilter; import org.argeo.cms.jcr.CmsJcrUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.eclipse.forms.AbstractFormPart; import org.argeo.cms.ui.eclipse.forms.IManagedForm; -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; @@ -146,7 +146,7 @@ public class GroupEditor extends AbstractRoleEditor { // GridLayout layout = new GridLayout(5, false); GridLayout layout = new GridLayout(2, false); body.setLayout(layout); - body.setLayoutData(CmsUiUtils.fillWidth()); + body.setLayoutData(CmsSwtUtils.fillWidth()); String cn = UserAdminUtils.getProperty(group, LdapAttrs.cn.name()); createReadOnlyLT(body, "Name", cn); @@ -287,7 +287,7 @@ public class GroupEditor extends AbstractRoleEditor { ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT); ToolBar toolBar = toolBarManager.createControl(body); - toolBar.setLayoutData(CmsUiUtils.fillWidth()); + toolBar.setLayoutData(CmsSwtUtils.fillWidth()); toolBarManager.add(action); toolBarManager.update(true); diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserEditor.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserEditor.java index 18753f7ba..a93100120 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserEditor.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserEditor.java @@ -20,10 +20,10 @@ import org.argeo.cms.e4.users.providers.CommonNameLP; import org.argeo.cms.e4.users.providers.DomainNameLP; import org.argeo.cms.e4.users.providers.RoleIconLP; import org.argeo.cms.e4.users.providers.UserFilter; +import org.argeo.cms.swt.CmsSwtUtils; 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.ui.util.CmsUiUtils; import org.argeo.eclipse.ui.ColumnDefinition; import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.eclipse.ui.parts.LdifUsersTable; @@ -278,7 +278,7 @@ public class UserEditor extends AbstractRoleEditor { // Composite body= parent; Composite body = new Composite(parent, SWT.BORDER); body.setLayout(new GridLayout()); - body.setLayoutData(CmsUiUtils.fillAll()); + body.setLayoutData(CmsSwtUtils.fillAll()); // boolean isAdmin = CurrentUser.isInRole(NodeConstants.ROLE_ADMIN); @@ -346,7 +346,7 @@ public class UserEditor extends AbstractRoleEditor { Action action = new RemoveMembershipAction(userViewer, user, tooltip, SecurityAdminImages.ICON_REMOVE_DESC); ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT); ToolBar toolBar = toolBarManager.createControl(body); - toolBar.setLayoutData(CmsUiUtils.fillWidth()); + toolBar.setLayoutData(CmsSwtUtils.fillWidth()); toolBarManager.add(action); toolBarManager.update(true); return userViewerCmp; diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/DataModels.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/DataModels.java index a1b500816..3d0f3a167 100644 --- a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/DataModels.java +++ b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/DataModels.java @@ -1,6 +1,6 @@ package org.argeo.cms.jcr.internal; -import static org.argeo.api.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE; +import static org.argeo.cms.osgi.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE; import java.util.ArrayList; import java.util.Collections; @@ -10,8 +10,8 @@ import java.util.TreeMap; 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.cms.osgi.DataModelNamespace; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/JcrDeployment.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/JcrDeployment.java index 0daaad47c..9915fb037 100644 --- a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/JcrDeployment.java +++ b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/JcrDeployment.java @@ -1,6 +1,6 @@ package org.argeo.cms.jcr.internal; -import static org.argeo.api.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE; +import static org.argeo.cms.osgi.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE; import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX; import java.io.File; @@ -31,7 +31,6 @@ import org.apache.commons.logging.LogFactory; 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.security.CryptoKeyring; @@ -42,6 +41,7 @@ import org.argeo.cms.jcr.CmsJcrUtils; import org.argeo.cms.jcr.internal.servlet.CmsRemotingServlet; import org.argeo.cms.jcr.internal.servlet.CmsWebDavServlet; import org.argeo.cms.jcr.internal.servlet.JcrHttpUtils; +import org.argeo.cms.osgi.DataModelNamespace; import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrException; import org.argeo.jcr.JcrUtils; diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/KernelUtils.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/KernelUtils.java index 98749cf43..ed04518c0 100644 --- a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/KernelUtils.java +++ b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/KernelUtils.java @@ -24,9 +24,9 @@ import javax.security.auth.login.LoginContext; 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.jcr.internal.osgi.CmsJcrActivator; +import org.argeo.cms.osgi.DataModelNamespace; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/CmsSessionProvider.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/CmsSessionProvider.java index 8ec2f45b3..45ca33855 100644 --- a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/CmsSessionProvider.java +++ b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/CmsSessionProvider.java @@ -20,7 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.jackrabbit.server.SessionProvider; import org.argeo.api.NodeConstants; -import org.argeo.cms.auth.CmsSession; +import org.argeo.api.cms.CmsSession; import org.argeo.jcr.JcrUtils; /** diff --git a/org.argeo.cms.jcr/src/org/argeo/security/jackrabbit/ArgeoSecurityManager.java b/org.argeo.cms.jcr/src/org/argeo/security/jackrabbit/ArgeoSecurityManager.java index 5767ecd5e..4b5945377 100644 --- a/org.argeo.cms.jcr/src/org/argeo/security/jackrabbit/ArgeoSecurityManager.java +++ b/org.argeo.cms.jcr/src/org/argeo/security/jackrabbit/ArgeoSecurityManager.java @@ -27,9 +27,10 @@ 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.cms.CmsSession; import org.argeo.api.security.AnonymousPrincipal; import org.argeo.api.security.DataAdminPrincipal; -import org.argeo.cms.auth.CmsSession; +import org.argeo.cms.osgi.CmsOsgiUtils; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; @@ -84,7 +85,7 @@ public class ArgeoSecurityManager extends DefaultSecurityManager { boolean isRegularUser = !userPrincipal.isEmpty(); CmsSession cmsSession = null; if (cmsBundleContext != null) { - cmsSession = CmsSession.getCmsSession(cmsBundleContext, subject); + cmsSession = CmsOsgiUtils.getCmsSession(cmsBundleContext, subject); if (log.isTraceEnabled()) log.trace("Opening JCR session for CMS session " + cmsSession); } diff --git a/org.argeo.cms.swt/bnd.bnd b/org.argeo.cms.swt/bnd.bnd index ad8e58178..9d4eae6c3 100644 --- a/org.argeo.cms.swt/bnd.bnd +++ b/org.argeo.cms.swt/bnd.bnd @@ -2,3 +2,6 @@ Import-Package: org.eclipse.swt,\ org.eclipse.jface.window,\ org.eclipse.core.commands.common,\ * + +Bundle-ActivationPolicy: lazy + \ No newline at end of file diff --git a/org.argeo.cms.swt/pom.xml b/org.argeo.cms.swt/pom.xml index 2e3942000..c6e772c89 100644 --- a/org.argeo.cms.swt/pom.xml +++ b/org.argeo.cms.swt/pom.xml @@ -21,6 +21,13 @@ 2.3-SNAPSHOT + + + org.argeo.commons + org.argeo.swt.specific.rap + 2.3-SNAPSHOT + provided + org.argeo.tp.rap.e4 diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsIcon.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsIcon.java new file mode 100644 index 000000000..4ff89f27a --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsIcon.java @@ -0,0 +1,25 @@ +package org.argeo.cms.swt; + +import org.argeo.api.cms.CmsTheme; +import org.eclipse.swt.graphics.Image; + +/** Can be applied to {@link Enum}s in order to generated {@link Image}s. */ +public interface CmsIcon { + String name(); + + default Image getSmallIcon(CmsTheme theme) { + return ((CmsSwtTheme) theme).getIcon(name(), getSmallIconSize()); + } + + default Image getBigIcon(CmsTheme theme) { + return ((CmsSwtTheme) theme).getIcon(name(), getBigIconSize()); + } + + default Integer getSmallIconSize() { + return 16; + } + + default Integer getBigIconSize() { + return 32; + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsStyles.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsStyles.java new file mode 100644 index 000000000..9eba6f6ec --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsStyles.java @@ -0,0 +1,32 @@ +package org.argeo.cms.swt; + +/** Styles references in the CSS. */ +@Deprecated +public interface CmsStyles { + // General + public final static String CMS_SHELL = "cms_shell"; + public final static String CMS_MENU_LINK = "cms_menu_link"; + + // Header + public final static String CMS_HEADER = "cms_header"; + public final static String CMS_HEADER_LEAD = "cms_header-lead"; + public final static String CMS_HEADER_CENTER = "cms_header-center"; + public final static String CMS_HEADER_END = "cms_header-end"; + + public final static String CMS_LEAD = "cms_lead"; + public final static String CMS_END = "cms_end"; + public final static String CMS_FOOTER = "cms_footer"; + + public final static String CMS_USER_MENU = "cms_user_menu"; + public final static String CMS_USER_MENU_LINK = "cms_user_menu-link"; + public final static String CMS_USER_MENU_ITEM = "cms_user_menu-item"; + public final static String CMS_LOGIN_DIALOG = "cms_login_dialog"; + public final static String CMS_LOGIN_DIALOG_USERNAME = "cms_login_dialog-username"; + public final static String CMS_LOGIN_DIALOG_PASSWORD = "cms_login_dialog-password"; + + // Body + public final static String CMS_SCROLLED_AREA = "cms_scrolled_area"; + public final static String CMS_BODY = "cms_body"; + public final static String CMS_STATIC_TEXT = "cms_static-text"; + public final static String CMS_LINK = "cms_link"; +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtTheme.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtTheme.java new file mode 100644 index 000000000..b5f7c0e4d --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtTheme.java @@ -0,0 +1,21 @@ +package org.argeo.cms.swt; + +import org.argeo.api.cms.CmsTheme; +import org.eclipse.swt.graphics.Image; + +/** SWT specific {@link CmsTheme}. */ +public interface CmsSwtTheme extends CmsTheme { + /** The image registered at this path, or null if not found. */ + Image getImage(String path); + + /** + * And icon with this file name (without the extension), with a best effort to + * find the appropriate size, or null if not found. + * + * @param name An icon file name without path and extension. + * @param preferredSize the preferred size, if null, + * {@link #getDefaultIconSize()} will be tried. + */ + Image getIcon(String name, Integer preferredSize); + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtUtils.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtUtils.java new file mode 100644 index 000000000..a94d70706 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtUtils.java @@ -0,0 +1,251 @@ +package org.argeo.cms.swt; + +import java.util.HashMap; +import java.util.Map; + +import org.argeo.api.cms.CmsStyle; +import org.argeo.api.cms.CmsTheme; +import org.argeo.api.cms.CmsView; +import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowData; +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.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Widget; + +/** SWT utilities. */ +public class CmsSwtUtils { + + /** Singleton. */ + private CmsSwtUtils() { + } + + public static CmsTheme getCmsTheme(Composite parent) { + CmsTheme theme = (CmsTheme) parent.getData(CmsTheme.class.getName()); + if (theme == null) { + // find parent shell + Shell topShell = parent.getShell(); + while (topShell.getParent() != null) + topShell = (Shell) topShell.getParent(); + theme = (CmsTheme) topShell.getData(CmsTheme.class.getName()); + parent.setData(CmsTheme.class.getName(), theme); + } + return theme; + } + + public static void registerCmsTheme(Shell shell, CmsTheme theme) { + // find parent shell + Shell topShell = shell; + while (topShell.getParent() != null) + topShell = (Shell) topShell.getParent(); + // check if already set + if (topShell.getData(CmsTheme.class.getName()) != null) { + CmsTheme registeredTheme = (CmsTheme) topShell.getData(CmsTheme.class.getName()); + throw new IllegalArgumentException( + "Theme " + registeredTheme.getThemeId() + " already registered in this shell"); + } + topShell.setData(CmsTheme.class.getName(), theme); + } + + public static CmsView getCmsView(Control parent) { + // find parent shell + Shell topShell = parent.getShell(); + while (topShell.getParent() != null) + topShell = (Shell) topShell.getParent(); + return (CmsView) topShell.getData(CmsView.class.getName()); + } + + public static void registerCmsView(Shell shell, CmsView view) { + // find parent shell + Shell topShell = shell; + while (topShell.getParent() != null) + topShell = (Shell) topShell.getParent(); + // check if already set + if (topShell.getData(CmsView.class.getName()) != null) { + CmsView registeredView = (CmsView) topShell.getData(CmsView.class.getName()); + throw new IllegalArgumentException("Cms view " + registeredView + " already registered in this shell"); + } + shell.setData(CmsView.class.getName(), view); + } + + /** Sends an event via {@link CmsView#sendEvent(String, Map)}. */ + public static void sendEventOnSelect(Control control, String topic, Map properties) { + SelectionListener listener = (Selected) (e) -> { + getCmsView(control.getParent()).sendEvent(topic, properties); + }; + if (control instanceof Button) { + ((Button) control).addSelectionListener(listener); + } else + throw new UnsupportedOperationException("Control type " + control.getClass() + " is not supported."); + } + + /** + * Convenience method to sends an event via + * {@link CmsView#sendEvent(String, Map)}. + */ + public static void sendEventOnSelect(Control control, String topic, String key, Object value) { + Map properties = new HashMap<>(); + properties.put(key, value); + sendEventOnSelect(control, topic, properties); + } + + /* + * GRID LAYOUT + */ + public static GridLayout noSpaceGridLayout() { + return noSpaceGridLayout(new GridLayout()); + } + + public static GridLayout noSpaceGridLayout(int columns) { + return noSpaceGridLayout(new GridLayout(columns, false)); + } + + /** @return the same layout, with spaces removed. */ + public static GridLayout noSpaceGridLayout(GridLayout layout) { + layout.horizontalSpacing = 0; + layout.verticalSpacing = 0; + layout.marginWidth = 0; + layout.marginHeight = 0; + return layout; + } + + public static GridData fillAll() { + return new GridData(SWT.FILL, SWT.FILL, true, true); + } + + public static GridData fillWidth() { + return grabWidth(SWT.FILL, SWT.FILL); + } + + public static GridData grabWidth(int horizontalAlignment, int verticalAlignment) { + return new GridData(horizontalAlignment, horizontalAlignment, true, false); + } + + public static GridData fillHeight() { + return grabHeight(SWT.FILL, SWT.FILL); + } + + public static GridData grabHeight(int horizontalAlignment, int verticalAlignment) { + return new GridData(horizontalAlignment, horizontalAlignment, false, true); + } + + /* + * ROW LAYOUT + */ + /** @return the same layout, with margins removed. */ + public static RowLayout noMarginsRowLayout(RowLayout rowLayout) { + rowLayout.marginTop = 0; + rowLayout.marginBottom = 0; + rowLayout.marginLeft = 0; + rowLayout.marginRight = 0; + return rowLayout; + } + + public static RowLayout noMarginsRowLayout(int type) { + return noMarginsRowLayout(new RowLayout(type)); + } + + public static RowData rowData16px() { + return new RowData(16, 16); + } + + /* + * FORM LAYOUT + */ + public static FormData coverAll() { + FormData fdLabel = new FormData(); + fdLabel.top = new FormAttachment(0, 0); + fdLabel.left = new FormAttachment(0, 0); + fdLabel.right = new FormAttachment(100, 0); + fdLabel.bottom = new FormAttachment(100, 0); + return fdLabel; + } + + /* + * STYLING + */ + + /** Style widget */ + public static T style(T widget, String style) { + if (style == null) + return widget;// does nothing + EclipseUiSpecificUtils.setStyleData(widget, style); + if (widget instanceof Control) { + CmsView cmsView = getCmsView((Control) widget); + if (cmsView != null) + cmsView.applyStyles(widget); + } + return widget; + } + + /** Style widget */ + public static T style(T widget, CmsStyle style) { + return style(widget, style.style()); + } + + /** Enable markups on widget */ + public static T markup(T widget) { + EclipseUiSpecificUtils.setMarkupData(widget); + return widget; + } + + /** Disable markup validation. */ + public static T disableMarkupValidation(T widget) { + EclipseUiSpecificUtils.setMarkupValidationDisabledData(widget); + return widget; + } + + /** + * Apply markup and set text on {@link Label}, {@link Button}, {@link Text}. + * + * @param widget the widget to style and to use in order to display text + * @param txt the object to display via its toString() method. + * This argument should not be null, but if it is null and + * assertions are disabled "" is displayed instead; if + * assertions are enabled the call will fail. + * + * @see markup + */ + public static T text(T widget, Object txt) { + assert txt != null; + String str = txt != null ? txt.toString() : ""; + markup(widget); + if (widget instanceof Label) + ((Label) widget).setText(str); + else if (widget instanceof Button) + ((Button) widget).setText(str); + else if (widget instanceof Text) + ((Text) widget).setText(str); + else + throw new IllegalArgumentException("Unsupported widget type " + widget.getClass()); + return widget; + } + + /** A {@link Label} with markup activated. */ + public static Label lbl(Composite parent, Object txt) { + return text(new Label(parent, SWT.NONE), txt); + } + + /** A read-only {@link Text} whose content can be copy/pasted. */ + public static Text txt(Composite parent, Object txt) { + return text(new Text(parent, SWT.NONE), txt); + } + + /** Dispose all children of a Composite */ + public static void clear(Composite composite) { + if (composite.isDisposed()) + return; + for (Control child : composite.getChildren()) + child.dispose(); + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/MouseDoubleClick.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/MouseDoubleClick.java new file mode 100644 index 000000000..b818b06d9 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/MouseDoubleClick.java @@ -0,0 +1,26 @@ +package org.argeo.cms.swt; + +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; + +/** + * {@link MouseListener#mouseDoubleClick(MouseEvent)} as a functional interface + * in order to use as a short lambda expression in UI code. + * {@link MouseListener#mouseDownouseEvent)} and + * {@link MouseListener#mouseUp(MouseEvent)} do nothing by default. + */ +@FunctionalInterface +public interface MouseDoubleClick extends MouseListener { + @Override + void mouseDoubleClick(MouseEvent e); + + @Override + default void mouseDown(MouseEvent e) { + // does nothing + } + + @Override + default void mouseUp(MouseEvent e) { + // does nothing + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/MouseDown.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/MouseDown.java new file mode 100644 index 000000000..baecb0072 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/MouseDown.java @@ -0,0 +1,26 @@ +package org.argeo.cms.swt; + +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; + +/** + * {@link MouseListener#mouseDown(MouseEvent)} as a functional interface in + * order to use as a short lambda expression in UI code. + * {@link MouseListener#mouseDoubleClick(MouseEvent)} and + * {@link MouseListener#mouseUp(MouseEvent)} do nothing by default. + */ +@FunctionalInterface +public interface MouseDown extends MouseListener { + @Override + void mouseDown(MouseEvent e); + + @Override + default void mouseDoubleClick(MouseEvent e) { + // does nothing + } + + @Override + default void mouseUp(MouseEvent e) { + // does nothing + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/Selected.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/Selected.java new file mode 100644 index 000000000..03fbad01e --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/Selected.java @@ -0,0 +1,21 @@ +package org.argeo.cms.swt; + +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; + +/** + * {@link SelectionListener} as a functional interface in order to use as a + * short lambda expression in UI code. + * {@link SelectionListener#widgetDefaultSelected(SelectionEvent)} does nothing + * by default. + */ +@FunctionalInterface +public interface Selected extends SelectionListener { + @Override + public void widgetSelected(SelectionEvent e); + + default public void widgetDefaultSelected(SelectionEvent e) { + // does nothing + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/SimpleSwtUxContext.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/SimpleSwtUxContext.java new file mode 100644 index 000000000..9c55e8b10 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/SimpleSwtUxContext.java @@ -0,0 +1,50 @@ +package org.argeo.cms.swt; + +import org.argeo.api.cms.UxContext; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +public class SimpleSwtUxContext implements UxContext { + private Point size; + private Point small = new Point(400, 400); + + public SimpleSwtUxContext() { + this(Display.getCurrent().getBounds()); + } + + public SimpleSwtUxContext(Rectangle rect) { + this.size = new Point(rect.width, rect.height); + } + + public SimpleSwtUxContext(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; + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLogin.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLogin.java new file mode 100644 index 000000000..8e12a8986 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLogin.java @@ -0,0 +1,334 @@ +package org.argeo.cms.swt.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 javax.servlet.http.HttpServletRequest; +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.api.cms.CmsView; +import org.argeo.cms.CmsMsg; +import org.argeo.cms.LocaleUtils; +import org.argeo.cms.auth.HttpRequestCallback; +import org.argeo.cms.swt.CmsStyles; +import org.argeo.cms.swt.CmsSwtUtils; +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 = null;// = Activator.getNodeState(); + if (nodeState != null) { + defaultLocale = nodeState.getDefaultLocale(); + List 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(CmsSwtUtils.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); + } + } + + public 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); + CmsSwtUtils.style(l, CMS_USER_MENU_ITEM); + l.setText(CmsMsg.logout.lead(locale)); + GridData lData = CmsSwtUtils.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()); + CmsSwtUtils.style(credentialsBlock, CMS_LOGIN_DIALOG); + + Integer textWidth = 120; + if (parent instanceof Shell) + CmsSwtUtils.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)); + CmsSwtUtils.style(usernameT, CMS_LOGIN_DIALOG_USERNAME); + GridData gd = CmsSwtUtils.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)); + CmsSwtUtils.style(passwordT, CMS_LOGIN_DIALOG_PASSWORD); + gd = CmsSwtUtils.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(CmsSwtUtils.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(true, true); + else + parent.layout(); + usernameT.setText(usernameStr); + passwordT.setTextChars(pwd); + } + + protected Composite createLocalesBlock(final Composite parent) { + Composite c = new Composite(parent, SWT.NONE); + CmsSwtUtils.style(c, CMS_USER_MENU_ITEM); + c.setLayout(CmsSwtUtils.noSpaceGridLayout()); + c.setLayoutData(CmsSwtUtils.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 locales = localeChoice.getLocales(); + for (Integer i = 0; i < locales.size(); i++) { + Locale locale = locales.get(i); + Button button = new Button(c, SWT.RADIO); + CmsSwtUtils.style(button, CMS_USER_MENU_ITEM); + button.setData(i); + button.setText(LocaleUtils.toLead(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; + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLoginShell.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLoginShell.java new file mode 100644 index 000000000..f6a35f136 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLoginShell.java @@ -0,0 +1,72 @@ +package org.argeo.cms.swt.auth; + +import org.argeo.api.cms.CmsView; +import org.argeo.cms.swt.CmsSwtUtils; +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(); +// 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() { + CmsSwtUtils.style(shell, CMS_USER_MENU); + 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); + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CompositeCallbackHandler.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CompositeCallbackHandler.java new file mode 100644 index 000000000..495007cb2 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CompositeCallbackHandler.java @@ -0,0 +1,273 @@ +package org.argeo.cms.swt.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:
+ *
    + *
  • {@link PasswordCallback}
  • + *
  • {@link NameCallback}
  • + *
  • {@link TextOutputCallback}
  • + *
+ * Supported Argeo {@link Callback}s are:
+ *
    + *
  • {@link LocaleChoice}
  • + *
+ */ +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(); + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/DynamicCallbackHandler.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/DynamicCallbackHandler.java new file mode 100644 index 000000000..b0c36c602 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/DynamicCallbackHandler.java @@ -0,0 +1,34 @@ +package org.argeo.cms.swt.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(); + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/LocaleChoice.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/LocaleChoice.java new file mode 100644 index 000000000..e98e390ee --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/LocaleChoice.java @@ -0,0 +1,86 @@ +package org.argeo.cms.swt.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 locales; + + private Integer selectedIndex = null; + private final Integer defaultIndex; + + public LocaleChoice(List 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 getLocales() { + return locales; + } + + public Locale getDefaultLocale() { + return locales.get(getDefaultIndex()); + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/package-info.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/package-info.java new file mode 100644 index 000000000..b431423d8 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/package-info.java @@ -0,0 +1,2 @@ +/** Argeo CMS authentication widgets, based on SWT. */ +package org.argeo.cms.swt.auth; \ No newline at end of file diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/ChangePasswordDialog.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/ChangePasswordDialog.java new file mode 100644 index 000000000..2cf0c8c57 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/ChangePasswordDialog.java @@ -0,0 +1,84 @@ +package org.argeo.cms.swt.dialogs; + +import java.security.PrivilegedAction; +import java.util.Arrays; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.api.cms.CmsView; +import org.argeo.cms.CmsMsg; +import org.argeo.cms.CmsUserManager; +import org.argeo.cms.swt.CmsSwtUtils; +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.Shell; +import org.eclipse.swt.widgets.Text; + +/** Dialog to change a password. */ +public class ChangePasswordDialog extends CmsMessageDialog { + private final static Log log = LogFactory.getLog(ChangePasswordDialog.class); + + private CmsUserManager cmsUserManager; + private CmsView cmsView; + + private PrivilegedAction doIt; + + public ChangePasswordDialog(Shell parentShell, String message, int kind, CmsUserManager cmsUserManager) { + super(parentShell, message, kind); + this.cmsUserManager = cmsUserManager; + cmsView = CmsSwtUtils.getCmsView(parentShell); + } + + @Override + protected Control createInputArea(Composite userSection) { + addFormLabel(userSection, CmsMsg.currentPassword.lead()); + Text previousPassword = new Text(userSection, SWT.BORDER | SWT.PASSWORD); + previousPassword.setLayoutData(CmsSwtUtils.fillWidth()); + addFormLabel(userSection, CmsMsg.newPassword.lead()); + Text newPassword = new Text(userSection, SWT.BORDER | SWT.PASSWORD); + newPassword.setLayoutData(CmsSwtUtils.fillWidth()); + addFormLabel(userSection, CmsMsg.repeatNewPassword.lead()); + Text confirmPassword = new Text(userSection, SWT.BORDER | SWT.PASSWORD); + confirmPassword.setLayoutData(CmsSwtUtils.fillWidth()); + + doIt = () -> { + if (Arrays.equals(newPassword.getTextChars(), confirmPassword.getTextChars())) { + try { + cmsUserManager.changeOwnPassword(previousPassword.getTextChars(), newPassword.getTextChars()); + return OK; + } catch (Exception e1) { + log.error("Could not change password", e1); + cancel(); + CmsMessageDialog.openError(CmsMsg.invalidPassword.lead()); + return CANCEL; + } + } else { + cancel(); + CmsMessageDialog.openError(CmsMsg.repeatNewPassword.lead()); + return CANCEL; + } + }; + + pack(); + return previousPassword; + } + + @Override + protected void okPressed() { + Integer returnCode = cmsView.doAs(doIt); + if (returnCode.equals(OK)) { + super.okPressed(); + CmsMessageDialog.openInformation(CmsMsg.passwordChanged.lead()); + } + } + + private static Label addFormLabel(Composite parent, String label) { + Label lbl = new Label(parent, SWT.WRAP); + lbl.setText(label); +// CmsUiUtils.style(lbl, SuiteStyle.simpleLabel); + return lbl; + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsFeedback.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsFeedback.java new file mode 100644 index 000000000..512829873 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsFeedback.java @@ -0,0 +1,101 @@ +package org.argeo.cms.swt.dialogs; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.cms.CmsMsg; +import org.argeo.cms.swt.Selected; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** A dialog feedback based on a {@link LightweightDialog}. */ +public class CmsFeedback extends LightweightDialog { + private final static Log log = LogFactory.getLog(CmsFeedback.class); + + private String message; + private Throwable exception; + + public CmsFeedback(Shell parentShell, String message, Throwable e) { + super(parentShell); + this.message = message; + this.exception = e; + log.error(message, e); + } + + public static CmsFeedback show(String message, Throwable e) { + // rethrow ThreaDeath in order to make sure that RAP will properly clean + // up the UI thread + if (e instanceof ThreadDeath) + throw (ThreadDeath) e; + + try { + CmsFeedback cmsFeedback = new CmsFeedback(null, message, e); + cmsFeedback.setBlockOnOpen(false); + cmsFeedback.open(); + return cmsFeedback; + } catch (Throwable e1) { + log.error("Cannot open error feedback (" + e.getMessage() + "), original error below", e); + return null; + } + } + + public static CmsFeedback show(String message) { + CmsFeedback cmsFeedback = new CmsFeedback(null, message, null); + cmsFeedback.open(); + return cmsFeedback; + } + + /** Tries to find a display */ + // private static Display getDisplay() { + // try { + // Display display = Display.getCurrent(); + // if (display != null) + // return display; + // else + // return Display.getDefault(); + // } catch (Exception e) { + // return Display.getCurrent(); + // } + // } + + protected Control createDialogArea(Composite parent) { + parent.setLayout(new GridLayout(2, false)); + + Label messageLbl = new Label(parent, SWT.WRAP); + if (message != null) + messageLbl.setText(message); + else if (exception != null) + messageLbl.setText(exception.getLocalizedMessage()); + + Button close = new Button(parent, SWT.FLAT); + close.setText(CmsMsg.close.lead()); + close.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false)); + close.addSelectionListener((Selected) (e) -> closeShell(OK)); + + // Composite composite = new Composite(dialogarea, SWT.NONE); + // composite.setLayout(new GridLayout(2, false)); + // composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + if (exception != null) { + Text stack = new Text(parent, SWT.MULTI | SWT.LEAD | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + stack.setEditable(false); + stack.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); + StringWriter sw = new StringWriter(); + exception.printStackTrace(new PrintWriter(sw)); + stack.setText(sw.toString()); + } + + // parent.pack(); + return messageLbl; + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsMessageDialog.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsMessageDialog.java new file mode 100644 index 000000000..66e640595 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsMessageDialog.java @@ -0,0 +1,167 @@ +package org.argeo.cms.swt.dialogs; + +import org.argeo.cms.CmsMsg; +import org.argeo.cms.swt.CmsSwtUtils; +import org.argeo.cms.swt.Selected; +import org.argeo.eclipse.ui.EclipseUiUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +/** Base class for dialogs displaying messages or small forms. */ +public class CmsMessageDialog extends LightweightDialog { + public final static int NONE = 0; + public final static int ERROR = 1; + public final static int INFORMATION = 2; + public final static int QUESTION = 3; + public final static int WARNING = 4; + public final static int CONFIRM = 5; + public final static int QUESTION_WITH_CANCEL = 6; + + private int kind; + private String message; + + public CmsMessageDialog(Shell parentShell, String message, int kind) { + super(parentShell); + this.kind = kind; + this.message = message; + } + + protected Control createDialogArea(Composite parent) { + parent.setLayout(new GridLayout()); + + TraverseListener traverseListener = new TraverseListener() { + private static final long serialVersionUID = -1158892811534971856L; + + public void keyTraversed(TraverseEvent e) { + if (e.detail == SWT.TRAVERSE_RETURN) + okPressed(); + else if (e.detail == SWT.TRAVERSE_ESCAPE) + cancelPressed(); + } + }; + + // message + Composite body = new Composite(parent, SWT.NONE); + body.addTraverseListener(traverseListener); + GridLayout bodyGridLayout = new GridLayout(); + bodyGridLayout.marginHeight = 20; + bodyGridLayout.marginWidth = 20; + body.setLayout(bodyGridLayout); + body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + if (message != null) { + Label messageLbl = new Label(body, SWT.WRAP); + CmsSwtUtils.markup(messageLbl); + messageLbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + messageLbl.setFont(EclipseUiUtils.getBoldFont(parent)); + messageLbl.setText(message); + } + + // buttons + Composite buttons = new Composite(parent, SWT.NONE); + buttons.addTraverseListener(traverseListener); + buttons.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); + if (kind == INFORMATION || kind == WARNING || kind == ERROR || kind == ERROR) { + GridLayout layout = new GridLayout(1, true); + layout.marginWidth = 0; + layout.marginHeight = 0; + buttons.setLayout(layout); + + Button close = new Button(buttons, SWT.FLAT); + close.setText(CmsMsg.close.lead()); + close.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + close.addSelectionListener((Selected) (e) -> closeShell(OK)); + close.setFocus(); + close.addTraverseListener(traverseListener); + + buttons.setTabList(new Control[] { close }); + } else if (kind == CONFIRM || kind == QUESTION || kind == QUESTION_WITH_CANCEL) { + Control input = createInputArea(body); + if (input != null) { + input.addTraverseListener(traverseListener); + body.setTabList(new Control[] { input }); + } + GridLayout layout = new GridLayout(2, true); + layout.marginWidth = 0; + layout.marginHeight = 0; + buttons.setLayout(layout); + + Button cancel = new Button(buttons, SWT.FLAT); + cancel.setText(CmsMsg.cancel.lead()); + cancel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + cancel.addSelectionListener((Selected) (e) -> cancelPressed()); + cancel.addTraverseListener(traverseListener); + + Button ok = new Button(buttons, SWT.FLAT); + ok.setText(CmsMsg.ok.lead()); + ok.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + ok.addSelectionListener((Selected) (e) -> okPressed()); + ok.addTraverseListener(traverseListener); + if (input == null) + ok.setFocus(); + else + input.setFocus(); + + buttons.setTabList(new Control[] { ok, cancel }); + } + // pack(); + parent.setTabList(new Control[] { body, buttons }); + return body; + } + + protected Control createInputArea(Composite parent) { + return null; + } + + protected void okPressed() { + closeShell(OK); + } + + protected void cancelPressed() { + closeShell(CANCEL); + } + + protected void cancel() { + closeShell(CANCEL); + } + + protected Point getInitialSize() { + return new Point(400, 200); + } + + public static boolean open(int kind, Shell parent, String message) { + CmsMessageDialog dialog = new CmsMessageDialog(parent, message, kind); + return dialog.open() == 0; + } + + public static boolean openConfirm(String message) { + return open(CONFIRM, Display.getCurrent().getActiveShell(), message); + } + + public static void openInformation(String message) { + open(INFORMATION, Display.getCurrent().getActiveShell(), message); + } + + public static boolean openQuestion(String message) { + return open(QUESTION, Display.getCurrent().getActiveShell(), message); + } + + public static void openWarning(String message) { + open(WARNING, Display.getCurrent().getActiveShell(), message); + } + + public static void openError(String message) { + open(ERROR, Display.getCurrent().getActiveShell(), message); + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsWizardDialog.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsWizardDialog.java new file mode 100644 index 000000000..59d9ab7f5 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsWizardDialog.java @@ -0,0 +1,220 @@ +package org.argeo.cms.swt.dialogs; + +import java.lang.reflect.InvocationTargetException; + +import org.argeo.cms.CmsMsg; +import org.argeo.cms.swt.CmsSwtUtils; +import org.argeo.cms.swt.Selected; +import org.argeo.eclipse.ui.EclipseUiUtils; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.IWizardContainer2; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.swt.SWT; +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.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; + +/** A wizard dialog based on {@link LightweightDialog}. */ +public class CmsWizardDialog extends LightweightDialog implements IWizardContainer2 { + private static final long serialVersionUID = -2123153353654812154L; + + private IWizard wizard; + private IWizardPage currentPage; + private int currentPageIndex; + + private Label titleBar; + private Label message; + private Composite[] pageBodies; + private Composite buttons; + private Button back; + private Button next; + private Button finish; + + public CmsWizardDialog(Shell parentShell, IWizard wizard) { + super(parentShell); + this.wizard = wizard; + wizard.setContainer(this); + // create the pages + wizard.addPages(); + currentPage = wizard.getStartingPage(); + if (currentPage == null) + throw new IllegalArgumentException("At least one wizard page is required"); + } + + @Override + protected Control createDialogArea(Composite parent) { + updateWindowTitle(); + + Composite messageArea = new Composite(parent, SWT.NONE); + messageArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + { + messageArea.setLayout(CmsSwtUtils.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)); + updateTitleBar(); + Button cancelButton = new Button(messageArea, SWT.FLAT); + cancelButton.setText(CmsMsg.cancel.lead()); + cancelButton.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false, 1, 3)); + cancelButton.addSelectionListener((Selected) (e) -> closeShell(CANCEL)); + message = new Label(messageArea, SWT.WRAP); + message.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 2)); + updateMessage(); + } + + Composite body = new Composite(parent, SWT.BORDER); + body.setLayout(new FormLayout()); + body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + pageBodies = new Composite[wizard.getPageCount()]; + IWizardPage[] pages = wizard.getPages(); + for (int i = 0; i < pages.length; i++) { + pageBodies[i] = new Composite(body, SWT.NONE); + pageBodies[i].setLayout(CmsSwtUtils.noSpaceGridLayout()); + setSwitchingFormData(pageBodies[i]); + pages[i].createControl(pageBodies[i]); + } + showPage(currentPage); + + buttons = new Composite(parent, SWT.NONE); + buttons.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); + { + boolean singlePage = wizard.getPageCount() == 1; + // singlePage = false;// dev + GridLayout layout = new GridLayout(singlePage ? 1 : 3, true); + layout.marginWidth = 0; + layout.marginHeight = 0; + buttons.setLayout(layout); + // TODO revert order for right-to-left languages + + if (!singlePage) { + back = new Button(buttons, SWT.PUSH); + back.setText(CmsMsg.wizardBack.lead()); + back.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + back.addSelectionListener((Selected) (e) -> backPressed()); + + next = new Button(buttons, SWT.PUSH); + next.setText(CmsMsg.wizardNext.lead()); + next.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + next.addSelectionListener((Selected) (e) -> nextPressed()); + } + finish = new Button(buttons, SWT.PUSH); + finish.setText(CmsMsg.wizardFinish.lead()); + finish.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + finish.addSelectionListener((Selected) (e) -> finishPressed()); + + updateButtons(); + } + return body; + } + + @Override + public IWizardPage getCurrentPage() { + return currentPage; + } + + @Override + public Shell getShell() { + return getForegoundShell(); + } + + @Override + public void showPage(IWizardPage page) { + IWizardPage[] pages = wizard.getPages(); + int index = -1; + for (int i = 0; i < pages.length; i++) { + if (page == pages[i]) { + index = i; + break; + } + } + if (index < 0) + throw new IllegalArgumentException("Cannot find index of wizard page " + page); + pageBodies[index].moveAbove(pageBodies[currentPageIndex]); + + // // clear + // for (Control c : body.getChildren()) + // c.dispose(); + // page.createControl(body); + // body.layout(true, true); + currentPageIndex = index; + currentPage = page; + } + + @Override + public void updateButtons() { + if (back != null) + back.setEnabled(wizard.getPreviousPage(currentPage) != null); + if (next != null) + next.setEnabled(wizard.getNextPage(currentPage) != null && currentPage.canFlipToNextPage()); + if (finish != null) { + finish.setEnabled(wizard.canFinish()); + } + } + + @Override + public void updateMessage() { + if (currentPage.getMessage() != null) + message.setText(currentPage.getMessage()); + } + + @Override + public void updateTitleBar() { + if (currentPage.getTitle() != null) + titleBar.setText(currentPage.getTitle()); + } + + @Override + public void updateWindowTitle() { + setTitle(wizard.getWindowTitle()); + } + + @Override + public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) + throws InvocationTargetException, InterruptedException { + runnable.run(null); + } + + @Override + public void updateSize() { + // TODO pack? + } + + protected boolean onCancel() { + return wizard.performCancel(); + } + + protected void nextPressed() { + IWizardPage page = wizard.getNextPage(currentPage); + showPage(page); + updateButtons(); + } + + protected void backPressed() { + IWizardPage page = wizard.getPreviousPage(currentPage); + showPage(page); + updateButtons(); + } + + protected void finishPressed() { + if (wizard.performFinish()) + closeShell(OK); + } + + private static void setSwitchingFormData(Composite composite) { + FormData fdLabel = new FormData(); + fdLabel.top = new FormAttachment(0, 0); + fdLabel.left = new FormAttachment(0, 0); + fdLabel.right = new FormAttachment(100, 0); + fdLabel.bottom = new FormAttachment(100, 0); + composite.setLayoutData(fdLabel); + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/LightweightDialog.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/LightweightDialog.java new file mode 100644 index 000000000..2f00a37a6 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/LightweightDialog.java @@ -0,0 +1,256 @@ +package org.argeo.cms.swt.dialogs; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.eclipse.ui.EclipseUiException; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.ShellAdapter; +import org.eclipse.swt.events.ShellEvent; +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; + +/** Generic lightweight dialog, not based on JFace. */ +public class LightweightDialog { + private final static Log log = LogFactory.getLog(LightweightDialog.class); + + // must be the same value as org.eclipse.jface.window.Window#OK + public final static int OK = 0; + // must be the same value as org.eclipse.jface.window.Window#CANCEL + public final static int CANCEL = 1; + + private Shell parentShell; + private Shell backgroundShell; + private Shell foregoundShell; + + private Integer returnCode = null; + private boolean block = true; + + private String title; + + /** Tries to find a display */ + private static Display getDisplay() { + try { + Display display = Display.getCurrent(); + if (display != null) + return display; + else + return Display.getDefault(); + } catch (Exception e) { + return Display.getCurrent(); + } + } + + public LightweightDialog(Shell parentShell) { + this.parentShell = parentShell; + } + + public int open() { + if (foregoundShell != null) + throw new EclipseUiException("There is already a shell"); + backgroundShell = new Shell(parentShell, SWT.ON_TOP); + backgroundShell.setFullScreen(true); + // if (parentShell != null) { + // backgroundShell.setBounds(parentShell.getBounds()); + // } else + // backgroundShell.setMaximized(true); + backgroundShell.setAlpha(128); + backgroundShell.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK)); + foregoundShell = new Shell(backgroundShell, SWT.NO_TRIM | SWT.ON_TOP); + if (title != null) + setTitle(title); + foregoundShell.setLayout(new GridLayout()); + foregoundShell.setSize(getInitialSize()); + createDialogArea(foregoundShell); + // shell.pack(); + // shell.layout(); + + Rectangle shellBounds = parentShell != null ? parentShell.getBounds() : Display.getCurrent().getBounds();// RAP + Point dialogSize = foregoundShell.getSize(); + int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2; + int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2; + foregoundShell.setLocation(x, y); + + foregoundShell.addShellListener(new ShellAdapter() { + private static final long serialVersionUID = -2701270481953688763L; + + @Override + public void shellDeactivated(ShellEvent e) { + if (hasChildShells()) + return; + if (returnCode == null)// not yet closed + closeShell(CANCEL); + } + + @Override + public void shellClosed(ShellEvent e) { + notifyClose(); + } + + }); + + backgroundShell.open(); + foregoundShell.open(); + // after the foreground shell has been opened + backgroundShell.addFocusListener(new FocusListener() { + private static final long serialVersionUID = 3137408447474661070L; + + @Override + public void focusLost(FocusEvent event) { + } + + @Override + public void focusGained(FocusEvent event) { + if (hasChildShells()) + return; + if (returnCode == null)// not yet closed + closeShell(CANCEL); + } + }); + + if (block) { + block(); + } + if (returnCode == null) + returnCode = OK; + return returnCode; + } + + public void block() { + try { + runEventLoop(foregoundShell); + } catch (ThreadDeath t) { + returnCode = CANCEL; + if (log.isTraceEnabled()) + log.error("Thread death, canceling dialog", t); + } catch (Throwable t) { + returnCode = CANCEL; + log.error("Cannot open blocking lightweight dialog", t); + } + } + + private boolean hasChildShells() { + if (foregoundShell == null) + return false; + return foregoundShell.getShells().length != 0; + } + + // public synchronized int openAndWait() { + // open(); + // while (returnCode == null) + // try { + // wait(100); + // } catch (InterruptedException e) { + // // silent + // } + // return returnCode; + // } + + private synchronized void notifyClose() { + if (returnCode == null) + returnCode = CANCEL; + notifyAll(); + } + + protected void closeShell(int returnCode) { + this.returnCode = returnCode; + if (CANCEL == returnCode) + onCancel(); + if (foregoundShell != null && !foregoundShell.isDisposed()) { + foregoundShell.close(); + foregoundShell.dispose(); + foregoundShell = null; + } + + if (backgroundShell != null && !backgroundShell.isDisposed()) { + backgroundShell.close(); + backgroundShell.dispose(); + } + } + + protected Point getInitialSize() { + // if (exception != null) + // return new Point(800, 600); + // else + return new Point(600, 400); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogarea = new Composite(parent, SWT.NONE); + dialogarea.setLayout(new GridLayout()); + dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return dialogarea; + } + + protected Shell getBackgroundShell() { + return backgroundShell; + } + + protected Shell getForegoundShell() { + return foregoundShell; + } + + public void setBlockOnOpen(boolean shouldBlock) { + block = shouldBlock; + } + + public void pack() { + foregoundShell.pack(); + } + + private void runEventLoop(Shell loopShell) { + Display display; + if (foregoundShell == null) { + display = Display.getCurrent(); + } else { + display = loopShell.getDisplay(); + } + + while (loopShell != null && !loopShell.isDisposed()) { + try { + if (!display.readAndDispatch()) { + display.sleep(); + } + } catch (UnsupportedOperationException e) { + throw e; + } catch (Throwable e) { + handleException(e); + } + } + if (!display.isDisposed()) + display.update(); + } + + protected void handleException(Throwable t) { + if (t instanceof ThreadDeath) { + // Don't catch ThreadDeath as this is a normal occurrence when + // the thread dies + throw (ThreadDeath) t; + } + // Try to keep running. + t.printStackTrace(); + } + + /** @return false, if the dialog should not be closed. */ + protected boolean onCancel() { + return true; + } + + public void setTitle(String title) { + this.title = title; + if (title != null && getForegoundShell() != null) + getForegoundShell().setText(title); + } + + public Integer getReturnCode() { + return returnCode; + } + +} \ No newline at end of file diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/SingleValueDialog.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/SingleValueDialog.java new file mode 100644 index 000000000..9404b81da --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/SingleValueDialog.java @@ -0,0 +1,82 @@ +package org.argeo.cms.swt.dialogs; + +import org.eclipse.jface.window.Window; +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.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** A dialog asking a for a single value. */ +public class SingleValueDialog extends CmsMessageDialog { + private Text valueT; + private String value; + private String defaultValue; + + public SingleValueDialog(Shell parentShell, String message) { + super(parentShell, message, QUESTION); + } + + public SingleValueDialog(Shell parentShell, String message, String defaultValue) { + super(parentShell, message, QUESTION); + this.defaultValue = defaultValue; + } + + @Override + protected Control createInputArea(Composite parent) { + valueT = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.SINGLE); + valueT.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); + if (defaultValue != null) + valueT.setText(defaultValue); + return valueT; + } + + @Override + protected void okPressed() { + value = valueT.getText(); + super.okPressed(); + } + + public String getString() { + return value; + } + + public Long getLong() { + return Long.valueOf(getString()); + } + + public Double getDouble() { + return Double.valueOf(getString()); + } + + public static String ask(String message) { + return ask(message, null); + } + + public static String ask(String message, String defaultValue) { + SingleValueDialog svd = new SingleValueDialog(Display.getCurrent().getActiveShell(), message, defaultValue); + if (svd.open() == Window.OK) + return svd.getString(); + else + return null; + } + + public static Long askLong(String message) { + SingleValueDialog svd = new SingleValueDialog(Display.getCurrent().getActiveShell(), message); + if (svd.open() == Window.OK) + return svd.getLong(); + else + return null; + } + + public static Double askDouble(String message) { + SingleValueDialog svd = new SingleValueDialog(Display.getCurrent().getActiveShell(), message); + if (svd.open() == Window.OK) + return svd.getDouble(); + else + return null; + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/package-info.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/package-info.java new file mode 100644 index 000000000..ac76dba81 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/package-info.java @@ -0,0 +1,2 @@ +/** SWT/JFace dialogs. */ +package org.argeo.cms.swt.dialogs; \ No newline at end of file diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/osgi/BundleCmsSwtTheme.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/osgi/BundleCmsSwtTheme.java new file mode 100644 index 000000000..b9b2751a7 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/osgi/BundleCmsSwtTheme.java @@ -0,0 +1,93 @@ +package org.argeo.cms.swt.osgi; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import org.argeo.cms.osgi.BundleCmsTheme; +import org.argeo.cms.swt.CmsSwtTheme; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.widgets.Display; + +/** Centralises some generic {@link CmsSwtTheme} patterns. */ +public class BundleCmsSwtTheme extends BundleCmsTheme implements CmsSwtTheme { + private Map imageCache = new HashMap<>(); + + private Map> iconPaths = new HashMap<>(); + + public Image getImage(String path) { + if (!imageCache.containsKey(path)) { + try (InputStream in = getResourceAsStream(path)) { + if (in == null) + return null; + ImageData imageData = new ImageData(in); + imageCache.put(path, imageData); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + ImageData imageData = imageCache.get(path); + Image image = new Image(Display.getCurrent(), imageData); + return image; + } + + /** + * And icon with this file name (without the extension), with a best effort to + * find the appropriate size, or null if not found. + * + * @param name An icon file name without path and extension. + * @param preferredSize the preferred size, if null, + * {@link #getDefaultIconSize()} will be tried. + */ + public Image getIcon(String name, Integer preferredSize) { + if (preferredSize == null) + preferredSize = getDefaultIconSize(); + Map subCache; + if (!iconPaths.containsKey(name)) + subCache = new HashMap<>(); + else + subCache = iconPaths.get(name); + Image image = null; + if (!subCache.containsKey(preferredSize)) { + Image bestMatchSoFar = null; + paths: for (String p : getImagesPaths()) { + int lastSlash = p.lastIndexOf('/'); + String fileName = p; + if (lastSlash >= 0) + fileName = p.substring(lastSlash + 1); + int lastDot = fileName.lastIndexOf('.'); + if (lastDot >= 0) + fileName = fileName.substring(0, lastDot); + if (fileName.equals(name)) {// matched + Image img = getImage(p); + int width = img.getBounds().width; + if (width == preferredSize) {// perfect match + subCache.put(preferredSize, p); + image = img; + break paths; + } + if (bestMatchSoFar == null) { + bestMatchSoFar = img; + } else { + if (Math.abs(width - preferredSize) < Math + .abs(bestMatchSoFar.getBounds().width - preferredSize)) + bestMatchSoFar = img; + } + } + } + + if (image == null) + image = bestMatchSoFar; + } else { + image = getImage(subCache.get(preferredSize)); + } + + if (image != null && !iconPaths.containsKey(name)) + iconPaths.put(name, subCache); + + return image; + } + +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/PickUpUserDialog.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/PickUpUserDialog.java new file mode 100644 index 000000000..6f5aa9dc1 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/PickUpUserDialog.java @@ -0,0 +1,246 @@ +package org.argeo.cms.swt.useradmin; + +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.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FillLayout; +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.Shell; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.service.useradmin.Group; +import org.osgi.service.useradmin.Role; +import org.osgi.service.useradmin.User; +import org.osgi.service.useradmin.UserAdmin; + +/** Dialog with a user (or group) list to pick up one */ +public class PickUpUserDialog extends TrayDialog { + private static final long serialVersionUID = -1420106871173920369L; + + // Business objects + private final UserAdmin userAdmin; + private User selectedUser; + + // this page widgets and UI objects + private String title; + private LdifUsersTable userTableViewerCmp; + private TableViewer userViewer; + private List columnDefs = new ArrayList(); + + /** + * A dialog to pick up a group or a user, showing a table with default + * columns + */ + public PickUpUserDialog(Shell parentShell, String title, UserAdmin userAdmin) { + super(parentShell); + this.title = title; + this.userAdmin = userAdmin; + + columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_ICON), "", + 24, 24)); + columnDefs.add(new ColumnDefinition( + new UserLP(UserLP.COL_DISPLAY_NAME), "Common Name", 150, 100)); + columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_DOMAIN), + "Domain", 100, 120)); + columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_DN), + "Distinguished Name", 300, 100)); + } + + /** A dialog to pick up a group or a user */ + public PickUpUserDialog(Shell parentShell, String title, + UserAdmin userAdmin, List columnDefs) { + super(parentShell); + this.title = title; + this.userAdmin = userAdmin; + this.columnDefs = columnDefs; + } + + @Override + protected void okPressed() { + if (getSelected() == null) + MessageDialog.openError(getShell(), "No user chosen", + "Please, choose a user or press Cancel."); + else + super.okPressed(); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + dialogArea.setLayout(new FillLayout()); + + Composite bodyCmp = new Composite(dialogArea, SWT.NO_FOCUS); + bodyCmp.setLayout(new GridLayout()); + + // Create and configure the table + userTableViewerCmp = new MyUserTableViewer(bodyCmp, SWT.MULTI + | SWT.H_SCROLL | SWT.V_SCROLL); + + userTableViewerCmp.setColumnDefinitions(columnDefs); + userTableViewerCmp.populateWithStaticFilters(false, false); + GridData gd = EclipseUiUtils.fillAll(); + gd.minimumHeight = 300; + userTableViewerCmp.setLayoutData(gd); + userTableViewerCmp.refresh(); + + // Controllers + userViewer = userTableViewerCmp.getTableViewer(); + userViewer.addDoubleClickListener(new MyDoubleClickListener()); + userViewer + .addSelectionChangedListener(new MySelectionChangedListener()); + + parent.pack(); + return dialogArea; + } + + public User getSelected() { + if (selectedUser == null) + return null; + else + return selectedUser; + } + + protected void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText(title); + } + + class MyDoubleClickListener implements IDoubleClickListener { + public void doubleClick(DoubleClickEvent evt) { + if (evt.getSelection().isEmpty()) + return; + + Object obj = ((IStructuredSelection) evt.getSelection()) + .getFirstElement(); + if (obj instanceof User) { + selectedUser = (User) obj; + okPressed(); + } + } + } + + class MySelectionChangedListener implements ISelectionChangedListener { + @Override + public void selectionChanged(SelectionChangedEvent event) { + if (event.getSelection().isEmpty()) { + selectedUser = null; + return; + } + Object obj = ((IStructuredSelection) event.getSelection()) + .getFirstElement(); + if (obj instanceof Group) { + selectedUser = (Group) obj; + } + } + } + + private class MyUserTableViewer extends LdifUsersTable { + private static final long serialVersionUID = 8467999509931900367L; + + private final String[] knownProps = { LdapAttrs.uid.name(), + LdapAttrs.cn.name(), LdapAttrs.DN }; + + private Button showSystemRoleBtn; + private Button showUserBtn; + + public MyUserTableViewer(Composite parent, int style) { + super(parent, style); + } + + protected void populateStaticFilters(Composite staticFilterCmp) { + staticFilterCmp.setLayout(new GridLayout()); + showSystemRoleBtn = new Button(staticFilterCmp, SWT.CHECK); + showSystemRoleBtn.setText("Show system roles "); + + showUserBtn = new Button(staticFilterCmp, SWT.CHECK); + showUserBtn.setText("Show users "); + + SelectionListener sl = new SelectionAdapter() { + private static final long serialVersionUID = -7033424592697691676L; + + @Override + public void widgetSelected(SelectionEvent e) { + refresh(); + } + }; + + showSystemRoleBtn.addSelectionListener(sl); + showUserBtn.addSelectionListener(sl); + } + + @Override + protected List listFilteredElements(String filter) { + Role[] roles; + try { + StringBuilder builder = new StringBuilder(); + + StringBuilder filterBuilder = new StringBuilder(); + if (notNull(filter)) + for (String prop : knownProps) { + filterBuilder.append("("); + filterBuilder.append(prop); + filterBuilder.append("=*"); + filterBuilder.append(filter); + filterBuilder.append("*)"); + } + + String typeStr = "(" + LdapAttrs.objectClass.name() + "=" + + LdapObjs.groupOfNames.name() + ")"; + if ((showUserBtn.getSelection())) + typeStr = "(|(" + LdapAttrs.objectClass.name() + "=" + + LdapObjs.inetOrgPerson.name() + ")" + typeStr + + ")"; + + if (!showSystemRoleBtn.getSelection()) + typeStr = "(& " + typeStr + "(!(" + LdapAttrs.DN + "=*" + + NodeConstants.ROLES_BASEDN + ")))"; + + if (filterBuilder.length() > 1) { + builder.append("(&" + typeStr); + builder.append("(|"); + builder.append(filterBuilder.toString()); + builder.append("))"); + } else { + builder.append(typeStr); + } + roles = userAdmin.getRoles(builder.toString()); + } catch (InvalidSyntaxException e) { + throw new EclipseUiException( + "Unable to get roles with filter: " + filter, e); + } + List users = new ArrayList(); + for (Role role : roles) + if (!users.contains(role)) + users.add((User) role); + return users; + } + } + + private boolean notNull(String string) { + if (string == null) + return false; + else + return !"".equals(string.trim()); + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UserLP.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UserLP.java new file mode 100644 index 000000000..88573cd0d --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UserLP.java @@ -0,0 +1,76 @@ +package org.argeo.cms.swt.useradmin; + +import org.argeo.api.NodeConstants; +import org.argeo.cms.auth.UserAdminUtils; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; +import org.osgi.service.useradmin.Role; +import org.osgi.service.useradmin.User; + +/** Centralize label providers for the group table */ +class UserLP extends ColumnLabelProvider { + private static final long serialVersionUID = -4645930210988368571L; + + final static String COL_ICON = "colID.icon"; + final static String COL_DN = "colID.dn"; + final static String COL_DISPLAY_NAME = "colID.displayName"; + final static String COL_DOMAIN = "colID.domain"; + + final String currType; + + // private Font italic; + private Font bold; + + UserLP(String colId) { + this.currType = colId; + } + + @Override + public Font getFont(Object element) { + // Current user as bold + if (UserAdminUtils.isCurrentUser(((User) element))) { + if (bold == null) + bold = JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.BOLD) + .createFont(Display.getCurrent()); + return bold; + } + return null; + } + + @Override + public Image getImage(Object element) { + if (COL_ICON.equals(currType)) { + User user = (User) element; + String dn = user.getName(); + if (dn.endsWith(NodeConstants.ROLES_BASEDN)) + return UsersImages.ICON_ROLE; + else if (user.getType() == Role.GROUP) + return UsersImages.ICON_GROUP; + else + return UsersImages.ICON_USER; + } else + return null; + } + + @Override + public String getText(Object element) { + User user = (User) element; + return getText(user); + + } + + public String getText(User user) { + if (COL_DN.equals(currType)) + return user.getName(); + else if (COL_DISPLAY_NAME.equals(currType)) + return UserAdminUtils.getCommonName(user); + else if (COL_DOMAIN.equals(currType)) + return UserAdminUtils.getDomainName(user); + else + return ""; + } +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UsersImages.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UsersImages.java new file mode 100644 index 000000000..21fc5afba --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UsersImages.java @@ -0,0 +1,14 @@ +package org.argeo.cms.swt.useradmin; + +import org.argeo.cms.ui.theme.CmsImages; +import org.eclipse.swt.graphics.Image; + +/** Specific users icons. */ +public class UsersImages { + private final static String PREFIX = "icons/"; + + public final static Image ICON_USER = CmsImages.createImg(PREFIX + "person.png"); + public final static Image ICON_GROUP = CmsImages.createImg(PREFIX + "group.png"); + public final static Image ICON_ROLE = CmsImages.createImg(PREFIX + "role.gif"); + public final static Image ICON_CHANGE_PASSWORD = CmsImages.createImg(PREFIX + "security.gif"); +} diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/package-info.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/package-info.java new file mode 100644 index 000000000..3597bfc57 --- /dev/null +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/package-info.java @@ -0,0 +1,2 @@ +/** SWT/JFace users management components. */ +package org.argeo.cms.swt.useradmin; \ No newline at end of file diff --git a/org.argeo.cms.swt/src/org/argeo/eclipse/ui/MouseDoubleClick.java b/org.argeo.cms.swt/src/org/argeo/eclipse/ui/MouseDoubleClick.java deleted file mode 100644 index 49d11e5b8..000000000 --- a/org.argeo.cms.swt/src/org/argeo/eclipse/ui/MouseDoubleClick.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.argeo.eclipse.ui; - -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseListener; - -/** - * {@link MouseListener#mouseDoubleClick(MouseEvent)} as a functional interface - * in order to use as a short lambda expression in UI code. - * {@link MouseListener#mouseDownouseEvent)} and - * {@link MouseListener#mouseUp(MouseEvent)} do nothing by default. - */ -@FunctionalInterface -public interface MouseDoubleClick extends MouseListener { - @Override - void mouseDoubleClick(MouseEvent e); - - @Override - default void mouseDown(MouseEvent e) { - // does nothing - } - - @Override - default void mouseUp(MouseEvent e) { - // does nothing - } -} diff --git a/org.argeo.cms.swt/src/org/argeo/eclipse/ui/MouseDown.java b/org.argeo.cms.swt/src/org/argeo/eclipse/ui/MouseDown.java deleted file mode 100644 index 7abed8079..000000000 --- a/org.argeo.cms.swt/src/org/argeo/eclipse/ui/MouseDown.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.argeo.eclipse.ui; - -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseListener; - -/** - * {@link MouseListener#mouseDown(MouseEvent)} as a functional interface in - * order to use as a short lambda expression in UI code. - * {@link MouseListener#mouseDoubleClick(MouseEvent)} and - * {@link MouseListener#mouseUp(MouseEvent)} do nothing by default. - */ -@FunctionalInterface -public interface MouseDown extends MouseListener { - @Override - void mouseDown(MouseEvent e); - - @Override - default void mouseDoubleClick(MouseEvent e) { - // does nothing - } - - @Override - default void mouseUp(MouseEvent e) { - // does nothing - } -} diff --git a/org.argeo.cms.swt/src/org/argeo/eclipse/ui/Selected.java b/org.argeo.cms.swt/src/org/argeo/eclipse/ui/Selected.java deleted file mode 100644 index 77bdd7970..000000000 --- a/org.argeo.cms.swt/src/org/argeo/eclipse/ui/Selected.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.argeo.eclipse.ui; - -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; - -/** - * {@link SelectionListener} as a functional interface in order to use as a - * short lambda expression in UI code. - * {@link SelectionListener#widgetDefaultSelected(SelectionEvent)} does nothing - * by default. - */ -@FunctionalInterface -public interface Selected extends SelectionListener { - @Override - public void widgetSelected(SelectionEvent e); - - default public void widgetDefaultSelected(SelectionEvent e) { - // does nothing - } - -} diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/AppUi.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/AppUi.java index 15b181780..30cff8f81 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/AppUi.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/AppUi.java @@ -10,11 +10,11 @@ import javax.script.Invocable; import javax.script.ScriptException; import org.argeo.api.NodeConstants; +import org.argeo.cms.swt.CmsSwtUtils; +import org.argeo.cms.swt.Selected; import org.argeo.cms.ui.CmsUiProvider; import org.argeo.cms.ui.util.CmsPane; -import org.argeo.cms.ui.util.CmsUiUtils; import org.argeo.cms.web.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; @@ -124,9 +124,9 @@ public class AppUi implements CmsUiProvider, Branding { if (false) { // QA - CmsUiUtils.style(cmsPane.getQaArea(), "qa"); + CmsSwtUtils.style(cmsPane.getQaArea(), "qa"); Button reload = new Button(cmsPane.getQaArea(), SWT.FLAT); - CmsUiUtils.style(reload, "qa"); + CmsSwtUtils.style(reload, "qa"); reload.setText("Reload"); reload.addSelectionListener(new Selected() { private static final long serialVersionUID = 1L; @@ -145,9 +145,9 @@ public class AppUi implements CmsUiProvider, Branding { }); // Support - CmsUiUtils.style(cmsPane.getSupportArea(), "support"); + CmsSwtUtils.style(cmsPane.getSupportArea(), "support"); Label msg = new Label(cmsPane.getSupportArea(), SWT.NONE); - CmsUiUtils.style(msg, "support"); + CmsSwtUtils.style(msg, "support"); msg.setText("UNSUPPORTED DEVELOPMENT VERSION"); } diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java index 3f0987199..9dd1509be 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java @@ -22,9 +22,9 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.api.cms.CmsTheme; import org.argeo.cms.CmsException; import org.argeo.cms.ui.CmsConstants; -import org.argeo.cms.ui.CmsTheme; import org.argeo.cms.ui.CmsUiProvider; import org.argeo.cms.ui.util.CmsUiUtils; import org.argeo.cms.web.BundleResourceLoader; diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java index 887490c41..504ed4978 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java @@ -24,12 +24,13 @@ 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.api.cms.CmsView; import org.argeo.cms.CmsException; import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.auth.HttpRequestCallback; import org.argeo.cms.auth.HttpRequestCallbackHandler; -import org.argeo.cms.ui.CmsStyles; -import org.argeo.cms.ui.CmsView; +import org.argeo.cms.swt.CmsStyles; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.eclipse.ui.specific.UiContext; import org.argeo.jcr.JcrUtils; import org.argeo.naming.AuthPassword; @@ -120,7 +121,7 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement @Override protected final void createContents(final Composite parent) { // UiContext.setData(CmsView.KEY, this); - CmsView.registerCmsView(parent.getShell(), this); + CmsSwtUtils.registerCmsView(parent.getShell(), this); Subject.doAs(getSubject(), new PrivilegedAction() { @Override public Void run() { diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsThemeResourceLoader.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsThemeResourceLoader.java index 0cf9a7269..5de0f9103 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsThemeResourceLoader.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsThemeResourceLoader.java @@ -3,7 +3,7 @@ package org.argeo.cms.web; import java.io.IOException; import java.io.InputStream; -import org.argeo.cms.ui.CmsTheme; +import org.argeo.api.cms.CmsTheme; import org.eclipse.rap.rwt.service.ResourceLoader; /** A RAP {@link ResourceLoader} based on a {@link CmsTheme}. */ diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebApp.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebApp.java index c1bd3ad98..e5b6c7efc 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebApp.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebApp.java @@ -7,10 +7,11 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.cms.ui.CmsApp; -import org.argeo.cms.ui.CmsAppListener; -import org.argeo.cms.ui.CmsTheme; -import org.argeo.cms.ui.CmsView; +import org.argeo.api.cms.CmsApp; +import org.argeo.api.cms.CmsAppListener; +import org.argeo.api.cms.CmsTheme; +import org.argeo.api.cms.CmsView; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.util.LangUtils; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.application.Application; @@ -78,7 +79,7 @@ public class CmsWebApp implements ApplicationConfiguration, ExceptionHandler, Cm public void handleException(Throwable throwable) { Display display = Display.getCurrent(); if (display != null && !display.isDisposed()) { - CmsView cmsView = CmsView.getCmsView(display.getActiveShell()); + CmsView cmsView = CmsSwtUtils.getCmsView(display.getActiveShell()); cmsView.exception(throwable); } else { log.error("Unexpected exception outside an UI thread", throwable); diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java index b1691cb05..4bdc5a0aa 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java @@ -15,18 +15,20 @@ 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.cms.CmsApp; +import org.argeo.api.cms.CmsImageManager; +import org.argeo.api.cms.CmsSession; +import org.argeo.api.cms.CmsUi; +import org.argeo.api.cms.CmsView; +import org.argeo.api.cms.UxContext; import org.argeo.cms.LocaleUtils; -import org.argeo.cms.auth.CmsSession; import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.auth.HttpRequestCallbackHandler; -import org.argeo.cms.ui.CmsApp; -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.ui.util.CmsUiUtils; +import org.argeo.cms.osgi.CmsOsgiUtils; +import org.argeo.cms.swt.CmsSwtUtils; +import org.argeo.cms.swt.SimpleSwtUxContext; +import org.argeo.cms.swt.dialogs.CmsFeedback; import org.argeo.cms.ui.util.DefaultImageManager; -import org.argeo.cms.ui.util.SimpleUxContext; import org.argeo.eclipse.ui.specific.UiContext; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.application.EntryPoint; @@ -59,7 +61,8 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL private UxContext uxContext; private CmsImageManager imageManager; - private Composite ui; + private Display display; + private CmsUi ui; private String uid; @@ -104,7 +107,7 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL @Override public Void run() { try { - uxContext = new SimpleUxContext(); + uxContext = new SimpleSwtUxContext(); imageManager = new DefaultImageManager(); CmsSession cmsSession = getCmsSession(); if (cmsSession != null) { @@ -115,8 +118,10 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL LocaleUtils.setThreadLocale(rwtLocale); } parent.setData(CmsApp.UI_NAME_PROPERTY, uiName); + display = parent.getDisplay(); ui = cmsWebApp.getCmsApp().initUi(parent); - ui.setLayoutData(CmsUiUtils.fillAll()); + if (ui instanceof Composite) + ((Composite) ui).setLayoutData(CmsSwtUtils.fillAll()); // we need ui to be set before refresh so that CmsView can store UI context data // in it. cmsWebApp.getCmsApp().refreshUi(ui, null); @@ -178,7 +183,7 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL if (swtError.code == SWT.ERROR_FUNCTION_DISPOSED) return; } - ui.getDisplay().syncExec(() -> { + display.syncExec(() -> { // CmsFeedback.show("Unexpected exception in CMS", e); exception = e; // log.error("Unexpected exception in CMS", e); @@ -230,7 +235,6 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL browserNavigation.pushState(state, title); } - @Override public CmsImageManager getImageManager() { return imageManager; } @@ -259,7 +263,7 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL @Override public CmsSession getCmsSession() { - CmsSession cmsSession = CmsSession.getCmsSession(cmsWebApp.getBundleContext(), getSubject()); + CmsSession cmsSession = CmsOsgiUtils.getCmsSession(cmsWebApp.getBundleContext(), getSubject()); return cmsSession; } @@ -289,8 +293,8 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL public int createUI() { Display display = new Display(); Shell shell = createShell(display); - shell.setLayout(CmsUiUtils.noSpaceGridLayout()); - CmsView.registerCmsView(shell, this); + shell.setLayout(CmsSwtUtils.noSpaceGridLayout()); + CmsSwtUtils.registerCmsView(shell, this); createContents(shell); shell.layout(); // if (shell.getMaximized()) { diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/MinimalWebApp.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/MinimalWebApp.java index 188391c42..2eff71ee8 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/MinimalWebApp.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/MinimalWebApp.java @@ -1,11 +1,11 @@ package org.argeo.cms.web; -import static org.argeo.cms.ui.util.BundleCmsTheme.CMS_THEME_BUNDLE_PROPERTY; +import static org.argeo.cms.osgi.BundleCmsTheme.CMS_THEME_BUNDLE_PROPERTY; import java.util.HashMap; import java.util.Map; -import org.argeo.cms.ui.util.BundleCmsTheme; +import org.argeo.cms.osgi.BundleCmsTheme; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.application.Application; import org.eclipse.rap.rwt.application.ApplicationConfiguration; diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/SimpleErgonomics.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/SimpleErgonomics.java index 9760f9dad..6e1165cf3 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/SimpleErgonomics.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/SimpleErgonomics.java @@ -9,14 +9,14 @@ import javax.jcr.RepositoryException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.api.cms.CmsImageManager; +import org.argeo.api.cms.UxContext; import org.argeo.cms.CmsException; -import org.argeo.cms.ui.CmsImageManager; -import org.argeo.cms.ui.CmsStyles; +import org.argeo.cms.swt.CmsStyles; +import org.argeo.cms.swt.CmsSwtUtils; +import org.argeo.cms.swt.SimpleSwtUxContext; import org.argeo.cms.ui.CmsUiProvider; -import org.argeo.cms.ui.UxContext; -import org.argeo.cms.ui.util.CmsUiUtils; import org.argeo.cms.ui.util.DefaultImageManager; -import org.argeo.cms.ui.util.SimpleUxContext; import org.argeo.cms.ui.util.SystemNotifications; import org.eclipse.rap.rwt.RWT; import org.eclipse.swt.SWT; @@ -62,9 +62,9 @@ public class SimpleErgonomics extends AbstractCmsEntryPoint { protected void initUi(Composite parent) { uid = UUID.randomUUID().toString(); parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, false))); + parent.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, false))); - uxContext = new SimpleUxContext(); + uxContext = new SimpleSwtUxContext(); if (!getUxContext().isMasterData()) createAdminArea(parent); headerArea = new Composite(parent, SWT.NONE); @@ -76,17 +76,17 @@ public class SimpleErgonomics extends AbstractCmsEntryPoint { // TODO: bi-directional leftArea = new Composite(parent, SWT.NONE); leftArea.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false)); - leftArea.setLayout(CmsUiUtils.noSpaceGridLayout()); + leftArea.setLayout(CmsSwtUtils.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()); + bodyArea.setLayout(CmsSwtUtils.noSpaceGridLayout()); // TODO: bi-directional rightArea = new Composite(parent, SWT.NONE); rightArea.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false)); - rightArea.setLayout(CmsUiUtils.noSpaceGridLayout()); + rightArea.setLayout(CmsSwtUtils.noSpaceGridLayout()); footerArea = new Composite(parent, SWT.NONE); // footerArea.setLayout(new FillLayout()); @@ -141,7 +141,7 @@ public class SimpleErgonomics extends AbstractCmsEntryPoint { for (Control child : area.getChildren()) child.dispose(); - CmsUiUtils.style(area, style); + CmsSwtUtils.style(area, style); try { uiProvider.createUi(area, getNode()); } catch (RepositoryException e) { @@ -164,7 +164,7 @@ public class SimpleErgonomics extends AbstractCmsEntryPoint { // clear for (Control child : bodyArea.getChildren()) child.dispose(); - bodyArea.setLayout(CmsUiUtils.noSpaceGridLayout()); + bodyArea.setLayout(CmsSwtUtils.noSpaceGridLayout()); try { Node node = getNode(); @@ -188,7 +188,6 @@ public class SimpleErgonomics extends AbstractCmsEntryPoint { return uid; } - @Override public CmsImageManager getImageManager() { return imageManager; } diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/WebThemeUtils.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/WebThemeUtils.java index a71ff97d3..a28b13fc6 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/WebThemeUtils.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/WebThemeUtils.java @@ -2,7 +2,7 @@ package org.argeo.cms.web; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.cms.ui.CmsTheme; +import org.argeo.api.cms.CmsTheme; import org.eclipse.rap.rwt.application.Application; import org.eclipse.rap.rwt.service.ResourceLoader; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/AbstractCmsApp.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/AbstractCmsApp.java deleted file mode 100644 index 77cd98383..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/AbstractCmsApp.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.argeo.cms.ui; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jcr.Repository; - -import org.eclipse.rap.rwt.RWT; - -/** Base class for {@link CmsApp}s. */ -public abstract class AbstractCmsApp implements CmsApp { - private Map themes = Collections.synchronizedMap(new HashMap<>()); - - private List cmsAppListeners = new ArrayList<>(); - - private Repository repository; - - protected abstract String getThemeId(String uiName); - - @Override - public CmsTheme getTheme(String uiName) { - String themeId = getThemeId(uiName); - if (themeId == null) - return null; - if (!themes.containsKey(themeId)) - throw new IllegalArgumentException("Theme " + themeId + " not found."); - return themes.get(themeId); - } - - @Override - public boolean allThemesAvailable() { - boolean themeMissing = false; - uiNames: for (String uiName : getUiNames()) { - String themeId = getThemeId(uiName); - if (RWT.DEFAULT_THEME_ID.equals(themeId)) - continue uiNames; - if (!themes.containsKey(themeId)) { - themeMissing = true; - break uiNames; - } - } - return !themeMissing; - } - - public void addTheme(CmsTheme theme, Map properties) { - themes.put(theme.getThemeId(), theme); - if (allThemesAvailable()) - for (CmsAppListener listener : cmsAppListeners) - listener.themingUpdated(); - } - - public void removeTheme(CmsTheme theme, Map properties) { - themes.remove(theme.getThemeId()); - } - - @Override - public void addCmsAppListener(CmsAppListener listener) { - cmsAppListeners.add(listener); - if (allThemesAvailable()) - listener.themingUpdated(); - } - - @Override - public void removeCmsAppListener(CmsAppListener listener) { - cmsAppListeners.remove(listener); - } - - protected Repository getRepository() { - return repository; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsApp.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsApp.java deleted file mode 100644 index bd7b00334..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsApp.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.argeo.cms.ui; - -import java.util.Set; - -import org.eclipse.swt.widgets.Composite; - -/** An extensible user interface base on the CMS backend. */ -public interface CmsApp { - /** - * If {@link Composite#setData(String, Object)} is set with this property, it - * indicates a different UI (typically with another theming. The {@link CmsApp} - * can use this information, but it doesn't have to be set, in which case a - * default UI must be provided. The provided value must belong to the values - * returned by {@link CmsApp#getUiNames()}. - */ - final static String UI_NAME_PROPERTY = CmsApp.class.getName() + ".ui.name"; - - Set getUiNames(); - - Composite initUi(Composite parent); - - void refreshUi(Composite parent, String state); - - void setState(Composite parent, String state); - - CmsTheme getTheme(String uiName); - - boolean allThemesAvailable(); - - void addCmsAppListener(CmsAppListener listener); - - void removeCmsAppListener(CmsAppListener listener); -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsAppListener.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsAppListener.java deleted file mode 100644 index 1fe3678f2..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsAppListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.argeo.cms.ui; - -/** Notifies important events in a {@link CmsApp} life cycle. */ -public interface CmsAppListener { - /** Theming has been updated and should be reloaded. */ - void themingUpdated(); -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsConstants.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsConstants.java index ef6fd5f2e..8c324ad74 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsConstants.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsConstants.java @@ -1,8 +1,9 @@ package org.argeo.cms.ui; -import org.eclipse.swt.graphics.Point; +import org.argeo.api.cms.Cms2DSize; /** Commons constants */ +@Deprecated public interface CmsConstants { // DATAKEYS // public final static String STYLE = EclipseUiConstants.CSS_CLASS; @@ -20,7 +21,7 @@ public interface CmsConstants { public final static String LOADING_IMAGE = "icons/loading.gif"; public final static String NO_IMAGE = "icons/noPic-square-640px.png"; - public final static Point NO_IMAGE_SIZE = new Point(320, 320); + public final static Cms2DSize NO_IMAGE_SIZE = new Cms2DSize(320, 320); public final static Float NO_IMAGE_RATIO = 1f; // MISCEALLENEOUS String DATE_TIME_FORMAT = "dd/MM/yyyy, HH:mm"; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsEditable.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsEditable.java deleted file mode 100644 index 72cc5971a..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsEditable.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.argeo.cms.ui; - -/** Abstraction of a simple edition life cycle. */ -public interface CmsEditable { - - /** Whether the calling thread can edit, the value is immutable */ - public Boolean canEdit(); - - public Boolean isEditing(); - - public void startEditing(); - - public void stopEditing(); - - public static CmsEditable NON_EDITABLE = new CmsEditable() { - - @Override - public void stopEditing() { - } - - @Override - public void startEditing() { - } - - @Override - public Boolean isEditing() { - return false; - } - - @Override - public Boolean canEdit() { - return false; - } - }; - - public static CmsEditable ALWAYS_EDITING = new CmsEditable() { - - @Override - public void stopEditing() { - } - - @Override - public void startEditing() { - } - - @Override - public Boolean isEditing() { - return true; - } - - @Override - public Boolean canEdit() { - return true; - } - }; - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsImageManager.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsImageManager.java deleted file mode 100644 index e0cfa3112..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsImageManager.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.argeo.cms.ui; - -import java.io.InputStream; - -import javax.jcr.Binary; -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.widgets.Control; - -/** Read and write access to images. */ -public interface CmsImageManager { - /** Load image in control */ - public Boolean load(Node node, Control control, Point size) throws RepositoryException; - - /** @return (0,0) if not available */ - public Point getImageSize(Node node) throws RepositoryException; - - /** - * The related <img> tag, with src, width and height set. - * - * @return null if not available - */ - public String getImageTag(Node node) throws RepositoryException; - - /** - * The related <img> tag, with url, width and height set. Caller must - * close the tag (or add additional attributes). - * - * @return null if not available - */ - public StringBuilder getImageTagBuilder(Node node, Point size) throws RepositoryException; - - /** - * Returns the remotely accessible URL of the image (registering it if - * needed) @return null if not available - */ - public String getImageUrl(Node node) throws RepositoryException; - - public Binary getImageBinary(Node node) throws RepositoryException; - - public Image getSwtImage(Node node) throws RepositoryException; - - /** @return URL */ - public String uploadImage(Node context, Node uploadFolder, String fileName, InputStream in, String contentType) - throws RepositoryException; - - @Deprecated - default String uploadImage(Node uploadFolder, String fileName, InputStream in) throws RepositoryException { - System.err.println("Context must be provided to " + CmsImageManager.class.getName()); - return uploadImage(null, uploadFolder, fileName, in, null); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsStyles.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsStyles.java deleted file mode 100644 index 678a49717..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsStyles.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.argeo.cms.ui; - -/** Styles references in the CSS. */ -@Deprecated -public interface CmsStyles { - // General - public final static String CMS_SHELL = "cms_shell"; - public final static String CMS_MENU_LINK = "cms_menu_link"; - - // Header - public final static String CMS_HEADER = "cms_header"; - public final static String CMS_HEADER_LEAD = "cms_header-lead"; - public final static String CMS_HEADER_CENTER = "cms_header-center"; - public final static String CMS_HEADER_END = "cms_header-end"; - - public final static String CMS_LEAD = "cms_lead"; - public final static String CMS_END = "cms_end"; - public final static String CMS_FOOTER = "cms_footer"; - - public final static String CMS_USER_MENU = "cms_user_menu"; - public final static String CMS_USER_MENU_LINK = "cms_user_menu-link"; - public final static String CMS_USER_MENU_ITEM = "cms_user_menu-item"; - public final static String CMS_LOGIN_DIALOG = "cms_login_dialog"; - public final static String CMS_LOGIN_DIALOG_USERNAME = "cms_login_dialog-username"; - public final static String CMS_LOGIN_DIALOG_PASSWORD = "cms_login_dialog-password"; - - // Body - public final static String CMS_SCROLLED_AREA = "cms_scrolled_area"; - public final static String CMS_BODY = "cms_body"; - public final static String CMS_STATIC_TEXT = "cms_static-text"; - public final static String CMS_LINK = "cms_link"; -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsTheme.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsTheme.java deleted file mode 100644 index c93991b27..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsTheme.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.argeo.cms.ui; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Set; - -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Shell; - -/** A CMS theme which can be applied to web apps as well as desktop apps. */ -public interface CmsTheme { - /** Unique ID of this theme. */ - String getThemeId(); - - /** - * Load a resource as an input stream, base don its relative path, or - * null if not found - */ - InputStream getResourceAsStream(String resourceName) throws IOException; - - /** Relative paths to standard web CSS. */ - Set getWebCssPaths(); - - /** Relative paths to RAP specific CSS. */ - Set getRapCssPaths(); - - /** Relative paths to SWT specific CSS. */ - Set getSwtCssPaths(); - - /** Relative paths to images such as icons. */ - Set getImagesPaths(); - - /** Relative paths to fonts. */ - Set getFontsPaths(); - - /** Tags to be added to the header section of the HTML page. */ - String getHtmlHeaders(); - - /** The HTML body to use. */ - String getBodyHtml(); - - /** The image registered at this path, or null if not found. */ - Image getImage(String path); - - /** The default icon size (typically the smallest). */ - Integer getDefaultIconSize(); - - /** Loads one of the relative path provided by the other methods. */ - InputStream loadPath(String path) throws IOException; - - /** - * And icon with this file name (without the extension), with a best effort to - * find the appropriate size, or null if not found. - * - * @param name An icon file name without path and extension. - * @param preferredSize the preferred size, if null, - * {@link #getDefaultIconSize()} will be tried. - */ - Image getIcon(String name, Integer preferredSize); - - static CmsTheme getCmsTheme(Composite parent) { - CmsTheme theme = (CmsTheme) parent.getData(CmsTheme.class.getName()); - if (theme == null) { - // find parent shell - Shell topShell = parent.getShell(); - while (topShell.getParent() != null) - topShell = (Shell) topShell.getParent(); - theme = (CmsTheme) topShell.getData(CmsTheme.class.getName()); - parent.setData(CmsTheme.class.getName(), theme); - } - return theme; - } - - static void registerCmsTheme(Shell shell, CmsTheme theme) { - // find parent shell - Shell topShell = shell; - while (topShell.getParent() != null) - topShell = (Shell) topShell.getParent(); - // check if already set - if (topShell.getData(CmsTheme.class.getName()) != null) { - CmsTheme registeredTheme = (CmsTheme) topShell.getData(CmsTheme.class.getName()); - throw new IllegalArgumentException( - "Theme " + registeredTheme.getThemeId() + " already registered in this shell"); - } - topShell.setData(CmsTheme.class.getName(), theme); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java index 00939e154..ec76321fe 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java @@ -3,6 +3,7 @@ package org.argeo.cms.ui; import javax.jcr.Node; import javax.jcr.RepositoryException; +import org.argeo.api.cms.MvcProvider; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsView.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsView.java deleted file mode 100644 index f8ab3a682..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsView.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.argeo.cms.ui; - -import java.security.PrivilegedAction; -import java.util.HashMap; -import java.util.Map; - -import javax.security.auth.login.LoginContext; - -import org.argeo.cms.auth.CmsSession; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Shell; - -/** Provides interaction with the CMS system. */ -public interface CmsView { - final static String CMS_VIEW_UID_PROPERTY = "argeo.cms.view.uid"; - // String KEY = "org.argeo.cms.ui.view"; - - String getUid(); - - UxContext getUxContext(); - - // NAVIGATION - void navigateTo(String state); - - // SECURITY - void authChange(LoginContext loginContext); - - void logout(); - - // void registerCallbackHandler(CallbackHandler callbackHandler); - - // SERVICES - void exception(Throwable e); - - CmsImageManager getImageManager(); - - boolean isAnonymous(); - - /** - * Send an event to this topic. Does nothing by default., but if implemented it - * MUST set the {@link #CMS_VIEW_UID_PROPERTY} in the properties. - */ - default void sendEvent(String topic, Map properties) { - - } - - /** - * Convenience methods for when {@link #sendEvent(String, Map)} only requires - * one single parameter. - */ - default void sendEvent(String topic, String param, Object value) { - Map properties = new HashMap<>(); - properties.put(param, value); - sendEvent(topic, properties); - } - - default void applyStyles(Object widget) { - - } - - default T doAs(PrivilegedAction action) { - throw new UnsupportedOperationException(); - } - - default Void runAs(Runnable runnable) { - return doAs(new PrivilegedAction() { - - @Override - public Void run() { - if (runnable != null) - runnable.run(); - return null; - } - }); - } - - default void stateChanged(String state, String title) { - } - - default CmsSession getCmsSession() { - throw new UnsupportedOperationException(); - } - - default Object getData(String key) { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("unchecked") - default T getUiContext(Class clss) { - return (T) getData(clss.getName()); - } - - default void setUiContext(Class clss, T instance) { - setData(clss.getName(), instance); - } - - default void setData(String key, Object value) { - throw new UnsupportedOperationException(); - } - - static CmsView getCmsView(Control parent) { - // find parent shell - Shell topShell = parent.getShell(); - while (topShell.getParent() != null) - topShell = (Shell) topShell.getParent(); - return (CmsView) topShell.getData(CmsView.class.getName()); - } - - static void registerCmsView(Shell shell, CmsView view) { - // find parent shell - Shell topShell = shell; - while (topShell.getParent() != null) - topShell = (Shell) topShell.getParent(); - // check if already set - if (topShell.getData(CmsView.class.getName()) != null) { - CmsView registeredView = (CmsView) topShell.getData(CmsView.class.getName()); - throw new IllegalArgumentException("Cms view " + registeredView + " already registered in this shell"); - } - shell.setData(CmsView.class.getName(), view); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/MvcProvider.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/MvcProvider.java deleted file mode 100644 index f29d6b76a..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/MvcProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.argeo.cms.ui; - -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 extends BiFunction { - W createUiPart(V parent, M context); - - /** - * 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 apply(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 createUiPart(parent, context); - } - - default W createUiPart(V parent) { - return createUiPart(parent, null); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/UxContext.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/UxContext.java deleted file mode 100644 index 42d7ab3ef..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/UxContext.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.argeo.cms.ui; - -public interface UxContext { - boolean isPortrait(); - - boolean isLandscape(); - - boolean isSquare(); - - boolean isSmall(); - - /** - * Is a production environment (must be false by default, and be explicitly - * set during the CMS deployment). When false, it can activate additional UI - * capabilities in order to facilitate QA. - */ - boolean isMasterData(); -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/ChangePasswordDialog.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/ChangePasswordDialog.java deleted file mode 100644 index 3728692d0..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/ChangePasswordDialog.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.argeo.cms.ui.dialogs; - -import java.security.PrivilegedAction; -import java.util.Arrays; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.cms.CmsMsg; -import org.argeo.cms.CmsUserManager; -import org.argeo.cms.ui.CmsView; -import org.argeo.cms.ui.util.CmsUiUtils; -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.Shell; -import org.eclipse.swt.widgets.Text; - -/** Dialog to change a password. */ -public class ChangePasswordDialog extends CmsMessageDialog { - private final static Log log = LogFactory.getLog(ChangePasswordDialog.class); - - private CmsUserManager cmsUserManager; - private CmsView cmsView; - - private PrivilegedAction doIt; - - public ChangePasswordDialog(Shell parentShell, String message, int kind, CmsUserManager cmsUserManager) { - super(parentShell, message, kind); - this.cmsUserManager = cmsUserManager; - cmsView = CmsView.getCmsView(parentShell); - } - - @Override - protected Control createInputArea(Composite userSection) { - addFormLabel(userSection, CmsMsg.currentPassword.lead()); - Text previousPassword = new Text(userSection, SWT.BORDER | SWT.PASSWORD); - previousPassword.setLayoutData(CmsUiUtils.fillWidth()); - addFormLabel(userSection, CmsMsg.newPassword.lead()); - Text newPassword = new Text(userSection, SWT.BORDER | SWT.PASSWORD); - newPassword.setLayoutData(CmsUiUtils.fillWidth()); - addFormLabel(userSection, CmsMsg.repeatNewPassword.lead()); - Text confirmPassword = new Text(userSection, SWT.BORDER | SWT.PASSWORD); - confirmPassword.setLayoutData(CmsUiUtils.fillWidth()); - - doIt = () -> { - if (Arrays.equals(newPassword.getTextChars(), confirmPassword.getTextChars())) { - try { - cmsUserManager.changeOwnPassword(previousPassword.getTextChars(), newPassword.getTextChars()); - return OK; - } catch (Exception e1) { - log.error("Could not change password", e1); - cancel(); - CmsMessageDialog.openError(CmsMsg.invalidPassword.lead()); - return CANCEL; - } - } else { - cancel(); - CmsMessageDialog.openError(CmsMsg.repeatNewPassword.lead()); - return CANCEL; - } - }; - - pack(); - return previousPassword; - } - - @Override - protected void okPressed() { - Integer returnCode = cmsView.doAs(doIt); - if (returnCode.equals(OK)) { - super.okPressed(); - CmsMessageDialog.openInformation(CmsMsg.passwordChanged.lead()); - } - } - - private static Label addFormLabel(Composite parent, String label) { - Label lbl = new Label(parent, SWT.WRAP); - lbl.setText(label); -// CmsUiUtils.style(lbl, SuiteStyle.simpleLabel); - return lbl; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsFeedback.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsFeedback.java deleted file mode 100644 index 30e2ad34f..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsFeedback.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.argeo.cms.ui.dialogs; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.cms.CmsMsg; -import org.argeo.eclipse.ui.Selected; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** A dialog feedback based on a {@link LightweightDialog}. */ -public class CmsFeedback extends LightweightDialog { - private final static Log log = LogFactory.getLog(CmsFeedback.class); - - private String message; - private Throwable exception; - - public CmsFeedback(Shell parentShell, String message, Throwable e) { - super(parentShell); - this.message = message; - this.exception = e; - log.error(message, e); - } - - public static CmsFeedback show(String message, Throwable e) { - // rethrow ThreaDeath in order to make sure that RAP will properly clean - // up the UI thread - if (e instanceof ThreadDeath) - throw (ThreadDeath) e; - - try { - CmsFeedback cmsFeedback = new CmsFeedback(null, message, e); - cmsFeedback.setBlockOnOpen(false); - cmsFeedback.open(); - return cmsFeedback; - } catch (Throwable e1) { - log.error("Cannot open error feedback (" + e.getMessage() + "), original error below", e); - return null; - } - } - - public static CmsFeedback show(String message) { - CmsFeedback cmsFeedback = new CmsFeedback(null, message, null); - cmsFeedback.open(); - return cmsFeedback; - } - - /** Tries to find a display */ - // private static Display getDisplay() { - // try { - // Display display = Display.getCurrent(); - // if (display != null) - // return display; - // else - // return Display.getDefault(); - // } catch (Exception e) { - // return Display.getCurrent(); - // } - // } - - protected Control createDialogArea(Composite parent) { - parent.setLayout(new GridLayout(2, false)); - - Label messageLbl = new Label(parent, SWT.WRAP); - if (message != null) - messageLbl.setText(message); - else if (exception != null) - messageLbl.setText(exception.getLocalizedMessage()); - - Button close = new Button(parent, SWT.FLAT); - close.setText(CmsMsg.close.lead()); - close.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false)); - close.addSelectionListener((Selected) (e) -> closeShell(OK)); - - // Composite composite = new Composite(dialogarea, SWT.NONE); - // composite.setLayout(new GridLayout(2, false)); - // composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - if (exception != null) { - Text stack = new Text(parent, SWT.MULTI | SWT.LEAD | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); - stack.setEditable(false); - stack.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); - StringWriter sw = new StringWriter(); - exception.printStackTrace(new PrintWriter(sw)); - stack.setText(sw.toString()); - } - - // parent.pack(); - return messageLbl; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsMessageDialog.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsMessageDialog.java deleted file mode 100644 index eb881c6bd..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsMessageDialog.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.argeo.cms.ui.dialogs; - -import org.argeo.cms.CmsMsg; -import org.argeo.cms.ui.util.CmsUiUtils; -import org.argeo.eclipse.ui.EclipseUiUtils; -import org.argeo.eclipse.ui.Selected; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.TraverseEvent; -import org.eclipse.swt.events.TraverseListener; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; - -/** Base class for dialogs displaying messages or small forms. */ -public class CmsMessageDialog extends LightweightDialog { - public final static int NONE = 0; - public final static int ERROR = 1; - public final static int INFORMATION = 2; - public final static int QUESTION = 3; - public final static int WARNING = 4; - public final static int CONFIRM = 5; - public final static int QUESTION_WITH_CANCEL = 6; - - private int kind; - private String message; - - public CmsMessageDialog(Shell parentShell, String message, int kind) { - super(parentShell); - this.kind = kind; - this.message = message; - } - - protected Control createDialogArea(Composite parent) { - parent.setLayout(new GridLayout()); - - TraverseListener traverseListener = new TraverseListener() { - private static final long serialVersionUID = -1158892811534971856L; - - public void keyTraversed(TraverseEvent e) { - if (e.detail == SWT.TRAVERSE_RETURN) - okPressed(); - else if (e.detail == SWT.TRAVERSE_ESCAPE) - cancelPressed(); - } - }; - - // message - Composite body = new Composite(parent, SWT.NONE); - body.addTraverseListener(traverseListener); - GridLayout bodyGridLayout = new GridLayout(); - bodyGridLayout.marginHeight = 20; - bodyGridLayout.marginWidth = 20; - body.setLayout(bodyGridLayout); - body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - if (message != null) { - Label messageLbl = new Label(body, SWT.WRAP); - CmsUiUtils.markup(messageLbl); - messageLbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - messageLbl.setFont(EclipseUiUtils.getBoldFont(parent)); - messageLbl.setText(message); - } - - // buttons - Composite buttons = new Composite(parent, SWT.NONE); - buttons.addTraverseListener(traverseListener); - buttons.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); - if (kind == INFORMATION || kind == WARNING || kind == ERROR || kind == ERROR) { - GridLayout layout = new GridLayout(1, true); - layout.marginWidth = 0; - layout.marginHeight = 0; - buttons.setLayout(layout); - - Button close = new Button(buttons, SWT.FLAT); - close.setText(CmsMsg.close.lead()); - close.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); - close.addSelectionListener((Selected) (e) -> closeShell(OK)); - close.setFocus(); - close.addTraverseListener(traverseListener); - - buttons.setTabList(new Control[] { close }); - } else if (kind == CONFIRM || kind == QUESTION || kind == QUESTION_WITH_CANCEL) { - Control input = createInputArea(body); - if (input != null) { - input.addTraverseListener(traverseListener); - body.setTabList(new Control[] { input }); - } - GridLayout layout = new GridLayout(2, true); - layout.marginWidth = 0; - layout.marginHeight = 0; - buttons.setLayout(layout); - - Button cancel = new Button(buttons, SWT.FLAT); - cancel.setText(CmsMsg.cancel.lead()); - cancel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); - cancel.addSelectionListener((Selected) (e) -> cancelPressed()); - cancel.addTraverseListener(traverseListener); - - Button ok = new Button(buttons, SWT.FLAT); - ok.setText(CmsMsg.ok.lead()); - ok.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); - ok.addSelectionListener((Selected) (e) -> okPressed()); - ok.addTraverseListener(traverseListener); - if (input == null) - ok.setFocus(); - else - input.setFocus(); - - buttons.setTabList(new Control[] { ok, cancel }); - } - // pack(); - parent.setTabList(new Control[] { body, buttons }); - return body; - } - - protected Control createInputArea(Composite parent) { - return null; - } - - protected void okPressed() { - closeShell(OK); - } - - protected void cancelPressed() { - closeShell(CANCEL); - } - - protected void cancel() { - closeShell(CANCEL); - } - - protected Point getInitialSize() { - return new Point(400, 200); - } - - public static boolean open(int kind, Shell parent, String message) { - CmsMessageDialog dialog = new CmsMessageDialog(parent, message, kind); - return dialog.open() == 0; - } - - public static boolean openConfirm(String message) { - return open(CONFIRM, Display.getCurrent().getActiveShell(), message); - } - - public static void openInformation(String message) { - open(INFORMATION, Display.getCurrent().getActiveShell(), message); - } - - public static boolean openQuestion(String message) { - return open(QUESTION, Display.getCurrent().getActiveShell(), message); - } - - public static void openWarning(String message) { - open(WARNING, Display.getCurrent().getActiveShell(), message); - } - - public static void openError(String message) { - open(ERROR, Display.getCurrent().getActiveShell(), message); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsWizardDialog.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsWizardDialog.java deleted file mode 100644 index e4fe35d34..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/CmsWizardDialog.java +++ /dev/null @@ -1,220 +0,0 @@ -package org.argeo.cms.ui.dialogs; - -import java.lang.reflect.InvocationTargetException; - -import org.argeo.cms.CmsMsg; -import org.argeo.cms.ui.util.CmsUiUtils; -import org.argeo.eclipse.ui.EclipseUiUtils; -import org.argeo.eclipse.ui.Selected; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.wizard.IWizard; -import org.eclipse.jface.wizard.IWizardContainer2; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.swt.SWT; -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.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; - -/** A wizard dialog based on {@link LightweightDialog}. */ -public class CmsWizardDialog extends LightweightDialog implements IWizardContainer2 { - private static final long serialVersionUID = -2123153353654812154L; - - private IWizard wizard; - private IWizardPage currentPage; - private int currentPageIndex; - - private Label titleBar; - private Label message; - private Composite[] pageBodies; - private Composite buttons; - private Button back; - private Button next; - private Button finish; - - public CmsWizardDialog(Shell parentShell, IWizard wizard) { - super(parentShell); - this.wizard = wizard; - wizard.setContainer(this); - // create the pages - wizard.addPages(); - currentPage = wizard.getStartingPage(); - if (currentPage == null) - throw new IllegalArgumentException("At least one wizard page is required"); - } - - @Override - protected Control createDialogArea(Composite parent) { - updateWindowTitle(); - - Composite messageArea = new Composite(parent, SWT.NONE); - messageArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, 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)); - updateTitleBar(); - Button cancelButton = new Button(messageArea, SWT.FLAT); - cancelButton.setText(CmsMsg.cancel.lead()); - cancelButton.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false, 1, 3)); - cancelButton.addSelectionListener((Selected) (e) -> closeShell(CANCEL)); - message = new Label(messageArea, SWT.WRAP); - message.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 2)); - updateMessage(); - } - - Composite body = new Composite(parent, SWT.BORDER); - body.setLayout(new FormLayout()); - body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - pageBodies = new Composite[wizard.getPageCount()]; - IWizardPage[] pages = wizard.getPages(); - for (int i = 0; i < pages.length; i++) { - pageBodies[i] = new Composite(body, SWT.NONE); - pageBodies[i].setLayout(CmsUiUtils.noSpaceGridLayout()); - setSwitchingFormData(pageBodies[i]); - pages[i].createControl(pageBodies[i]); - } - showPage(currentPage); - - buttons = new Composite(parent, SWT.NONE); - buttons.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); - { - boolean singlePage = wizard.getPageCount() == 1; - // singlePage = false;// dev - GridLayout layout = new GridLayout(singlePage ? 1 : 3, true); - layout.marginWidth = 0; - layout.marginHeight = 0; - buttons.setLayout(layout); - // TODO revert order for right-to-left languages - - if (!singlePage) { - back = new Button(buttons, SWT.PUSH); - back.setText(CmsMsg.wizardBack.lead()); - back.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); - back.addSelectionListener((Selected) (e) -> backPressed()); - - next = new Button(buttons, SWT.PUSH); - next.setText(CmsMsg.wizardNext.lead()); - next.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); - next.addSelectionListener((Selected) (e) -> nextPressed()); - } - finish = new Button(buttons, SWT.PUSH); - finish.setText(CmsMsg.wizardFinish.lead()); - finish.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); - finish.addSelectionListener((Selected) (e) -> finishPressed()); - - updateButtons(); - } - return body; - } - - @Override - public IWizardPage getCurrentPage() { - return currentPage; - } - - @Override - public Shell getShell() { - return getForegoundShell(); - } - - @Override - public void showPage(IWizardPage page) { - IWizardPage[] pages = wizard.getPages(); - int index = -1; - for (int i = 0; i < pages.length; i++) { - if (page == pages[i]) { - index = i; - break; - } - } - if (index < 0) - throw new IllegalArgumentException("Cannot find index of wizard page " + page); - pageBodies[index].moveAbove(pageBodies[currentPageIndex]); - - // // clear - // for (Control c : body.getChildren()) - // c.dispose(); - // page.createControl(body); - // body.layout(true, true); - currentPageIndex = index; - currentPage = page; - } - - @Override - public void updateButtons() { - if (back != null) - back.setEnabled(wizard.getPreviousPage(currentPage) != null); - if (next != null) - next.setEnabled(wizard.getNextPage(currentPage) != null && currentPage.canFlipToNextPage()); - if (finish != null) { - finish.setEnabled(wizard.canFinish()); - } - } - - @Override - public void updateMessage() { - if (currentPage.getMessage() != null) - message.setText(currentPage.getMessage()); - } - - @Override - public void updateTitleBar() { - if (currentPage.getTitle() != null) - titleBar.setText(currentPage.getTitle()); - } - - @Override - public void updateWindowTitle() { - setTitle(wizard.getWindowTitle()); - } - - @Override - public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) - throws InvocationTargetException, InterruptedException { - runnable.run(null); - } - - @Override - public void updateSize() { - // TODO pack? - } - - protected boolean onCancel() { - return wizard.performCancel(); - } - - protected void nextPressed() { - IWizardPage page = wizard.getNextPage(currentPage); - showPage(page); - updateButtons(); - } - - protected void backPressed() { - IWizardPage page = wizard.getPreviousPage(currentPage); - showPage(page); - updateButtons(); - } - - protected void finishPressed() { - if (wizard.performFinish()) - closeShell(OK); - } - - private static void setSwitchingFormData(Composite composite) { - FormData fdLabel = new FormData(); - fdLabel.top = new FormAttachment(0, 0); - fdLabel.left = new FormAttachment(0, 0); - fdLabel.right = new FormAttachment(100, 0); - fdLabel.bottom = new FormAttachment(100, 0); - composite.setLayoutData(fdLabel); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/LightweightDialog.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/LightweightDialog.java deleted file mode 100644 index 8f6347913..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/LightweightDialog.java +++ /dev/null @@ -1,256 +0,0 @@ -package org.argeo.cms.ui.dialogs; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.eclipse.ui.EclipseUiException; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.ShellAdapter; -import org.eclipse.swt.events.ShellEvent; -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; - -/** Generic lightweight dialog, not based on JFace. */ -public class LightweightDialog { - private final static Log log = LogFactory.getLog(LightweightDialog.class); - - // must be the same value as org.eclipse.jface.window.Window#OK - public final static int OK = 0; - // must be the same value as org.eclipse.jface.window.Window#CANCEL - public final static int CANCEL = 1; - - private Shell parentShell; - private Shell backgroundShell; - private Shell foregoundShell; - - private Integer returnCode = null; - private boolean block = true; - - private String title; - - /** Tries to find a display */ - private static Display getDisplay() { - try { - Display display = Display.getCurrent(); - if (display != null) - return display; - else - return Display.getDefault(); - } catch (Exception e) { - return Display.getCurrent(); - } - } - - public LightweightDialog(Shell parentShell) { - this.parentShell = parentShell; - } - - public int open() { - if (foregoundShell != null) - throw new EclipseUiException("There is already a shell"); - backgroundShell = new Shell(parentShell, SWT.ON_TOP); - backgroundShell.setFullScreen(true); - // if (parentShell != null) { - // backgroundShell.setBounds(parentShell.getBounds()); - // } else - // backgroundShell.setMaximized(true); - backgroundShell.setAlpha(128); - backgroundShell.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK)); - foregoundShell = new Shell(backgroundShell, SWT.NO_TRIM | SWT.ON_TOP); - if (title != null) - setTitle(title); - foregoundShell.setLayout(new GridLayout()); - foregoundShell.setSize(getInitialSize()); - createDialogArea(foregoundShell); - // shell.pack(); - // shell.layout(); - - Rectangle shellBounds = parentShell != null ? parentShell.getBounds() : Display.getCurrent().getBounds();// RAP - Point dialogSize = foregoundShell.getSize(); - int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2; - int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2; - foregoundShell.setLocation(x, y); - - foregoundShell.addShellListener(new ShellAdapter() { - private static final long serialVersionUID = -2701270481953688763L; - - @Override - public void shellDeactivated(ShellEvent e) { - if (hasChildShells()) - return; - if (returnCode == null)// not yet closed - closeShell(CANCEL); - } - - @Override - public void shellClosed(ShellEvent e) { - notifyClose(); - } - - }); - - backgroundShell.open(); - foregoundShell.open(); - // after the foreground shell has been opened - backgroundShell.addFocusListener(new FocusListener() { - private static final long serialVersionUID = 3137408447474661070L; - - @Override - public void focusLost(FocusEvent event) { - } - - @Override - public void focusGained(FocusEvent event) { - if (hasChildShells()) - return; - if (returnCode == null)// not yet closed - closeShell(CANCEL); - } - }); - - if (block) { - block(); - } - if (returnCode == null) - returnCode = OK; - return returnCode; - } - - public void block() { - try { - runEventLoop(foregoundShell); - } catch (ThreadDeath t) { - returnCode = CANCEL; - if (log.isTraceEnabled()) - log.error("Thread death, canceling dialog", t); - } catch (Throwable t) { - returnCode = CANCEL; - log.error("Cannot open blocking lightweight dialog", t); - } - } - - private boolean hasChildShells() { - if (foregoundShell == null) - return false; - return foregoundShell.getShells().length != 0; - } - - // public synchronized int openAndWait() { - // open(); - // while (returnCode == null) - // try { - // wait(100); - // } catch (InterruptedException e) { - // // silent - // } - // return returnCode; - // } - - private synchronized void notifyClose() { - if (returnCode == null) - returnCode = CANCEL; - notifyAll(); - } - - protected void closeShell(int returnCode) { - this.returnCode = returnCode; - if (CANCEL == returnCode) - onCancel(); - if (foregoundShell != null && !foregoundShell.isDisposed()) { - foregoundShell.close(); - foregoundShell.dispose(); - foregoundShell = null; - } - - if (backgroundShell != null && !backgroundShell.isDisposed()) { - backgroundShell.close(); - backgroundShell.dispose(); - } - } - - protected Point getInitialSize() { - // if (exception != null) - // return new Point(800, 600); - // else - return new Point(600, 400); - } - - protected Control createDialogArea(Composite parent) { - Composite dialogarea = new Composite(parent, SWT.NONE); - dialogarea.setLayout(new GridLayout()); - dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return dialogarea; - } - - protected Shell getBackgroundShell() { - return backgroundShell; - } - - protected Shell getForegoundShell() { - return foregoundShell; - } - - public void setBlockOnOpen(boolean shouldBlock) { - block = shouldBlock; - } - - public void pack() { - foregoundShell.pack(); - } - - private void runEventLoop(Shell loopShell) { - Display display; - if (foregoundShell == null) { - display = Display.getCurrent(); - } else { - display = loopShell.getDisplay(); - } - - while (loopShell != null && !loopShell.isDisposed()) { - try { - if (!display.readAndDispatch()) { - display.sleep(); - } - } catch (UnsupportedOperationException e) { - throw e; - } catch (Throwable e) { - handleException(e); - } - } - if (!display.isDisposed()) - display.update(); - } - - protected void handleException(Throwable t) { - if (t instanceof ThreadDeath) { - // Don't catch ThreadDeath as this is a normal occurrence when - // the thread dies - throw (ThreadDeath) t; - } - // Try to keep running. - t.printStackTrace(); - } - - /** @return false, if the dialog should not be closed. */ - protected boolean onCancel() { - return true; - } - - public void setTitle(String title) { - this.title = title; - if (title != null && getForegoundShell() != null) - getForegoundShell().setText(title); - } - - public Integer getReturnCode() { - return returnCode; - } - -} \ No newline at end of file diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/SingleValueDialog.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/SingleValueDialog.java deleted file mode 100644 index 45a227e23..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/SingleValueDialog.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.argeo.cms.ui.dialogs; - -import org.eclipse.jface.window.Window; -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.Display; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** A dialog asking a for a single value. */ -public class SingleValueDialog extends CmsMessageDialog { - private Text valueT; - private String value; - private String defaultValue; - - public SingleValueDialog(Shell parentShell, String message) { - super(parentShell, message, QUESTION); - } - - public SingleValueDialog(Shell parentShell, String message, String defaultValue) { - super(parentShell, message, QUESTION); - this.defaultValue = defaultValue; - } - - @Override - protected Control createInputArea(Composite parent) { - valueT = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.SINGLE); - valueT.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); - if (defaultValue != null) - valueT.setText(defaultValue); - return valueT; - } - - @Override - protected void okPressed() { - value = valueT.getText(); - super.okPressed(); - } - - public String getString() { - return value; - } - - public Long getLong() { - return Long.valueOf(getString()); - } - - public Double getDouble() { - return Double.valueOf(getString()); - } - - public static String ask(String message) { - return ask(message, null); - } - - public static String ask(String message, String defaultValue) { - SingleValueDialog svd = new SingleValueDialog(Display.getCurrent().getActiveShell(), message, defaultValue); - if (svd.open() == Window.OK) - return svd.getString(); - else - return null; - } - - public static Long askLong(String message) { - SingleValueDialog svd = new SingleValueDialog(Display.getCurrent().getActiveShell(), message); - if (svd.open() == Window.OK) - return svd.getLong(); - else - return null; - } - - public static Double askDouble(String message) { - SingleValueDialog svd = new SingleValueDialog(Display.getCurrent().getActiveShell(), message); - if (svd.open() == Window.OK) - return svd.getDouble(); - else - return null; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/package-info.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/package-info.java deleted file mode 100644 index c88ac07a0..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/dialogs/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** SWT/JFace dialogs. */ -package org.argeo.cms.ui.dialogs; \ No newline at end of file diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java index 2b3f61e94..fd3f48e3a 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java @@ -5,7 +5,7 @@ import java.util.List; import javax.jcr.Node; import javax.jcr.RepositoryException; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.viewers.EditablePart; import org.argeo.cms.ui.widgets.StyledControl; import org.argeo.eclipse.ui.EclipseUiUtils; @@ -70,7 +70,7 @@ public class EditableMultiStringProperty extends StyledControl implements Editab /** To be overridden */ protected void setContainerLayoutData(Composite composite) { - composite.setLayoutData(CmsUiUtils.fillWidth()); + composite.setLayoutData(CmsSwtUtils.fillWidth()); } @Override @@ -115,8 +115,8 @@ public class EditableMultiStringProperty extends StyledControl implements Editab 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()); + CmsSwtUtils.markup(label); + CmsSwtUtils.style(label, FormStyle.propertyText.style()); return label; } @@ -131,7 +131,7 @@ public class EditableMultiStringProperty extends StyledControl implements Editab 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); + CmsSwtUtils.style(deleteBtn, FormStyle.delete.style() + FormStyle.BUTTON_SUFFIX); GridData gd = new GridData(); gd.heightHint = btnHeight; gd.widthHint = btnWidth; @@ -146,7 +146,7 @@ public class EditableMultiStringProperty extends StyledControl implements Editab // The "add new value" text is not meant to change, so we can set it on // creation text.setMessage(message); - CmsUiUtils.style(text, style); + CmsSwtUtils.style(text, style); text.setFocus(); text.addTraverseListener(new TraverseListener() { @@ -211,8 +211,8 @@ public class EditableMultiStringProperty extends StyledControl implements Editab if (canEdit) { Label lbl = new Label(box, getStyle()); lbl.setText(message); - CmsUiUtils.style(lbl, style); - CmsUiUtils.markup(lbl); + CmsSwtUtils.style(lbl, style); + CmsSwtUtils.markup(lbl); if (mouseListener != null) lbl.addMouseListener(mouseListener); return lbl; @@ -244,13 +244,13 @@ public class EditableMultiStringProperty extends StyledControl implements Editab } public synchronized void startEditing() { - CmsUiUtils.style(getControl(), FormStyle.propertyText.style()); + CmsSwtUtils.style(getControl(), FormStyle.propertyText.style()); // getControl().setData(STYLE, FormStyle.propertyText.style()); super.startEditing(); } public synchronized void stopEditing() { - CmsUiUtils.style(getControl(), FormStyle.propertyMessage.style()); + CmsSwtUtils.style(getControl(), FormStyle.propertyMessage.style()); // getControl().setData(STYLE, FormStyle.propertyMessage.style()); super.stopEditing(); } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java index fd7095f87..8591a925f 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java @@ -7,7 +7,7 @@ import java.util.GregorianCalendar; import javax.jcr.Node; import javax.jcr.RepositoryException; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.viewers.EditablePart; import org.argeo.cms.ui.widgets.StyledControl; import org.argeo.eclipse.ui.EclipseUiUtils; @@ -91,17 +91,17 @@ public class EditablePropertyDate extends StyledControl implements EditablePart public synchronized void startEditing() { // if (dateTxt != null && !dateTxt.isDisposed()) - CmsUiUtils.style(getControl(), FormStyle.propertyText); + CmsSwtUtils.style(getControl(), FormStyle.propertyText); // getControl().setData(STYLE, FormStyle.propertyText.style()); super.startEditing(); } public synchronized void stopEditing() { if (EclipseUiUtils.isEmpty(dateTxt.getText())) - CmsUiUtils.style(getControl(), FormStyle.propertyMessage); + CmsSwtUtils.style(getControl(), FormStyle.propertyMessage); // getControl().setData(STYLE, FormStyle.propertyMessage.style()); else - CmsUiUtils.style(getControl(), FormStyle.propertyText); + CmsSwtUtils.style(getControl(), FormStyle.propertyText); // getControl().setData(STYLE, FormStyle.propertyText.style()); super.stopEditing(); } @@ -120,27 +120,27 @@ public class EditablePropertyDate extends StyledControl implements EditablePart 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); + lbl.setLayoutData(CmsSwtUtils.fillWidth()); + CmsSwtUtils.style(lbl, style); + CmsSwtUtils.markup(lbl); if (mouseListener != null) lbl.addMouseListener(mouseListener); return lbl; } private Control createCustomEditableControl(Composite box, String style) { - box.setLayoutData(CmsUiUtils.fillWidth()); + box.setLayoutData(CmsSwtUtils.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); + CmsSwtUtils.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); + CmsSwtUtils.style(openCalBtn, FormStyle.calendar.style() + FormStyle.BUTTON_SUFFIX); GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false); gd.heightHint = 17; openCalBtn.setLayoutData(gd); @@ -224,8 +224,8 @@ public class EditablePropertyDate extends StyledControl implements EditablePart 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()); + CmsSwtUtils.markup(CalendarPopup.this); + CmsSwtUtils.style(CalendarPopup.this, FormStyle.popupCalendar.style()); pack(); layout(); setLocation(source.toDisplay((source.getLocation().x - 2), (source.getSize().y) + 3)); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java index c170e8c2f..092009355 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java @@ -6,7 +6,7 @@ import static org.argeo.cms.ui.forms.FormStyle.propertyText; import javax.jcr.Node; import javax.jcr.RepositoryException; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.viewers.EditablePart; import org.argeo.cms.ui.widgets.EditableText; import org.argeo.eclipse.ui.EclipseUiUtils; @@ -62,15 +62,15 @@ public class EditablePropertyString extends EditableText implements EditablePart } public synchronized void startEditing() { - CmsUiUtils.style(getControl(), FormStyle.propertyText); + CmsSwtUtils.style(getControl(), FormStyle.propertyText); super.startEditing(); } public synchronized void stopEditing() { if (EclipseUiUtils.isEmpty(((Text) getControl()).getText())) - CmsUiUtils.style(getControl(), FormStyle.propertyMessage); + CmsSwtUtils.style(getControl(), FormStyle.propertyMessage); else - CmsUiUtils.style(getControl(), FormStyle.propertyText); + CmsSwtUtils.style(getControl(), FormStyle.propertyText); super.stopEditing(); } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java index 7d4612731..f3a56f7b9 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java @@ -5,8 +5,8 @@ import java.util.Observer; import javax.jcr.Node; -import org.argeo.cms.ui.CmsEditable; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.api.cms.CmsEditable; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; @@ -57,10 +57,10 @@ public class FormEditorHeader implements SelectionListener, Observer { display = new Composite(parent, SWT.NONE); display.setLayoutData(layoutData); - CmsUiUtils.style(display, FormStyle.header.style()); + CmsSwtUtils.style(display, FormStyle.header.style()); display.setBackgroundMode(SWT.INHERIT_FORCE); - display.setLayout(CmsUiUtils.noSpaceGridLayout()); + display.setLayout(CmsSwtUtils.noSpaceGridLayout()); publishBtn = createSimpleBtn(display, getPublishButtonLabel()); display.moveAbove(null); @@ -70,7 +70,7 @@ public class FormEditorHeader implements SelectionListener, Observer { 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()); + CmsSwtUtils.style(button, FormStyle.header.style()); button.addSelectionListener(this); return button; } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java index 981f6efc5..bf0e86bea 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java @@ -16,10 +16,10 @@ import javax.jcr.ValueFormatException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.cms.ui.CmsEditable; -import org.argeo.cms.ui.CmsImageManager; -import org.argeo.cms.ui.CmsView; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.api.cms.Cms2DSize; +import org.argeo.api.cms.CmsEditable; +import org.argeo.api.cms.CmsImageManager; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.viewers.AbstractPageViewer; import org.argeo.cms.ui.viewers.EditablePart; import org.argeo.cms.ui.viewers.Section; @@ -74,7 +74,7 @@ public class FormPageViewer extends AbstractPageViewer { // 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 CmsImageManager imageManager; private FileUploadListener fileUploadListener; public FormPageViewer(Section mainSection, int style, CmsEditable cmsEditable) throws RepositoryException { @@ -304,9 +304,9 @@ public class FormPageViewer extends AbstractPageViewer { return mainSection; } - protected CmsImageManager imageManager() { + protected CmsImageManager imageManager() { if (imageManager == null) - imageManager = CmsView.getCmsView(mainSection).getImageManager(); + imageManager = (CmsImageManager) CmsSwtUtils.getCmsView(mainSection).getImageManager(); return imageManager; } @@ -315,8 +315,8 @@ public class FormPageViewer extends AbstractPageViewer { Section section = null; if (node != null) { section = new Section(body, SWT.NO_FOCUS, node); - section.setLayoutData(CmsUiUtils.fillWidth()); - section.setLayout(CmsUiUtils.noSpaceGridLayout()); + section.setLayoutData(CmsSwtUtils.fillWidth()); + section.setLayout(CmsSwtUtils.noSpaceGridLayout()); } return section; } @@ -328,7 +328,7 @@ public class FormPageViewer extends AbstractPageViewer { EditablePropertyString eps = new EditablePropertyString(bodyRow, SWT.WRAP | SWT.LEFT, node, propName, msg); eps.setMouseListener(getMouseListener()); eps.setFocusListener(getFocusListener()); - eps.setLayoutData(CmsUiUtils.fillWidth()); + eps.setLayoutData(CmsSwtUtils.fillWidth()); } } @@ -353,7 +353,7 @@ public class FormPageViewer extends AbstractPageViewer { addListeners(emsp); // emsp.setMouseListener(getMouseListener()); emsp.setStyle(FormStyle.propertyMessage.style()); - emsp.setLayoutData(CmsUiUtils.fillWidth()); + emsp.setLayoutData(CmsSwtUtils.fillWidth()); } } @@ -365,7 +365,7 @@ public class FormPageViewer extends AbstractPageViewer { // boolean isSmall = CmsView.getCmsView(parent).getUxContext().isSmall(); Label label = new Label(parent, SWT.LEAD | SWT.WRAP); label.setText(value + " "); - CmsUiUtils.style(label, FormStyle.propertyLabel.style()); + CmsSwtUtils.style(label, FormStyle.propertyLabel.style()); GridData gd = new GridData(SWT.LEAD, vAlign, false, false); if (labelColWidth != null) gd.widthHint = labelColWidth; @@ -376,13 +376,13 @@ public class FormPageViewer extends AbstractPageViewer { protected Label newStyledLabel(Composite parent, String style, String value) { Label label = new Label(parent, SWT.NONE); label.setText(value); - CmsUiUtils.style(label, style); + CmsSwtUtils.style(label, style); return label; } protected Composite createRowLayoutComposite(Composite parent) throws RepositoryException { Composite bodyRow = new Composite(parent, SWT.NO_FOCUS); - bodyRow.setLayoutData(CmsUiUtils.fillWidth()); + bodyRow.setLayoutData(CmsSwtUtils.fillWidth()); RowLayout rl = new RowLayout(SWT.WRAP); rl.type = SWT.HORIZONTAL; rl.spacing = rowLayoutHSpacing; @@ -448,24 +448,20 @@ public class FormPageViewer extends AbstractPageViewer { // for a while cleanedName = System.currentTimeMillis() % 100000 + "_" + cleanedName; - try { - imageManager().uploadImage(context, context, cleanedName, stream, details.getContentType()); - // 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 JcrException("Unable to refresh " + "image section for " + context, re); - } + imageManager().uploadImage(context, context, cleanedName, stream, details.getContentType()); + // 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 JcrException("Unable to refresh " + "image section for " + context, re); } - }); - } catch (RepositoryException re) { - throw new JcrException("unable to upload image " + name + " at " + context, re); - } + } + }); } } @@ -475,20 +471,20 @@ public class FormPageViewer extends AbstractPageViewer { } protected Img createImgComposite(Composite parent, Node node, Point preferredSize) throws RepositoryException { - Img img = new Img(parent, SWT.NONE, node, preferredSize) { + Img img = new Img(parent, SWT.NONE, node, new Cms2DSize(preferredSize.x, preferredSize.y)) { private static final long serialVersionUID = 1297900641952417540L; @Override protected void setContainerLayoutData(Composite composite) { - composite.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); + composite.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); } @Override protected void setControlLayoutData(Control control) { - control.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); + control.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); } }; - img.setLayoutData(CmsUiUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); + img.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT)); updateContent(img); addListeners(img); return img; @@ -497,7 +493,7 @@ public class FormPageViewer extends AbstractPageViewer { 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.setLayoutData(CmsSwtUtils.fillAll()); comp.setLayout(new FormLayout()); // The body to be populated @@ -507,7 +503,7 @@ public class FormPageViewer extends AbstractPageViewer { if (getCmsEditable().canEdit()) { // the delete button Button deleteBtn = new Button(comp, SWT.FLAT); - CmsUiUtils.style(deleteBtn, FormStyle.deleteOverlay.style()); + CmsSwtUtils.style(deleteBtn, FormStyle.deleteOverlay.style()); FormData formData = new FormData(); formData.right = new FormAttachment(rightWeight, 0); formData.top = new FormAttachment(topWeight, 0); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormStyle.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormStyle.java index 7a05e2b2b..24067eaaa 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormStyle.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormStyle.java @@ -1,6 +1,6 @@ package org.argeo.cms.ui.forms; -import org.argeo.cms.ui.util.CmsStyle; +import org.argeo.api.cms.CmsStyle; /** Syles used */ public enum FormStyle implements CmsStyle { diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormUtils.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormUtils.java index a5475d6e5..822473973 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormUtils.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormUtils.java @@ -11,8 +11,8 @@ import javax.jcr.RepositoryException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.api.cms.CmsView; 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; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java index 4a7e9bd3f..5a5ecdb8b 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java @@ -21,7 +21,7 @@ import javax.jcr.Session; import org.argeo.cms.CmsException; import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.jcr.CmsJcrUtils; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.eclipse.ui.ColumnDefinition; import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider; @@ -277,7 +277,7 @@ public class CmsFsBrowser extends Composite { else nameStr = path.getFileName().toString(); elemBtn.setText(nameStr + " >> "); - CmsUiUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN); + CmsSwtUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN); elemBtn.addSelectionListener(new SelectionAdapter() { private static final long serialVersionUID = -4103695476023480651L; @@ -323,7 +323,7 @@ public class CmsFsBrowser extends Composite { } private void populateBookmarks(Composite parent) { - CmsUiUtils.clear(parent); + CmsSwtUtils.clear(parent); parent.setLayout(new GridLayout()); ISelectionChangedListener selList = new BookmarksSelChangeListener(); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java index f45629b04..03ec415d8 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java @@ -18,7 +18,7 @@ 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.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.eclipse.ui.dialogs.SingleValue; import org.eclipse.jface.dialogs.MessageDialog; @@ -70,7 +70,7 @@ public class FsContextMenu extends Shell { Composite boxCmp = new Composite(this, SWT.NO_FOCUS | SWT.BORDER); boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout()); - CmsUiUtils.style(boxCmp, FsStyles.CONTEXT_MENU_BOX); + CmsSwtUtils.style(boxCmp, FsStyles.CONTEXT_MENU_BOX); createContextMenu(boxCmp); addShellListener(new ActionsShellListener()); @@ -82,8 +82,8 @@ public class FsContextMenu extends Shell { Button btn = new Button(boxCmp, SWT.FLAT | SWT.PUSH | SWT.LEAD); btn.setText(getLabel(actionId)); btn.setLayoutData(EclipseUiUtils.fillWidth()); - CmsUiUtils.markup(btn); - CmsUiUtils.style(btn, actionId + FsStyles.BUTTON_SUFFIX); + CmsSwtUtils.markup(btn); + CmsSwtUtils.style(btn, actionId + FsStyles.BUTTON_SUFFIX); btn.setData(KEY_ACTION_ID, actionId); btn.addSelectionListener(asl); actionButtons.put(actionId, btn); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java index c2399968b..c8582f0c1 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java @@ -11,7 +11,7 @@ import javax.jcr.RepositoryException; import javax.jcr.nodetype.NodeType; import org.apache.commons.io.FilenameUtils; -import org.argeo.cms.ui.CmsImageManager; +import org.argeo.api.cms.CmsImageManager; import org.argeo.cms.ui.widgets.Img; import org.argeo.jcr.JcrException; import org.argeo.jcr.JcrUtils; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java index 5602d991b..c5c1a01a2 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java @@ -2,9 +2,10 @@ package org.argeo.cms.ui.internal; import javax.jcr.RepositoryException; +import org.argeo.api.cms.Cms2DSize; +import org.argeo.cms.swt.CmsSwtUtils; 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; import org.eclipse.swt.widgets.Text; @@ -14,7 +15,7 @@ public class SimpleEditableImage extends EditableImage { private static final long serialVersionUID = -5689145523114022890L; private String src; - private Point imageSize; + private Cms2DSize imageSize; public SimpleEditableImage(Composite parent, int swtStyle) { super(parent, swtStyle); @@ -22,8 +23,7 @@ public class SimpleEditableImage extends EditableImage { getParent().layout(); } - public SimpleEditableImage(Composite parent, int swtStyle, String src, - Point imageSize) { + public SimpleEditableImage(Composite parent, int swtStyle, String src, Cms2DSize imageSize) { super(parent, swtStyle); this.src = src; this.imageSize = imageSize; @@ -43,14 +43,13 @@ public class SimpleEditableImage extends EditableImage { if (src != null) imgTag = CmsUiUtils.img(src, imageSize); else - imgTag = CmsUiUtils.noImg(imageSize != null ? imageSize - : NO_IMAGE_SIZE); + imgTag = CmsUiUtils.noImg(imageSize != null ? imageSize : NO_IMAGE_SIZE); return imgTag; } protected Text createText(Composite box, String style) { Text text = new Text(box, getStyle()); - CmsUiUtils.style(text, style); + CmsSwtUtils.style(text, style); return text; } @@ -62,11 +61,11 @@ public class SimpleEditableImage extends EditableImage { this.src = src; } - public Point getImageSize() { + public Cms2DSize getImageSize() { return imageSize; } - public void setImageSize(Point imageSize) { + public void setImageSize(Cms2DSize imageSize) { this.imageSize = imageSize; } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/rwt/UserUi.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/rwt/UserUi.java deleted file mode 100644 index 5e21cc428..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/rwt/UserUi.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.argeo.cms.ui.internal.rwt; - -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; - -public class UserUi implements ApplicationConfiguration { - @Override - public void configure(Application application) { - application.setOperationMode(OperationMode.SWT_COMPATIBILITY); - application.addEntryPoint("/login", LoginEntryPoint.class, null); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/PickUpUserDialog.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/PickUpUserDialog.java deleted file mode 100644 index d074254de..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/PickUpUserDialog.java +++ /dev/null @@ -1,246 +0,0 @@ -package org.argeo.cms.ui.useradmin; - -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.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.TrayDialog; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.FillLayout; -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.Shell; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.service.useradmin.Group; -import org.osgi.service.useradmin.Role; -import org.osgi.service.useradmin.User; -import org.osgi.service.useradmin.UserAdmin; - -/** Dialog with a user (or group) list to pick up one */ -public class PickUpUserDialog extends TrayDialog { - private static final long serialVersionUID = -1420106871173920369L; - - // Business objects - private final UserAdmin userAdmin; - private User selectedUser; - - // this page widgets and UI objects - private String title; - private LdifUsersTable userTableViewerCmp; - private TableViewer userViewer; - private List columnDefs = new ArrayList(); - - /** - * A dialog to pick up a group or a user, showing a table with default - * columns - */ - public PickUpUserDialog(Shell parentShell, String title, UserAdmin userAdmin) { - super(parentShell); - this.title = title; - this.userAdmin = userAdmin; - - columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_ICON), "", - 24, 24)); - columnDefs.add(new ColumnDefinition( - new UserLP(UserLP.COL_DISPLAY_NAME), "Common Name", 150, 100)); - columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_DOMAIN), - "Domain", 100, 120)); - columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_DN), - "Distinguished Name", 300, 100)); - } - - /** A dialog to pick up a group or a user */ - public PickUpUserDialog(Shell parentShell, String title, - UserAdmin userAdmin, List columnDefs) { - super(parentShell); - this.title = title; - this.userAdmin = userAdmin; - this.columnDefs = columnDefs; - } - - @Override - protected void okPressed() { - if (getSelected() == null) - MessageDialog.openError(getShell(), "No user chosen", - "Please, choose a user or press Cancel."); - else - super.okPressed(); - } - - protected Control createDialogArea(Composite parent) { - Composite dialogArea = (Composite) super.createDialogArea(parent); - dialogArea.setLayout(new FillLayout()); - - Composite bodyCmp = new Composite(dialogArea, SWT.NO_FOCUS); - bodyCmp.setLayout(new GridLayout()); - - // Create and configure the table - userTableViewerCmp = new MyUserTableViewer(bodyCmp, SWT.MULTI - | SWT.H_SCROLL | SWT.V_SCROLL); - - userTableViewerCmp.setColumnDefinitions(columnDefs); - userTableViewerCmp.populateWithStaticFilters(false, false); - GridData gd = EclipseUiUtils.fillAll(); - gd.minimumHeight = 300; - userTableViewerCmp.setLayoutData(gd); - userTableViewerCmp.refresh(); - - // Controllers - userViewer = userTableViewerCmp.getTableViewer(); - userViewer.addDoubleClickListener(new MyDoubleClickListener()); - userViewer - .addSelectionChangedListener(new MySelectionChangedListener()); - - parent.pack(); - return dialogArea; - } - - public User getSelected() { - if (selectedUser == null) - return null; - else - return selectedUser; - } - - protected void configureShell(Shell shell) { - super.configureShell(shell); - shell.setText(title); - } - - class MyDoubleClickListener implements IDoubleClickListener { - public void doubleClick(DoubleClickEvent evt) { - if (evt.getSelection().isEmpty()) - return; - - Object obj = ((IStructuredSelection) evt.getSelection()) - .getFirstElement(); - if (obj instanceof User) { - selectedUser = (User) obj; - okPressed(); - } - } - } - - class MySelectionChangedListener implements ISelectionChangedListener { - @Override - public void selectionChanged(SelectionChangedEvent event) { - if (event.getSelection().isEmpty()) { - selectedUser = null; - return; - } - Object obj = ((IStructuredSelection) event.getSelection()) - .getFirstElement(); - if (obj instanceof Group) { - selectedUser = (Group) obj; - } - } - } - - private class MyUserTableViewer extends LdifUsersTable { - private static final long serialVersionUID = 8467999509931900367L; - - private final String[] knownProps = { LdapAttrs.uid.name(), - LdapAttrs.cn.name(), LdapAttrs.DN }; - - private Button showSystemRoleBtn; - private Button showUserBtn; - - public MyUserTableViewer(Composite parent, int style) { - super(parent, style); - } - - protected void populateStaticFilters(Composite staticFilterCmp) { - staticFilterCmp.setLayout(new GridLayout()); - showSystemRoleBtn = new Button(staticFilterCmp, SWT.CHECK); - showSystemRoleBtn.setText("Show system roles "); - - showUserBtn = new Button(staticFilterCmp, SWT.CHECK); - showUserBtn.setText("Show users "); - - SelectionListener sl = new SelectionAdapter() { - private static final long serialVersionUID = -7033424592697691676L; - - @Override - public void widgetSelected(SelectionEvent e) { - refresh(); - } - }; - - showSystemRoleBtn.addSelectionListener(sl); - showUserBtn.addSelectionListener(sl); - } - - @Override - protected List listFilteredElements(String filter) { - Role[] roles; - try { - StringBuilder builder = new StringBuilder(); - - StringBuilder filterBuilder = new StringBuilder(); - if (notNull(filter)) - for (String prop : knownProps) { - filterBuilder.append("("); - filterBuilder.append(prop); - filterBuilder.append("=*"); - filterBuilder.append(filter); - filterBuilder.append("*)"); - } - - String typeStr = "(" + LdapAttrs.objectClass.name() + "=" - + LdapObjs.groupOfNames.name() + ")"; - if ((showUserBtn.getSelection())) - typeStr = "(|(" + LdapAttrs.objectClass.name() + "=" - + LdapObjs.inetOrgPerson.name() + ")" + typeStr - + ")"; - - if (!showSystemRoleBtn.getSelection()) - typeStr = "(& " + typeStr + "(!(" + LdapAttrs.DN + "=*" - + NodeConstants.ROLES_BASEDN + ")))"; - - if (filterBuilder.length() > 1) { - builder.append("(&" + typeStr); - builder.append("(|"); - builder.append(filterBuilder.toString()); - builder.append("))"); - } else { - builder.append(typeStr); - } - roles = userAdmin.getRoles(builder.toString()); - } catch (InvalidSyntaxException e) { - throw new EclipseUiException( - "Unable to get roles with filter: " + filter, e); - } - List users = new ArrayList(); - for (Role role : roles) - if (!users.contains(role)) - users.add((User) role); - return users; - } - } - - private boolean notNull(String string) { - if (string == null) - return false; - else - return !"".equals(string.trim()); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/UserLP.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/UserLP.java deleted file mode 100644 index 05c6f3778..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/UserLP.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.argeo.cms.ui.useradmin; - -import org.argeo.api.NodeConstants; -import org.argeo.cms.auth.UserAdminUtils; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Display; -import org.osgi.service.useradmin.Role; -import org.osgi.service.useradmin.User; - -/** Centralize label providers for the group table */ -class UserLP extends ColumnLabelProvider { - private static final long serialVersionUID = -4645930210988368571L; - - final static String COL_ICON = "colID.icon"; - final static String COL_DN = "colID.dn"; - final static String COL_DISPLAY_NAME = "colID.displayName"; - final static String COL_DOMAIN = "colID.domain"; - - final String currType; - - // private Font italic; - private Font bold; - - UserLP(String colId) { - this.currType = colId; - } - - @Override - public Font getFont(Object element) { - // Current user as bold - if (UserAdminUtils.isCurrentUser(((User) element))) { - if (bold == null) - bold = JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.BOLD) - .createFont(Display.getCurrent()); - return bold; - } - return null; - } - - @Override - public Image getImage(Object element) { - if (COL_ICON.equals(currType)) { - User user = (User) element; - String dn = user.getName(); - if (dn.endsWith(NodeConstants.ROLES_BASEDN)) - return UsersImages.ICON_ROLE; - else if (user.getType() == Role.GROUP) - return UsersImages.ICON_GROUP; - else - return UsersImages.ICON_USER; - } else - return null; - } - - @Override - public String getText(Object element) { - User user = (User) element; - return getText(user); - - } - - public String getText(User user) { - if (COL_DN.equals(currType)) - return user.getName(); - else if (COL_DISPLAY_NAME.equals(currType)) - return UserAdminUtils.getCommonName(user); - else if (COL_DOMAIN.equals(currType)) - return UserAdminUtils.getDomainName(user); - else - return ""; - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/UsersImages.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/UsersImages.java deleted file mode 100644 index eca486738..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/UsersImages.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.argeo.cms.ui.useradmin; - -import org.argeo.cms.ui.theme.CmsImages; -import org.eclipse.swt.graphics.Image; - -/** Specific users icons. */ -public class UsersImages { - private final static String PREFIX = "icons/"; - - public final static Image ICON_USER = CmsImages.createImg(PREFIX + "person.png"); - public final static Image ICON_GROUP = CmsImages.createImg(PREFIX + "group.png"); - public final static Image ICON_ROLE = CmsImages.createImg(PREFIX + "role.gif"); - public final static Image ICON_CHANGE_PASSWORD = CmsImages.createImg(PREFIX + "security.gif"); -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/package-info.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/package-info.java deleted file mode 100644 index 3fc191c16..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/useradmin/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** SWT/JFace users management components. */ -package org.argeo.cms.ui.useradmin; \ No newline at end of file diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/AbstractCmsTheme.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/AbstractCmsTheme.java deleted file mode 100644 index c3fd7960d..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/AbstractCmsTheme.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.argeo.cms.ui.util; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import org.argeo.cms.ui.CmsTheme; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.widgets.Display; - -/** Centralises some generic {@link CmsTheme} patterns. */ -public abstract class AbstractCmsTheme implements CmsTheme { - private Map imageCache = new HashMap<>(); - - private Map> iconPaths = new HashMap<>(); - - private Integer defaultIconSize = 16; - - public Image getImage(String path) { - if (!imageCache.containsKey(path)) { - try (InputStream in = getResourceAsStream(path)) { - if (in == null) - return null; - ImageData imageData = new ImageData(in); - imageCache.put(path, imageData); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - ImageData imageData = imageCache.get(path); - Image image = new Image(Display.getCurrent(), imageData); - return image; - } - - @Override - public Image getIcon(String name, Integer preferredSize) { - if (preferredSize == null) - preferredSize = defaultIconSize; - Map subCache; - if (!iconPaths.containsKey(name)) - subCache = new HashMap<>(); - else - subCache = iconPaths.get(name); - Image image = null; - if (!subCache.containsKey(preferredSize)) { - Image bestMatchSoFar = null; - paths: for (String p : getImagesPaths()) { - int lastSlash = p.lastIndexOf('/'); - String fileName = p; - if (lastSlash >= 0) - fileName = p.substring(lastSlash + 1); - int lastDot = fileName.lastIndexOf('.'); - if (lastDot >= 0) - fileName = fileName.substring(0, lastDot); - if (fileName.equals(name)) {// matched - Image img = getImage(p); - int width = img.getBounds().width; - if (width == preferredSize) {// perfect match - subCache.put(preferredSize, p); - image = img; - break paths; - } - if (bestMatchSoFar == null) { - bestMatchSoFar = img; - } else { - if (Math.abs(width - preferredSize) < Math - .abs(bestMatchSoFar.getBounds().width - preferredSize)) - bestMatchSoFar = img; - } - } - } - - if (image == null) - image = bestMatchSoFar; - } else { - image = getImage(subCache.get(preferredSize)); - } - - if (image != null && !iconPaths.containsKey(name)) - iconPaths.put(name, subCache); - - return image; - } - - @Override - public Integer getDefaultIconSize() { - return defaultIconSize; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/BundleCmsTheme.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/BundleCmsTheme.java deleted file mode 100644 index 6b997e6a3..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/BundleCmsTheme.java +++ /dev/null @@ -1,352 +0,0 @@ -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.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; - -import org.apache.commons.io.IOUtils; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; - -/** - * Simplifies the theming of an app (only RAP is supported at this stage).
- * - * Additional fonts listed in /fonts.txt.
- * Additional (standard CSS) header in /header.css.
- * RAP specific CSS files in /rap/*.css.
- * All images added as additional resources based on extensions - * / ** /*.{png,gif,jpeg,...}.
- */ -public class BundleCmsTheme extends AbstractCmsTheme { - public final static String DEFAULT_CMS_THEME_BUNDLE = "org.argeo.theme.argeo2"; - - public final static String CMS_THEME_PROPERTY = "argeo.cms.theme"; - public final static String CMS_THEME_BUNDLE_PROPERTY = "argeo.cms.theme.bundle"; - - private final static String HEADER_CSS = "header.css"; - private final static String FONTS_TXT = "fonts.txt"; - private final static String BODY_HTML = "body.html"; - -// private final static Log log = LogFactory.getLog(BundleCmsTheme.class); - - private String themeId; - private Set webCssPaths = new TreeSet<>(); - private Set rapCssPaths = new TreeSet<>(); - private Set swtCssPaths = new TreeSet<>(); - private Set imagesPaths = new TreeSet<>(); - private Set fontsPaths = new TreeSet<>(); - - private String headerCss; - private List fonts = new ArrayList<>(); - - private String bodyHtml=""; - - private String basePath; - private String styleCssPath; -// private String webCssPath; -// private String rapCssPath; -// private String swtCssPath; - private Bundle themeBundle; - - public BundleCmsTheme() { - - } - - public void init(BundleContext bundleContext, Map properties) { - initResources(bundleContext, null); - } - - public void destroy(BundleContext bundleContext, Map properties) { - - } - - @Deprecated - public BundleCmsTheme(BundleContext bundleContext) { - this(bundleContext, null); - } - - @Deprecated - public BundleCmsTheme(BundleContext bundleContext, String symbolicName) { - initResources(bundleContext, symbolicName); - } - - private void initResources(BundleContext bundleContext, String symbolicName) { - if (symbolicName == null) { - themeBundle = bundleContext.getBundle(); -// basePath = "/theme/"; -// cssPath = basePath; - } else { - themeBundle = findThemeBundle(bundleContext, symbolicName); - } - basePath = "/"; - styleCssPath = "/style/"; -// webCssPath = "/css/"; -// rapCssPath = "/rap/"; -// swtCssPath = "/swt/"; -// this.themeId = RWT.DEFAULT_THEME_ID; - this.themeId = themeBundle.getSymbolicName(); - webCssPaths = addCss(themeBundle, "/css/"); - rapCssPaths = addCss(themeBundle, "/rap/"); - swtCssPaths = addCss(themeBundle, "/swt/"); - addImages("*.png"); - addImages("*.gif"); - addImages("*.jpg"); - addImages("*.jpeg"); - addImages("*.svg"); - addImages("*.ico"); - - addFonts("*.woff"); - addFonts("*.woff2"); - - // 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) { - // added to plain Web CSS - webCssPaths.add(basePath + HEADER_CSS); - // and it will also be used by RAP: - try (BufferedReader buffer = new BufferedReader(new InputStreamReader(headerCssUrl.openStream(), UTF_8))) { - headerCss = buffer.lines().collect(Collectors.joining("\n")); - } catch (IOException e) { - throw new IllegalArgumentException("Cannot read " + headerCssUrl, e); - } - } - - // body - URL bodyUrl = themeBundle.getEntry(basePath + BODY_HTML); - if (bodyUrl != null) { - loadBodyHtml(bodyUrl); - } -} - - public String getHtmlHeaders() { - StringBuilder sb = new StringBuilder(); - if (headerCss != null) { - sb.append("\n"); - } - for (String link : fonts) { - sb.append("\n"); - } - if (sb.length() == 0) - return null; - else - return sb.toString(); - } - - - - @Override - public String getBodyHtml() { - return bodyHtml; - } - - Set addCss(Bundle themeBundle, String path) { - Set paths = new TreeSet<>(); - - // common CSS - Enumeration commonResources = themeBundle.findEntries(styleCssPath, "*.css", true); - if (commonResources != null) { - while (commonResources.hasMoreElements()) { - String resource = commonResources.nextElement().getPath(); - // remove first '/' so that RWT registers it - resource = resource.substring(1); - if (!resource.endsWith("/")) { - paths.add(resource); - } - } - } - - // specific CSS - Enumeration themeResources = themeBundle.findEntries(path, "*.css", true); - if (themeResources != null) { - while (themeResources.hasMoreElements()) { - String resource = themeResources.nextElement().getPath(); - // remove first '/' so that RWT registers it - resource = resource.substring(1); - if (!resource.endsWith("/")) { - paths.add(resource); - } - } - } - return paths; - } - - 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 IllegalArgumentException("Cannot load URL " + url, e); - } - } - - void loadBodyHtml(URL url) { - try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) { - bodyHtml= IOUtils.toString(url,StandardCharsets.UTF_8); - } catch (IOException e) { - throw new IllegalArgumentException("Cannot load URL " + url, e); - } - } - - void addImages(String pattern) { - Enumeration 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); - imagesPaths.add(resource); - } - - } - - } - - void addFonts(String pattern) { - Enumeration 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); - fontsPaths.add(resource); - } - - } - - } - - @Override - public InputStream getResourceAsStream(String resourceName) throws IOException { - URL res = themeBundle.getEntry(resourceName); - if (res == null) { - res = themeBundle.getResource(resourceName); - if (res == null) - return null; -// throw new IllegalArgumentException( -// "Resource " + resourceName + " not found in bundle " + themeBundle.getSymbolicName()); - } - return res.openStream(); - } - - 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 getRapCssPath() { -// return rapCssPath; -// } -// -// public void setRapCssPath(String cssPath) { -// this.rapCssPath = cssPath; -// } - - @Override - public Set getWebCssPaths() { - return webCssPaths; - } - - @Override - public Set getRapCssPaths() { - return rapCssPaths; - } - - @Override - public Set getSwtCssPaths() { - return swtCssPaths; - } - - @Override - public Set getImagesPaths() { - return imagesPaths; - } - - @Override - public Set getFontsPaths() { - return fontsPaths; - } - - @Override - public InputStream loadPath(String path) throws IOException { - URL url = themeBundle.getResource(path); - if (url == null) - throw new IllegalArgumentException( - "Path " + path + " not found in bundle " + themeBundle.getSymbolicName()); - return url.openStream(); - } - - private 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; - } - - @Override - public int hashCode() { - return themeId.hashCode(); - } - - @Override - public String toString() { - return "Bundle CMS Theme " + themeId; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsEvent.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsEvent.java deleted file mode 100644 index ca0797ba1..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.argeo.cms.ui.util; - -import org.argeo.cms.ui.CmsView; - -/** - * Can be applied to {@link Enum}s in order to define events used by - * {@link CmsView#sendEvent(String, java.util.Map)}. - */ -public interface CmsEvent { - String name(); - - default String topic() { - return getTopicBase() + "/" + name(); - } - - default String getTopicBase() { - return "argeo/cms"; - } - - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsIcon.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsIcon.java deleted file mode 100644 index 33f13ad8a..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsIcon.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.argeo.cms.ui.util; - -import org.argeo.cms.ui.CmsTheme; -import org.eclipse.swt.graphics.Image; - -/** Can be applied to {@link Enum}s in order to generated {@link Image}s. */ -public interface CmsIcon { - String name(); - - default Image getSmallIcon(CmsTheme theme) { - return theme.getIcon(name(), getSmallIconSize()); - } - - default Image getBigIcon(CmsTheme theme) { - return theme.getIcon(name(), getBigIconSize()); - } - - default Integer getSmallIconSize() { - return 16; - } - - default Integer getBigIconSize() { - return 32; - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsLink.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsLink.java index 33772bc8e..af7e4020d 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsLink.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsLink.java @@ -10,8 +10,10 @@ import javax.jcr.RepositoryException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.api.cms.CmsStyle; import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.jcr.CmsJcrUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.CmsUiProvider; import org.argeo.jcr.JcrException; import org.eclipse.rap.rwt.RWT; @@ -90,10 +92,10 @@ public class CmsLink implements CmsUiProvider { // } Composite comp = new Composite(parent, SWT.NONE); - comp.setLayout(CmsUiUtils.noSpaceGridLayout()); + comp.setLayout(CmsSwtUtils.noSpaceGridLayout()); Label link = new Label(comp, SWT.NONE); - CmsUiUtils.markup(link); + CmsSwtUtils.markup(link); GridData layoutData = new GridData(horizontalAlignment, verticalAlignment, false, false); if (image != null) { if (imageHeight != null) @@ -104,8 +106,8 @@ public class CmsLink implements CmsUiProvider { } link.setLayoutData(layoutData); - CmsUiUtils.style(comp, style != null ? style : getDefaultStyle()); - CmsUiUtils.style(link, style != null ? style : getDefaultStyle()); + CmsSwtUtils.style(comp, style != null ? style : getDefaultStyle()); + CmsSwtUtils.style(link, style != null ? style : getDefaultStyle()); // label StringBuilder labelText = new StringBuilder(); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsPane.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsPane.java index 68f1e0f89..fc0c82146 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsPane.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsPane.java @@ -1,5 +1,6 @@ package org.argeo.cms.ui.util; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -14,7 +15,7 @@ public class CmsPane { private Composite supportArea; public CmsPane(Composite parent, int style) { - parent.setLayout(CmsUiUtils.noSpaceGridLayout()); + parent.setLayout(CmsSwtUtils.noSpaceGridLayout()); // qaArea = new Composite(parent, SWT.NONE); // qaArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsStyle.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsStyle.java deleted file mode 100644 index ed2244b8d..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsStyle.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.argeo.cms.ui.util; - -/** Can be applied to {@link Enum}s in order to generate (CSS) class names. */ -public interface CmsStyle { - String name(); - - /** @deprecated use {@link #style()} instead. */ - @Deprecated - default String toStyleClass() { - return style(); - } - - default String style() { - String classPrefix = getClassPrefix(); - return "".equals(classPrefix) ? name() : classPrefix + "-" + name(); - } - - default String getClassPrefix() { - return ""; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java index 2bfeb43cf..ef4f7fa44 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java @@ -6,8 +6,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; import java.util.StringTokenizer; import javax.jcr.Node; @@ -15,74 +13,39 @@ import javax.jcr.RepositoryException; import javax.servlet.http.HttpServletRequest; import org.argeo.api.NodeConstants; +import org.argeo.api.cms.Cms2DSize; +import org.argeo.api.cms.CmsView; import org.argeo.cms.jcr.CmsJcrUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.CmsConstants; -import org.argeo.cms.ui.CmsView; -import org.argeo.eclipse.ui.Selected; -import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils; -import org.argeo.jcr.JcrException; 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.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.FormAttachment; -import org.eclipse.swt.layout.FormData; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowData; -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.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 { +public class CmsUiUtils { // private final static Log log = LogFactory.getLog(CmsUiUtils.class); /* * CMS VIEW */ - /** Sends an event via {@link CmsView#sendEvent(String, Map)}. */ - public static void sendEventOnSelect(Control control, String topic, Map properties) { - SelectionListener listener = (Selected) (e) -> { - CmsView.getCmsView(control.getParent()).sendEvent(topic, properties); - }; - if (control instanceof Button) { - ((Button) control).addSelectionListener(listener); - } else - throw new UnsupportedOperationException("Control type " + control.getClass() + " is not supported."); - } - - /** - * Convenience method to sends an event via - * {@link CmsView#sendEvent(String, Map)}. - */ - public static void sendEventOnSelect(Control control, String topic, String key, Object value) { - Map properties = new HashMap<>(); - properties.put(key, value); - sendEventOnSelect(control, topic, properties); - } - /** * The CMS view related to this display, or null if none is available from this * call. * - * @deprecated Use {@link CmsView#getCmsView(Composite)} instead. + * @deprecated Use {@link CmsSwtUtils#getCmsView(Composite)} instead. */ @Deprecated public static CmsView getCmsView() { // return UiContext.getData(CmsView.class.getName()); - return CmsView.getCmsView(Display.getCurrent().getActiveShell()); + return CmsSwtUtils.getCmsView(Display.getCurrent().getActiveShell()); } public static StringBuilder getServerBaseUrl(HttpServletRequest request) { @@ -99,7 +62,7 @@ public class CmsUiUtils implements CmsConstants { } // - public static String getDataUrl(Node node, HttpServletRequest request) throws RepositoryException { + public static String getDataUrl(Node node, HttpServletRequest request) { try { StringBuilder buf = getServerBaseUrl(request); buf.append(getDataPath(node)); @@ -110,21 +73,21 @@ public class CmsUiUtils implements CmsConstants { } /** A path in the node repository */ - public static String getDataPath(Node node) throws RepositoryException { + public static String getDataPath(Node node) { return getDataPath(NodeConstants.EGO_REPOSITORY, node); } - public static String getDataPath(String cn, Node node) throws RepositoryException { + public static String getDataPath(String cn, Node node) { return CmsJcrUtils.getDataPath(cn, node); } /** Clean reserved URL characters for use in HTTP links. */ - public static String getDataPathForUrl(Node node) throws RepositoryException { + public static String getDataPathForUrl(Node node) { return cleanPathForUrl(getDataPath(node)); } /** Clean reserved URL characters for use in HTTP links. */ - public static String cleanPathForUrl(String path) throws RepositoryException { + public static String cleanPathForUrl(String path) { StringTokenizer st = new StringTokenizer(path, "/"); StringBuilder sb = new StringBuilder(); while (st.hasMoreElements()) { @@ -141,162 +104,19 @@ public class CmsUiUtils implements CmsConstants { @Deprecated public static RowData ROW_DATA_16px = new RowData(16, 16); - /* - * GRID LAYOUT - */ - public static GridLayout noSpaceGridLayout() { - return noSpaceGridLayout(new GridLayout()); - } - - public static GridLayout noSpaceGridLayout(int columns) { - return noSpaceGridLayout(new GridLayout(columns, false)); - } - - /** @return the same layout, with spaces removed. */ - public static GridLayout noSpaceGridLayout(GridLayout layout) { - layout.horizontalSpacing = 0; - layout.verticalSpacing = 0; - layout.marginWidth = 0; - layout.marginHeight = 0; - return layout; - } - - public static GridData fillAll() { - return new GridData(SWT.FILL, SWT.FILL, true, true); - } - - public static GridData fillWidth() { - return grabWidth(SWT.FILL, SWT.FILL); - } - - public static GridData grabWidth(int horizontalAlignment, int verticalAlignment) { - return new GridData(horizontalAlignment, horizontalAlignment, true, false); - } - - public static GridData fillHeight() { - return grabHeight(SWT.FILL, SWT.FILL); - } - - public static GridData grabHeight(int horizontalAlignment, int verticalAlignment) { - return new GridData(horizontalAlignment, horizontalAlignment, false, true); - } - - /* - * ROW LAYOUT - */ - /** @return the same layout, with margins removed. */ - public static RowLayout noMarginsRowLayout(RowLayout rowLayout) { - rowLayout.marginTop = 0; - rowLayout.marginBottom = 0; - rowLayout.marginLeft = 0; - rowLayout.marginRight = 0; - return rowLayout; - } - - public static RowLayout noMarginsRowLayout(int type) { - return noMarginsRowLayout(new RowLayout(type)); - } - - public static RowData rowData16px() { - return new RowData(16, 16); - } + /* * FORM LAYOUT */ - public static FormData coverAll() { - FormData fdLabel = new FormData(); - fdLabel.top = new FormAttachment(0, 0); - fdLabel.left = new FormAttachment(0, 0); - fdLabel.right = new FormAttachment(100, 0); - fdLabel.bottom = new FormAttachment(100, 0); - return fdLabel; - } - - /* - * STYLING - */ - - /** Style widget */ - public static T style(T widget, String style) { - if (style == null) - return widget;// does nothing - EclipseUiSpecificUtils.setStyleData(widget, style); - if (widget instanceof Control) { - CmsView cmsView = CmsView.getCmsView((Control) widget); - if (cmsView != null) - cmsView.applyStyles(widget); - } - return widget; - } - - /** Style widget */ - public static T style(T widget, CmsStyle style) { - return style(widget, style.toStyleClass()); - } - - /** Enable markups on widget */ - public static T markup(T widget) { - EclipseUiSpecificUtils.setMarkupData(widget); - return widget; - } - - /** Disable markup validation. */ - public static T disableMarkupValidation(T widget) { - EclipseUiSpecificUtils.setMarkupValidationDisabledData(widget); - return widget; - } - - /** - * Apply markup and set text on {@link Label}, {@link Button}, {@link Text}. - * - * @param widget the widget to style and to use in order to display text - * @param txt the object to display via its toString() method. - * This argument should not be null, but if it is null and - * assertions are disabled "" is displayed instead; if - * assertions are enabled the call will fail. - * - * @see #markup(Widget) - */ - public static T text(T widget, Object txt) { - assert txt != null; - String str = txt != null ? txt.toString() : ""; - markup(widget); - if (widget instanceof Label) - ((Label) widget).setText(str); - else if (widget instanceof Button) - ((Button) widget).setText(str); - else if (widget instanceof Text) - ((Text) widget).setText(str); - else - throw new IllegalArgumentException("Unsupported widget type " + widget.getClass()); - return widget; - } - - /** A {@link Label} with markup activated. */ - public static Label lbl(Composite parent, Object txt) { - return text(new Label(parent, SWT.NONE), txt); - } - - /** A read-only {@link Text} whose content can be copy/pasted. */ - public static Text txt(Composite parent, Object txt) { - return text(new Text(parent, SWT.NONE), txt); - } + @Deprecated 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) { - if (composite.isDisposed()) - return; - for (Control child : composite.getChildren()) - child.dispose(); - } - // // JCR // @@ -328,6 +148,7 @@ public class CmsUiUtils implements CmsConstants { } // IMAGES + public static String img(Node fileNode, String width, String height) { return img(null, fileNode, width, height); } @@ -335,11 +156,7 @@ public class CmsUiUtils implements CmsConstants { public static String img(String serverBase, Node fileNode, String width, String height) { // String src = (serverBase != null ? serverBase : "") + NodeUtils.getDataPath(fileNode); String src; - try { - src = (serverBase != null ? serverBase : "") + getDataPathForUrl(fileNode); - } catch (RepositoryException e) { - throw new JcrException("Cannot get URL data path for " + fileNode, e); - } + src = (serverBase != null ? serverBase : "") + getDataPathForUrl(fileNode); return imgBuilder(src, width, height).append("/>").toString(); } @@ -347,8 +164,8 @@ public class CmsUiUtils implements CmsConstants { 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 String img(String src, Cms2DSize size) { + return img(src, Integer.toString(size.getWidth()), Integer.toString(size.getHeight())); } public static StringBuilder imgBuilder(String src, String width, String height) { @@ -356,22 +173,22 @@ public class CmsUiUtils implements CmsConstants { .append("' src='").append(src).append("'"); } - public static String noImg(Point size) { + public static String noImg(Cms2DSize size) { ResourceManager rm = RWT.getResourceManager(); - return CmsUiUtils.img(rm.getLocation(NO_IMAGE), size); + return CmsUiUtils.img(rm.getLocation(CmsConstants.NO_IMAGE), size); } public static String noImg() { - return noImg(NO_IMAGE_SIZE); + return noImg(CmsConstants.NO_IMAGE_SIZE); } - public static Image noImage(Point size) { + public static Image noImage(Cms2DSize size) { ResourceManager rm = RWT.getResourceManager(); InputStream in = null; try { - in = rm.getRegisteredContent(NO_IMAGE); + in = rm.getRegisteredContent(CmsConstants.NO_IMAGE); ImageData id = new ImageData(in); - ImageData scaled = id.scaledTo(size.x, size.y); + ImageData scaled = id.scaledTo(size.getWidth(), size.getHeight()); Image image = new Image(Display.getCurrent(), scaled); return image; } finally { diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java index 6c4a870c4..d7f3d7c03 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java @@ -9,8 +9,6 @@ import static org.argeo.cms.ui.CmsConstants.NO_IMAGE_SIZE; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; @@ -22,7 +20,9 @@ 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.ui.CmsImageManager; +import org.argeo.api.cms.Cms2DSize; +import org.argeo.api.cms.CmsImageManager; +import org.argeo.jcr.JcrException; import org.argeo.jcr.JcrUtils; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.service.ResourceManager; @@ -35,17 +35,17 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; /** Manages only public images so far. */ -public class DefaultImageManager implements CmsImageManager { +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; + public Boolean load(Node node, Control control, Cms2DSize preferredSize) { + Cms2DSize imageSize = getImageSize(node); + Cms2DSize 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) { + if (preferredSize == null || imageSize.getWidth() == 0 || imageSize.getHeight() == 0 + || (preferredSize.getWidth() == 0 && preferredSize.getHeight() == 0)) { + if (imageSize.getWidth() != 0 && imageSize.getHeight() != 0) { // actual image size if completely known size = imageSize; } else { @@ -54,15 +54,15 @@ public class DefaultImageManager implements CmsImageManager { imgTag = CmsUiUtils.noImg(size); } - } else if (preferredSize.x != 0 && preferredSize.y != 0) { + } else if (preferredSize.getWidth() != 0 && preferredSize.getHeight() != 0) { // given size if completely provided size = preferredSize; } else { // at this stage : // image is completely known - assert imageSize.x != 0 && imageSize.y != 0; + assert imageSize.getWidth() != 0 && imageSize.getHeight() != 0; // one and only one of the dimension as been specified - assert preferredSize.x == 0 || preferredSize.y == 0; + assert preferredSize.getWidth() == 0 || preferredSize.getHeight() == 0; size = resizeTo(imageSize, preferredSize); } @@ -87,7 +87,7 @@ public class DefaultImageManager implements CmsImageManager { } else if (control instanceof FileUpload) { FileUpload lbl = (FileUpload) control; lbl.setImage(CmsUiUtils.noImage(size)); - lbl.setSize(size); + lbl.setSize(new Point(size.getWidth(), size.getHeight())); return loaded; } else loaded = false; @@ -95,15 +95,17 @@ public class DefaultImageManager implements CmsImageManager { return loaded; } - private Point resizeTo(Point orig, Point constraints) { - if (constraints.x != 0 && constraints.y != 0) { + private Cms2DSize resizeTo(Cms2DSize orig, Cms2DSize constraints) { + if (constraints.getWidth() != 0 && constraints.getHeight() != 0) { return constraints; - } else if (constraints.x == 0 && constraints.y == 0) { + } else if (constraints.getWidth() == 0 && constraints.getHeight() == 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); + } else if (constraints.getHeight() == 0) {// force width + return new Cms2DSize(constraints.getWidth(), + scale(orig.getHeight(), orig.getWidth(), constraints.getWidth())); + } else if (constraints.getWidth() == 0) {// force height + return new Cms2DSize(scale(orig.getWidth(), orig.getHeight(), constraints.getHeight()), + constraints.getHeight()); } throw new IllegalArgumentException("Cannot resize " + orig + " to " + constraints); } @@ -116,19 +118,19 @@ public class DefaultImageManager implements CmsImageManager { return ((float) a) / ((float) b); } - public Point getImageSize(Node node) throws RepositoryException { + public Cms2DSize getImageSize(Node node) { // TODO optimise Image image = getSwtImage(node); - return new Point(image.getBounds().width, image.getBounds().height); + return new Cms2DSize(image.getBounds().width, image.getBounds().height); } /** @return null if not available */ @Override - public String getImageTag(Node node) throws RepositoryException { + public String getImageTag(Node node) { return getImageTag(node, getImageSize(node)); } - private String getImageTag(Node node, Point size) throws RepositoryException { + private String getImageTag(Node node, Cms2DSize size) { StringBuilder buf = getImageTagBuilder(node, size); if (buf == null) return null; @@ -137,12 +139,12 @@ public class DefaultImageManager implements CmsImageManager { /** @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)); + public StringBuilder getImageTagBuilder(Node node, Cms2DSize size) { + return getImageTagBuilder(node, Integer.toString(size.getWidth()), Integer.toString(size.getHeight())); } /** @return null if not available */ - private StringBuilder getImageTagBuilder(Node node, String width, String height) throws RepositoryException { + private StringBuilder getImageTagBuilder(Node node, String width, String height) { String url = getImageUrl(node); if (url == null) return null; @@ -151,27 +153,35 @@ public class DefaultImageManager implements CmsImageManager { /** @return null if not available */ @Override - public String getImageUrl(Node node) throws RepositoryException { + public String getImageUrl(Node node) { return CmsUiUtils.getDataPathForUrl(node); } - 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(); + protected String getResourceName(Node node) { + try { + String workspace = node.getSession().getWorkspace().getName(); + if (node.hasNode(JCR_CONTENT)) + return workspace + '_' + node.getNode(JCR_CONTENT).getIdentifier(); + else + return workspace + '_' + node.getIdentifier(); + } catch (RepositoryException e) { + throw new JcrException(e); + } } - 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 Binary getImageBinary(Node node) { + try { + if (node.isNodeType(NT_FILE)) { + return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary(); + } else { + return null; + } + } catch (RepositoryException e) { + throw new JcrException(e); } } - public Image getSwtImage(Node node) throws RepositoryException { + public Image getSwtImage(Node node) { InputStream inputStream = null; Binary binary = getImageBinary(node); if (binary == null) @@ -179,6 +189,8 @@ public class DefaultImageManager implements CmsImageManager { try { inputStream = binary.getStream(); return new Image(Display.getCurrent(), inputStream); + } catch (RepositoryException e) { + throw new JcrException(e); } finally { IOUtils.closeQuietly(inputStream); JcrUtils.closeQuietly(binary); @@ -186,8 +198,7 @@ public class DefaultImageManager implements CmsImageManager { } @Override - public String uploadImage(Node context, Node parentNode, String fileName, InputStream in, String contentType) - throws RepositoryException { + public String uploadImage(Node context, Node parentNode, String fileName, InputStream in, String contentType) { InputStream inputStream = null; try { String previousResourceName = null; @@ -222,6 +233,8 @@ public class DefaultImageManager implements CmsImageManager { return CmsUiUtils.getDataPath(fileNode); } catch (IOException e) { throw new RuntimeException("Cannot upload image " + fileName + " in " + parentNode, e); + } catch (RepositoryException e) { + throw new JcrException(e); } finally { IOUtils.closeQuietly(inputStream); } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/LoginEntryPoint.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/LoginEntryPoint.java deleted file mode 100644 index 0bbed1d77..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/LoginEntryPoint.java +++ /dev/null @@ -1,191 +0,0 @@ -package org.argeo.cms.ui.util; - -import java.util.Locale; -import java.util.UUID; - -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; - private String uid; - - @Override - public int createUI() { - uid = UUID.randomUUID().toString(); - final Display display = createDisplay(); -// UiContext.setData(CmsView.KEY, this); - - CmsLoginShell loginShell = createCmsLoginShell(); - CmsView.registerCmsView(loginShell.getShell(), this); - 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 not - * 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 String getUid() { - return uid; - } - - @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 diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/MenuLink.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/MenuLink.java index d58143659..284d2bd0c 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/MenuLink.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/MenuLink.java @@ -1,6 +1,6 @@ package org.argeo.cms.ui.util; -import org.argeo.cms.ui.CmsStyles; +import org.argeo.cms.swt.CmsStyles; /** * Convenience class setting the custom style {@link CmsStyles#CMS_MENU_LINK} on diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java index 04ce5a290..e8bf66297 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java @@ -7,7 +7,8 @@ import javax.jcr.Node; import javax.jcr.RepositoryException; import org.argeo.cms.CmsException; -import org.argeo.cms.ui.CmsStyles; +import org.argeo.cms.swt.CmsStyles; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.CmsUiProvider; import org.eclipse.rap.rwt.RWT; import org.eclipse.swt.SWT; @@ -29,7 +30,7 @@ public class SimpleCmsHeader implements CmsUiProvider { 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))); + header.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, false))); configurePart(context, header, lead); configurePart(context, header, center); @@ -58,7 +59,7 @@ public class SimpleCmsHeader implements CmsUiProvider { 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))); + part.setLayout(CmsSwtUtils.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)); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java index d394f23ac..63e504b7a 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java @@ -3,7 +3,7 @@ package org.argeo.cms.ui.util; import javax.jcr.Node; import javax.jcr.RepositoryException; -import org.argeo.cms.ui.CmsStyles; +import org.argeo.cms.swt.CmsStyles; import org.argeo.cms.ui.CmsUiProvider; import org.eclipse.rap.rwt.RWT; import org.eclipse.swt.SWT; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStyle.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStyle.java index 4bbd19cf9..8ed06a292 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStyle.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStyle.java @@ -1,5 +1,7 @@ package org.argeo.cms.ui.util; +import org.argeo.api.cms.CmsStyle; + /** Simple styles used by the CMS UI utilities. */ public enum SimpleStyle implements CmsStyle { link; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleUxContext.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleUxContext.java deleted file mode 100644 index f85a1ab53..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleUxContext.java +++ /dev/null @@ -1,50 +0,0 @@ -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; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SystemNotifications.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SystemNotifications.java index f53e55262..156a6082f 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SystemNotifications.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SystemNotifications.java @@ -9,7 +9,8 @@ import java.util.Date; import org.apache.commons.io.IOUtils; import org.argeo.cms.CmsException; -import org.argeo.cms.ui.CmsStyles; +import org.argeo.cms.swt.CmsStyles; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.rap.rwt.RWT; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; @@ -89,7 +90,7 @@ public class SystemNotifications extends Shell implements CmsStyles, .append(e.getMessage()); } Label mailTo = new Label(pane, SWT.NONE); - CmsUiUtils.markup(mailTo); + CmsSwtUtils.markup(mailTo); mailTo.setText("Send details"); mailTo.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenu.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenu.java index 07b60696b..316cb51c0 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenu.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenu.java @@ -3,7 +3,7 @@ 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.argeo.cms.swt.auth.CmsLoginShell; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenuLink.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenuLink.java index cc470e414..317a7b55b 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenuLink.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenuLink.java @@ -4,8 +4,8 @@ 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.argeo.cms.swt.CmsStyles; +import org.argeo.cms.swt.auth.CmsLoginShell; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MouseEvent; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/VerticalMenu.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/VerticalMenu.java index e7dfb4b88..7f846c932 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/VerticalMenu.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/VerticalMenu.java @@ -6,6 +6,7 @@ import java.util.List; import javax.jcr.Node; import javax.jcr.RepositoryException; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.CmsUiProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; @@ -20,7 +21,7 @@ public class VerticalMenu implements CmsUiProvider { 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()); + part.setLayout(CmsSwtUtils.noSpaceGridLayout()); for (CmsUiProvider uiProvider : items) { Control subPart = uiProvider.createUi(part, context); subPart.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false)); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java index e5ae67a79..60cb22843 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java @@ -13,7 +13,7 @@ import javax.security.auth.Subject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.cms.ui.CmsEditable; +import org.argeo.api.cms.CmsEditable; import org.argeo.cms.ui.widgets.ScrolledPage; import org.argeo.jcr.JcrException; import org.eclipse.jface.viewers.ContentViewer; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java index dfd143829..11162e87f 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java @@ -8,8 +8,8 @@ import javax.jcr.Session; import javax.jcr.nodetype.NodeType; import javax.jcr.version.VersionManager; +import org.argeo.api.cms.CmsEditable; 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; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java index 88585e185..d282eebbe 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java @@ -7,7 +7,7 @@ import java.util.Map; import javax.jcr.Node; import javax.jcr.RepositoryException; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.widgets.JcrComposite; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; @@ -38,7 +38,7 @@ public class Section extends JcrComposite { } else { relativeDepth = 0; } - setLayout(CmsUiUtils.noSpaceGridLayout()); + setLayout(CmsSwtUtils.noSpaceGridLayout()); } catch (RepositoryException e) { throw new IllegalStateException("Cannot create section from " + node, e); } @@ -78,8 +78,8 @@ public class Section extends JcrComposite { sectionHeader.dispose(); sectionHeader = new Composite(parent, SWT.NONE); - sectionHeader.setLayoutData(CmsUiUtils.fillWidth()); - sectionHeader.setLayout(CmsUiUtils.noSpaceGridLayout()); + sectionHeader.setLayoutData(CmsSwtUtils.fillWidth()); + sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout()); // sectionHeader.moveAbove(null); // layout(); return sectionHeader; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java index f8ca531c3..7bc0f79b5 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java @@ -1,6 +1,6 @@ package org.argeo.cms.ui.widgets; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; @@ -24,7 +24,7 @@ public class ContextOverlay extends ScrolledPage { public ContextOverlay(Control control, int style) { super(createShell(control, style), SWT.NONE); Shell shell = getShell(); - setLayoutData(CmsUiUtils.fillAll()); + setLayoutData(CmsSwtUtils.fillAll()); // TODO make autohide configurable? //shell.addShellListener(new AutoHideShellListener()); this.control = control; @@ -40,10 +40,10 @@ public class ContextOverlay extends ScrolledPage { if (control.isDisposed()) throw new IllegalArgumentException("Control is disposed"); Shell shell = new Shell(control.getShell(), SWT.NO_TRIM); - shell.setLayout(CmsUiUtils.noSpaceGridLayout()); + shell.setLayout(CmsSwtUtils.noSpaceGridLayout()); Composite placeholder = new Composite(shell, SWT.BORDER); - placeholder.setLayoutData(CmsUiUtils.fillAll()); - placeholder.setLayout(CmsUiUtils.noSpaceGridLayout()); + placeholder.setLayoutData(CmsSwtUtils.fillAll()); + placeholder.setLayout(CmsSwtUtils.noSpaceGridLayout()); return placeholder; } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableImage.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableImage.java index 0a327cd51..e5f269a40 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableImage.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableImage.java @@ -5,6 +5,8 @@ import javax.jcr.RepositoryException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.api.cms.Cms2DSize; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.util.CmsUiUtils; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; @@ -17,21 +19,19 @@ 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 Cms2DSize preferredImageSize; private Boolean loaded = false; public EditableImage(Composite parent, int swtStyle) { super(parent, swtStyle); } - public EditableImage(Composite parent, int swtStyle, - Point preferredImageSize) { + public EditableImage(Composite parent, int swtStyle, Cms2DSize preferredImageSize) { super(parent, swtStyle); this.preferredImageSize = preferredImageSize; } - public EditableImage(Composite parent, int style, Node node, - boolean cacheImmediately, Point preferredImageSize) + public EditableImage(Composite parent, int style, Node node, boolean cacheImmediately, Cms2DSize preferredImageSize) throws RepositoryException { super(parent, style, node, cacheImmediately); this.preferredImageSize = preferredImageSize; @@ -49,15 +49,15 @@ public abstract class EditableImage extends StyledControl { /** To be overriden. */ protected String createImgTag() throws RepositoryException { - return CmsUiUtils.noImg(preferredImageSize != null ? preferredImageSize - : getSize()); + return CmsUiUtils + .noImg(preferredImageSize != null ? preferredImageSize : new Cms2DSize(getSize().x, getSize().y)); } protected Label createLabel(Composite box, String style) { Label lbl = new Label(box, getStyle()); // lbl.setLayoutData(CmsUiUtils.fillWidth()); - CmsUiUtils.markup(lbl); - CmsUiUtils.style(lbl, style); + CmsSwtUtils.markup(lbl); + CmsSwtUtils.style(lbl, style); if (mouseListener != null) lbl.addMouseListener(mouseListener); load(lbl); @@ -83,7 +83,8 @@ public abstract class EditableImage extends StyledControl { loaded = true; if (control != null) { ((Label) control).setText(imgTag); - control.setSize(preferredImageSize != null ? preferredImageSize + control.setSize(preferredImageSize != null + ? new Point(preferredImageSize.getWidth(), preferredImageSize.getHeight()) : getSize()); } else { loaded = false; @@ -92,7 +93,7 @@ public abstract class EditableImage extends StyledControl { return loaded; } - public void setPreferredSize(Point size) { + public void setPreferredSize(Cms2DSize size) { this.preferredImageSize = size; if (!loaded) { load((Label) getControl()); @@ -101,11 +102,11 @@ public abstract class EditableImage extends StyledControl { protected Text createText(Composite box, String style) { Text text = new Text(box, getStyle()); - CmsUiUtils.style(text, style); + CmsSwtUtils.style(text, style); return text; } - public Point getPreferredImageSize() { + public Cms2DSize getPreferredImageSize() { return preferredImageSize; } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableText.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableText.java index 27b7c9b10..e3499ac4b 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableText.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableText.java @@ -3,7 +3,7 @@ package org.argeo.cms.ui.widgets; import javax.jcr.Item; import javax.jcr.RepositoryException; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; @@ -54,10 +54,10 @@ public class EditableText extends StyledControl { protected Label createLabel(Composite box, String style) { Label lbl = new Label(box, getStyle() | SWT.WRAP); - lbl.setLayoutData(CmsUiUtils.fillWidth()); + lbl.setLayoutData(CmsSwtUtils.fillWidth()); if (style != null) - CmsUiUtils.style(lbl, style); - CmsUiUtils.markup(lbl); + CmsSwtUtils.style(lbl, style); + CmsSwtUtils.markup(lbl); if (mouseListener != null) lbl.addMouseListener(mouseListener); return lbl; @@ -66,10 +66,10 @@ public class EditableText extends StyledControl { protected Text createTextLabel(Composite box, String style) { Text lbl = new Text(box, getStyle() | SWT.MULTI); lbl.setEditable(false); - lbl.setLayoutData(CmsUiUtils.fillWidth()); + lbl.setLayoutData(CmsSwtUtils.fillWidth()); if (style != null) - CmsUiUtils.style(lbl, style); - CmsUiUtils.markup(lbl); + CmsSwtUtils.style(lbl, style); + CmsSwtUtils.markup(lbl); if (mouseListener != null) lbl.addMouseListener(mouseListener); return lbl; @@ -85,11 +85,11 @@ public class EditableText extends StyledControl { final Text text = new Text(box, getStyle() | SWT.MULTI | SWT.WRAP); text.setEditable(editable); - GridData textLayoutData = CmsUiUtils.fillWidth(); + GridData textLayoutData = CmsSwtUtils.fillWidth(); // textLayoutData.heightHint = preferredHeight; text.setLayoutData(textLayoutData); if (style != null) - CmsUiUtils.style(text, style); + CmsSwtUtils.style(text, style); text.setFocus(); return text; } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/Img.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/Img.java index fb1091a02..3a4a60c9f 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/Img.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/Img.java @@ -3,10 +3,10 @@ package org.argeo.cms.ui.widgets; import javax.jcr.Node; import javax.jcr.RepositoryException; -import org.argeo.cms.ui.CmsImageManager; -import org.argeo.cms.ui.CmsView; +import org.argeo.api.cms.Cms2DSize; +import org.argeo.api.cms.CmsImageManager; +import org.argeo.cms.swt.CmsSwtUtils; 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; @@ -20,7 +20,6 @@ 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; @@ -30,11 +29,11 @@ public class Img extends EditableImage implements SectionPart, NodePart { private final Section section; - private final CmsImageManager imageManager; + private final CmsImageManager imageManager; private FileUploadHandler currentUploadHandler = null; private FileUploadListener fileUploadListener; - public Img(Composite parent, int swtStyle, Node imgNode, Point preferredImageSize) throws RepositoryException { + public Img(Composite parent, int swtStyle, Node imgNode, Cms2DSize preferredImageSize) throws RepositoryException { this(Section.findSection(parent), parent, swtStyle, imgNode, preferredImageSize, null); setStyle(TextStyles.TEXT_IMAGE); } @@ -44,17 +43,19 @@ public class Img extends EditableImage implements SectionPart, NodePart { setStyle(TextStyles.TEXT_IMAGE); } - public Img(Composite parent, int swtStyle, Node imgNode, CmsImageManager imageManager) throws RepositoryException { + public Img(Composite parent, int swtStyle, Node imgNode, CmsImageManager imageManager) + throws RepositoryException { this(Section.findSection(parent), parent, swtStyle, imgNode, null, imageManager); setStyle(TextStyles.TEXT_IMAGE); } - Img(Section section, Composite parent, int swtStyle, Node imgNode, Point preferredImageSize, - CmsImageManager imageManager) throws RepositoryException { + Img(Section section, Composite parent, int swtStyle, Node imgNode, Cms2DSize preferredImageSize, + CmsImageManager imageManager) throws RepositoryException { super(parent, swtStyle, imgNode, false, preferredImageSize); this.section = section; - this.imageManager = imageManager != null ? imageManager : CmsView.getCmsView(section).getImageManager(); - CmsUiUtils.style(this, TextStyles.TEXT_IMG); + this.imageManager = imageManager != null ? imageManager + : (CmsImageManager) CmsSwtUtils.getCmsView(section).getImageManager(); + CmsSwtUtils.style(this, TextStyles.TEXT_IMG); } @Override @@ -78,14 +79,10 @@ public class Img extends EditableImage implements SectionPart, NodePart { @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 JcrException("Cannot load " + getNodeId() + " from image manager", e); - } + Node imgNode = getNode(); + boolean loaded = imageManager.load(imgNode, lbl, getPreferredImageSize()); + // getParent().layout(); + return loaded; } protected Node getUploadFolder() { @@ -97,7 +94,7 @@ public class Img extends EditableImage implements SectionPart, NodePart { return Jcr.getName(node) + '[' + Jcr.getIndex(node) + ']'; } - protected CmsImageManager getImageManager() { + protected CmsImageManager getImageManager() { return imageManager; } @@ -109,7 +106,7 @@ public class Img extends EditableImage implements SectionPart, NodePart { currentUploadHandler = prepareUpload(receiver); final ServerPushSession pushSession = new ServerPushSession(); final FileUpload fileUpload = new FileUpload(box, SWT.NONE); - CmsUiUtils.style(fileUpload, style); + CmsSwtUtils.style(fileUpload, style); fileUpload.addSelectionListener(new SelectionAdapter() { private static final long serialVersionUID = -9158471843941668562L; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java index 2d394c6f8..5d3576f27 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java @@ -7,7 +7,7 @@ import javax.jcr.Property; import javax.jcr.RepositoryException; import javax.jcr.Session; -import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.jcr.JcrException; import org.eclipse.swt.widgets.Composite; @@ -57,7 +57,7 @@ public class JcrComposite extends Composite { if (cacheImmediately) this.cache = node; // } - setLayout(CmsUiUtils.noSpaceGridLayout()); + setLayout(CmsSwtUtils.noSpaceGridLayout()); } catch (RepositoryException e) { throw new IllegalStateException("Cannot create composite from " + item, e); } diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java index b413faf3e..84e4cce86 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java @@ -2,8 +2,8 @@ package org.argeo.cms.ui.widgets; import javax.jcr.Item; +import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.ui.CmsConstants; -import org.argeo.cms.ui.util.CmsUiUtils; import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusListener; @@ -28,7 +28,7 @@ public abstract class StyledControl extends JcrComposite implements CmsConstants public StyledControl(Composite parent, int swtStyle) { super(parent, swtStyle); - setLayout(CmsUiUtils.noSpaceGridLayout()); + setLayout(CmsSwtUtils.noSpaceGridLayout()); } public StyledControl(Composite parent, int style, Item item) { @@ -44,14 +44,14 @@ public abstract class StyledControl extends JcrComposite implements CmsConstants protected Composite createBox() { Composite box = new Composite(container, SWT.INHERIT_DEFAULT); setContainerLayoutData(box); - box.setLayout(CmsUiUtils.noSpaceGridLayout(3)); + box.setLayout(CmsSwtUtils.noSpaceGridLayout(3)); return box; } protected Composite createContainer() { Composite container = new Composite(this, SWT.INHERIT_DEFAULT); setContainerLayoutData(container); - container.setLayout(CmsUiUtils.noSpaceGridLayout()); + container.setLayout(CmsSwtUtils.noSpaceGridLayout()); return container; } @@ -104,19 +104,19 @@ public abstract class StyledControl extends JcrComposite implements CmsConstants refreshControl(style); if (style != null) { - CmsUiUtils.style(box, style + "_box"); - CmsUiUtils.style(container, style + "_container"); + CmsSwtUtils.style(box, style + "_box"); + CmsSwtUtils.style(container, style + "_container"); } } /** To be overridden */ protected void setControlLayoutData(Control control) { - control.setLayoutData(CmsUiUtils.fillWidth()); + control.setLayoutData(CmsSwtUtils.fillWidth()); } /** To be overridden */ protected void setContainerLayoutData(Composite composite) { - composite.setLayoutData(CmsUiUtils.fillWidth()); + composite.setLayoutData(CmsSwtUtils.fillWidth()); } protected void clear(boolean deep) { diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/AbstractLoginDialog.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/AbstractLoginDialog.java deleted file mode 100644 index e7998cf2d..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/AbstractLoginDialog.java +++ /dev/null @@ -1,183 +0,0 @@ -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"); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CmsLogin.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CmsLogin.java deleted file mode 100644 index 51c0ab4f5..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CmsLogin.java +++ /dev/null @@ -1,335 +0,0 @@ -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 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); - } - } - - public 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(true, true); - 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 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.toLead(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; - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CmsLoginShell.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CmsLoginShell.java deleted file mode 100644 index f260f83e6..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CmsLoginShell.java +++ /dev/null @@ -1,72 +0,0 @@ -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(); -// 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() { - CmsUiUtils.style(shell, CMS_USER_MENU); - 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); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CompositeCallbackHandler.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CompositeCallbackHandler.java deleted file mode 100644 index 974b6765b..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/CompositeCallbackHandler.java +++ /dev/null @@ -1,273 +0,0 @@ -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:
- *
    - *
  • {@link PasswordCallback}
  • - *
  • {@link NameCallback}
  • - *
  • {@link TextOutputCallback}
  • - *
- * Supported Argeo {@link Callback}s are:
- *
    - *
  • {@link LocaleChoice}
  • - *
- */ -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(); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/DefaultLoginDialog.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/DefaultLoginDialog.java deleted file mode 100644 index 6ffc2efbd..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/DefaultLoginDialog.java +++ /dev/null @@ -1,61 +0,0 @@ -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() { - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/DynamicCallbackHandler.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/DynamicCallbackHandler.java deleted file mode 100644 index e470bda0b..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/DynamicCallbackHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -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(); - } - -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/LocaleChoice.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/LocaleChoice.java deleted file mode 100644 index 677c879e9..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/LocaleChoice.java +++ /dev/null @@ -1,86 +0,0 @@ -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 locales; - - private Integer selectedIndex = null; - private final Integer defaultIndex; - - public LocaleChoice(List 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 getLocales() { - return locales; - } - - public Locale getDefaultLocale() { - return locales.get(getDefaultIndex()); - } -} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/package-info.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/package-info.java deleted file mode 100644 index 9a37a584a..000000000 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** Argeo CMS authentication widgets, based on SWT. */ -package org.argeo.cms.ui.widgets.auth; \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/AbstractCmsApp.java b/org.argeo.cms/src/org/argeo/cms/AbstractCmsApp.java new file mode 100644 index 000000000..a7049a4f4 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/AbstractCmsApp.java @@ -0,0 +1,69 @@ +package org.argeo.cms; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.argeo.api.cms.CmsApp; +import org.argeo.api.cms.CmsAppListener; +import org.argeo.api.cms.CmsTheme; + +/** Base class for {@link CmsApp}s. */ +public abstract class AbstractCmsApp implements CmsApp { + private Map themes = Collections.synchronizedMap(new HashMap<>()); + + private List cmsAppListeners = new ArrayList<>(); + + protected abstract String getThemeId(String uiName); + + @Override + public CmsTheme getTheme(String uiName) { + String themeId = getThemeId(uiName); + if (themeId == null) + return null; + if (!themes.containsKey(themeId)) + throw new IllegalArgumentException("Theme " + themeId + " not found."); + return themes.get(themeId); + } + + @Override + public boolean allThemesAvailable() { + boolean themeMissing = false; + uiNames: for (String uiName : getUiNames()) { + String themeId = getThemeId(uiName); + if ("org.eclipse.rap.rwt.theme.Default".equals(themeId)) + continue uiNames; + if (!themes.containsKey(themeId)) { + themeMissing = true; + break uiNames; + } + } + return !themeMissing; + } + + public void addTheme(CmsTheme theme, Map properties) { + themes.put(theme.getThemeId(), theme); + if (allThemesAvailable()) + for (CmsAppListener listener : cmsAppListeners) + listener.themingUpdated(); + } + + public void removeTheme(CmsTheme theme, Map properties) { + themes.remove(theme.getThemeId()); + } + + @Override + public void addCmsAppListener(CmsAppListener listener) { + cmsAppListeners.add(listener); + if (allThemesAvailable()) + listener.themingUpdated(); + } + + @Override + public void removeCmsAppListener(CmsAppListener listener) { + cmsAppListeners.remove(listener); + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java index 4c09650d4..e854f5adf 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java @@ -14,6 +14,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.argeo.api.NodeConstants; +import org.argeo.api.cms.CmsSession; +import org.argeo.api.cms.CmsSessionId; import org.argeo.api.security.AnonymousPrincipal; import org.argeo.api.security.DataAdminPrincipal; import org.argeo.api.security.NodeSecurityUtils; @@ -186,7 +188,7 @@ class CmsAuthUtils { } } - public static CmsSession cmsSessionFromHttpSession(BundleContext bc, String httpSessionId) { + public static CmsSessionImpl cmsSessionFromHttpSession(BundleContext bc, String httpSessionId) { Authorization authorization = null; Collection> sr; try { @@ -195,9 +197,9 @@ class CmsAuthUtils { } catch (InvalidSyntaxException e) { throw new IllegalArgumentException("Cannot get CMS session for id " + httpSessionId, e); } - CmsSession cmsSession; + CmsSessionImpl cmsSession; if (sr.size() == 1) { - cmsSession = bc.getService(sr.iterator().next()); + cmsSession = (CmsSessionImpl) bc.getService(sr.iterator().next()); // locale = cmsSession.getLocale(); authorization = cmsSession.getAuthorization(); if (authorization.getName() == null) diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CmsSession.java b/org.argeo.cms/src/org/argeo/cms/auth/CmsSession.java deleted file mode 100644 index ad91cb7f0..000000000 --- a/org.argeo.cms/src/org/argeo/cms/auth/CmsSession.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.argeo.cms.auth; - -import java.time.ZonedDateTime; -import java.util.Collection; -import java.util.Locale; -import java.util.UUID; - -import javax.naming.ldap.LdapName; -import javax.security.auth.Subject; - -import org.argeo.naming.LdapAttrs; -import org.osgi.framework.BundleContext; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceReference; -import org.osgi.service.useradmin.Authorization; - -/** An authenticated user session. */ -public interface CmsSession { - final static String USER_DN = LdapAttrs.DN; - final static String SESSION_UUID = LdapAttrs.entryUUID.name(); - final static String SESSION_LOCAL_ID = LdapAttrs.uniqueIdentifier.name(); - - UUID getUuid(); - - String getUserRole(); - - LdapName getUserDn(); - - String getLocalId(); - - Authorization getAuthorization(); - - Subject getSubject(); - - boolean isAnonymous(); - - ZonedDateTime getCreationTime(); - - ZonedDateTime getEnd(); - - Locale getLocale(); - - boolean isValid(); - - void registerView(String uid, Object view); - - /** @return The {@link CmsSession} for this {@link Subject} or null. */ - static CmsSession getCmsSession(BundleContext bc, Subject subject) { - if (subject.getPrivateCredentials(CmsSessionId.class).isEmpty()) - return null; - CmsSessionId cmsSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next(); - String uuid = cmsSessionId.getUuid().toString(); - Collection> sr; - try { - sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + uuid + ")"); - } catch (InvalidSyntaxException e) { - throw new IllegalArgumentException("Cannot get CMS session for uuid " + uuid, e); - } - ServiceReference cmsSessionRef; - if (sr.size() == 1) { - cmsSessionRef = sr.iterator().next(); - return bc.getService(cmsSessionRef); - } else if (sr.size() == 0) { - return null; - } else - throw new IllegalStateException(sr.size() + " CMS sessions registered for " + uuid); - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CmsSessionId.java b/org.argeo.cms/src/org/argeo/cms/auth/CmsSessionId.java deleted file mode 100644 index cc435aeb8..000000000 --- a/org.argeo.cms/src/org/argeo/cms/auth/CmsSessionId.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.argeo.cms.auth; - -import java.util.UUID; - -import javax.security.auth.Subject; - -/** - * The ID of a {@link CmsSession}, which must be available in the private - * credentials of an authenticated {@link Subject}. - */ -public class CmsSessionId { - private final UUID uuid; - - public CmsSessionId(UUID value) { - if (value == null) - throw new IllegalArgumentException("Value cannot be null"); - this.uuid = value; - } - - public UUID getUuid() { - return uuid; - } - - @Override - public int hashCode() { - return uuid.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof CmsSessionId && ((CmsSessionId) obj).getUuid().equals(uuid); - } - - @Override - public String toString() { - return "Node Session " + uuid; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java b/org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java index eaaf41ab7..9808305ce 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java @@ -14,6 +14,8 @@ import javax.security.auth.Subject; import javax.security.auth.x500.X500Principal; import org.argeo.api.NodeConstants; +import org.argeo.api.cms.CmsSession; +import org.argeo.api.cms.CmsSessionId; import org.argeo.cms.internal.auth.CmsSessionImpl; import org.argeo.cms.internal.auth.ImpliedByPrincipal; import org.argeo.cms.internal.kernel.Activator; diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java index 8cb524fbe..c2dfead78 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.cms.internal.auth.CmsSessionImpl; import org.argeo.cms.internal.kernel.Activator; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; @@ -73,7 +74,7 @@ public class HttpSessionLoginModule implements LoginModule { String httpSessionId = httpSession.getId(); if (log.isTraceEnabled()) log.trace("HTTP login: " + request.getPathInfo() + " #" + httpSessionId); - CmsSession cmsSession = CmsAuthUtils.cmsSessionFromHttpSession(bc, httpSessionId); + CmsSessionImpl cmsSession = CmsAuthUtils.cmsSessionFromHttpSession(bc, httpSessionId); if (cmsSession != null) { authorization = cmsSession.getAuthorization(); locale = cmsSession.getLocale(); @@ -93,7 +94,7 @@ public class HttpSessionLoginModule implements LoginModule { String httpSessionId = httpSession.getId(); if (log.isTraceEnabled()) log.trace("HTTP login: " + request.getPathInfo() + " #" + httpSessionId); - CmsSession cmsSession = CmsAuthUtils.cmsSessionFromHttpSession(bc, httpSessionId); + CmsSessionImpl cmsSession = CmsAuthUtils.cmsSessionFromHttpSession(bc, httpSessionId); if (cmsSession != null) { authorization = cmsSession.getAuthorization(); locale = cmsSession.getLocale(); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java index 734b874ef..4e9b4e072 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java @@ -24,8 +24,8 @@ import javax.security.auth.x500.X500Principal; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.api.NodeConstants; +import org.argeo.api.cms.CmsSession; import org.argeo.api.security.NodeSecurityUtils; -import org.argeo.cms.auth.CmsSession; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; @@ -93,7 +93,6 @@ public class CmsSessionImpl implements CmsSession, Serializable { end = ZonedDateTime.now(); serviceRegistration.unregister(); - try { LoginContext lc; if (isAnonymous()) { @@ -133,12 +132,16 @@ public class CmsSessionImpl implements CmsSession, Serializable { return getEnd() != null; } - @Override public Authorization getAuthorization() { checkValid(); return authorization; } + @Override + public String getDisplayName() { + return authorization.toString(); + } + @Override public UUID getUuid() { return uuid; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/PkgServlet.java b/org.argeo.cms/src/org/argeo/cms/internal/http/PkgServlet.java index e12456ebb..26046b246 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/http/PkgServlet.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/http/PkgServlet.java @@ -13,7 +13,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; -import org.argeo.api.PublishNamespace; +import org.argeo.cms.osgi.PublishNamespace; import org.argeo.osgi.util.FilterRequirement; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java index 8c9e4ba6c..f29d9e98e 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java @@ -16,7 +16,7 @@ import java.util.TreeMap; import java.util.TreeSet; import org.apache.commons.logging.Log; -import org.argeo.api.DataModelNamespace; +import org.argeo.cms.osgi.DataModelNamespace; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/BundleCmsTheme.java b/org.argeo.cms/src/org/argeo/cms/osgi/BundleCmsTheme.java new file mode 100644 index 000000000..75a2212b6 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/osgi/BundleCmsTheme.java @@ -0,0 +1,360 @@ +package org.argeo.cms.osgi; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import org.apache.commons.io.IOUtils; +import org.argeo.api.cms.CmsTheme; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; + +/** + * Simplifies the theming of an app (only RAP is supported at this stage).
+ * + * Additional fonts listed in /fonts.txt.
+ * Additional (standard CSS) header in /header.css.
+ * RAP specific CSS files in /rap/*.css.
+ * All images added as additional resources based on extensions + * / ** /*.{png,gif,jpeg,...}.
+ */ +public class BundleCmsTheme implements CmsTheme { + public final static String DEFAULT_CMS_THEME_BUNDLE = "org.argeo.theme.argeo2"; + + public final static String CMS_THEME_PROPERTY = "argeo.cms.theme"; + public final static String CMS_THEME_BUNDLE_PROPERTY = "argeo.cms.theme.bundle"; + + private final static String HEADER_CSS = "header.css"; + private final static String FONTS_TXT = "fonts.txt"; + private final static String BODY_HTML = "body.html"; + +// private final static Log log = LogFactory.getLog(BundleCmsTheme.class); + + private String themeId; + private Set webCssPaths = new TreeSet<>(); + private Set rapCssPaths = new TreeSet<>(); + private Set swtCssPaths = new TreeSet<>(); + private Set imagesPaths = new TreeSet<>(); + private Set fontsPaths = new TreeSet<>(); + + private String headerCss; + private List fonts = new ArrayList<>(); + + private String bodyHtml=""; + + private String basePath; + private String styleCssPath; +// private String webCssPath; +// private String rapCssPath; +// private String swtCssPath; + private Bundle themeBundle; + + private Integer defaultIconSize = 16; + + public BundleCmsTheme() { + + } + + public void init(BundleContext bundleContext, Map properties) { + initResources(bundleContext, null); + } + + public void destroy(BundleContext bundleContext, Map properties) { + + } + + @Deprecated + public BundleCmsTheme(BundleContext bundleContext) { + this(bundleContext, null); + } + + @Deprecated + public BundleCmsTheme(BundleContext bundleContext, String symbolicName) { + initResources(bundleContext, symbolicName); + } + + private void initResources(BundleContext bundleContext, String symbolicName) { + if (symbolicName == null) { + themeBundle = bundleContext.getBundle(); +// basePath = "/theme/"; +// cssPath = basePath; + } else { + themeBundle = findThemeBundle(bundleContext, symbolicName); + } + basePath = "/"; + styleCssPath = "/style/"; +// webCssPath = "/css/"; +// rapCssPath = "/rap/"; +// swtCssPath = "/swt/"; +// this.themeId = RWT.DEFAULT_THEME_ID; + this.themeId = themeBundle.getSymbolicName(); + webCssPaths = addCss(themeBundle, "/css/"); + rapCssPaths = addCss(themeBundle, "/rap/"); + swtCssPaths = addCss(themeBundle, "/swt/"); + addImages("*.png"); + addImages("*.gif"); + addImages("*.jpg"); + addImages("*.jpeg"); + addImages("*.svg"); + addImages("*.ico"); + + addFonts("*.woff"); + addFonts("*.woff2"); + + // 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) { + // added to plain Web CSS + webCssPaths.add(basePath + HEADER_CSS); + // and it will also be used by RAP: + try (BufferedReader buffer = new BufferedReader(new InputStreamReader(headerCssUrl.openStream(), UTF_8))) { + headerCss = buffer.lines().collect(Collectors.joining("\n")); + } catch (IOException e) { + throw new IllegalArgumentException("Cannot read " + headerCssUrl, e); + } + } + + // body + URL bodyUrl = themeBundle.getEntry(basePath + BODY_HTML); + if (bodyUrl != null) { + loadBodyHtml(bodyUrl); + } +} + + public String getHtmlHeaders() { + StringBuilder sb = new StringBuilder(); + if (headerCss != null) { + sb.append("\n"); + } + for (String link : fonts) { + sb.append("\n"); + } + if (sb.length() == 0) + return null; + else + return sb.toString(); + } + + + + @Override + public String getBodyHtml() { + return bodyHtml; + } + + Set addCss(Bundle themeBundle, String path) { + Set paths = new TreeSet<>(); + + // common CSS + Enumeration commonResources = themeBundle.findEntries(styleCssPath, "*.css", true); + if (commonResources != null) { + while (commonResources.hasMoreElements()) { + String resource = commonResources.nextElement().getPath(); + // remove first '/' so that RWT registers it + resource = resource.substring(1); + if (!resource.endsWith("/")) { + paths.add(resource); + } + } + } + + // specific CSS + Enumeration themeResources = themeBundle.findEntries(path, "*.css", true); + if (themeResources != null) { + while (themeResources.hasMoreElements()) { + String resource = themeResources.nextElement().getPath(); + // remove first '/' so that RWT registers it + resource = resource.substring(1); + if (!resource.endsWith("/")) { + paths.add(resource); + } + } + } + return paths; + } + + 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 IllegalArgumentException("Cannot load URL " + url, e); + } + } + + void loadBodyHtml(URL url) { + try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) { + bodyHtml= IOUtils.toString(url,StandardCharsets.UTF_8); + } catch (IOException e) { + throw new IllegalArgumentException("Cannot load URL " + url, e); + } + } + + void addImages(String pattern) { + Enumeration 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); + imagesPaths.add(resource); + } + + } + + } + + void addFonts(String pattern) { + Enumeration 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); + fontsPaths.add(resource); + } + + } + + } + + @Override + public InputStream getResourceAsStream(String resourceName) throws IOException { + URL res = themeBundle.getEntry(resourceName); + if (res == null) { + res = themeBundle.getResource(resourceName); + if (res == null) + return null; +// throw new IllegalArgumentException( +// "Resource " + resourceName + " not found in bundle " + themeBundle.getSymbolicName()); + } + return res.openStream(); + } + + 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 getRapCssPath() { +// return rapCssPath; +// } +// +// public void setRapCssPath(String cssPath) { +// this.rapCssPath = cssPath; +// } + + @Override + public Set getWebCssPaths() { + return webCssPaths; + } + + @Override + public Set getRapCssPaths() { + return rapCssPaths; + } + + @Override + public Set getSwtCssPaths() { + return swtCssPaths; + } + + @Override + public Set getImagesPaths() { + return imagesPaths; + } + + @Override + public Set getFontsPaths() { + return fontsPaths; + } + + @Override + public Integer getDefaultIconSize() { + return defaultIconSize; + } + + @Override + public InputStream loadPath(String path) throws IOException { + URL url = themeBundle.getResource(path); + if (url == null) + throw new IllegalArgumentException( + "Path " + path + " not found in bundle " + themeBundle.getSymbolicName()); + return url.openStream(); + } + + private 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; + } + + @Override + public int hashCode() { + return themeId.hashCode(); + } + + @Override + public String toString() { + return "Bundle CMS Theme " + themeId; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/CmsOsgiUtils.java b/org.argeo.cms/src/org/argeo/cms/osgi/CmsOsgiUtils.java new file mode 100644 index 000000000..424d62f68 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/osgi/CmsOsgiUtils.java @@ -0,0 +1,40 @@ +package org.argeo.cms.osgi; + +import java.util.Collection; + +import javax.security.auth.Subject; + +import org.argeo.api.cms.CmsSession; +import org.argeo.api.cms.CmsSessionId; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; + +public class CmsOsgiUtils { + + /** @return The {@link CmsSession} for this {@link Subject} or null. */ + public static CmsSession getCmsSession(BundleContext bc, Subject subject) { + if (subject.getPrivateCredentials(CmsSessionId.class).isEmpty()) + return null; + CmsSessionId cmsSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next(); + String uuid = cmsSessionId.getUuid().toString(); + Collection> sr; + try { + sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + uuid + ")"); + } catch (InvalidSyntaxException e) { + throw new IllegalArgumentException("Cannot get CMS session for uuid " + uuid, e); + } + ServiceReference cmsSessionRef; + if (sr.size() == 1) { + cmsSessionRef = sr.iterator().next(); + return bc.getService(cmsSessionRef); + } else if (sr.size() == 0) { + return null; + } else + throw new IllegalStateException(sr.size() + " CMS sessions registered for " + uuid); + } + + /** Singleton.*/ + private CmsOsgiUtils() { + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/DataModelNamespace.java b/org.argeo.cms/src/org/argeo/cms/osgi/DataModelNamespace.java new file mode 100644 index 000000000..8e07061a0 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/osgi/DataModelNamespace.java @@ -0,0 +1,18 @@ +package org.argeo.cms.osgi; + +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 + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/PublishNamespace.java b/org.argeo.cms/src/org/argeo/cms/osgi/PublishNamespace.java new file mode 100644 index 000000000..606d51f91 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/osgi/PublishNamespace.java @@ -0,0 +1,16 @@ +package org.argeo.cms.osgi; + +import org.osgi.resource.Namespace; + +/** Namespace defining which resources can be published. Typically use to expose icon of scripts to the web. */ +public class PublishNamespace extends Namespace { + + public static final String CMS_PUBLISH_NAMESPACE = "cms.publish"; + public static final String PKG = "pkg"; + public static final String FILE = "file"; + + private PublishNamespace() { + // empty + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/servlet/ServletAuthUtils.java b/org.argeo.cms/src/org/argeo/cms/servlet/ServletAuthUtils.java index 333fa1aa0..67db467ce 100644 --- a/org.argeo.cms/src/org/argeo/cms/servlet/ServletAuthUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/servlet/ServletAuthUtils.java @@ -8,8 +8,9 @@ import java.util.function.Supplier; import javax.security.auth.Subject; import javax.servlet.http.HttpServletRequest; -import org.argeo.cms.auth.CmsSession; +import org.argeo.api.cms.CmsSession; import org.argeo.cms.auth.CurrentUser; +import org.argeo.cms.osgi.CmsOsgiUtils; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.service.http.HttpContext; @@ -59,7 +60,7 @@ public class ServletAuthUtils { public static CmsSession getCmsSession(HttpServletRequest req) { Subject subject = Subject .getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName())); - CmsSession cmsSession = CmsSession.getCmsSession(bundleContext, subject); + CmsSession cmsSession = CmsOsgiUtils.getCmsSession(bundleContext, subject); return cmsSession; } }