org.argeo.util \
org.argeo.api.uuid \
org.argeo.api.acr \
+org.argeo.api.cli \
org.argeo.api.cms \
org.argeo.cms \
org.argeo.cms.sql \
org.argeo.cms.ux \
eclipse/org.argeo.ext.equinox.jetty \
eclipse/org.argeo.cms.servlet \
-eclipse/org.argeo.cms.swt \
-eclipse/org.argeo.cms.e4 \
-rap/org.argeo.cms.ui.rap \
-rap/org.argeo.swt.specific.rap \
-rap/org.argeo.cms.e4.rap \
+swt/org.argeo.cms.swt \
+swt/org.argeo.cms.e4 \
+swt/rap/org.argeo.swt.specific.rap \
+swt/rap/org.argeo.cms.swt.rap \
+swt/rap/org.argeo.cms.swt.rap.cli \
+swt/rap/org.argeo.cms.e4.rap \
jcr/org.argeo.cms.jcr \
jcr/org.argeo.cms.ui \
A2_OUTPUT = $(SDK_BUILD_BASE)/a2
A2_BASE = $(A2_OUTPUT)
-VPATH = .:eclipse:rap:jcr
+VPATH = .:eclipse:rap:jcr:swt:swt/rap
DEP_CATEGORIES = \
org.argeo.tp \
$(MAKE) -C jni clean
$(MAKE) -f Makefile-rcp.mk clean
+A2_BUNDLES_CLASSPATH = $(subst $(space),$(pathsep),$(strip $(A2_BUNDLES)))
+
+native-image:
+ mkdir -p $(A2_OUTPUT)/libexec/$(A2_CATEGORY)
+ cd $(A2_OUTPUT)/libexec/$(A2_CATEGORY) && /opt/graalvm-ce/bin/native-image \
+ -cp $(A2_CLASSPATH):$(A2_BUNDLES_CLASSPATH) org.argeo.eclipse.ui.jetty.CmsRapCli \
+ --enable-url-protocols=http,https \
+ -H:AdditionalSecurityProviders=sun.security.jgss.SunProvider,org.bouncycastle.jce.provider.BouncyCastleProvider,net.i2p.crypto.eddsa.EdDSASecurityProvider \
+ --initialize-at-build-time=org.argeo.init.logging.ThinLogging,org.slf4j.LoggerFactory \
+ --no-fallback
+
+
include $(SDK_SRC_BASE)/sdk/argeo-build/osgi.mk
\ No newline at end of file
A2_CATEGORY = org.argeo.cms.eclipse.rcp
BUNDLES = \
-rcp/org.argeo.cms.e4.rcp \
-rcp/org.argeo.cms.ui.rcp \
rcp/org.argeo.swt.minidesktop \
-rcp/org.argeo.swt.specific.rcp \
+swt/rcp/org.argeo.swt.specific.rcp \
+swt/rcp/org.argeo.cms.swt.rcp \
+swt/rcp/org.argeo.cms.swt.rcp.cli \
+swt/rcp/org.argeo.cms.e4.rcp \
A2_OUTPUT = $(SDK_BUILD_BASE)/a2
A2_BASE = $(A2_OUTPUT)
clean:
rm -rf $(BUILD_BASE)
-VPATH = .:rcp
+VPATH = .:rcp:swt/rcp
include $(SDK_SRC_BASE)/sdk/argeo-build/osgi.mk
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.cms.e4</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default CallbackHandler">
- <implementation class="org.argeo.cms.swt.auth.DynamicCallbackHandler"/>
- <service>
- <provide interface="javax.security.auth.callback.CallbackHandler"/>
- </service>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="Home Repository">
- <implementation class="org.argeo.cms.e4.OsgiFilterContextFunction"/>
- <property name="service.context.key" type="String" value="(cn=home)"/>
- <service>
- <provide interface="org.eclipse.e4.core.contexts.IContextFunction"/>
- </service>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="User Admin Wrapper">
- <implementation class="org.argeo.cms.e4.users.UserAdminWrapper"/>
- <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.util.transaction.WorkTransaction" name="UserTransaction" policy="static"/>
- <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
- <service>
- <provide interface="org.argeo.cms.e4.users.UserAdminWrapper"/>
- </service>
- <reference bind="addUserDirectory" cardinality="0..n" interface="org.argeo.osgi.useradmin.UserDirectory" name="UserDirectory" policy="static" unbind="removeUserDirectory"/>
-</scr:component>
+++ /dev/null
-Service-Component: OSGI-INF/homeRepository.xml,\
-OSGI-INF/userAdminWrapper.xml,\
-OSGI-INF/defaultCallbackHandler.xml
-Bundle-ActivationPolicy: lazy
-
-Import-Package: \
-org.argeo.api.acr,\
-org.eclipse.swt,\
-org.eclipse.swt.widgets;version="0.0.0",\
-org.eclipse.e4.ui.model.application.ui,\
-org.eclipse.e4.ui.model.application,\
-javax.jcr.nodetype,\
-org.argeo.cms,\
-org.eclipse.core.commands.common,\
-org.eclipse.jface.window,\
-org.argeo.cms.swt.auth,\
-org.apache.jackrabbit.*;version="[2,3)",\
-javax.servlet.*;version="[3,5)",\
-*
+++ /dev/null
-output.. = bin/
-bin.includes = META-INF/,\
- OSGI-INF/,\
- .,\
- OSGI-INF/homeRepository.xml,\
- OSGI-INF/userAdminWrapper.xml,\
- OSGI-INF/defaultCallbackHandler.xml,\
- e4xmi/cms-demo.e4xmi
-source.. = src/
+++ /dev/null
-<?xml version="1.0" encoding="ASCII"?>
-<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:advanced="http://www.eclipse.org/ui/2010/UIModel/application/ui/advanced" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_XqkCQKknEeObFrG_clJBYA" elementId="">
- <children xsi:type="basic:TrimmedWindow" xmi:id="_Zdy6cKknEeObFrG_clJBYA" elementId="org.argeo.cms.e4.apps.admin.trimmedwindow.0" label="" x="10" y="10" width="500" height="500">
- <persistedState key="styleOverride" value="8"/>
- <tags>shellMaximized</tags>
- <tags>auth.cn=admin,ou=roles,ou=node</tags>
- <children xsi:type="advanced:PerspectiveStack" xmi:id="_jXVqsCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.perspectivestack.0" selectedElement="_xOVlsDvOEeiF1foPJZSZkw">
- <children xsi:type="advanced:Perspective" xmi:id="_xOVlsDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.perspective.users" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png">
- <tags>auth.cn=admin,ou=roles,ou=node</tags>
- <children xsi:type="basic:PartSashContainer" xmi:id="_1tQoEDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partsashcontainer.2" horizontal="true">
- <children xsi:type="basic:PartStack" xmi:id="_vtbKkDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.4" containerData="4000" selectedElement="_9gukYDvOEeiF1foPJZSZkw">
- <children xsi:type="basic:Part" xmi:id="_9gukYDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.part.users" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.UsersView" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/person.png">
- <handlers xmi:id="_0mN68DvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.4" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.handlers.NewUser" command="_uL5i4DvjEeiF1foPJZSZkw"/>
- <handlers xmi:id="_ODLdgDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.5" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.handlers.DeleteUsers" command="_xkcMADvjEeiF1foPJZSZkw"/>
- <toolbar xmi:id="_jLWmkDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.toolbar.1">
- <children xsi:type="menu:HandledToolItem" xmi:id="_jy_OUDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.new" label="New" iconURI="platform:/plugin/org.argeo.cms.swt/icons/add.png" command="_uL5i4DvjEeiF1foPJZSZkw"/>
- <children xsi:type="menu:HandledToolItem" xmi:id="_9qszMDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/delete.png" command="_xkcMADvjEeiF1foPJZSZkw"/>
- </toolbar>
- </children>
- </children>
- <children xsi:type="basic:PartStack" xmi:id="__g1a8DvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.3" containerData="4000">
- <tags>usersEditorArea</tags>
- </children>
- <children xsi:type="basic:PartStack" xmi:id="_-mFn8DvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.5" containerData="2000">
- <children xsi:type="basic:Part" xmi:id="_6etk4DvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.part.groups" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.GroupsView" label="Groups" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png">
- <handlers xmi:id="_cmShoDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.6" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.handlers.NewGroup" command="_uL5i4DvjEeiF1foPJZSZkw"/>
- <handlers xmi:id="_fbYfcDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.7" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.handlers.DeleteGroups" command="_xkcMADvjEeiF1foPJZSZkw"/>
- <toolbar xmi:id="_Us0rADvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.toolbar.2">
- <children xsi:type="menu:HandledToolItem" xmi:id="_VQTLgDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.new" label="New" iconURI="platform:/plugin/org.argeo.cms.swt/icons/add.png" command="_uL5i4DvjEeiF1foPJZSZkw"/>
- <children xsi:type="menu:HandledToolItem" xmi:id="_XfME8DvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/delete.png" command="_xkcMADvjEeiF1foPJZSZkw"/>
- </toolbar>
- </children>
- </children>
- </children>
- </children>
- <children xsi:type="advanced:Perspective" xmi:id="_jvjWYCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.perspective.data" label="Data" iconURI="platform:/plugin/org.argeo.cms.swt/icons/nodes.gif">
- <children xsi:type="basic:PartSashContainer" xmi:id="_h3tvMCkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partsashcontainer.0" selectedElement="_0B9SECkxEein5vuhpK-Dew" horizontal="true">
- <children xsi:type="basic:PartStack" xmi:id="_0B9SECkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.0" containerData="4000" selectedElement="_WAjPkCkTEein5vuhpK-Dew">
- <children xsi:type="basic:Part" xmi:id="_WAjPkCkTEein5vuhpK-Dew" elementId="org.argeo.cms.e4.jcrbrowser" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR" iconURI="platform:/plugin/org.argeo.cms.swt/icons/browser.gif">
- <menus xsi:type="menu:PopupMenu" xmi:id="_eXiUECqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.popupmenu.nodeViewer">
- <children xsi:type="menu:HandledMenuItem" xmi:id="_GVeO8CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.swt/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_fU238CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_U4o9cCqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.swt/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_Ncxo0CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.remove" label="Remove" iconURI="platform:/plugin/org.argeo.cms.swt/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
- </menus>
- <menus xmi:id="_oRg_ACqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.menu.0">
- <tags>ViewMenu</tags>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_yJR8ECqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.swt/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_o6HQECqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_5D7aACqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.swt/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_7rR2wCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_XsHLgFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledmenuitem.0" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addRepo.gif" command="_ZWpasFgQEeiknZQLx-vtnA"/>
- </menus>
- </children>
- </children>
- <children xsi:type="basic:PartStack" xmi:id="_mHrEUCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.1" containerData="6000">
- <tags>dataExplorer</tags>
- </children>
- </children>
- </children>
- <children xsi:type="advanced:Perspective" xmi:id="_u5ZakFhJEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.perspective.monitoring" label="Monitoring" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif">
- <children xsi:type="basic:PartStack" xmi:id="_7i7t8FhJEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.partstack.6">
- <children xsi:type="basic:Part" xmi:id="_Z-3cMFhbEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.osgiConfigurations" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.OsgiConfigurationsView" label="OSGi Configurations" iconURI="platform:/plugin/org.argeo.cms.swt/icons/node.gif"/>
- <children xsi:type="basic:Part" xmi:id="_8dM90FhJEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.cmsSessions" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.CmsSessionsView" label="CMS Sessions" iconURI="platform:/plugin/org.argeo.cms.swt/icons/person-logged-in.png"/>
- <children xsi:type="basic:Part" xmi:id="_KqRZIFhNEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.modules" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.ModulesView" label="Modules" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif"/>
- <children xsi:type="basic:Part" xmi:id="_dXtIoFhNEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.bundles" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.BundlesView" label="Bundles" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif"/>
- </children>
- </children>
- <children xsi:type="advanced:Perspective" xmi:id="_ABK2ADsNEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.perspective.files" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif">
- <children xsi:type="basic:PartSashContainer" xmi:id="_FPimEDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.partsashcontainer.1" horizontal="true">
- <children xsi:type="basic:PartStack" xmi:id="_H93NgDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.partstack.2" containerData="4000">
- <children xsi:type="basic:Part" xmi:id="_Izxh0DsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.part.files" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.files.NodeFsBrowserView" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif"/>
- </children>
- <children xsi:type="basic:Part" xmi:id="_TMqBMDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.part.0" containerData="6000"/>
- </children>
- </children>
- </children>
- <handlers xmi:id="_Vwax0DvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.8" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.OpenPerspective" command="_AF1UsDvrEeiF1foPJZSZkw"/>
- <trimBars xmi:id="_euVxMCk2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.trimbar.0" side="Left">
- <children xsi:type="menu:ToolBar" xmi:id="_fotHsCk2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.toolbar.0">
- <children xsi:type="menu:HandledToolItem" xmi:id="_jCSQgDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.users" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png" command="_AF1UsDvrEeiF1foPJZSZkw">
- <tags>auth.cn=admin,ou=roles,ou=node</tags>
- <parameters xmi:id="_lu_uYDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.2" name="perspectiveId" value="org.argeo.cms.e4.perspective.users"/>
- </children>
- <children xsi:type="menu:HandledToolItem" xmi:id="_jfUM4Ck2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.handledtoolitem.test" label="Data" iconURI="platform:/plugin/org.argeo.cms.swt/icons/nodes.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
- <parameters xmi:id="_KDlXQDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.0" name="perspectiveId" value="org.argeo.cms.e4.perspective.data"/>
- </children>
- <children xsi:type="menu:HandledToolItem" xmi:id="_dhv80FhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledtoolitem.monitoring" label="Monitoring" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
- <parameters xmi:id="_kjN0cFhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.parameter.3" name="perspectiveId" value="org.argeo.cms.e4.perspective.monitoring"/>
- </children>
- <children xsi:type="menu:HandledToolItem" xmi:id="_b0OHUDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.files" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
- <parameters xmi:id="_fXvRYDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.1" name="perspectiveId" value="org.argeo.cms.e4.perspective.files"/>
- </children>
- <children xsi:type="menu:ToolBarSeparator" xmi:id="_wuoL8FhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.toolbarseparator.0"/>
- <children xsi:type="menu:HandledToolItem" xmi:id="_2v8DkFhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledtoolitem.logout" label="Log out" iconURI="platform:/plugin/org.argeo.cms.swt/icons/logout.png" command="_PsWd0FhLEeiknZQLx-vtnA"/>
- </children>
- </trimBars>
- </children>
- <handlers xmi:id="_Xp-P4CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.0" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.AddFolderNode" command="_RgE5cCqREeidr6NYQH6GbQ"/>
- <handlers xmi:id="_jbnNwCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.1" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.DeleteNodes" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
- <handlers xmi:id="_loxB0CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.2" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.Refresh" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
- <handlers xmi:id="_omPfkCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.3" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.RenameNode" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
- <handlers xmi:id="_dUg-cFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.9" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.AddRemoteRepository" command="_ZWpasFgQEeiknZQLx-vtnA"/>
- <handlers xmi:id="_RQyFAFhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.10" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.CloseWorkbench" command="_PsWd0FhLEeiknZQLx-vtnA"/>
- <descriptors xmi:id="_XzfoMCqlEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.partdescriptor.nodeEditor" label="Node Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/node.gif" allowMultiple="true" category="dataExplorer" closeable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrNodeEditor"/>
- <descriptors xmi:id="_sAdNwDvdEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partdescriptor.userEditor" label="User Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/person.png" allowMultiple="true" category="usersEditorArea" closeable="true" dirtyable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.UserEditor"/>
- <descriptors xmi:id="_5nK7EDvdEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partdescriptor.groupEditor" label="Group Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png" allowMultiple="true" category="usersEditorArea" closeable="true" dirtyable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.GroupEditor"/>
- <commands xmi:id="_RgE5cCqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.addFolderNode" commandName="Add folder node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
- <commands xmi:id="_ChJ-4CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.deleteNodes" commandName="Delete nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
- <commands xmi:id="_TOKHsCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.refreshNodes" commandName="Refresh nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
- <commands xmi:id="_ZrcUMCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.renameNode" commandName="Rename node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
- <commands xmi:id="_uL5i4DvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.add" commandName="Add"/>
- <commands xmi:id="_xkcMADvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.delete" commandName="Delete"/>
- <commands xmi:id="_AF1UsDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.openPerspective" commandName="Open Perspective">
- <parameters xmi:id="_F3WAUDvrEeiF1foPJZSZkw" elementId="perspectiveId" name="Perspective Id" optional="false"/>
- </commands>
- <commands xmi:id="_ZWpasFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.addRemoteRepository" commandName="Add Remote Repository"/>
- <commands xmi:id="_PsWd0FhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.logout" commandName="Log out"/>
- <addons xmi:id="_XqkCQaknEeObFrG_clJBYA" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
- <addons xmi:id="_XqkCQqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
- <addons xmi:id="_XqkCQ6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
- <addons xmi:id="_XqkCRKknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
- <addons xmi:id="_XqkCRaknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
- <addons xmi:id="_XqkCRqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
- <addons xmi:id="_XqkCR6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
- <addons xmi:id="_8VnK8OdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.locale" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.LocaleAddon"/>
- <addons xmi:id="_-xeJYOdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.auth" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.AuthAddon"/>
- <categories xmi:id="_MDkwUCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.category.jcrBrowser" name="JCR Browser"/>
-</application:Application>
+++ /dev/null
-<?xml version="1.0" encoding="ASCII"?>
-<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_XqkCQKknEeObFrG_clJBYA" elementId="">
- <children xsi:type="basic:TrimmedWindow" xmi:id="_Zdy6cKknEeObFrG_clJBYA" elementId="org.argeo.cms.e4.apps.admin.trimmedwindow.0" label="" x="10" y="10" width="500" height="500">
- <persistedState key="styleOverride" value="8"/>
- <tags>shellMaximized</tags>
- <tags>auth.cn=user,ou=roles,ou=node</tags>
- <children xsi:type="basic:PartSashContainer" xmi:id="_h3tvMCkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partsashcontainer.0" selectedElement="_0B9SECkxEein5vuhpK-Dew" horizontal="true">
- <children xsi:type="basic:PartStack" xmi:id="_0B9SECkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.0" containerData="4000" selectedElement="_WAjPkCkTEein5vuhpK-Dew">
- <children xsi:type="basic:Part" xmi:id="_WAjPkCkTEein5vuhpK-Dew" elementId="org.argeo.cms.e4.jcrbrowser" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/browser.gif">
- <menus xsi:type="menu:PopupMenu" xmi:id="_eXiUECqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.popupmenu.nodeViewer">
- <children xsi:type="menu:HandledMenuItem" xmi:id="_GVeO8CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_fU238CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_U4o9cCqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_Ncxo0CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.remove" label="Remove" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
- </menus>
- <menus xmi:id="_oRg_ACqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.menu.0">
- <tags>ViewMenu</tags>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_yJR8ECqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_o6HQECqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_5D7aACqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_7rR2wCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
- <children xsi:type="menu:HandledMenuItem" xmi:id="_XsHLgFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledmenuitem.0" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/addRepo.gif" command="_ZWpasFgQEeiknZQLx-vtnA"/>
- </menus>
- </children>
- </children>
- <children xsi:type="basic:PartStack" xmi:id="_mHrEUCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.1" containerData="6000">
- <tags>dataExplorer</tags>
- <children xsi:type="basic:Part" xmi:id="_LyT80MKKEeqaPNgZ5fEKYw" elementId="org.argeo.cms.e4.part.egoDashboard" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.parts.EgoDashboard" label="" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/home.png">
- <toolbar xmi:id="_Ut8wMMKMEeqaPNgZ5fEKYw" elementId="org.argeo.cms.e4.toolbar.0">
- <children xsi:type="menu:HandledToolItem" xmi:id="_nElwUMKMEeq1Ytjq4ALs6g" elementId="org.argeo.cms.e4.handledtoolitem.changepassword" label="Change password" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/actions/edit.png" command="_jEjCUMKMEeq1Ytjq4ALs6g"/>
- <children xsi:type="menu:HandledToolItem" xmi:id="_WAD4UMKMEeqaPNgZ5fEKYw" elementId="org.argeo.cms.e4.handledtoolitem.logout" label="Log out" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/logout.png" command="_PsWd0FhLEeiknZQLx-vtnA"/>
- </toolbar>
- </children>
- </children>
- </children>
- </children>
- <handlers xmi:id="_Xp-P4CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.0" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.AddFolderNode" command="_RgE5cCqREeidr6NYQH6GbQ"/>
- <handlers xmi:id="_jbnNwCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.1" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.DeleteNodes" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
- <handlers xmi:id="_loxB0CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.2" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.Refresh" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
- <handlers xmi:id="_omPfkCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.3" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.RenameNode" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
- <handlers xmi:id="_dUg-cFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.9" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.AddRemoteRepository" command="_ZWpasFgQEeiknZQLx-vtnA"/>
- <handlers xmi:id="_RQyFAFhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.logout" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.CloseWorkbench" command="_PsWd0FhLEeiknZQLx-vtnA"/>
- <handlers xmi:id="_lN4GUMKMEeq1Ytjq4ALs6g" elementId="org.argeo.suite.e4.handler.changePassword" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.ChangePassword" command="_jEjCUMKMEeq1Ytjq4ALs6g"/>
- <descriptors xmi:id="_XzfoMCqlEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.partdescriptor.nodeEditor" label="Node Editor" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/node.gif" allowMultiple="true" category="dataExplorer" closeable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrNodeEditor"/>
- <commands xmi:id="_RgE5cCqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.addFolderNode" commandName="Add folder node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
- <commands xmi:id="_ChJ-4CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.deleteNodes" commandName="Delete nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
- <commands xmi:id="_TOKHsCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.refreshNodes" commandName="Refresh nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
- <commands xmi:id="_ZrcUMCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.renameNode" commandName="Rename node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
- <commands xmi:id="_uL5i4DvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.add" commandName="Add"/>
- <commands xmi:id="_xkcMADvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.delete" commandName="Delete"/>
- <commands xmi:id="_AF1UsDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.openPerspective" commandName="Open Perspective">
- <parameters xmi:id="_F3WAUDvrEeiF1foPJZSZkw" elementId="perspectiveId" name="Perspective Id" optional="false"/>
- </commands>
- <commands xmi:id="_ZWpasFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.addRemoteRepository" commandName="Add Remote Repository"/>
- <commands xmi:id="_PsWd0FhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.logout" commandName="Log out"/>
- <commands xmi:id="_jEjCUMKMEeq1Ytjq4ALs6g" elementId="org.argeo.cms.e4.command.changePassword" commandName="Change Password"/>
- <addons xmi:id="_XqkCQaknEeObFrG_clJBYA" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
- <addons xmi:id="_XqkCQqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
- <addons xmi:id="_XqkCQ6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
- <addons xmi:id="_XqkCRKknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
- <addons xmi:id="_XqkCRaknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
- <addons xmi:id="_XqkCRqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
- <addons xmi:id="_XqkCR6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
- <addons xmi:id="_8VnK8OdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.locale" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.LocaleAddon"/>
- <addons xmi:id="_-xeJYOdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.auth" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.AuthAddon"/>
- <categories xmi:id="_MDkwUCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.category.jcrBrowser" name="JCR Browser"/>
-</application:Application>
+++ /dev/null
-package org.argeo.cms.e4;
-
-import java.util.List;
-
-import org.argeo.cms.swt.CmsException;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.eclipse.e4.ui.model.application.commands.MCommand;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
-import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
-import org.eclipse.e4.ui.workbench.modeling.EModelService;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-
-/** Static utilities simplifying recurring Eclipse 4 patterns. */
-public class CmsE4Utils {
- /** Open an editor based on its id. */
- public static void openEditor(EPartService partService, String editorId, String key, String state) {
- for (MPart part : partService.getParts()) {
- String id = part.getPersistedState().get(key);
- if (id != null && state.equals(id)) {
- partService.showPart(part, PartState.ACTIVATE);
- return;
- }
- }
-
- // new part
- MPart part = partService.createPart(editorId);
- if (part == null)
- throw new CmsException("No editor found with id " + editorId);
- part.getPersistedState().put(key, state);
- partService.showPart(part, PartState.ACTIVATE);
- }
-
- /** Dynamically creates an handled menu item from a command ID. */
- public static MHandledMenuItem createHandledMenuItem(EModelService modelService, MApplication app,
- String commandId) {
- MCommand command = findCommand(modelService, app, commandId);
- if (command == null)
- return null;
- MHandledMenuItem handledItem = modelService.createModelElement(MHandledMenuItem.class);
- handledItem.setCommand(command);
- return handledItem;
-
- }
-
- /**
- * Finds a command by ID.
- *
- * @return the {@link MCommand} or <code>null</code> if not found.
- */
- public static MCommand findCommand(EModelService modelService, MApplication app, String commandId) {
- List<MCommand> cmds = modelService.findElements(app, null, MCommand.class, null);
- for (MCommand cmd : cmds) {
- if (cmd.getElementId().equals(commandId)) {
- return cmd;
- }
- }
- return null;
- }
-
- /** Dynamically creates a direct menu item from a class. */
- public static MDirectMenuItem createDirectMenuItem(EModelService modelService, Class<?> clss, String label) {
- MDirectMenuItem dynamicItem = modelService.createModelElement(MDirectMenuItem.class);
- dynamicItem.setLabel(label);
- Bundle bundle = FrameworkUtil.getBundle(clss);
- dynamicItem.setContributionURI("bundleclass://" + bundle.getSymbolicName() + "/" + clss.getName());
- return dynamicItem;
- }
-
- /** Singleton. */
- private CmsE4Utils() {
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4;
-
-import org.argeo.cms.swt.CmsException;
-import org.eclipse.e4.core.contexts.ContextFunction;
-import org.eclipse.e4.core.contexts.IEclipseContext;
-import org.eclipse.e4.core.di.IInjector;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-/** An Eclipse 4 {@link ContextFunction} based on an OSGi filter. */
-public class OsgiFilterContextFunction extends ContextFunction {
-
- private BundleContext bc = FrameworkUtil.getBundle(OsgiFilterContextFunction.class).getBundleContext();
-
- @Override
- public Object compute(IEclipseContext context, String contextKey) {
- ServiceReference<?>[] srs;
- try {
- srs = bc.getServiceReferences((String) null, contextKey);
- } catch (InvalidSyntaxException e) {
- throw new CmsException("Context key " + contextKey + " must be a valid osgi filter", e);
- }
- if (srs == null || srs.length == 0) {
- return IInjector.NOT_A_VALUE;
- } else {
- // return the first one
- return bc.getService(srs[0]);
- }
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4;
-
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-import javax.security.auth.Subject;
-
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.jobs.Job;
-
-/**
- * Propagate authentication to an eclipse job. Typically to execute a privileged
- * action outside the UI thread
- */
-public abstract class PrivilegedJob extends Job {
- private final Subject subject;
-
- public PrivilegedJob(String jobName) {
- this(jobName, AccessController.getContext());
- }
-
- public PrivilegedJob(String jobName,
- AccessControlContext accessControlContext) {
- super(jobName);
- subject = Subject.getSubject(accessControlContext);
-
- // Must be called *before* the job is scheduled,
- // it is required for the progress window to appear
- setUser(true);
- }
-
- @Override
- protected IStatus run(final IProgressMonitor progressMonitor) {
- PrivilegedAction<IStatus> privilegedAction = new PrivilegedAction<IStatus>() {
- public IStatus run() {
- return doRun(progressMonitor);
- }
- };
- return Subject.doAs(subject, privilegedAction);
- }
-
- /**
- * Implement here what should be executed with default context
- * authentication
- */
- protected abstract IStatus doRun(IProgressMonitor progressMonitor);
-}
+++ /dev/null
-package org.argeo.cms.e4.addons;
-
-import java.security.AccessController;
-import java.util.Iterator;
-
-import javax.annotation.PostConstruct;
-import javax.security.auth.Subject;
-import javax.servlet.http.HttpServletRequest;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsException;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.eclipse.e4.ui.model.application.ui.MElementContainer;
-import org.eclipse.e4.ui.model.application.ui.MUIElement;
-import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
-import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
-import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
-
-public class AuthAddon {
- private final static CmsLog log = CmsLog.getLog(AuthAddon.class);
-
- public final static String AUTH = "auth.";
-
- @PostConstruct
- void init(MApplication application) {
- Iterator<MWindow> windows = application.getChildren().iterator();
- boolean atLeastOneTopLevelWindowVisible = false;
- windows: while (windows.hasNext()) {
- MWindow window = windows.next();
- // main window
- boolean windowVisible = process(window);
- if (!windowVisible) {
-// windows.remove();
- continue windows;
- }
- atLeastOneTopLevelWindowVisible = true;
- // trim bars
- if (window instanceof MTrimmedWindow) {
- Iterator<MTrimBar> trimBars = ((MTrimmedWindow) window).getTrimBars().iterator();
- while (trimBars.hasNext()) {
- MTrimBar trimBar = trimBars.next();
- if (!process(trimBar)) {
- trimBars.remove();
- }
- }
- }
- }
-
- if (!atLeastOneTopLevelWindowVisible) {
- log.warn("No top-level window is authorized for user " + CurrentUser.getUsername() + ", logging out..");
- logout();
- }
- }
-
- protected boolean process(MUIElement element) {
- for (String tag : element.getTags()) {
- if (tag.startsWith(AUTH)) {
- String role = tag.substring(AUTH.length(), tag.length());
- if (!CurrentUser.isInRole(role)) {
- element.setVisible(false);
- element.setToBeRendered(false);
- return false;
- }
- }
- }
-
- // children
- if (element instanceof MElementContainer) {
- @SuppressWarnings("unchecked")
- MElementContainer<? extends MUIElement> container = (MElementContainer<? extends MUIElement>) element;
- Iterator<? extends MUIElement> children = container.getChildren().iterator();
- while (children.hasNext()) {
- MUIElement child = children.next();
- boolean visible = process(child);
- if (!visible)
- children.remove();
- }
-
- for (Object child : container.getChildren()) {
- if (child instanceof MUIElement) {
- boolean visible = process((MUIElement) child);
- if (!visible)
- container.getChildren().remove(child);
- }
- }
- }
-
- return true;
- }
-
- protected void logout() {
- Subject subject = Subject.getSubject(AccessController.getContext());
- try {
- CurrentUser.logoutCmsSession(subject);
- } catch (Exception e) {
- throw new CmsException("Cannot log out", e);
- }
- HttpServletRequest request = org.argeo.eclipse.ui.specific.UiContext.getHttpRequest();
- if (request != null)
- request.getSession().setMaxInactiveInterval(0);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.addons;
-
-import java.security.AccessController;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
-import javax.annotation.PostConstruct;
-import javax.security.auth.Subject;
-
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.eclipse.e4.core.services.nls.ILocaleChangeService;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
-import org.eclipse.e4.ui.workbench.modeling.EModelService;
-import org.eclipse.e4.ui.workbench.modeling.ElementMatcher;
-import org.eclipse.swt.SWT;
-
-/** Integrate workbench with the locale provided at log in. */
-public class LocaleAddon {
- private final static String STYLE_OVERRIDE = "styleOverride";
-
- // Right to left languages
- private final static String ARABIC = "ar";
- private final static String HEBREW = "he";
-
- @PostConstruct
- public void init(ILocaleChangeService localeChangeService, EModelService modelService, MApplication application) {
- Subject subject = Subject.getSubject(AccessController.getContext());
- Set<Locale> locales = subject.getPublicCredentials(Locale.class);
- if (!locales.isEmpty()) {
- Locale locale = locales.iterator().next();
- localeChangeService.changeApplicationLocale(locale);
- UiContext.setLocale(locale);
-
- if (locale.getLanguage().equals(ARABIC) || locale.getLanguage().equals(HEBREW)) {
- List<MWindow> windows = modelService.findElements(application, MWindow.class, EModelService.ANYWHERE,
- new ElementMatcher(null, null, (String) null));
- for (MWindow window : windows) {
- String currentStyle = window.getPersistedState().get(STYLE_OVERRIDE);
- int style = 0;
- if (currentStyle != null) {
- style = Integer.parseInt(currentStyle);
- }
- style = style | SWT.RIGHT_TO_LEFT;
- window.getPersistedState().put(STYLE_OVERRIDE, Integer.toString(style));
- }
- }
- }
- }
-}
+++ /dev/null
-/** Eclipse 4 addons to integrate with Argeo CMS. */
-package org.argeo.cms.e4.addons;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.files;
-
-import java.net.URI;
-import java.nio.file.FileSystem;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.spi.FileSystemProvider;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.eclipse.ui.fs.AdvancedFsBrowser;
-import org.argeo.eclipse.ui.fs.SimpleFsBrowser;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-
-/** Browse the node file system. */
-public class NodeFsBrowserView {
- // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID +
- // ".nodeFsBrowserView";
-
- @Inject
- FileSystemProvider nodeFileSystemProvider;
-
- @PostConstruct
- public void createPartControl(Composite parent) {
- try {
- //URI uri = new URI("node://root:demo@localhost:7070/");
- URI uri = new URI("node:///");
- FileSystem fileSystem = nodeFileSystemProvider.getFileSystem(uri);
- if (fileSystem == null)
- fileSystem = nodeFileSystemProvider.newFileSystem(uri, null);
- Path nodePath = fileSystem.getPath("/");
-
- Path localPath = Paths.get(System.getProperty("user.home"));
-
- SimpleFsBrowser browser = new SimpleFsBrowser(parent, SWT.NO_FOCUS);
- browser.setInput(nodePath, localPath);
-// AdvancedFsBrowser browser = new AdvancedFsBrowser();
-// browser.createUi(parent, localPath);
- } catch (Exception e) {
- throw new CmsException("Cannot open file system browser", e);
- }
- }
-
- public void setFocus() {
- }
-}
+++ /dev/null
-/** Files browser perspective. */
-package org.argeo.cms.e4.files;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.handlers;
-
-import java.util.Locale;
-
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.core.services.nls.ILocaleChangeService;
-
-public class ChangeLanguage {
- @Execute
- public void execute(ILocaleChangeService localeChangeService) {
- localeChangeService.changeApplicationLocale(Locale.FRENCH);
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.handlers;
-
-import static org.argeo.cms.CmsMsg.changePassword;
-import static org.argeo.cms.CmsMsg.currentPassword;
-import static org.argeo.cms.CmsMsg.newPassword;
-import static org.argeo.cms.CmsMsg.passwordChanged;
-import static org.argeo.cms.CmsMsg.repeatNewPassword;
-
-import java.util.Arrays;
-
-import javax.inject.Inject;
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.security.CryptoKeyring;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.dialogs.CmsMessageDialog;
-import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.util.transaction.WorkTransaction;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.core.di.annotations.Optional;
-import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-/** Change the password of the logged-in user. */
-public class ChangePassword {
- @Inject
- private UserAdmin userAdmin;
- @Inject
- private WorkTransaction userTransaction;
- @Inject
- @Optional
- private CryptoKeyring keyring = null;
-
- @Execute
- public void execute() {
- ChangePasswordDialog dialog = new ChangePasswordDialog(Display.getCurrent().getActiveShell(), userAdmin);
- if (dialog.open() == Dialog.OK) {
- new CmsMessageDialog(Display.getCurrent().getActiveShell(), passwordChanged.lead(),
- CmsMessageDialog.INFORMATION).open();
- }
- }
-
- protected void changePassword(char[] oldPassword, char[] newPassword) {
- String name = CurrentUser.getUsername();
- LdapName dn;
- try {
- dn = new LdapName(name);
- } catch (InvalidNameException e) {
- throw new CmsException("Invalid user dn " + name, e);
- }
- User user = (User) userAdmin.getRole(dn.toString());
- if (!user.hasCredential(null, oldPassword))
- throw new CmsException("Invalid password");
- if (Arrays.equals(newPassword, new char[0]))
- throw new CmsException("New password empty");
- try {
- userTransaction.begin();
- user.getCredentials().put(null, newPassword);
- if (keyring != null) {
- keyring.changePassword(oldPassword, newPassword);
- // TODO change secret keys in the CMS session
- }
- userTransaction.commit();
- } catch (Exception e) {
- try {
- userTransaction.rollback();
- } catch (Exception e1) {
- e1.printStackTrace();
- }
- if (e instanceof RuntimeException)
- throw (RuntimeException) e;
- else
- throw new CmsException("Cannot change password", e);
- }
- }
-
- class ChangePasswordDialog extends CmsMessageDialog {
- private Text oldPassword, newPassword1, newPassword2;
-
- public ChangePasswordDialog(Shell parentShell, UserAdmin securityService) {
- super(parentShell, changePassword.lead(), CONFIRM);
- }
-
-// protected Point getInitialSize() {
-// return new Point(400, 450);
-// }
-
- protected Control createDialogArea(Composite parent) {
- Composite dialogarea = (Composite) super.createDialogArea(parent);
- dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- Composite composite = new Composite(dialogarea, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
- composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- oldPassword = createLP(composite, currentPassword.lead());
- newPassword1 = createLP(composite, newPassword.lead());
- newPassword2 = createLP(composite, repeatNewPassword.lead());
-
-// parent.pack();
- oldPassword.setFocus();
- return composite;
- }
-
- @Override
- protected void okPressed() {
- try {
- if (!newPassword1.getText().equals(newPassword2.getText()))
- throw new CmsException("New passwords are different");
- changePassword(oldPassword.getTextChars(), newPassword1.getTextChars());
- closeShell(OK);
- } catch (Exception e) {
- ErrorFeedback.show("Cannot change password", e);
- }
- }
-
- /** Creates label and password. */
- protected Text createLP(Composite parent, String label) {
- new Label(parent, SWT.NONE).setText(label);
- Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD | SWT.BORDER);
- text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- return text;
- }
-
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.handlers;
-
-import org.eclipse.e4.core.di.annotations.CanExecute;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-
-public class CloseAllParts {
-
- @Execute
- void execute(EPartService partService) {
- for (MPart part : partService.getParts()) {
- if (part.isCloseable()) {
- if (part.isDirty()) {
- if (partService.savePart(part, true)) {
- partService.hidePart(part, true);
- }
- } else {
- partService.hidePart(part, true);
- }
- }
- }
- }
-
- @CanExecute
- boolean canExecute(EPartService partService) {
- boolean atLeastOnePart = false;
- for (MPart part : partService.getParts()) {
- if (part.isVisible() && part.isCloseable()) {
- atLeastOnePart = true;
- break;
- }
- }
- return atLeastOnePart;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.handlers;
-
-import java.security.AccessController;
-
-import javax.security.auth.Subject;
-
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsException;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.workbench.IWorkbench;
-
-public class CloseWorkbench {
- @Execute
- public void execute(IWorkbench workbench) {
- logout();
- workbench.close();
- }
-
- protected void logout() {
- Subject subject = Subject.getSubject(AccessController.getContext());
- try {
- CurrentUser.logoutCmsSession(subject);
- } catch (Exception e) {
- throw new CmsException("Cannot log out", e);
- }
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.handlers;
-
-import org.eclipse.e4.core.di.annotations.Execute;
-
-public class DoNothing {
- @Execute
- public void execute() {
-
- }
-}
+++ /dev/null
-
-package org.argeo.cms.e4.handlers;
-
-import java.util.Date;
-import java.util.List;
-
-import org.eclipse.e4.ui.di.AboutToHide;
-import org.eclipse.e4.ui.di.AboutToShow;
-import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
-import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
-import org.eclipse.e4.ui.workbench.modeling.EModelService;
-
-public class LanguageMenuContribution {
- @AboutToShow
- public void aboutToShow(List<MMenuElement> items, EModelService modelService) {
- MDirectMenuItem dynamicItem = modelService.createModelElement(MDirectMenuItem.class);
- dynamicItem.setLabel("Dynamic Menu Item (" + new Date() + ")");
- //dynamicItem.setContributorURI("platform:/plugin/org.argeo.cms.e4");
- //dynamicItem.setContributionURI("bundleclass://org.argeo.cms.e4/" + ChangeLanguage.class.getName());
- dynamicItem.setEnabled(true);
- dynamicItem.setContributionURI("bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.ChangeLanguage");
- items.add(dynamicItem);
- }
-
- @AboutToHide
- public void aboutToHide() {
-
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.handlers;
-
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
-import org.eclipse.e4.ui.workbench.modeling.EModelService;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-
-public class OpenPerspective {
- @Inject
- MApplication application;
- @Inject
- EPartService partService;
- @Inject
- EModelService modelService;
-
- @Execute
- public void execute(@Named("perspectiveId") String perspectiveId) {
- List<MPerspective> perspectives = modelService.findElements(application, perspectiveId, MPerspective.class,
- null);
- if (perspectives.size() == 0)
- return;
- MPerspective perspective = perspectives.get(0);
- partService.switchPerspective(perspective);
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.handlers;
-
-import org.eclipse.e4.core.di.annotations.CanExecute;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-
-public class SaveAllParts {
-
- @Execute
- void execute(EPartService partService) {
- partService.saveAll(false);
- }
-
- @CanExecute
- boolean canExecute(EPartService partService) {
- return partService.getDirtyParts().size() > 0;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.handlers;
-
-import org.eclipse.e4.core.di.annotations.CanExecute;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-
-public class SavePart {
- @Execute
- void execute(EPartService partService, MPart part) {
- partService.savePart(part, false);
- }
-
- @CanExecute
- boolean canExecute(MPart part) {
- return part.isDirty();
- }
-}
\ No newline at end of file
+++ /dev/null
-/** Generic Eclipse 4 handlers. */
-package org.argeo.cms.e4.handlers;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.jcr;
-
-import org.argeo.jcr.JcrMonitor;
-import org.eclipse.core.runtime.IProgressMonitor;
-
-/**
- * Wraps an Eclipse {@link IProgressMonitor} so that it can be passed to
- * framework agnostic Argeo routines.
- */
-public class EclipseJcrMonitor implements JcrMonitor {
- private final IProgressMonitor progressMonitor;
-
- public EclipseJcrMonitor(IProgressMonitor progressMonitor) {
- this.progressMonitor = progressMonitor;
- }
-
- public void beginTask(String name, int totalWork) {
- progressMonitor.beginTask(name, totalWork);
- }
-
- public void done() {
- progressMonitor.done();
- }
-
- public boolean isCanceled() {
- return progressMonitor.isCanceled();
- }
-
- public void setCanceled(boolean value) {
- progressMonitor.setCanceled(value);
- }
-
- public void setTaskName(String name) {
- progressMonitor.setTaskName(name);
- }
-
- public void subTask(String name) {
- progressMonitor.subTask(name);
- }
-
- public void worked(int work) {
- progressMonitor.worked(work);
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.jcr.PropertyLabelProvider;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.layout.TreeColumnLayout;
-import org.eclipse.jface.viewers.ColumnWeightData;
-import org.eclipse.jface.viewers.IBaseLabelProvider;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeColumn;
-
-/**
- * Generic editor property page. Lists all properties of current node as a
- * complex tree. TODO: enable editing
- */
-public class GenericPropertyPage {
-
- // Main business Objects
- private Node currentNode;
-
- public GenericPropertyPage(Node currentNode) {
- this.currentNode = currentNode;
- }
-
- protected void createFormContent(Composite parent) {
- Composite innerBox = new Composite(parent, SWT.NONE);
- // Composite innerBox = new Composite(body, SWT.NO_FOCUS);
- FillLayout layout = new FillLayout();
- layout.marginHeight = 5;
- layout.marginWidth = 5;
- innerBox.setLayout(layout);
- createComplexTree(innerBox);
- // TODO TreeColumnLayout triggers a scroll issue with the form:
- // The inside body is always to big and a scroll bar is shown
- // Composite tableCmp = new Composite(body, SWT.NO_FOCUS);
- // createComplexTree(tableCmp);
- }
-
- private TreeViewer createComplexTree(Composite parent) {
- int style = SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION;
- Tree tree = new Tree(parent, style);
- TreeColumnLayout tableColumnLayout = new TreeColumnLayout();
-
- createColumn(tree, tableColumnLayout, "Property", SWT.LEFT, 200, 30);
- createColumn(tree, tableColumnLayout, "Value(s)", SWT.LEFT, 300, 60);
- createColumn(tree, tableColumnLayout, "Type", SWT.LEFT, 75, 10);
- createColumn(tree, tableColumnLayout, "Attributes", SWT.LEFT, 75, 0);
- // Do not apply the treeColumnLayout it does not work yet
- // parent.setLayout(tableColumnLayout);
-
- tree.setLinesVisible(true);
- tree.setHeaderVisible(true);
-
- TreeViewer treeViewer = new TreeViewer(tree);
- treeViewer.setContentProvider(new TreeContentProvider());
- treeViewer.setLabelProvider((IBaseLabelProvider) new PropertyLabelProvider());
- treeViewer.setInput(currentNode);
- treeViewer.expandAll();
- return treeViewer;
- }
-
- private static TreeColumn createColumn(Tree parent, TreeColumnLayout tableColumnLayout, String name, int style,
- int width, int weight) {
- TreeColumn column = new TreeColumn(parent, style);
- column.setText(name);
- column.setWidth(width);
- column.setMoveable(true);
- column.setResizable(true);
- tableColumnLayout.setColumnData(column, new ColumnWeightData(weight, width, true));
- return column;
- }
-
- private class TreeContentProvider implements ITreeContentProvider {
- private static final long serialVersionUID = -6162736530019406214L;
-
- public Object[] getElements(Object parent) {
- Object[] props = null;
- try {
-
- if (parent instanceof Node) {
- Node node = (Node) parent;
- PropertyIterator pi;
- pi = node.getProperties();
- List<Property> propList = new ArrayList<Property>();
- while (pi.hasNext()) {
- propList.add(pi.nextProperty());
- }
- props = propList.toArray();
- }
- } catch (RepositoryException e) {
- throw new EclipseUiException("Unexpected exception while listing node properties", e);
- }
- return props;
- }
-
- public Object getParent(Object child) {
- return null;
- }
-
- public Object[] getChildren(Object parent) {
- if (parent instanceof Property) {
- Property prop = (Property) parent;
- try {
- if (prop.isMultiple())
- return prop.getValues();
- } catch (RepositoryException e) {
- throw new EclipseUiException("Cannot get multi-prop values on " + prop, e);
- }
- }
- return null;
- }
-
- public boolean hasChildren(Object parent) {
- try {
- return (parent instanceof Property && ((Property) parent).isMultiple());
- } catch (RepositoryException e) {
- throw new EclipseUiException("Cannot check if property is multiple for " + parent, e);
- }
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
-
- public void dispose() {
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr;
-
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.jcr.Property;
-import javax.jcr.PropertyType;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.RepositoryFactory;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventListener;
-import javax.jcr.observation.ObservationManager;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.security.CryptoKeyring;
-import org.argeo.cms.security.Keyring;
-import org.argeo.cms.swt.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.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
-import org.argeo.eclipse.ui.jcr.util.NodeViewerComparer;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.e4.core.contexts.IEclipseContext;
-import org.eclipse.e4.core.di.annotations.Optional;
-import org.eclipse.e4.ui.services.EMenuService;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.IBaseLabelProvider;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-
-/**
- * Basic View to display a sash form to browse a JCR compliant multiple
- * repository environment
- */
-public class JcrBrowserView {
- final static String ID = "org.argeo.cms.e4.jcrbrowser";
- final static String NODE_VIEWER_POPUP_MENU_ID = "org.argeo.cms.e4.popupmenu.nodeViewer";
-
- private boolean sortChildNodes = true;
-
- /* DEPENDENCY INJECTION */
- @Inject
- @Optional
- private Keyring keyring;
- @Inject
- private RepositoryFactory repositoryFactory;
- @Inject
- private Repository nodeRepository;
-
- // Current user session on the home repository default workspace
- private Session userSession;
-
- private OsgiRepositoryRegister repositoryRegister = new OsgiRepositoryRegister();
-
- // This page widgets
- private TreeViewer nodesViewer;
- private NodeContentProvider nodeContentProvider;
- private TableViewer propertiesViewer;
- private EventListener resultsObserver;
-
- @PostConstruct
- public void createPartControl(Composite parent, IEclipseContext context, EPartService partService,
- ESelectionService selectionService, EMenuService menuService) {
- repositoryRegister.init();
-
- parent.setLayout(new FillLayout());
- SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
- // sashForm.setSashWidth(4);
- // sashForm.setLayout(new FillLayout());
-
- // Create the tree on top of the view
- Composite top = new Composite(sashForm, SWT.NONE);
- // GridLayout gl = new GridLayout(1, false);
- top.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
- try {
- this.userSession = this.nodeRepository.login(CmsConstants.HOME_WORKSPACE);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot open user session", e);
- }
-
- nodeContentProvider = new NodeContentProvider(userSession, keyring, repositoryRegister, repositoryFactory,
- sortChildNodes);
-
- // nodes viewer
- nodesViewer = createNodeViewer(top, nodeContentProvider);
-
- // context menu : it is completely defined in the plugin.xml file.
- // MenuManager menuManager = new MenuManager();
- // Menu menu = menuManager.createContextMenu(nodesViewer.getTree());
-
- // nodesViewer.getTree().setMenu(menu);
-
- nodesViewer.setInput("");
-
- // Create the property viewer on the bottom
- Composite bottom = new Composite(sashForm, SWT.NONE);
- bottom.setLayout(CmsSwtUtils.noSpaceGridLayout());
- propertiesViewer = createPropertiesViewer(bottom);
-
- sashForm.setWeights(getWeights());
- nodesViewer.setComparer(new NodeViewerComparer());
- nodesViewer.addSelectionChangedListener(new ISelectionChangedListener() {
- public void selectionChanged(SelectionChangedEvent event) {
- IStructuredSelection selection = (IStructuredSelection) event.getSelection();
- selectionService.setSelection(selection.toList());
- }
- });
- nodesViewer.addDoubleClickListener(new JcrE4DClickListener(nodesViewer, partService));
- menuService.registerContextMenu(nodesViewer.getControl(), NODE_VIEWER_POPUP_MENU_ID);
- // getSite().registerContextMenu(menuManager, nodesViewer);
- // getSite().setSelectionProvider(nodesViewer);
- }
-
- @PreDestroy
- public void dispose() {
- JcrUtils.logoutQuietly(userSession);
- repositoryRegister.destroy();
- }
-
- public void refresh(Object obj) {
- // Enable full refresh from a command when no element of the tree is
- // selected
- if (obj == null) {
- Object[] elements = nodeContentProvider.getElements(null);
- for (Object el : elements) {
- if (el instanceof TreeParent)
- JcrBrowserUtils.forceRefreshIfNeeded((TreeParent) el);
- getNodeViewer().refresh(el);
- }
- } else
- getNodeViewer().refresh(obj);
- }
-
- /**
- * To be overridden to adapt size of form and result frames.
- */
- protected int[] getWeights() {
- return new int[] { 70, 30 };
- }
-
- protected TreeViewer createNodeViewer(Composite parent, final ITreeContentProvider nodeContentProvider) {
-
- final TreeViewer tmpNodeViewer = new TreeViewer(parent, SWT.MULTI);
-
- tmpNodeViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
- tmpNodeViewer.setContentProvider(nodeContentProvider);
- tmpNodeViewer.setLabelProvider((IBaseLabelProvider) new NodeLabelProvider());
- tmpNodeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
- public void selectionChanged(SelectionChangedEvent event) {
- if (!event.getSelection().isEmpty()) {
- IStructuredSelection sel = (IStructuredSelection) event.getSelection();
- Object firstItem = sel.getFirstElement();
- if (firstItem instanceof SingleJcrNodeElem)
- propertiesViewer.setInput(((SingleJcrNodeElem) firstItem).getNode());
- } else {
- propertiesViewer.setInput("");
- }
- }
- });
-
- resultsObserver = new TreeObserver(tmpNodeViewer.getTree().getDisplay());
- if (keyring != null)
- try {
- ObservationManager observationManager = userSession.getWorkspace().getObservationManager();
- observationManager.addEventListener(resultsObserver, Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED, "/",
- true, null, null, false);
- } catch (RepositoryException e) {
- throw new EclipseUiException("Cannot register listeners", e);
- }
-
- // tmpNodeViewer.addDoubleClickListener(new JcrDClickListener(tmpNodeViewer));
- return tmpNodeViewer;
- }
-
- protected TableViewer createPropertiesViewer(Composite parent) {
- propertiesViewer = new TableViewer(parent, SWT.NONE);
- propertiesViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- propertiesViewer.getTable().setHeaderVisible(true);
- propertiesViewer.setContentProvider(new PropertiesContentProvider());
- TableViewerColumn col = new TableViewerColumn(propertiesViewer, SWT.NONE);
- col.getColumn().setText("Name");
- col.getColumn().setWidth(200);
- col.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -6684361063107478595L;
-
- public String getText(Object element) {
- try {
- return ((Property) element).getName();
- } catch (RepositoryException e) {
- throw new EclipseUiException("Unexpected exception in label provider", e);
- }
- }
- });
- col = new TableViewerColumn(propertiesViewer, SWT.NONE);
- col.getColumn().setText("Value");
- col.getColumn().setWidth(400);
- col.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -8201994187693336657L;
-
- public String getText(Object element) {
- try {
- Property property = (Property) element;
- if (property.getType() == PropertyType.BINARY)
- return "<binary>";
- else if (property.isMultiple()) {
- StringBuffer buf = new StringBuffer("[");
- Value[] values = property.getValues();
- for (int i = 0; i < values.length; i++) {
- if (i != 0)
- buf.append(", ");
- buf.append(values[i].getString());
- }
- buf.append(']');
- return buf.toString();
- } else
- return property.getValue().getString();
- } catch (RepositoryException e) {
- throw new EclipseUiException("Unexpected exception in label provider", e);
- }
- }
- });
- col = new TableViewerColumn(propertiesViewer, SWT.NONE);
- col.getColumn().setText("Type");
- col.getColumn().setWidth(200);
- col.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -6009599998150286070L;
-
- public String getText(Object element) {
- return JcrBrowserUtils.getPropertyTypeAsString((Property) element);
- }
- });
- propertiesViewer.setInput("");
- return propertiesViewer;
- }
-
- protected TreeViewer getNodeViewer() {
- return nodesViewer;
- }
-
- /**
- * Resets the tree content provider
- *
- * @param sortChildNodes if true the content provider will use a comparer to
- * sort nodes that might slow down the display
- */
- public void setSortChildNodes(boolean sortChildNodes) {
- this.sortChildNodes = sortChildNodes;
- ((NodeContentProvider) nodesViewer.getContentProvider()).setSortChildren(sortChildNodes);
- nodesViewer.setInput("");
- }
-
- /** Notifies the current view that a node has been added */
- public void nodeAdded(TreeParent parentNode) {
- // insure that Ui objects have been correctly created:
- JcrBrowserUtils.forceRefreshIfNeeded(parentNode);
- getNodeViewer().refresh(parentNode);
- getNodeViewer().expandToLevel(parentNode, 1);
- }
-
- /** Notifies the current view that a node has been removed */
- public void nodeRemoved(TreeParent parentNode) {
- IStructuredSelection newSel = new StructuredSelection(parentNode);
- getNodeViewer().setSelection(newSel, true);
- // Force refresh
- IStructuredSelection tmpSel = (IStructuredSelection) getNodeViewer().getSelection();
- getNodeViewer().refresh(tmpSel.getFirstElement());
- }
-
- class TreeObserver extends AsyncUiEventListener {
-
- public TreeObserver(Display display) {
- super(display);
- }
-
- @Override
- protected Boolean willProcessInUiThread(List<Event> events) throws RepositoryException {
- for (Event event : events) {
- if (getLog().isTraceEnabled())
- getLog().debug("Received event " + event);
- String path = event.getPath();
- int index = path.lastIndexOf('/');
- String propertyName = path.substring(index + 1);
- if (getLog().isTraceEnabled())
- getLog().debug("Concerned property " + propertyName);
- }
- return false;
- }
-
- protected void onEventInUiThread(List<Event> events) throws RepositoryException {
- if (getLog().isTraceEnabled())
- getLog().trace("Refresh result list");
- nodesViewer.refresh();
- }
-
- }
-
- public boolean getSortChildNodes() {
- return sortChildNodes;
- }
-
- public void setFocus() {
- getNodeViewer().getTree().setFocus();
- }
-
- /* DEPENDENCY INJECTION */
- // public void setRepositoryRegister(RepositoryRegister repositoryRegister) {
- // this.repositoryRegister = repositoryRegister;
- // }
-
- public void setKeyring(CryptoKeyring keyring) {
- this.keyring = keyring;
- }
-
- public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
- this.repositoryFactory = repositoryFactory;
- }
-
- public void setNodeRepository(Repository nodeRepository) {
- this.nodeRepository = nodeRepository;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.ui.jcr.JcrDClickListener;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
-import org.eclipse.jface.viewers.TreeViewer;
-
-public class JcrE4DClickListener extends JcrDClickListener {
- EPartService partService;
-
- public JcrE4DClickListener(TreeViewer nodeViewer, EPartService partService) {
- super(nodeViewer);
- this.partService = partService;
- }
-
- @Override
- protected void openNode(Node node) {
- MPart part = partService.createPart(JcrNodeEditor.DESCRIPTOR_ID);
- try {
- part.setLabel(node.getName());
- part.getPersistedState().put("nodeWorkspace", node.getSession().getWorkspace().getName());
- part.getPersistedState().put("nodePath", node.getPath());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot open " + node, e);
- }
-
- // the provided part is be shown
- partService.showPart(part, PartState.ACTIVATE);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr;
-
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.jcr.Node;
-
-import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Composite;
-
-public class JcrNodeEditor {
- final static String DESCRIPTOR_ID = "org.argeo.cms.e4.partdescriptor.nodeEditor";
-
- @PostConstruct
- public void createUi(Composite parent, MPart part, ESelectionService selectionService) {
- parent.setLayout(new FillLayout());
- List<?> selection = (List<?>) selectionService.getSelection();
- Node node = ((SingleJcrNodeElem) selection.get(0)).getNode();
- GenericPropertyPage propertyPage = new GenericPropertyPage(node);
- propertyPage.createFormContent(parent);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr;
-
-import javax.annotation.PostConstruct;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-
-public class SimplePart {
-
- @PostConstruct
- void init(Composite parent) {
- parent.setLayout(new GridLayout());
- Label label = new Label(parent, SWT.NONE);
- label.setText("Hello e4 World");
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr.handlers;
-
-import java.util.List;
-
-import javax.inject.Named;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
-import org.argeo.cms.e4.jcr.JcrBrowserView;
-import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.argeo.cms.ui.jcr.model.WorkspaceElem;
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.eclipse.ui.dialogs.SingleValue;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.services.IServiceConstants;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-
-/**
- * Adds a node of type nt:folder, only on {@link SingleJcrNodeElem} and
- * {@link WorkspaceElem} TreeObject types.
- *
- * This handler assumes that a selection provider is available and picks only
- * first selected item. It is UI's job to enable the command only when the
- * selection contains one and only one element. Thus no parameter is passed
- * through the command.
- */
-public class AddFolderNode {
- @Execute
- public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
- List<?> selection = (List<?>) selectionService.getSelection();
- JcrBrowserView view = (JcrBrowserView) part.getObject();
-
- if (selection != null && selection.size() == 1) {
- TreeParent treeParentNode = null;
- Node jcrParentNode = null;
- Object obj = selection.get(0);
-
- if (obj instanceof SingleJcrNodeElem) {
- treeParentNode = (TreeParent) obj;
- jcrParentNode = ((SingleJcrNodeElem) treeParentNode).getNode();
- } else if (obj instanceof WorkspaceElem) {
- treeParentNode = (TreeParent) obj;
- jcrParentNode = ((WorkspaceElem) treeParentNode).getRootNode();
- } else
- return;
-
- String folderName = SingleValue.ask("Folder name", "Enter folder name");
- if (folderName != null) {
- try {
- jcrParentNode.addNode(folderName, NodeType.NT_FOLDER);
- jcrParentNode.getSession().save();
- view.nodeAdded(treeParentNode);
- } catch (RepositoryException e) {
- ErrorFeedback.show("Cannot create folder " + folderName + " under " + treeParentNode, e);
- }
- }
- } else {
- // ErrorFeedback.show(WorkbenchUiPlugin
- // .getMessage("errorUnvalidNtFolderNodeType"));
- ErrorFeedback.show("Invalid NT folder node type");
- }
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr.handlers;
-
-import java.net.URI;
-import java.util.Hashtable;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryFactory;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.ArgeoNames;
-import org.argeo.cms.ArgeoTypes;
-import org.argeo.cms.e4.jcr.JcrBrowserView;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.security.Keyring;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.core.di.annotations.Optional;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.services.IServiceConstants;
-import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.jface.dialogs.IMessageProvider;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.dialogs.TitleAreaDialog;
-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.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;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Connect to a remote repository and, if successful publish it as an OSGi
- * service.
- */
-public class AddRemoteRepository {
-
- @Inject
- private RepositoryFactory repositoryFactory;
- @Inject
- private Repository nodeRepository;
- @Inject
- @Optional
- private Keyring keyring;
-
- @Execute
- public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part) {
- JcrBrowserView view = (JcrBrowserView) part.getObject();
- RemoteRepositoryLoginDialog dlg = new RemoteRepositoryLoginDialog(Display.getDefault().getActiveShell());
- if (dlg.open() == Dialog.OK) {
- view.refresh(null);
- }
- }
-
- // public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
- // this.repositoryFactory = repositoryFactory;
- // }
- //
- // public void setKeyring(Keyring keyring) {
- // this.keyring = keyring;
- // }
- //
- // public void setNodeRepository(Repository nodeRepository) {
- // this.nodeRepository = nodeRepository;
- // }
-
- class RemoteRepositoryLoginDialog extends TitleAreaDialog {
- private static final long serialVersionUID = 2234006887750103399L;
- private Text name;
- private Text uri;
- private Text username;
- private Text password;
- private Button saveInKeyring;
-
- public RemoteRepositoryLoginDialog(Shell parentShell) {
- super(parentShell);
- }
-
- protected Point getInitialSize() {
- return new Point(600, 400);
- }
-
- protected Control createDialogArea(Composite parent) {
- Composite dialogarea = (Composite) super.createDialogArea(parent);
- dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- Composite composite = new Composite(dialogarea, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
- composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- setMessage("Login to remote repository", IMessageProvider.NONE);
- name = createLT(composite, "Name", "remoteRepository");
- uri = createLT(composite, "URI", "http://localhost:7070/jcr/node");
- username = createLT(composite, "User", "");
- password = createLP(composite, "Password");
-
- saveInKeyring = createLC(composite, "Remember password", false);
- parent.pack();
- return composite;
- }
-
- @Override
- protected void createButtonsForButtonBar(Composite parent) {
- super.createButtonsForButtonBar(parent);
- Button test = createButton(parent, 2, "Test", false);
- test.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -1829962269440419560L;
-
- public void widgetSelected(SelectionEvent arg0) {
- testConnection();
- }
- });
- }
-
- void testConnection() {
- Session session = null;
- try {
- URI checkedUri = new URI(uri.getText());
- String checkedUriStr = checkedUri.toString();
-
- Hashtable<String, String> params = new Hashtable<String, String>();
- params.put(CmsConstants.LABELED_URI, checkedUriStr);
- Repository repository = repositoryFactory.getRepository(params);
- if (username.getText().trim().equals("")) {// anonymous
- // FIXME make it more generic
- session = repository.login(CmsConstants.SYS_WORKSPACE);
- } else {
- // FIXME use getTextChars() when upgrading to 3.7
- // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=297412
- char[] pwd = password.getText().toCharArray();
- SimpleCredentials sc = new SimpleCredentials(username.getText(), pwd);
- session = repository.login(sc, "main");
- MessageDialog.openInformation(getParentShell(), "Success",
- "Connection to '" + uri.getText() + "' successful");
- }
- } catch (Exception e) {
- ErrorFeedback.show("Connection test failed for " + uri.getText(), e);
- } finally {
- JcrUtils.logoutQuietly(session);
- }
- }
-
- @Override
- protected void okPressed() {
- Session nodeSession = null;
- try {
- nodeSession = nodeRepository.login();
- Node home = CmsJcrUtils.getUserHome(nodeSession);
-
- Node remote = home.hasNode(ArgeoNames.ARGEO_REMOTE) ? home.getNode(ArgeoNames.ARGEO_REMOTE)
- : home.addNode(ArgeoNames.ARGEO_REMOTE);
- if (remote.hasNode(name.getText()))
- throw new EclipseUiException("There is already a remote repository named " + name.getText());
- Node remoteRepository = remote.addNode(name.getText(), ArgeoTypes.ARGEO_REMOTE_REPOSITORY);
- remoteRepository.setProperty(ArgeoNames.ARGEO_URI, uri.getText());
- remoteRepository.setProperty(ArgeoNames.ARGEO_USER_ID, username.getText());
- nodeSession.save();
- if (saveInKeyring.getSelection()) {
- String pwdPath = remoteRepository.getPath() + '/' + ArgeoNames.ARGEO_PASSWORD;
- keyring.set(pwdPath, password.getText().toCharArray());
- }
- nodeSession.save();
- MessageDialog.openInformation(getParentShell(), "Repository Added",
- "Remote repository '" + username.getText() + "@" + uri.getText() + "' added");
-
- super.okPressed();
- } catch (Exception e) {
- ErrorFeedback.show("Cannot add remote repository", e);
- } finally {
- JcrUtils.logoutQuietly(nodeSession);
- }
- }
-
- /** Creates label and text. */
- protected Text createLT(Composite parent, String label, String initial) {
- new Label(parent, SWT.NONE).setText(label);
- Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
- text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- text.setText(initial);
- return text;
- }
-
- /** Creates label and check. */
- protected Button createLC(Composite parent, String label, Boolean initial) {
- new Label(parent, SWT.NONE).setText(label);
- Button check = new Button(parent, SWT.CHECK);
- check.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- check.setSelection(initial);
- return check;
- }
-
- protected Text createLP(Composite parent, String label) {
- new Label(parent, SWT.NONE).setText(label);
- Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER | SWT.PASSWORD);
- text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- return text;
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr.handlers;
-
-import java.util.List;
-
-import javax.inject.Named;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.e4.jcr.JcrBrowserView;
-import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.argeo.cms.ui.jcr.model.WorkspaceElem;
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.services.IServiceConstants;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.widgets.Display;
-
-/**
- * Delete the selected nodes: both in the JCR repository and in the UI view.
- * Warning no check is done, except implementation dependent native checks,
- * handle with care.
- *
- * This handler is still 'hard linked' to a GenericJcrBrowser view to enable
- * correct tree refresh when a node is added. This must be corrected in future
- * versions.
- */
-public class DeleteNodes {
- @Execute
- public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
- List<?> selection = (List<?>) selectionService.getSelection();
- if (selection == null)
- return;
-
- JcrBrowserView view = (JcrBrowserView) part.getObject();
-
- // confirmation
- StringBuffer buf = new StringBuffer("");
- for (Object o : selection) {
- SingleJcrNodeElem sjn = (SingleJcrNodeElem) o;
- buf.append(sjn.getName()).append(' ');
- }
- Boolean doRemove = MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "Confirm deletion",
- "Do you want to delete " + buf + "?");
-
- // operation
- if (doRemove) {
- SingleJcrNodeElem ancestor = null;
- WorkspaceElem rootAncestor = null;
- try {
- for (Object obj : selection) {
- if (obj instanceof SingleJcrNodeElem) {
- // Cache objects
- SingleJcrNodeElem sjn = (SingleJcrNodeElem) obj;
- TreeParent tp = (TreeParent) sjn.getParent();
- Node node = sjn.getNode();
-
- // Jcr Remove
- node.remove();
- node.getSession().save();
- // UI remove
- tp.removeChild(sjn);
-
- // Check if the parent is the root node
- if (tp instanceof WorkspaceElem)
- rootAncestor = (WorkspaceElem) tp;
- else
- ancestor = getOlder(ancestor, (SingleJcrNodeElem) tp);
- }
- }
- if (rootAncestor != null)
- view.nodeRemoved(rootAncestor);
- else if (ancestor != null)
- view.nodeRemoved(ancestor);
- } catch (Exception e) {
- ErrorFeedback.show("Cannot delete selected node ", e);
- }
- }
- }
-
- private SingleJcrNodeElem getOlder(SingleJcrNodeElem A, SingleJcrNodeElem B) {
- try {
- if (A == null)
- return B == null ? null : B;
- // Todo enhanced this method
- else
- return A.getNode().getDepth() <= B.getNode().getDepth() ? A : B;
- } catch (RepositoryException re) {
- throw new EclipseUiException("Cannot find ancestor", re);
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr.handlers;
-
-import java.util.List;
-
-import javax.inject.Named;
-
-import org.argeo.cms.e4.jcr.JcrBrowserView;
-import org.argeo.cms.ui.jcr.JcrBrowserUtils;
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.services.IServiceConstants;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-
-/**
- * Force the selected objects of the active view to be refreshed doing the
- * following:
- * <ol>
- * <li>The model objects are recomputed</li>
- * <li>the view is refreshed</li>
- * </ol>
- */
-public class Refresh {
-
- @Execute
- public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, EPartService partService,
- ESelectionService selectionService) {
-
- JcrBrowserView view = (JcrBrowserView) part.getObject();
- List<?> selection = (List<?>) selectionService.getSelection();
-
- if (selection != null && !selection.isEmpty()) {
- for (Object obj : selection)
- if (obj instanceof TreeParent) {
- TreeParent tp = (TreeParent) obj;
- JcrBrowserUtils.forceRefreshIfNeeded(tp);
- view.refresh(obj);
- }
- } else if (view instanceof JcrBrowserView)
- view.refresh(null); // force full refresh
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.jcr.handlers;
-
-import java.util.List;
-
-import javax.inject.Named;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.cms.e4.jcr.JcrBrowserView;
-import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.dialogs.SingleValue;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.services.IServiceConstants;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-
-/**
- * Canonically call JCR Session#move(String, String) on the first element
- * returned by HandlerUtil#getActiveWorkbenchWindow()
- * (...getActivePage().getSelection()), if it is a {@link SingleJcrNodeElem}.
- * The user must then fill a new name in and confirm
- */
-public class RenameNode {
- @Execute
- public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, EPartService partService,
- ESelectionService selectionService) {
- List<?> selection = (List<?>) selectionService.getSelection();
- if (selection == null || selection.size() != 1)
- return;
- JcrBrowserView view = (JcrBrowserView) part.getObject();
-
- Object element = selection.get(0);
- if (element instanceof SingleJcrNodeElem) {
- SingleJcrNodeElem sjn = (SingleJcrNodeElem) element;
- Node node = sjn.getNode();
- Session session = null;
- String newName = null;
- String oldPath = null;
- try {
- newName = SingleValue.ask("New node name", "Please provide a new name for [" + node.getName() + "]");
- // TODO sanity check and user feedback
- newName = JcrUtils.replaceInvalidChars(newName);
- oldPath = node.getPath();
- session = node.getSession();
- session.move(oldPath, JcrUtils.parentPath(oldPath) + "/" + newName);
- session.save();
-
- // Manually refresh the browser view. Must be enhanced
- view.refresh(sjn);
- } catch (RepositoryException e) {
- throw new EclipseUiException("Unable to rename " + node + " to " + newName, e);
- }
- }
- }
-}
+++ /dev/null
-/** JCR browser handlers. */
-package org.argeo.cms.e4.jcr.handlers;
\ No newline at end of file
+++ /dev/null
-/** JCR browser perspective. */
-package org.argeo.cms.e4.jcr;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-import java.util.Collection;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-abstract class AbstractOsgiComposite extends Composite {
- private static final long serialVersionUID = -4097415973477517137L;
- protected final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
- protected final CmsLog log = CmsLog.getLog(getClass());
-
- public AbstractOsgiComposite(Composite parent, int style) {
- super(parent, style);
- parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
- setLayout(CmsSwtUtils.noSpaceGridLayout());
- setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
- initUi(style);
- }
-
- protected abstract void initUi(int style);
-
- protected <T> T getService(Class<? extends T> clazz) {
- return bc.getService(bc.getServiceReference(clazz));
- }
-
- protected <T> Collection<ServiceReference<T>> getServiceReferences(Class<T> clazz, String filter) {
- try {
- return bc.getServiceReferences(clazz, filter);
- } catch (InvalidSyntaxException e) {
- throw new IllegalArgumentException("Filter " + filter + " is invalid", e);
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-import static org.eclipse.swt.SWT.RIGHT;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.LinkedHashMap;
-
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-
-import org.argeo.api.cms.ux.Cms2DSize;
-import org.argeo.cms.swt.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.widgets.EditableImage;
-import org.argeo.cms.ui.widgets.Img;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ILazyContentProvider;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.Text;
-
-public class Browse implements CmsUiProvider {
-
- // Some local constants to experiment. should be cleaned
- private final static String BROWSE_PREFIX = "browse#";
- private final static int THUMBNAIL_WIDTH = 400;
- private final static int COLUMN_WIDTH = 160;
- private DateFormat timeFormatter = new SimpleDateFormat("dd-MM-yyyy', 'HH:mm");
-
- // keep a cache of the opened nodes
- // Key is the path
- private LinkedHashMap<String, FilterEntitiesVirtualTable> browserCols = new LinkedHashMap<String, Browse.FilterEntitiesVirtualTable>();
- private Composite nodeDisplayParent;
- private Composite colViewer;
- private ScrolledComposite scrolledCmp;
- private Text parentPathTxt;
- private Text filterTxt;
- private Node currEdited;
-
- private String initialPath;
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- if (context == null)
- // return null;
- throw new CmsException("Context cannot be null");
- GridLayout layout = CmsSwtUtils.noSpaceGridLayout();
- layout.numColumns = 2;
- parent.setLayout(layout);
-
- // Left
- Composite leftCmp = new Composite(parent, SWT.NO_FOCUS);
- leftCmp.setLayoutData(CmsSwtUtils.fillAll());
- createBrowserPart(leftCmp, context);
-
- // Right
- nodeDisplayParent = new Composite(parent, SWT.NO_FOCUS | SWT.BORDER);
- GridData gd = new GridData(SWT.RIGHT, SWT.FILL, false, true);
- gd.widthHint = THUMBNAIL_WIDTH;
- nodeDisplayParent.setLayoutData(gd);
- createNodeView(nodeDisplayParent, context);
-
- // INIT
- setEdited(context);
- initialPath = context.getPath();
-
- // Workaround we don't yet manage the delete to display parent of the
- // initial context node
-
- return null;
- }
-
- private void createBrowserPart(Composite parent, Node context) throws RepositoryException {
- GridLayout layout = CmsSwtUtils.noSpaceGridLayout();
- parent.setLayout(layout);
- Composite filterCmp = new Composite(parent, SWT.NO_FOCUS);
- filterCmp.setLayoutData(CmsSwtUtils.fillWidth());
-
- // top filter
- addFilterPanel(filterCmp);
-
- // scrolled composite
- scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER | SWT.NO_FOCUS);
- scrolledCmp.setLayoutData(CmsSwtUtils.fillAll());
- scrolledCmp.setExpandVertical(true);
- scrolledCmp.setExpandHorizontal(true);
- scrolledCmp.setShowFocusedControl(true);
-
- colViewer = new Composite(scrolledCmp, SWT.NO_FOCUS);
- scrolledCmp.setContent(colViewer);
- scrolledCmp.addControlListener(new ControlAdapter() {
- private static final long serialVersionUID = 6589392045145698201L;
-
- @Override
- public void controlResized(ControlEvent e) {
- Rectangle r = scrolledCmp.getClientArea();
- scrolledCmp.setMinSize(colViewer.computeSize(SWT.DEFAULT, r.height));
- }
- });
- initExplorer(colViewer, context);
- }
-
- private Control initExplorer(Composite parent, Node context) throws RepositoryException {
- parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
- createBrowserColumn(parent, context);
- return null;
- }
-
- private Control createBrowserColumn(Composite parent, Node context) throws RepositoryException {
- // TODO style is not correctly managed.
- FilterEntitiesVirtualTable table = new FilterEntitiesVirtualTable(parent, SWT.BORDER | SWT.NO_FOCUS, context);
- // CmsUiUtils.style(table, ArgeoOrgStyle.browserColumn.style());
- table.filterList("*");
- table.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true));
- browserCols.put(context.getPath(), table);
- return null;
- }
-
- public void addFilterPanel(Composite parent) {
-
- parent.setLayout(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(CmsSwtUtils.fillWidth());
- filterTxt.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = 7709303319740056286L;
-
- public void modifyText(ModifyEvent event) {
- modifyFilter(false);
- }
- });
-
- filterTxt.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -4523394262771183968L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
- // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
- FilterEntitiesVirtualTable currTable = null;
- if (currEdited != null) {
- FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited));
- if (table != null && !table.isDisposed())
- currTable = table;
- }
-
- try {
- if (e.keyCode == SWT.ARROW_DOWN)
- currTable.setFocus();
- else if (e.keyCode == SWT.BS) {
- if (filterTxt.getText().equals("")
- && !(getPath(currEdited).equals("/") || getPath(currEdited).equals(initialPath))) {
- setEdited(currEdited.getParent());
- e.doit = false;
- filterTxt.setFocus();
- }
- } else if (e.keyCode == SWT.TAB && !shiftPressed) {
- if (currEdited.getNodes(filterTxt.getText() + "*").getSize() == 1) {
- setEdited(currEdited.getNodes(filterTxt.getText() + "*").nextNode());
- }
- filterTxt.setFocus();
- e.doit = false;
- }
- } catch (RepositoryException e1) {
- throw new CmsException("Unexpected error in key management for " + currEdited + "with filter "
- + filterTxt.getText(), e1);
- }
-
- }
- });
- }
-
- private void setEdited(Node node) {
- try {
- currEdited = node;
- CmsSwtUtils.clear(nodeDisplayParent);
- createNodeView(nodeDisplayParent, currEdited);
- nodeDisplayParent.layout();
- refreshFilters(node);
- refreshBrowser(node);
- } catch (RepositoryException re) {
- throw new CmsException("Unable to update browser for " + node, re);
- }
- }
-
- private void refreshFilters(Node node) throws RepositoryException {
- String currNodePath = node.getPath();
- parentPathTxt.setText(currNodePath);
- filterTxt.setText("");
- filterTxt.getParent().layout();
- }
-
- private void refreshBrowser(Node node) throws RepositoryException {
-
- // Retrieve
- String currNodePath = node.getPath();
- String currParPath = "";
- if (!"/".equals(currNodePath))
- currParPath = JcrUtils.parentPath(currNodePath);
- if ("".equals(currParPath))
- currParPath = "/";
-
- Object[][] colMatrix = new Object[browserCols.size()][2];
-
- int i = 0, j = -1, k = -1;
- for (String path : browserCols.keySet()) {
- colMatrix[i][0] = path;
- colMatrix[i][1] = browserCols.get(path);
- if (j >= 0 && k < 0 && !currNodePath.equals("/")) {
- boolean leaveOpened = path.startsWith(currNodePath);
-
- // workaround for same name siblings
- // fix me weird side effect when we go left or click on anb
- // already selected, unfocused node
- if (leaveOpened && (path.lastIndexOf("/") == 0 && currNodePath.lastIndexOf("/") == 0
- || JcrUtils.parentPath(path).equals(JcrUtils.parentPath(currNodePath))))
- leaveOpened = JcrUtils.lastPathElement(path).equals(JcrUtils.lastPathElement(currNodePath));
-
- if (!leaveOpened)
- k = i;
- }
- if (currParPath.equals(path))
- j = i;
- i++;
- }
-
- if (j >= 0 && k >= 0)
- // remove useless cols
- for (int l = i - 1; l >= k; l--) {
- browserCols.remove(colMatrix[l][0]);
- ((FilterEntitiesVirtualTable) colMatrix[l][1]).dispose();
- }
-
- // Remove disposed columns
- // TODO investigate and fix the mechanism that leave them there after
- // disposal
- if (browserCols.containsKey(currNodePath)) {
- FilterEntitiesVirtualTable currCol = browserCols.get(currNodePath);
- if (currCol.isDisposed())
- browserCols.remove(currNodePath);
- }
-
- if (!browserCols.containsKey(currNodePath))
- createBrowserColumn(colViewer, node);
-
- colViewer.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false)));
- // colViewer.pack();
- colViewer.layout();
- // also resize the scrolled composite
- scrolledCmp.layout();
- scrolledCmp.getShowFocusedControl();
- // colViewer.getParent().layout();
- // if (JcrUtils.parentPath(currNodePath).equals(currBrowserKey)) {
- // } else {
- // }
- }
-
- private void modifyFilter(boolean fromOutside) {
- if (!fromOutside)
- if (currEdited != null) {
- String filter = filterTxt.getText() + "*";
- FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited));
- if (table != null && !table.isDisposed())
- table.filterList(filter);
- }
-
- }
-
- private String getPath(Node node) {
- try {
- return node.getPath();
- } catch (RepositoryException e) {
- throw new CmsException("Unable to get path for node " + node, e);
- }
- }
-
- private Cms2DSize imageWidth = new Cms2DSize(250, 0);
-
- /**
- * Recreates the content of the box that displays information about the current
- * selected node.
- */
- private Control createNodeView(Composite parent, Node context) throws RepositoryException {
-
- parent.setLayout(new GridLayout(2, false));
-
- if (isImg(context)) {
- EditableImage image = new Img(parent, RIGHT, context, imageWidth);
- image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 2, 1));
- }
-
- // Name and primary type
- Label contextL = new Label(parent, SWT.NONE);
- CmsSwtUtils.markup(contextL);
- contextL.setText("<b>" + context.getName() + "</b>");
- new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType().getName());
-
- // Children
- for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) {
- Node child = nIt.nextNode();
- new CmsLink(child.getName(), BROWSE_PREFIX + child.getPath()).createUi(parent, context);
- new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType().getName());
- }
-
- // Properties
- for (PropertyIterator pIt = context.getProperties(); pIt.hasNext();) {
- Property property = pIt.nextProperty();
- Label label = new Label(parent, SWT.NONE);
- label.setText(property.getName());
- label.setToolTipText(JcrUtils.getPropertyDefinitionAsString(property));
- new Label(parent, SWT.NONE).setText(getPropAsString(property));
- }
-
- return null;
- }
-
- private boolean isImg(Node node) throws RepositoryException {
- // TODO support images
- return false;
-// return node.hasNode(JCR_CONTENT) && node.isNodeType(CmsTypes.CMS_IMAGE);
- }
-
- private String getPropAsString(Property property) throws RepositoryException {
- String result = "";
- if (property.isMultiple()) {
- result = getMultiAsString(property, ", ");
- } else {
- Value value = property.getValue();
- if (value.getType() == PropertyType.BINARY)
- result = "<binary>";
- else if (value.getType() == PropertyType.DATE)
- result = timeFormatter.format(value.getDate().getTime());
- else
- result = value.getString();
- }
- return result;
- }
-
- private String getMultiAsString(Property property, String separator) throws RepositoryException {
- if (separator == null)
- separator = "; ";
- Value[] values = property.getValues();
- StringBuilder builder = new StringBuilder();
- for (Value val : values) {
- String currStr = val.getString();
- if (!"".equals(currStr.trim()))
- builder.append(currStr).append(separator);
- }
- if (builder.lastIndexOf(separator) >= 0)
- return builder.substring(0, builder.length() - separator.length());
- else
- return builder.toString();
- }
-
- /** Almost canonical implementation of a table that display entities */
- private class FilterEntitiesVirtualTable extends Composite {
- private static final long serialVersionUID = 8798147431706283824L;
-
- // Context
- private Node context;
-
- // UI Objects
- private TableViewer entityViewer;
-
- // enable management of multiple columns
- Node getNode() {
- return context;
- }
-
- @Override
- public boolean setFocus() {
- if (entityViewer.getTable().isDisposed())
- return false;
- if (entityViewer.getSelection().isEmpty()) {
- Object first = entityViewer.getElementAt(0);
- if (first != null) {
- entityViewer.setSelection(new StructuredSelection(first), true);
- }
- }
- return entityViewer.getTable().setFocus();
- }
-
- void filterList(String filter) {
- try {
- NodeIterator nit = context.getNodes(filter);
- refreshFilteredList(nit);
- } catch (RepositoryException e) {
- throw new CmsException("Unable to filter " + getNode() + " children with filter " + filter, e);
- }
-
- }
-
- public FilterEntitiesVirtualTable(Composite parent, int style, Node context) {
- super(parent, SWT.NO_FOCUS);
- this.context = context;
- populate();
- }
-
- protected void populate() {
- Composite parent = this;
- GridLayout layout = CmsSwtUtils.noSpaceGridLayout();
-
- this.setLayout(layout);
- createTableViewer(parent);
- }
-
- private void createTableViewer(final Composite parent) {
- // the list
- // We must limit the size of the table otherwise the full list is
- // loaded
- // before the layout happens
- Composite listCmp = new Composite(parent, SWT.NO_FOCUS);
- GridData gd = new GridData(SWT.LEFT, SWT.FILL, false, true);
- gd.widthHint = COLUMN_WIDTH;
- listCmp.setLayoutData(gd);
- listCmp.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
- entityViewer = new TableViewer(listCmp, SWT.VIRTUAL | SWT.SINGLE);
- Table table = entityViewer.getTable();
-
- table.setLayoutData(CmsSwtUtils.fillAll());
- table.setLinesVisible(true);
- table.setHeaderVisible(false);
- CmsSwtUtils.markup(table);
-
- CmsSwtUtils.style(table, MaintenanceStyles.BROWSER_COLUMN);
-
- // first column
- TableViewerColumn column = new TableViewerColumn(entityViewer, SWT.NONE);
- TableColumn tcol = column.getColumn();
- tcol.setWidth(COLUMN_WIDTH);
- tcol.setResizable(true);
- column.setLabelProvider(new SimpleNameLP());
-
- entityViewer.setContentProvider(new MyLazyCP(entityViewer));
- entityViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection();
- if (selection.isEmpty())
- return;
- else
- setEdited((Node) selection.getFirstElement());
-
- }
- });
-
- table.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -330694313896036230L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
-
- IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection();
- Node selected = null;
- if (!selection.isEmpty())
- selected = ((Node) selection.getFirstElement());
- try {
- if (e.keyCode == SWT.ARROW_RIGHT) {
- if (selected != null) {
- setEdited(selected);
- browserCols.get(selected.getPath()).setFocus();
- }
- } else if (e.keyCode == SWT.ARROW_LEFT) {
- try {
- selected = getNode().getParent();
- String newPath = selected.getPath(); // getNode().getParent()
- setEdited(selected);
- if (browserCols.containsKey(newPath))
- browserCols.get(newPath).setFocus();
- } catch (ItemNotFoundException ie) {
- // root silent
- }
- }
- } catch (RepositoryException ie) {
- throw new CmsException("Error while managing arrow " + "events in the browser for " + selected,
- ie);
- }
- }
- });
- }
-
- private class MyLazyCP implements ILazyContentProvider {
- private static final long serialVersionUID = 1L;
- private TableViewer viewer;
- private Object[] elements;
-
- public MyLazyCP(TableViewer viewer) {
- this.viewer = viewer;
- }
-
- public void dispose() {
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- // IMPORTANT: don't forget this: an exception will be thrown if
- // a selected object is not part of the results anymore.
- viewer.setSelection(null);
- this.elements = (Object[]) newInput;
- }
-
- public void updateElement(int index) {
- viewer.replace(elements[index], index);
- }
- }
-
- protected void refreshFilteredList(NodeIterator children) {
- Object[] rows = JcrUtils.nodeIteratorToList(children).toArray();
- entityViewer.setInput(rows);
- entityViewer.setItemCount(rows.length);
- entityViewer.refresh();
- }
-
- public class SimpleNameLP extends ColumnLabelProvider {
- private static final long serialVersionUID = 2465059387875338553L;
-
- @Override
- public String getText(Object element) {
- if (element instanceof Node) {
- Node curr = ((Node) element);
- try {
- return curr.getName();
- } catch (RepositoryException e) {
- throw new CmsException("Unable to get name for" + curr);
- }
- }
- return super.getText(element);
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.useradmin.UserAdmin;
-
-class ConnectivityDeploymentUi extends AbstractOsgiComposite {
- private static final long serialVersionUID = 590221539553514693L;
-
- public ConnectivityDeploymentUi(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected void initUi(int style) {
- StringBuffer text = new StringBuffer();
- text.append("<span style='font-variant: small-caps;'>Provided Servers</span><br/>");
-
- ServiceReference<HttpService> userAdminRef = bc.getServiceReference(HttpService.class);
- if (userAdminRef != null) {
- // FIXME use constants
- Object httpPort = userAdminRef.getProperty("http.port");
- Object httpsPort = userAdminRef.getProperty("https.port");
- if (httpPort != null)
- text.append("<b>http</b> ").append(httpPort).append("<br/>");
- if (httpsPort != null)
- text.append("<b>https</b> ").append(httpsPort).append("<br/>");
-
- }
-
- text.append("<br/>");
- text.append("<span style='font-variant: small-caps;'>Referenced Servers</span><br/>");
-
- Label label = new Label(this, SWT.NONE);
- label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
- CmsSwtUtils.markup(label);
- label.setText(text.toString());
- }
-
- protected boolean isDeployed() {
- return bc.getServiceReference(UserAdmin.class) != null;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.FileStore;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Collection;
-
-import org.apache.jackrabbit.core.RepositoryContext;
-import org.apache.jackrabbit.core.config.RepositoryConfig;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.ServiceReference;
-
-class DataDeploymentUi extends AbstractOsgiComposite {
- private static final long serialVersionUID = 590221539553514693L;
-
- public DataDeploymentUi(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected void initUi(int style) {
- if (isDeployed()) {
- initCurrentUi(this);
- } else {
- initNewUi(this);
- }
- }
-
- private void initNewUi(Composite parent) {
-// try {
-// ConfigurationAdmin confAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class));
-// Configuration[] confs = confAdmin.listConfigurations(
-// "(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + NodeConstants.NODE_REPOS_FACTORY_PID + ")");
-// if (confs == null || confs.length == 0) {
-// Group buttonGroup = new Group(parent, SWT.NONE);
-// buttonGroup.setText("Repository Type");
-// buttonGroup.setLayout(new GridLayout(2, true));
-// buttonGroup.setLayoutData(new GridData(GridData.FILL_VERTICAL));
-//
-// SelectionListener selectionListener = new SelectionAdapter() {
-// private static final long serialVersionUID = 6247064348421088092L;
-//
-// public void widgetSelected(SelectionEvent event) {
-// Button radio = (Button) event.widget;
-// if (!radio.getSelection())
-// return;
-// log.debug(event);
-// JackrabbitType nodeType = (JackrabbitType) radio.getData();
-// if (log.isDebugEnabled())
-// log.debug(" selected = " + nodeType.name());
-// };
-// };
-//
-// for (JackrabbitType nodeType : JackrabbitType.values()) {
-// Button radio = new Button(buttonGroup, SWT.RADIO);
-// radio.setText(nodeType.name());
-// radio.setData(nodeType);
-// if (nodeType.equals(JackrabbitType.localfs))
-// radio.setSelection(true);
-// radio.addSelectionListener(selectionListener);
-// }
-//
-// } else if (confs.length == 1) {
-//
-// } else {
-// throw new CmsException("Multiple repos not yet supported");
-// }
-// } catch (Exception e) {
-// throw new CmsException("Cannot initialize UI", e);
-// }
-
- }
-
- private void initCurrentUi(Composite parent) {
- parent.setLayout(new GridLayout());
- Collection<ServiceReference<RepositoryContext>> contexts = getServiceReferences(RepositoryContext.class,
- "(" + CmsConstants.CN + "=*)");
- StringBuffer text = new StringBuffer();
- text.append("<span style='font-variant: small-caps;'>Jackrabbit Repositories</span><br/>");
- for (ServiceReference<RepositoryContext> sr : contexts) {
- RepositoryContext repositoryContext = bc.getService(sr);
- String alias = sr.getProperty(CmsConstants.CN).toString();
- String rootNodeId = repositoryContext.getRootNodeId().toString();
- RepositoryConfig repositoryConfig = repositoryContext.getRepositoryConfig();
- Path repoHomePath = new File(repositoryConfig.getHomeDir()).toPath().toAbsolutePath();
- // TODO check data store
-
- text.append("<b>" + alias + "</b><br/>");
- text.append("rootNodeId: " + rootNodeId + "<br/>");
- try {
- FileStore fileStore = Files.getFileStore(repoHomePath);
- text.append("partition: " + fileStore.toString() + "<br/>");
- text.append(
- percentUsed(fileStore) + " used (" + humanReadable(fileStore.getUsableSpace()) + " free)<br/>");
- } catch (IOException e) {
- log.error("Cannot check fileStore for " + repoHomePath, e);
- }
- }
- Label label = new Label(parent, SWT.NONE);
- label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
- CmsSwtUtils.markup(label);
- label.setText("<span style=''>" + text.toString() + "</span>");
- }
-
- private String humanReadable(long bytes) {
- long mb = bytes / (1024 * 1024);
- return mb >= 2048 ? Long.toString(mb / 1024) + " GB" : Long.toString(mb) + " MB";
- }
-
- private String percentUsed(FileStore fs) throws IOException {
- long used = fs.getTotalSpace() - fs.getUnallocatedSpace();
- long percent = used * 100 / fs.getTotalSpace();
- if (log.isTraceEnabled()) {
- // output identical to `df -B 1`)
- log.trace(fs.getTotalSpace() + "," + used + "," + fs.getUsableSpace());
- }
- String span;
- if (percent < 80)
- span = "<span style='color:green;font-weight:bold'>";
- else if (percent < 95)
- span = "<span style='color:orange;font-weight:bold'>";
- else
- span = "<span style='color:red;font-weight:bold'>";
- return span + percent + "%</span>";
- }
-
- protected boolean isDeployed() {
- return bc.getServiceReference(RepositoryContext.class) != null;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsContext;
-import org.argeo.api.cms.CmsDeployment;
-import org.argeo.api.cms.CmsState;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Group;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-
-class DeploymentEntryPoint {
- private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
-
- protected void createContents(Composite parent) {
- // FIXME manage authentication if needed
- // if (!CurrentUser.roles().contains(AuthConstants.ROLE_ADMIN))
- // return;
-
- // parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- if (isDesktop()) {
- parent.setLayout(new GridLayout(2, true));
- } else {
- // TODO add scrolling
- parent.setLayout(new GridLayout(1, true));
- }
-
- initHighLevelSummary(parent);
-
- Group securityGroup = createHighLevelGroup(parent, "Security");
- securityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
- new SecurityDeploymentUi(securityGroup, SWT.NONE);
-
- Group dataGroup = createHighLevelGroup(parent, "Data");
- dataGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
- new DataDeploymentUi(dataGroup, SWT.NONE);
-
- Group logGroup = createHighLevelGroup(parent, "Notifications");
- logGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
- new LogDeploymentUi(logGroup, SWT.NONE);
-
- Group connectivityGroup = createHighLevelGroup(parent, "Connectivity");
- new ConnectivityDeploymentUi(connectivityGroup, SWT.NONE);
- connectivityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
-
- }
-
- private void initHighLevelSummary(Composite parent) {
- Composite composite = new Composite(parent, SWT.NONE);
- GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
- if (isDesktop())
- gridData.horizontalSpan = 3;
- composite.setLayoutData(gridData);
- composite.setLayout(new FillLayout());
-
- ServiceReference<CmsState> nodeStateRef = bc.getServiceReference(CmsState.class);
- if (nodeStateRef == null)
- throw new IllegalStateException("No CMS state available");
- CmsState nodeState = bc.getService(nodeStateRef);
- ServiceReference<CmsContext> nodeDeploymentRef = bc.getServiceReference(CmsContext.class);
- Label label = new Label(composite, SWT.WRAP);
- CmsSwtUtils.markup(label);
- if (nodeDeploymentRef == null) {
- label.setText("Not yet deployed on <br>" + nodeState.getHostname() + "</br>, please configure below.");
- } else {
- Object stateUuid = nodeStateRef.getProperty(CmsConstants.CN);
- CmsContext nodeDeployment = bc.getService(nodeDeploymentRef);
- GregorianCalendar calendar = new GregorianCalendar();
- calendar.setTimeInMillis(nodeDeployment.getAvailableSince());
- calendar.setTimeZone(TimeZone.getDefault());
- label.setText("[" + "<b>" + nodeState.getHostname() + "</b>]# " + "Deployment state " + stateUuid
- + ", available since <b>" + calendar.getTime() + "</b>");
- }
- }
-
- private static Group createHighLevelGroup(Composite parent, String text) {
- Group group = new Group(parent, SWT.NONE);
- group.setText(text);
- CmsSwtUtils.markup(group);
- return group;
- }
-
- private boolean isDesktop() {
- return true;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Enumeration;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.log.LogEntry;
-import org.osgi.service.log.LogListener;
-import org.osgi.service.log.LogReaderService;
-
-class LogDeploymentUi extends AbstractOsgiComposite implements LogListener {
- private static final long serialVersionUID = 590221539553514693L;
-
- private DateFormat dateFormat = new SimpleDateFormat("MMdd HH:mm");
-
- private Display display;
- private Text logDisplay;
-
- public LogDeploymentUi(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected void initUi(int style) {
- LogReaderService logReader = getService(LogReaderService.class);
- // FIXME use server push
- // logReader.addLogListener(this);
- this.display = getDisplay();
- this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- logDisplay = new Text(this, SWT.WRAP | SWT.MULTI | SWT.READ_ONLY);
- logDisplay.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- CmsSwtUtils.markup(logDisplay);
- Enumeration<LogEntry> logEntries = (Enumeration<LogEntry>) logReader.getLog();
- while (logEntries.hasMoreElements())
- logDisplay.append(printEntry(logEntries.nextElement()));
- }
-
- private String printEntry(LogEntry entry) {
- StringBuilder sb = new StringBuilder();
- GregorianCalendar calendar = new GregorianCalendar(TimeZone.getDefault());
- calendar.setTimeInMillis(entry.getTime());
- sb.append(dateFormat.format(calendar.getTime())).append(' ');
- sb.append(entry.getMessage());
- sb.append('\n');
- return sb.toString();
- }
-
- @Override
- public void logged(LogEntry entry) {
- if (display.isDisposed())
- return;
- display.asyncExec(() -> {
- if (logDisplay.isDisposed())
- return;
- logDisplay.append(printEntry(entry));
- });
- display.wake();
- }
-
- // @Override
- // public void dispose() {
- // super.dispose();
- // getService(LogReaderService.class).removeLogListener(this);
- // }
-}
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-/** Specific styles used by the various maintenance pages . */
-public interface MaintenanceStyles {
- // General
- public final static String PREFIX = "maintenance_";
-
- // Browser
- public final static String BROWSER_COLUMN = "browser_column";
- }
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-public class NonAdminPage implements CmsUiProvider{
-
- @Override
- public Control createUi(Composite parent, Node context)
- throws RepositoryException {
- Composite body = new Composite(parent, SWT.NO_FOCUS);
- body.setLayoutData(CmsSwtUtils.fillAll());
- body.setLayout(new GridLayout());
- Label label = new Label(body, SWT.NONE);
- label.setText("You should be an admin to perform maintenance operations. "
- + "Are you sure you are logged in?");
- label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
- return null;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.maintenance;
-
-import java.net.URI;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.UserAdmin;
-
-class SecurityDeploymentUi extends AbstractOsgiComposite {
- private static final long serialVersionUID = 590221539553514693L;
-
- public SecurityDeploymentUi(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected void initUi(int style) {
- if (isDeployed()) {
- initCurrentUi(this);
- } else {
- initNewUi(this);
- }
- }
-
- private void initNewUi(Composite parent) {
- new Label(parent, SWT.NONE).setText("Security is not configured");
- }
-
- private void initCurrentUi(Composite parent) {
- ServiceReference<UserAdmin> userAdminRef = bc.getServiceReference(UserAdmin.class);
- UserAdmin userAdmin = bc.getService(userAdminRef);
- StringBuffer text = new StringBuffer();
- text.append("<span style='font-variant: small-caps;'>Domains</span><br/>");
- domains: for (String key : userAdminRef.getPropertyKeys()) {
- if (!key.startsWith("/"))
- continue domains;
- URI uri;
- try {
- uri = new URI(key);
- } catch (Exception e) {
- // ignore non URI keys
- continue domains;
- }
-
- String rootDn = uri.getPath().substring(1, uri.getPath().length());
- // FIXME make reading query options more robust, using utils
- boolean readOnly = uri.getQuery().equals("readOnly=true");
- if (readOnly)
- text.append("<span style='font-weight:bold;font-style: italic'>");
- else
- text.append("<span style='font-weight:bold'>");
-
- text.append(rootDn);
- text.append("</span><br/>");
- try {
- Role[] roles = userAdmin.getRoles("(dn=*," + rootDn + ")");
- long userCount = 0;
- long groupCount = 0;
- for (Role role : roles) {
- if (role.getType() == Role.USER)
- userCount++;
- else
- groupCount++;
- }
- text.append(" " + userCount + " users, " + groupCount +" groups.<br/>");
- } catch (InvalidSyntaxException e) {
- log.error("Invalid syntax", e);
- }
- }
- Label label = new Label(parent, SWT.NONE);
- label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
- CmsSwtUtils.markup(label);
- label.setText(text.toString());
- }
-
- protected boolean isDeployed() {
- return bc.getServiceReference(UserAdmin.class) != null;
- }
-}
+++ /dev/null
-/** Maintenance perspective. */
-package org.argeo.cms.e4.maintenance;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.monitoring;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
-
-/** A tree element representing a {@link Bundle} */
-class BundleNode extends TreeParent {
- private final Bundle bundle;
-
- public BundleNode(Bundle bundle) {
- this(bundle, false);
- }
-
- @SuppressWarnings("rawtypes")
- public BundleNode(Bundle bundle, boolean hasChildren) {
- super(bundle.getSymbolicName());
- this.bundle = bundle;
-
- if (hasChildren) {
- // REFERENCES
- ServiceReference[] usedServices = bundle.getServicesInUse();
- if (usedServices != null) {
- for (ServiceReference sr : usedServices) {
- if (sr != null)
- addChild(new ServiceReferenceNode(sr, false));
- }
- }
-
- // SERVICES
- ServiceReference[] registeredServices = bundle
- .getRegisteredServices();
- if (registeredServices != null) {
- for (ServiceReference sr : registeredServices) {
- if (sr != null)
- addChild(new ServiceReferenceNode(sr, true));
- }
- }
- }
-
- }
-
- Bundle getBundle() {
- return bundle;
- }
-}
+++ /dev/null
-//package org.argeo.eclipse.ui.workbench.osgi;
-//public class BundlesView {}
-
-package org.argeo.cms.e4.monitoring;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.eclipse.ui.ColumnViewerComparator;
-import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-
-/**
- * Overview of the bundles as a table. Equivalent to Equinox 'ss' console
- * command.
- */
-public class BundlesView {
- private final static BundleContext bc = FrameworkUtil.getBundle(BundlesView.class).getBundleContext();
- private TableViewer viewer;
-
- @PostConstruct
- public void createPartControl(Composite parent) {
- viewer = new TableViewer(parent);
- viewer.setContentProvider(new BundleContentProvider());
- viewer.getTable().setHeaderVisible(true);
-
- EclipseUiSpecificUtils.enableToolTipSupport(viewer);
-
- // ID
- TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(30);
- column.getColumn().setText("ID");
- column.getColumn().setAlignment(SWT.RIGHT);
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -3122136344359358605L;
-
- public String getText(Object element) {
- return Long.toString(((Bundle) element).getBundleId());
- }
- });
- new ColumnViewerComparator(column);
-
- // State
- column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(18);
- column.getColumn().setText("State");
- column.setLabelProvider(new StateLabelProvider());
- new ColumnViewerComparator(column);
-
- // Symbolic name
- column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(250);
- column.getColumn().setText("Symbolic Name");
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -4280840684440451080L;
-
- public String getText(Object element) {
- return ((Bundle) element).getSymbolicName();
- }
- });
- new ColumnViewerComparator(column);
-
- // Version
- column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(250);
- column.getColumn().setText("Version");
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = 6871926308708629989L;
-
- public String getText(Object element) {
- Bundle bundle = (org.osgi.framework.Bundle) element;
- return bundle.getVersion().toString();
- }
- });
- new ColumnViewerComparator(column);
-
- viewer.setInput(bc);
-
- }
-
- @Focus
- public void setFocus() {
- if (viewer != null)
- viewer.getControl().setFocus();
- }
-
- /** Content provider managing the array of bundles */
- private static class BundleContentProvider implements IStructuredContentProvider {
- private static final long serialVersionUID = -8533792785725875977L;
-
- public Object[] getElements(Object inputElement) {
- if (inputElement instanceof BundleContext) {
- BundleContext bc = (BundleContext) inputElement;
- return bc.getBundles();
- }
- return null;
- }
-
- public void dispose() {
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
- }
-}
+++ /dev/null
-//package org.argeo.eclipse.ui.workbench.osgi;
-//public class BundlesView {}
-
-package org.argeo.cms.e4.monitoring;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.api.cms.CmsSession;
-import org.argeo.cms.auth.RoleNameUtils;
-import org.argeo.eclipse.ui.ColumnViewerComparator;
-import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
-import org.argeo.util.LangUtils;
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-/**
- * Overview of the active CMS sessions.
- */
-public class CmsSessionsView {
- private final static BundleContext bc = FrameworkUtil.getBundle(CmsSessionsView.class).getBundleContext();
-
- private TableViewer viewer;
-
- @PostConstruct
- public void createPartControl(Composite parent) {
- viewer = new TableViewer(parent);
- viewer.setContentProvider(new CmsSessionContentProvider());
- viewer.getTable().setHeaderVisible(true);
-
- EclipseUiSpecificUtils.enableToolTipSupport(viewer);
-
- int longColWidth = 150;
- int smallColWidth = 100;
-
- // Display name
- TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(longColWidth);
- column.getColumn().setText("User");
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -5234573509093747505L;
-
- public String getText(Object element) {
- return ((CmsSession) element).getDisplayName();
- }
-
- public String getToolTipText(Object element) {
- return ((CmsSession) element).getUserDn().toString();
- }
- });
- new ColumnViewerComparator(column);
-
- // Creation time
- column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(smallColWidth);
- column.getColumn().setText("Since");
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -5234573509093747505L;
-
- public String getText(Object element) {
- return LangUtils.since(((CmsSession) element).getCreationTime());
- }
-
- public String getToolTipText(Object element) {
- return ((CmsSession) element).getCreationTime().toString();
- }
- });
- new ColumnViewerComparator(column);
-
- // Username
- column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(smallColWidth);
- column.getColumn().setText("Username");
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -5234573509093747505L;
-
- public String getText(Object element) {
- String userDn = ((CmsSession) element).getUserDn();
- return RoleNameUtils.getLastRdnValue(userDn);
- }
-
- public String getToolTipText(Object element) {
- return ((CmsSession) element).getUserDn().toString();
- }
- });
- new ColumnViewerComparator(column);
-
- // UUID
- column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(smallColWidth);
- column.getColumn().setText("UUID");
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -5234573509093747505L;
-
- public String getText(Object element) {
- return ((CmsSession) element).getUuid().toString();
- }
-
- public String getToolTipText(Object element) {
- return getText(element);
- }
- });
- new ColumnViewerComparator(column);
-
- // Local ID
- column = new TableViewerColumn(viewer, SWT.NONE);
- column.getColumn().setWidth(smallColWidth);
- column.getColumn().setText("Local ID");
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = -5234573509093747505L;
-
- public String getText(Object element) {
- return ((CmsSession) element).getLocalId();
- }
-
- public String getToolTipText(Object element) {
- return getText(element);
- }
- });
- new ColumnViewerComparator(column);
-
- viewer.setInput(bc);
-
- }
-
- @Focus
- public void setFocus() {
- if (viewer != null)
- viewer.getControl().setFocus();
- }
-
- /** Content provider managing the array of bundles */
- private static class CmsSessionContentProvider implements IStructuredContentProvider {
- private static final long serialVersionUID = -8533792785725875977L;
-
- public Object[] getElements(Object inputElement) {
- if (inputElement instanceof BundleContext) {
- BundleContext bc = (BundleContext) inputElement;
- Collection<ServiceReference<CmsSession>> srs;
- try {
- srs = bc.getServiceReferences(CmsSession.class, null);
- } catch (InvalidSyntaxException e) {
- throw new IllegalArgumentException("Cannot retrieve CMS sessions", e);
- }
- List<CmsSession> res = new ArrayList<>();
- for (ServiceReference<CmsSession> sr : srs) {
- res.add(bc.getService(sr));
- }
- return res.toArray();
- }
- return null;
- }
-
- public void dispose() {
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.monitoring;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-
-/** The OSGi runtime from a module perspective. */
-public class ModulesView {
- private final static BundleContext bc = FrameworkUtil.getBundle(ModulesView.class).getBundleContext();
- private TreeViewer viewer;
-
- @PostConstruct
- public void createPartControl(Composite parent) {
- viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
- viewer.setContentProvider(new ModulesContentProvider());
- viewer.setLabelProvider(new ModulesLabelProvider());
- viewer.setInput(bc);
- }
-
- @Focus
- public void setFocus() {
- viewer.getTree().setFocus();
- }
-
- private class ModulesContentProvider implements ITreeContentProvider {
- private static final long serialVersionUID = 3819934804640641721L;
-
- public Object[] getElements(Object inputElement) {
- return getChildren(inputElement);
- }
-
- public Object[] getChildren(Object parentElement) {
- if (parentElement instanceof BundleContext) {
- BundleContext bundleContext = (BundleContext) parentElement;
- Bundle[] bundles = bundleContext.getBundles();
-
- List<BundleNode> modules = new ArrayList<BundleNode>();
- for (Bundle bundle : bundles) {
- if (bundle.getState() == Bundle.ACTIVE)
- modules.add(new BundleNode(bundle, true));
- }
- return modules.toArray();
- } else if (parentElement instanceof TreeParent) {
- return ((TreeParent) parentElement).getChildren();
- } else {
- return null;
- }
- }
-
- public Object getParent(Object element) {
- // TODO Auto-generated method stub
- return null;
- }
-
- public boolean hasChildren(Object element) {
- if (element instanceof TreeParent) {
- return ((TreeParent) element).hasChildren();
- }
- return false;
- }
-
- public void dispose() {
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
- }
-
- private class ModulesLabelProvider extends StateLabelProvider {
- private static final long serialVersionUID = 5290046145534824722L;
-
- @Override
- public String getText(Object element) {
- if (element instanceof BundleNode)
- return element.toString() + " [" + ((BundleNode) element).getBundle().getBundleId() + "]";
- return element.toString();
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.monitoring;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Dictionary;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.cms.swt.CmsException;
-import org.argeo.util.LangUtils;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.TreeViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-
-public class OsgiConfigurationsView {
- private final static BundleContext bc = FrameworkUtil.getBundle(OsgiConfigurationsView.class).getBundleContext();
-
- @PostConstruct
- public void createPartControl(Composite parent) {
- ConfigurationAdmin configurationAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class));
-
- TreeViewer viewer = new TreeViewer(parent);
- // viewer.getTree().setHeaderVisible(true);
-
- TreeViewerColumn tvc = new TreeViewerColumn(viewer, SWT.NONE);
- tvc.getColumn().setWidth(400);
- tvc.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = 835407996597566763L;
-
- @Override
- public String getText(Object element) {
- if (element instanceof Configuration) {
- return ((Configuration) element).getPid();
- } else if (element instanceof Prop) {
- return ((Prop) element).key;
- }
- return super.getText(element);
- }
-
- @Override
- public Image getImage(Object element) {
- if (element instanceof Configuration)
- return OsgiExplorerImages.CONFIGURATION;
- return null;
- }
-
- });
-
- tvc = new TreeViewerColumn(viewer, SWT.NONE);
- tvc.getColumn().setWidth(400);
- tvc.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = 6999659261190014687L;
-
- @Override
- public String getText(Object element) {
- if (element instanceof Configuration) {
- // return ((Configuration) element).getFactoryPid();
- return null;
- } else if (element instanceof Prop) {
- return ((Prop) element).value.toString();
- }
- return super.getText(element);
- }
- });
-
- viewer.setContentProvider(new ConfigurationsContentProvider());
- viewer.setInput(configurationAdmin);
- }
-
- static class ConfigurationsContentProvider implements ITreeContentProvider {
- private static final long serialVersionUID = -4892768279440981042L;
- private ConfigurationComparator configurationComparator = new ConfigurationComparator();
-
- @Override
- public void dispose() {
- }
-
- @Override
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
-
- @Override
- public Object[] getElements(Object inputElement) {
- ConfigurationAdmin configurationAdmin = (ConfigurationAdmin) inputElement;
- try {
- Configuration[] configurations = configurationAdmin.listConfigurations(null);
- Arrays.sort(configurations, configurationComparator);
- return configurations;
- } catch (IOException | InvalidSyntaxException e) {
- throw new CmsException("Cannot list configurations", e);
- }
- }
-
- @Override
- public Object[] getChildren(Object parentElement) {
- if (parentElement instanceof Configuration) {
- List<Prop> res = new ArrayList<>();
- Configuration configuration = (Configuration) parentElement;
- Dictionary<String, Object> props = configuration.getProperties();
- keys: for (String key : LangUtils.keys(props)) {
- if (Constants.SERVICE_PID.equals(key))
- continue keys;
- if (ConfigurationAdmin.SERVICE_FACTORYPID.equals(key))
- continue keys;
- res.add(new Prop(configuration, key, props.get(key)));
- }
- return res.toArray(new Prop[res.size()]);
- }
- return null;
- }
-
- @Override
- public Object getParent(Object element) {
- if (element instanceof Prop)
- return ((Prop) element).configuration;
- return null;
- }
-
- @Override
- public boolean hasChildren(Object element) {
- if (element instanceof Configuration)
- return true;
- return false;
- }
-
- }
-
- static class Prop {
- final Configuration configuration;
- final String key;
- final Object value;
-
- public Prop(Configuration configuration, String key, Object value) {
- this.configuration = configuration;
- this.key = key;
- this.value = value;
- }
-
- }
-
- static class ConfigurationComparator implements Comparator<Configuration> {
-
- @Override
- public int compare(Configuration o1, Configuration o2) {
- return o1.getPid().compareTo(o2.getPid());
- }
-
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.monitoring;
-
-import org.argeo.cms.ui.theme.CmsImages;
-import org.eclipse.swt.graphics.Image;
-
-/** Shared icons. */
-public class OsgiExplorerImages extends CmsImages {
- public final static Image INSTALLED = createIcon("installed.gif");
- public final static Image RESOLVED = createIcon("resolved.gif");
- public final static Image STARTING = createIcon("starting.gif");
- public final static Image ACTIVE = createIcon("active.gif");
- public final static Image SERVICE_PUBLISHED = createIcon("service_published.gif");
- public final static Image SERVICE_REFERENCED = createIcon("service_referenced.gif");
- public final static Image CONFIGURATION = createIcon("node.gif");
-}
+++ /dev/null
-package org.argeo.cms.e4.monitoring;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
-
-/** A tree element representing a {@link ServiceReference} */
-@SuppressWarnings({ "rawtypes" })
-class ServiceReferenceNode extends TreeParent {
- private final ServiceReference serviceReference;
- private final boolean published;
-
- public ServiceReferenceNode(ServiceReference serviceReference,
- boolean published) {
- super(serviceReference.toString());
- this.serviceReference = serviceReference;
- this.published = published;
-
- if (isPublished()) {
- Bundle[] usedBundles = serviceReference.getUsingBundles();
- if (usedBundles != null) {
- for (Bundle b : usedBundles) {
- if (b != null)
- addChild(new BundleNode(b));
- }
- }
- } else {
- Bundle provider = serviceReference.getBundle();
- addChild(new BundleNode(provider));
- }
-
- for (String key : serviceReference.getPropertyKeys()) {
- addChild(new TreeParent(key + "="
- + serviceReference.getProperty(key)));
- }
-
- }
-
- public ServiceReference getServiceReference() {
- return serviceReference;
- }
-
- public boolean isPublished() {
- return published;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.monitoring;
-
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.graphics.Image;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
-
-/** Label provider showing the sate of bundles */
-class StateLabelProvider extends ColumnLabelProvider {
- private static final long serialVersionUID = -7885583135316000733L;
-
- @Override
- public Image getImage(Object element) {
- int state;
- if (element instanceof Bundle)
- state = ((Bundle) element).getState();
- else if (element instanceof BundleNode)
- state = ((BundleNode) element).getBundle().getState();
- else if (element instanceof ServiceReferenceNode)
- if (((ServiceReferenceNode) element).isPublished())
- return OsgiExplorerImages.SERVICE_PUBLISHED;
- else
- return OsgiExplorerImages.SERVICE_REFERENCED;
- else
- return null;
-
- switch (state) {
- case Bundle.UNINSTALLED:
- return OsgiExplorerImages.INSTALLED;
- case Bundle.INSTALLED:
- return OsgiExplorerImages.INSTALLED;
- case Bundle.RESOLVED:
- return OsgiExplorerImages.RESOLVED;
- case Bundle.STARTING:
- return OsgiExplorerImages.STARTING;
- case Bundle.STOPPING:
- return OsgiExplorerImages.STARTING;
- case Bundle.ACTIVE:
- return OsgiExplorerImages.ACTIVE;
- default:
- return null;
- }
- }
-
- @Override
- public String getText(Object element) {
- return null;
- }
-
- @Override
- public String getToolTipText(Object element) {
- Bundle bundle = (Bundle) element;
- Integer state = bundle.getState();
- switch (state) {
- case Bundle.UNINSTALLED:
- return "UNINSTALLED";
- case Bundle.INSTALLED:
- return "INSTALLED";
- case Bundle.RESOLVED:
- return "RESOLVED";
- case Bundle.STARTING:
- String activationPolicy = bundle.getHeaders()
- .get(Constants.BUNDLE_ACTIVATIONPOLICY).toString();
-
- // .get("Bundle-ActivationPolicy").toString();
- // FIXME constant triggers the compilation failure
- if (activationPolicy != null
- && activationPolicy.equals(Constants.ACTIVATION_LAZY))
- // && activationPolicy.equals("lazy"))
- // FIXME constant triggers the compilation failure
- // && activationPolicy.equals(Constants.ACTIVATION_LAZY))
- return "<<LAZY>>";
- return "STARTING";
- case Bundle.STOPPING:
- return "STOPPING";
- case Bundle.ACTIVE:
- return "ACTIVE";
- default:
- return null;
- }
- }
-}
+++ /dev/null
-/** Monitoring perspective. */
-package org.argeo.cms.e4.monitoring;
\ No newline at end of file
+++ /dev/null
-/** Eclipse 4 user interfaces. */
-package org.argeo.cms.e4;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.parts;
-
-import java.time.ZonedDateTime;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.api.cms.CmsSession;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** A canonical view of the logged in user. */
-public class EgoDashboard {
-// private BundleContext bc = FrameworkUtil.getBundle(EgoDashboard.class).getBundleContext();
-
- @PostConstruct
- public void createPartControl(Composite p) {
- p.setLayout(new GridLayout());
- String username = CurrentUser.getUsername();
-
- CmsSwtUtils.lbl(p, "<strong>" + CurrentUser.getDisplayName() + "</strong>");
- CmsSwtUtils.txt(p, username);
- CmsSwtUtils.lbl(p, "Roles:");
- roles: for (String role : CurrentUser.roles()) {
- if (username.equals(role))
- continue roles;
- CmsSwtUtils.txt(p, role);
- }
-
-// Subject subject = Subject.getSubject(AccessController.getContext());
-// if (subject != null) {
- CmsSession cmsSession = CurrentUser.getCmsSession();
- ZonedDateTime loggedIndSince = cmsSession.getCreationTime();
- CmsSwtUtils.lbl(p, "Session:");
- CmsSwtUtils.txt(p, cmsSession.getUuid().toString());
- CmsSwtUtils.lbl(p, "Logged in since:");
- CmsSwtUtils.txt(p, loggedIndSince.toString());
-// }
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
-import org.argeo.cms.ui.eclipse.forms.IManagedForm;
-import org.argeo.cms.ui.eclipse.forms.ManagedForm;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.util.naming.LdapAttrs;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.e4.ui.di.Persist;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-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.Label;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-import org.osgi.service.useradmin.UserAdminEvent;
-
-/** Editor for a user, might be a user or a group. */
-public abstract class AbstractRoleEditor {
-
- // public final static String USER_EDITOR_ID = WorkbenchUiPlugin.PLUGIN_ID +
- // ".userEditor";
- // public final static String GROUP_EDITOR_ID = WorkbenchUiPlugin.PLUGIN_ID +
- // ".groupEditor";
-
- /* DEPENDENCY INJECTION */
- @Inject
- protected UserAdminWrapper userAdminWrapper;
-
- @Inject
- private MPart mPart;
-
- // @Inject
- // Composite parent;
-
- private UserAdmin userAdmin;
-
- // Context
- private User user;
- private String username;
-
- private NameChangeListener listener;
-
- private ManagedForm managedForm;
-
- // public void init(IEditorSite site, IEditorInput input) throws
- // PartInitException {
- @PostConstruct
- public void init(Composite parent) {
- this.userAdmin = userAdminWrapper.getUserAdmin();
- username = mPart.getPersistedState().get(LdapAttrs.uid.name());
- user = (User) userAdmin.getRole(username);
-
- listener = new NameChangeListener(Display.getCurrent());
- userAdminWrapper.addListener(listener);
- updateEditorTitle(null);
-
- managedForm = new ManagedForm(parent) {
-
- @Override
- public void staleStateChanged() {
- refresh();
- }
- };
- ScrolledComposite scrolled = managedForm.getForm();
- Composite body = new Composite(scrolled, SWT.NONE);
- scrolled.setContent(body);
- createUi(body);
- managedForm.refresh();
- }
-
- abstract void createUi(Composite parent);
-
- /**
- * returns the list of all authorizations for the given user or of the current
- * displayed user if parameter is null
- */
- protected List<User> getFlatGroups(User aUser) {
- Authorization currAuth;
- if (aUser == null)
- currAuth = userAdmin.getAuthorization(this.user);
- else
- currAuth = userAdmin.getAuthorization(aUser);
-
- String[] roles = currAuth.getRoles();
-
- List<User> groups = new ArrayList<User>();
- for (String roleStr : roles) {
- User currRole = (User) userAdmin.getRole(roleStr);
- if (currRole != null && !groups.contains(currRole))
- groups.add(currRole);
- }
- return groups;
- }
-
- protected IManagedForm getManagedForm() {
- return managedForm;
- }
-
- /** Exposes the user (or group) that is displayed by the current editor */
- protected User getDisplayedUser() {
- return user;
- }
-
- private void setDisplayedUser(User user) {
- this.user = user;
- }
-
- void updateEditorTitle(String title) {
- if (title == null) {
- String commonName = UserAdminUtils.getProperty(user, LdapAttrs.cn.name());
- title = "".equals(commonName) ? user.getName() : commonName;
- }
- setPartName(title);
- }
-
- protected void setPartName(String name) {
- mPart.setLabel(name);
- }
-
- // protected void addPages() {
- // try {
- // if (user.getType() == Role.GROUP)
- // addPage(new GroupMainPage(this, userAdminWrapper, repository, nodeInstance));
- // else
- // addPage(new UserMainPage(this, userAdminWrapper));
- // } catch (Exception e) {
- // throw new CmsException("Cannot add pages", e);
- // }
- // }
-
- @Persist
- public void doSave(IProgressMonitor monitor) {
- userAdminWrapper.beginTransactionIfNeeded();
- commitPages(true);
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- // firePropertyChange(PROP_DIRTY);
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_REMOVED, user));
- }
-
- protected void commitPages(boolean b) {
- managedForm.commit(b);
- }
-
- @PreDestroy
- public void dispose() {
- userAdminWrapper.removeListener(listener);
- managedForm.dispose();
- }
-
- // CONTROLERS FOR THIS EDITOR AND ITS PAGES
-
- class NameChangeListener extends UiUserAdminListener {
- public NameChangeListener(Display display) {
- super(display);
- }
-
- @Override
- public void roleChangedToUiThread(UserAdminEvent event) {
- Role changedRole = event.getRole();
- if (changedRole == null || changedRole.equals(user)) {
- updateEditorTitle(null);
- User reloadedUser = (User) userAdminWrapper.getUserAdmin().getRole(user.getName());
- setDisplayedUser(reloadedUser);
- }
- }
- }
-
- class MainInfoListener extends UiUserAdminListener {
- private final AbstractFormPart part;
-
- public MainInfoListener(Display display, AbstractFormPart part) {
- super(display);
- this.part = part;
- }
-
- @Override
- public void roleChangedToUiThread(UserAdminEvent event) {
- // Rollback
- if (event.getRole() == null)
- part.markStale();
- }
- }
-
- class GroupChangeListener extends UiUserAdminListener {
- private final AbstractFormPart part;
-
- public GroupChangeListener(Display display, AbstractFormPart part) {
- super(display);
- this.part = part;
- }
-
- @Override
- public void roleChangedToUiThread(UserAdminEvent event) {
- // always mark as stale
- part.markStale();
- }
- }
-
- /** Registers a listener that will notify this part */
- class FormPartML implements ModifyListener {
- private static final long serialVersionUID = 6299808129505381333L;
- private AbstractFormPart formPart;
-
- public FormPartML(AbstractFormPart generalPart) {
- this.formPart = generalPart;
- }
-
- public void modifyText(ModifyEvent e) {
- // Discard event when the control does not have the focus, typically
- // to avoid all editors being marked as dirty during a Rollback
- if (((Control) e.widget).isFocusControl())
- formPart.markDirty();
- }
- }
-
- /* DEPENDENCY INJECTION */
- public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
- this.userAdminWrapper = userAdminWrapper;
- }
-
- /** Creates label and multiline text. */
- Text createLMT(Composite parent, String label, String value) {
- Label lbl = new Label(parent, SWT.NONE);
- lbl.setText(label);
- lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
- Text text = new Text(parent, SWT.NONE);
- text.setText(value);
- text.setLayoutData(new GridData(SWT.LEAD, SWT.FILL, true, true));
- return text;
- }
-
- /** Creates label and password. */
- Text createLP(Composite parent, String label, String value) {
- Label lbl = new Label(parent, SWT.NONE);
- lbl.setText(label);
- lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
- Text text = new Text(parent, SWT.PASSWORD | SWT.BORDER);
- text.setText(value);
- text.setLayoutData(new GridData(SWT.LEAD, SWT.FILL, true, false));
- return text;
- }
-
- /** Creates label and text. */
- Text createLT(Composite parent, String label, String value) {
- Label lbl = new Label(parent, SWT.NONE);
- lbl.setText(label);
- lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
- lbl.setFont(EclipseUiUtils.getBoldFont(parent));
- Text text = new Text(parent, SWT.BORDER);
- text.setText(value);
- text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
- return text;
- }
-
- Text createReadOnlyLT(Composite parent, String label, String value) {
- Label lbl = new Label(parent, SWT.NONE);
- lbl.setText(label);
- lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
- lbl.setFont(EclipseUiUtils.getBoldFont(parent));
- Text text = new Text(parent, SWT.NONE);
- text.setText(value);
- text.setLayoutData(new GridData(SWT.LEAD, SWT.FILL, true, false));
- text.setEditable(false);
- // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
- return text;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-/** Centralize the declaration of Workbench specific CSS Styles */
-interface CmsWorkbenchStyles {
-
- // Specific People layouting
- String WORKBENCH_FORM_TEXT = "workbench_form_text";
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import static org.argeo.api.cms.CmsContext.WORKGROUP;
-import static org.argeo.cms.auth.UserAdminUtils.setProperty;
-import static org.argeo.util.naming.LdapAttrs.businessCategory;
-import static org.argeo.util.naming.LdapAttrs.description;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsContext;
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.cms.e4.users.providers.CommonNameLP;
-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.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.parts.LdifUsersTable;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.transaction.WorkTransaction;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.ToolBarManager;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.ViewerDropAdapter;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.dnd.DND;
-import org.eclipse.swt.dnd.DropTargetEvent;
-import org.eclipse.swt.dnd.TextTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.dnd.TransferData;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Link;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolBar;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
-//import org.eclipse.ui.forms.AbstractFormPart;
-//import org.eclipse.ui.forms.IManagedForm;
-//import org.eclipse.ui.forms.SectionPart;
-//import org.eclipse.ui.forms.editor.FormEditor;
-//import org.eclipse.ui.forms.editor.FormPage;
-//import org.eclipse.ui.forms.widgets.FormToolkit;
-//import org.eclipse.ui.forms.widgets.ScrolledForm;
-//import org.eclipse.ui.forms.widgets.Section;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-import org.osgi.service.useradmin.UserAdminEvent;
-
-/** Display/edit main properties of a given group */
-public class GroupEditor extends AbstractRoleEditor {
- // final static String ID = "GroupEditor.mainPage";
-
- @Inject
- private EPartService partService;
-
- // private final UserEditor editor;
- @Inject
- private Repository repository;
- @Inject
- private CmsContext nodeInstance;
- // private final UserAdminWrapper userAdminWrapper;
- private Session groupsSession;
-
- // public GroupMainPage(FormEditor editor, UserAdminWrapper userAdminWrapper,
- // Repository repository,
- // NodeInstance nodeInstance) {
- // super(editor, ID, "Main");
- // try {
- // session = repository.login();
- // } catch (RepositoryException e) {
- // throw new CmsException("Cannot retrieve session of in MainGroupPage
- // constructor", e);
- // }
- // this.editor = (UserEditor) editor;
- // this.userAdminWrapper = userAdminWrapper;
- // this.nodeInstance = nodeInstance;
- // }
-
- // protected void createFormContent(final IManagedForm mf) {
- // ScrolledForm form = mf.getForm();
- // Composite body = form.getBody();
- // GridLayout mainLayout = new GridLayout();
- // body.setLayout(mainLayout);
- // Group group = (Group) editor.getDisplayedUser();
- // appendOverviewPart(body, group);
- // appendMembersPart(body, group);
- // }
-
- @Override
- protected void createUi(Composite parent) {
- try {
- groupsSession = repository.login(CmsConstants.SRV_WORKSPACE);
- } catch (RepositoryException e) {
- throw new JcrException("Cannot retrieve session", e);
- }
- // ScrolledForm form = mf.getForm();
- // Composite body = form.getBody();
- // Composite body = new Composite(parent, SWT.NONE);
- Composite body = parent;
- GridLayout mainLayout = new GridLayout();
- body.setLayout(mainLayout);
- Group group = (Group) getDisplayedUser();
- appendOverviewPart(body, group);
- appendMembersPart(body, group);
- }
-
- @PreDestroy
- public void dispose() {
- JcrUtils.logoutQuietly(groupsSession);
- super.dispose();
- }
-
- /** Creates the general section */
- protected void appendOverviewPart(final Composite parent, final Group group) {
- Composite body = new Composite(parent, SWT.NONE);
- // GridLayout layout = new GridLayout(5, false);
- GridLayout layout = new GridLayout(2, false);
- body.setLayout(layout);
- body.setLayoutData(CmsSwtUtils.fillWidth());
-
- String cn = UserAdminUtils.getProperty(group, LdapAttrs.cn.name());
- createReadOnlyLT(body, "Name", cn);
- createReadOnlyLT(body, "DN", group.getName());
- createReadOnlyLT(body, "Domain", UserAdminUtils.getDomainName(group));
-
- // Description
- Label descLbl = new Label(body, SWT.LEAD);
- descLbl.setFont(EclipseUiUtils.getBoldFont(body));
- descLbl.setText("Description");
- descLbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false, 2, 1));
- final Text descTxt = new Text(body, SWT.LEAD | SWT.MULTI | SWT.WRAP | SWT.BORDER);
- GridData gd = EclipseUiUtils.fillWidth();
- gd.heightHint = 50;
- gd.horizontalSpan = 2;
- descTxt.setLayoutData(gd);
-
- // Mark as workgroup
- Link markAsWorkgroupLk = new Link(body, SWT.NONE);
- markAsWorkgroupLk.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
-
- // create form part (controller)
- final AbstractFormPart part = new AbstractFormPart() {
-
- private MainInfoListener listener;
-
- @Override
- public void initialize(IManagedForm form) {
- super.initialize(form);
- listener = new MainInfoListener(parent.getDisplay(), this);
- userAdminWrapper.addListener(listener);
- }
-
- @Override
- public void dispose() {
- userAdminWrapper.removeListener(listener);
- super.dispose();
- }
-
- public void commit(boolean onSave) {
- // group.getProperties().put(LdapAttrs.description.name(), descTxt.getText());
- setProperty(group, description, descTxt.getText());
- super.commit(onSave);
- }
-
- @Override
- public void refresh() {
- // dnTxt.setText(group.getName());
- // cnTxt.setText(UserAdminUtils.getProperty(group, LdapAttrs.cn.name()));
- descTxt.setText(UserAdminUtils.getProperty(group, LdapAttrs.description.name()));
- Node workgroupHome = CmsJcrUtils.getGroupHome(groupsSession, cn);
- if (workgroupHome == null)
- markAsWorkgroupLk.setText("<a>Mark as workgroup</a>");
- else
- markAsWorkgroupLk.setText("Configured as workgroup");
- parent.layout(true, true);
- super.refresh();
- }
- };
-
- markAsWorkgroupLk.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -6439340898096365078L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- boolean confirmed = MessageDialog.openConfirm(parent.getShell(), "Mark as workgroup",
- "Are you sure you want to mark " + cn + " as being a workgroup? ");
- if (confirmed) {
- Node workgroupHome = CmsJcrUtils.getGroupHome(groupsSession, cn);
- if (workgroupHome != null)
- return; // already marked as workgroup, do nothing
- else {
- // improve transaction management
- userAdminWrapper.beginTransactionIfNeeded();
- nodeInstance.createWorkgroup(group.getName());
- setProperty(group, businessCategory, WORKGROUP);
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
- part.refresh();
- }
- }
- }
- });
-
- ModifyListener defaultListener = new FormPartML(part);
- descTxt.addModifyListener(defaultListener);
- getManagedForm().addPart(part);
- }
-
- /** Filtered table with members. Has drag and drop ability */
- protected void appendMembersPart(Composite parent, Group group) {
- // Section section = tk.createSection(parent, Section.TITLE_BAR);
- // section.setText("Members");
- // section.setLayoutData(EclipseUiUtils.fillAll());
-
- Composite body = new Composite(parent, SWT.BORDER);
- body.setLayout(new GridLayout());
- // section.setClient(body);
- body.setLayoutData(EclipseUiUtils.fillAll());
-
- // Define the displayed columns
- List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
- columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
- columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
- columnDefs.add(new ColumnDefinition(new MailLP(), "Mail", 150));
- // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name",
- // 240));
-
- // Create and configure the table
- LdifUsersTable userViewerCmp = new MyUserTableViewer(body, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL,
- userAdminWrapper.getUserAdmin());
-
- userViewerCmp.setColumnDefinitions(columnDefs);
- userViewerCmp.populate(true, false);
- userViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
-
- // Controllers
- TableViewer userViewer = userViewerCmp.getTableViewer();
- userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
- int operations = DND.DROP_COPY | DND.DROP_MOVE;
- Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
- userViewer.addDropSupport(operations, tt,
- new GroupDropListener(userAdminWrapper, userViewerCmp, (Group) getDisplayedUser()));
-
- AbstractFormPart part = new GroupMembersPart(userViewerCmp);
- getManagedForm().addPart(part);
-
- // remove button
- // addRemoveAbility(toolBarManager, userViewerCmp.getTableViewer(), group);
- Action action = new RemoveMembershipAction(userViewer, group, "Remove selected items from this group",
- SecurityAdminImages.ICON_REMOVE_DESC);
-
- ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
- ToolBar toolBar = toolBarManager.createControl(body);
- toolBar.setLayoutData(CmsSwtUtils.fillWidth());
-
- toolBarManager.add(action);
- toolBarManager.update(true);
-
- }
-
- // private LdifUsersTable createMemberPart(Composite parent, Group group) {
- //
- // // Define the displayed columns
- // List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
- // columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
- // columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
- // columnDefs.add(new ColumnDefinition(new MailLP(), "Mail", 150));
- // // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished
- // Name",
- // // 240));
- //
- // // Create and configure the table
- // LdifUsersTable userViewerCmp = new MyUserTableViewer(parent, SWT.MULTI |
- // SWT.H_SCROLL | SWT.V_SCROLL,
- // userAdminWrapper.getUserAdmin());
- //
- // userViewerCmp.setColumnDefinitions(columnDefs);
- // userViewerCmp.populate(true, false);
- // userViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
- //
- // // Controllers
- // TableViewer userViewer = userViewerCmp.getTableViewer();
- // userViewer.addDoubleClickListener(new
- // UserTableDefaultDClickListener(partService));
- // int operations = DND.DROP_COPY | DND.DROP_MOVE;
- // Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
- // userViewer.addDropSupport(operations, tt,
- // new GroupDropListener(userAdminWrapper, userViewerCmp, (Group)
- // getDisplayedUser()));
- //
- // // userViewerCmp.refresh();
- // return userViewerCmp;
- // }
-
- // Local viewers
- private class MyUserTableViewer extends LdifUsersTable {
- private static final long serialVersionUID = 8467999509931900367L;
-
- private final UserFilter userFilter;
-
- public MyUserTableViewer(Composite parent, int style, UserAdmin userAdmin) {
- super(parent, style, true);
- userFilter = new UserFilter();
-
- }
-
- @Override
- protected List<User> listFilteredElements(String filter) {
- // reload user and set it in the editor
- Group group = (Group) getDisplayedUser();
- Role[] roles = group.getMembers();
- List<User> users = new ArrayList<User>();
- userFilter.setSearchText(filter);
- // userFilter.setShowSystemRole(true);
- for (Role role : roles)
- // if (role.getType() == Role.GROUP)
- if (userFilter.select(null, null, role))
- users.add((User) role);
- return users;
- }
- }
-
- // private void addRemoveAbility(ToolBarManager toolBarManager, TableViewer
- // userViewer, Group group) {
- // // Section section = sectionPart.getSection();
- // // ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
- // // ToolBar toolbar = toolBarManager.createControl(parent);
- // // ToolBar toolbar = toolBarManager.getControl();
- // // final Cursor handCursor = new Cursor(toolbar.getDisplay(),
- // SWT.CURSOR_HAND);
- // // toolbar.setCursor(handCursor);
- // // toolbar.addDisposeListener(new DisposeListener() {
- // // private static final long serialVersionUID = 3882131405820522925L;
- // //
- // // public void widgetDisposed(DisposeEvent e) {
- // // if ((handCursor != null) && (handCursor.isDisposed() == false)) {
- // // handCursor.dispose();
- // // }
- // // }
- // // });
- //
- // Action action = new RemoveMembershipAction(userViewer, group, "Remove
- // selected items from this group",
- // SecurityAdminImages.ICON_REMOVE_DESC);
- // toolBarManager.add(action);
- // toolBarManager.update(true);
- // // section.setTextClient(toolbar);
- // }
-
- private class RemoveMembershipAction extends Action {
- private static final long serialVersionUID = -1337713097184522588L;
-
- private final TableViewer userViewer;
- private final Group group;
-
- RemoveMembershipAction(TableViewer userViewer, Group group, String name, ImageDescriptor img) {
- super(name, img);
- this.userViewer = userViewer;
- this.group = group;
- }
-
- @Override
- public void run() {
- ISelection selection = userViewer.getSelection();
- if (selection.isEmpty())
- return;
-
- @SuppressWarnings("unchecked")
- Iterator<User> it = ((IStructuredSelection) selection).iterator();
- List<User> users = new ArrayList<User>();
- while (it.hasNext()) {
- User currUser = it.next();
- users.add(currUser);
- }
-
- userAdminWrapper.beginTransactionIfNeeded();
- for (User user : users) {
- group.removeMember(user);
- }
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
- }
- }
-
- // LOCAL CONTROLLERS
- private class GroupMembersPart extends AbstractFormPart {
- private final LdifUsersTable userViewer;
- // private final Group group;
-
- private GroupChangeListener listener;
-
- public GroupMembersPart(LdifUsersTable userViewer) {
- // super(section);
- this.userViewer = userViewer;
- // this.group = group;
- }
-
- @Override
- public void initialize(IManagedForm form) {
- super.initialize(form);
- listener = new GroupChangeListener(userViewer.getDisplay(), GroupMembersPart.this);
- userAdminWrapper.addListener(listener);
- }
-
- @Override
- public void dispose() {
- userAdminWrapper.removeListener(listener);
- super.dispose();
- }
-
- @Override
- public void refresh() {
- userViewer.refresh();
- super.refresh();
- }
- }
-
- /**
- * Defines this table as being a potential target to add group membership
- * (roles) to this group
- */
- private class GroupDropListener extends ViewerDropAdapter {
- private static final long serialVersionUID = 2893468717831451621L;
-
- private final UserAdminWrapper userAdminWrapper;
- // private final LdifUsersTable myUserViewerCmp;
- private final Group myGroup;
-
- public GroupDropListener(UserAdminWrapper userAdminWrapper, LdifUsersTable userTableViewerCmp, Group group) {
- super(userTableViewerCmp.getTableViewer());
- this.userAdminWrapper = userAdminWrapper;
- this.myGroup = group;
- // this.myUserViewerCmp = userTableViewerCmp;
- }
-
- @Override
- public boolean validateDrop(Object target, int operation, TransferData transferType) {
- // Target is always OK in a list only view
- // TODO check if not a string
- boolean validDrop = true;
- return validDrop;
- }
-
- @Override
- public void drop(DropTargetEvent event) {
- // TODO Is there an opportunity to perform the check before?
- String newUserName = (String) event.data;
- UserAdmin myUserAdmin = userAdminWrapper.getUserAdmin();
- Role role = myUserAdmin.getRole(newUserName);
- if (role.getType() == Role.GROUP) {
- Group newGroup = (Group) role;
- Shell shell = getViewer().getControl().getShell();
- // Sanity checks
- if (myGroup == newGroup) { // Equality
- MessageDialog.openError(shell, "Forbidden addition ", "A group cannot be a member of itself.");
- return;
- }
-
- // Cycle
- String myName = myGroup.getName();
- List<User> myMemberships = getFlatGroups(myGroup);
- if (myMemberships.contains(newGroup)) {
- MessageDialog.openError(shell, "Forbidden addition: cycle",
- "Cannot add " + newUserName + " to group " + myName + ". This would create a cycle");
- return;
- }
-
- // Already member
- List<User> newGroupMemberships = getFlatGroups(newGroup);
- if (newGroupMemberships.contains(myGroup)) {
- MessageDialog.openError(shell, "Forbidden addition",
- "Cannot add " + newUserName + " to group " + myName + ", this membership already exists");
- return;
- }
- userAdminWrapper.beginTransactionIfNeeded();
- myGroup.addMember(newGroup);
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, myGroup));
- } else if (role.getType() == Role.USER) {
- // TODO check if the group is already member of this group
- WorkTransaction transaction = userAdminWrapper.beginTransactionIfNeeded();
- User user = (User) role;
- myGroup.addMember(user);
- if (UserAdminWrapper.COMMIT_ON_SAVE)
- try {
- transaction.commit();
- } catch (Exception e) {
- throw new IllegalStateException(
- "Cannot commit transaction " + "after user group membership update", e);
- }
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, myGroup));
- }
- super.drop(event);
- }
-
- @Override
- public boolean performDrop(Object data) {
- // myUserViewerCmp.refresh();
- return true;
- }
- }
-
- // LOCAL HELPERS
- // private Composite addSection(FormToolkit tk, Composite parent) {
- // Section section = tk.createSection(parent, SWT.NO_FOCUS);
- // section.setLayoutData(EclipseUiUtils.fillWidth());
- // Composite body = tk.createComposite(section, SWT.WRAP);
- // body.setLayoutData(EclipseUiUtils.fillAll());
- // section.setClient(body);
- // return body;
- // }
-
- /** Creates label and text. */
- // private Text createLT(Composite parent, String label, String value) {
- // FormToolkit toolkit = getManagedForm().getToolkit();
- // Label lbl = toolkit.createLabel(parent, label);
- // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
- // lbl.setFont(EclipseUiUtils.getBoldFont(parent));
- // Text text = toolkit.createText(parent, value, SWT.BORDER);
- // text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
- // return text;
- // }
- //
- // Text createReadOnlyLT(Composite parent, String label, String value) {
- // FormToolkit toolkit = getManagedForm().getToolkit();
- // Label lbl = toolkit.createLabel(parent, label);
- // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
- // lbl.setFont(EclipseUiUtils.getBoldFont(parent));
- // Text text = toolkit.createText(parent, value, SWT.NONE);
- // text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- // text.setEditable(false);
- // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
- // return text;
- // }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.auth.CurrentUser;
-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.UserDragListener;
-import org.argeo.cms.swt.CmsException;
-//import org.argeo.cms.ui.workbench.WorkbenchUiPlugin;
-//import org.argeo.cms.ui.workbench.internal.useradmin.UiUserAdminListener;
-//import org.argeo.cms.ui.workbench.internal.useradmin.UserAdminWrapper;
-//import org.argeo.cms.ui.workbench.internal.useradmin.providers.CommonNameLP;
-//import org.argeo.cms.ui.workbench.internal.useradmin.providers.DomainNameLP;
-//import org.argeo.cms.ui.workbench.internal.useradmin.providers.RoleIconLP;
-//import org.argeo.cms.ui.workbench.internal.useradmin.providers.UserDragListener;
-//import org.argeo.cms.ui.workbench.internal.useradmin.providers.UserTableDefaultDClickListener;
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.parts.LdifUsersTable;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-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.dnd.DND;
-import org.eclipse.swt.dnd.TextTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-//import org.eclipse.ui.part.ViewPart;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdminEvent;
-import org.osgi.service.useradmin.UserAdminListener;
-
-/** List all groups with filter */
-public class GroupsView {
- private final static CmsLog log = CmsLog.getLog(GroupsView.class);
- // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".groupsView";
-
- @Inject
- private EPartService partService;
- @Inject
- private UserAdminWrapper userAdminWrapper;
-
- // UI Objects
- private LdifUsersTable groupTableViewerCmp;
- private TableViewer userViewer;
- private List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
-
- private UserAdminListener listener;
-
- @PostConstruct
- public void createPartControl(Composite parent, ESelectionService selectionService) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
- // boolean isAdmin = CurrentUser.isInRole(NodeConstants.ROLE_ADMIN);
-
- // Define the displayed columns
- columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 19));
- columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
- columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 100));
- // Only show technical DN to admin
- // if (isAdmin)
- // columnDefs.add(new ColumnDefinition(new UserNameLP(),
- // "Distinguished Name", 300));
-
- // Create and configure the table
- groupTableViewerCmp = new MyUserTableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
-
- groupTableViewerCmp.setColumnDefinitions(columnDefs);
- // if (isAdmin)
- // groupTableViewerCmp.populateWithStaticFilters(false, false);
- // else
- groupTableViewerCmp.populate(true, false);
-
- groupTableViewerCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
- // Links
- userViewer = groupTableViewerCmp.getTableViewer();
- userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
- // getViewSite().setSelectionProvider(userViewer);
- userViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- IStructuredSelection selection = (IStructuredSelection) event.getSelection();
- selectionService.setSelection(selection.toList());
- }
- });
-
- // Really?
- groupTableViewerCmp.refresh();
-
- // Drag and drop
- int operations = DND.DROP_COPY | DND.DROP_MOVE;
- Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
- userViewer.addDragSupport(operations, tt, new UserDragListener(userViewer));
-
- // // Register a useradmin listener
- // listener = new UserAdminListener() {
- // @Override
- // public void roleChanged(UserAdminEvent event) {
- // if (userViewer != null && !userViewer.getTable().isDisposed())
- // refresh();
- // }
- // };
- // userAdminWrapper.addListener(listener);
- // }
-
- // Register a useradmin listener
- listener = new MyUiUAListener(parent.getDisplay());
- userAdminWrapper.addListener(listener);
- }
-
- private class MyUiUAListener extends UiUserAdminListener {
- public MyUiUAListener(Display display) {
- super(display);
- }
-
- @Override
- public void roleChangedToUiThread(UserAdminEvent event) {
- if (userViewer != null && !userViewer.getTable().isDisposed())
- refresh();
- }
- }
-
- private class MyUserTableViewer extends LdifUsersTable {
- private static final long serialVersionUID = 8467999509931900367L;
-
- private boolean showSystemRoles = true;
-
- private final String[] knownProps = { LdapAttrs.uid.name(), LdapAttrs.cn.name(), LdapAttrs.DN };
-
- public MyUserTableViewer(Composite parent, int style) {
- super(parent, style);
- showSystemRoles = CurrentUser.isInRole(CmsConstants.ROLE_ADMIN);
- }
-
- protected void populateStaticFilters(Composite staticFilterCmp) {
- staticFilterCmp.setLayout(new GridLayout());
- final Button showSystemRoleBtn = new Button(staticFilterCmp, SWT.CHECK);
- showSystemRoleBtn.setText("Show system roles");
- showSystemRoles = CurrentUser.isInRole(CmsConstants.ROLE_ADMIN);
- showSystemRoleBtn.setSelection(showSystemRoles);
-
- showSystemRoleBtn.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -7033424592697691676L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- showSystemRoles = showSystemRoleBtn.getSelection();
- refresh();
- }
-
- });
- }
-
- @Override
- protected List<User> listFilteredElements(String filter) {
- Role[] roles;
- try {
- StringBuilder builder = new StringBuilder();
- StringBuilder tmpBuilder = new StringBuilder();
- if (EclipseUiUtils.notEmpty(filter))
- for (String prop : knownProps) {
- tmpBuilder.append("(");
- tmpBuilder.append(prop);
- tmpBuilder.append("=*");
- tmpBuilder.append(filter);
- tmpBuilder.append("*)");
- }
- if (tmpBuilder.length() > 1) {
- builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
- .append(LdapObjs.groupOfNames.name()).append(")");
- // hide tokens
- builder.append("(!(").append(LdapAttrs.DN).append("=*").append(CmsConstants.TOKENS_BASEDN)
- .append("))");
-
- if (!showSystemRoles)
- builder.append("(!(").append(LdapAttrs.DN).append("=*").append(CmsConstants.ROLES_BASEDN)
- .append("))");
- builder.append("(|");
- builder.append(tmpBuilder.toString());
- builder.append("))");
- } else {
- if (!showSystemRoles)
- builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
- .append(LdapObjs.groupOfNames.name()).append(")(!(").append(LdapAttrs.DN).append("=*")
- .append(CmsConstants.ROLES_BASEDN).append("))(!(").append(LdapAttrs.DN).append("=*")
- .append(CmsConstants.TOKENS_BASEDN).append(")))");
- else
- builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
- .append(LdapObjs.groupOfNames.name()).append(")(!(").append(LdapAttrs.DN).append("=*")
- .append(CmsConstants.TOKENS_BASEDN).append(")))");
-
- }
- roles = userAdminWrapper.getUserAdmin().getRoles(builder.toString());
- } catch (InvalidSyntaxException e) {
- throw new CmsException("Unable to get roles with filter: " + filter, e);
- }
- List<User> users = new ArrayList<User>();
- for (Role role : roles)
- if (!users.contains(role))
- users.add((User) role);
- else
- log.warn("Duplicated role: " + role);
-
- return users;
- }
- }
-
- public void refresh() {
- groupTableViewerCmp.refresh();
- }
-
- @PreDestroy
- public void dispose() {
- userAdminWrapper.removeListener(listener);
- }
-
- @Focus
- public void setFocus() {
- groupTableViewerCmp.setFocus();
- }
-
- /* DEPENDENCY INJECTION */
- public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
- this.userAdminWrapper = userAdminWrapper;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import org.argeo.cms.ui.theme.CmsImages;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.swt.graphics.Image;
-
-/** Shared icons that must be declared programmatically . */
-public class SecurityAdminImages extends CmsImages {
- private final static String PREFIX = "icons/";
-
- public final static ImageDescriptor ICON_REMOVE_DESC = createDesc(PREFIX + "delete.png");
- public final static ImageDescriptor ICON_USER_DESC = createDesc(PREFIX + "person.png");
-
- public final static Image ICON_USER = ICON_USER_DESC.createImage();
- public final static Image ICON_GROUP = createImg(PREFIX + "group.png");
- public final static Image ICON_WORKGROUP = createImg(PREFIX + "workgroup.png");
- public final static Image ICON_ROLE = createImg(PREFIX + "role.gif");
-
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import org.argeo.util.transaction.WorkTransaction;
-
-/** First effort to centralize back end methods used by the user admin UI */
-public class UiAdminUtils {
- /*
- * INTERNAL METHODS: Below methods are meant to stay here and are not part
- * of a potential generic backend to manage the useradmin
- */
- /** Easily notify the ActiveWindow that the transaction had a state change */
- public final static void notifyTransactionStateChange(
- WorkTransaction userTransaction) {
-// try {
-// IWorkbenchWindow aww = PlatformUI.getWorkbench()
-// .getActiveWorkbenchWindow();
-// ISourceProviderService sourceProviderService = (ISourceProviderService) aww
-// .getService(ISourceProviderService.class);
-// UserTransactionProvider esp = (UserTransactionProvider) sourceProviderService
-// .getSourceProvider(UserTransactionProvider.TRANSACTION_STATE);
-// esp.fireTransactionStateChange();
-// } catch (Exception e) {
-// throw new CmsException("Unable to begin transaction", e);
-// }
- }
-
- /**
- * Email addresses must match this regexp pattern ({@value #EMAIL_PATTERN}.
- * Thanks to <a href=
- * "http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/"
- * >this tip</a>.
- */
- public final static String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import org.eclipse.swt.widgets.Display;
-import org.osgi.service.useradmin.UserAdminEvent;
-import org.osgi.service.useradmin.UserAdminListener;
-
-/** Convenience class to insure the call to refresh is done in the UI thread */
-public abstract class UiUserAdminListener implements UserAdminListener {
-
- private final Display display;
-
- public UiUserAdminListener(Display display) {
- this.display = display;
- }
-
- @Override
- public void roleChanged(final UserAdminEvent event) {
- display.asyncExec(new Runnable() {
- @Override
- public void run() {
- roleChangedToUiThread(event);
- }
- });
- }
-
- public abstract void roleChangedToUiThread(UserAdminEvent event);
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.osgi.useradmin.UserDirectory;
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.transaction.WorkTransaction;
-import org.osgi.service.useradmin.UserAdmin;
-import org.osgi.service.useradmin.UserAdminEvent;
-import org.osgi.service.useradmin.UserAdminListener;
-
-/** Centralise interaction with the UserAdmin in this bundle */
-public class UserAdminWrapper {
-
- private UserAdmin userAdmin;
- // private ServiceReference<UserAdmin> userAdminServiceReference;
-// private Set<String> uris;
- private Map<UserDirectory, Hashtable<String, String>> userDirectories = Collections
- .synchronizedMap(new LinkedHashMap<>());
- private WorkTransaction userTransaction;
-
- // First effort to simplify UX while managing users and groups
- public final static boolean COMMIT_ON_SAVE = true;
-
- // Registered listeners
- List<UserAdminListener> listeners = new ArrayList<UserAdminListener>();
-
- /**
- * Starts a transaction if necessary. Should always been called together with
- * {@link UserAdminWrapper#commitOrNotifyTransactionStateChange()} once the
- * security model changes have been performed.
- */
- public WorkTransaction beginTransactionIfNeeded() {
- try {
- // UserTransaction userTransaction = getUserTransaction();
- if (userTransaction.isNoTransactionStatus()) {
- userTransaction.begin();
- // UiAdminUtils.notifyTransactionStateChange(userTransaction);
- }
- return userTransaction;
- } catch (Exception e) {
- throw new CmsException("Unable to begin transaction", e);
- }
- }
-
- /**
- * Depending on the current application configuration, it will either commit the
- * current transaction or throw a notification that the transaction state has
- * changed (In the later case, it must be called from the UI thread).
- */
- public void commitOrNotifyTransactionStateChange() {
- try {
- // UserTransaction userTransaction = getUserTransaction();
- if (userTransaction.isNoTransactionStatus())
- return;
-
- if (UserAdminWrapper.COMMIT_ON_SAVE)
- userTransaction.commit();
- else
- UiAdminUtils.notifyTransactionStateChange(userTransaction);
- } catch (Exception e) {
- throw new CmsException("Unable to clean transaction", e);
- }
- }
-
- // TODO implement safer mechanism
- public void addListener(UserAdminListener userAdminListener) {
- if (!listeners.contains(userAdminListener))
- listeners.add(userAdminListener);
- }
-
- public void removeListener(UserAdminListener userAdminListener) {
- if (listeners.contains(userAdminListener))
- listeners.remove(userAdminListener);
- }
-
- public void notifyListeners(UserAdminEvent event) {
- for (UserAdminListener listener : listeners)
- listener.roleChanged(event);
- }
-
- public Map<String, String> getKnownBaseDns(boolean onlyWritable) {
- Map<String, String> dns = new HashMap<String, String>();
- for (UserDirectory userDirectory : userDirectories.keySet()) {
- Boolean readOnly = userDirectory.isReadOnly();
- String baseDn = userDirectory.getContext();
-
- if (onlyWritable && readOnly)
- continue;
- if (baseDn.equalsIgnoreCase(CmsConstants.ROLES_BASEDN))
- continue;
- if (baseDn.equalsIgnoreCase(CmsConstants.TOKENS_BASEDN))
- continue;
- dns.put(baseDn, DirectoryConf.propertiesAsUri(userDirectories.get(userDirectory)).toString());
-
- }
-// for (String uri : uris) {
-// if (!uri.startsWith("/"))
-// continue;
-// Dictionary<String, ?> props = UserAdminConf.uriAsProperties(uri);
-// String readOnly = UserAdminConf.readOnly.getValue(props);
-// String baseDn = UserAdminConf.baseDn.getValue(props);
-//
-// if (onlyWritable && "true".equals(readOnly))
-// continue;
-// if (baseDn.equalsIgnoreCase(NodeConstants.ROLES_BASEDN))
-// continue;
-// if (baseDn.equalsIgnoreCase(NodeConstants.TOKENS_BASEDN))
-// continue;
-// dns.put(baseDn, uri);
-// }
- return dns;
- }
-
- public UserAdmin getUserAdmin() {
- return userAdmin;
- }
-
- public WorkTransaction getUserTransaction() {
- return userTransaction;
- }
-
- /* DEPENDENCY INJECTION */
- public void setUserAdmin(UserAdmin userAdmin, Map<String, String> properties) {
- this.userAdmin = userAdmin;
-// this.uris = Collections.unmodifiableSortedSet(new TreeSet<>(properties.keySet()));
- }
-
- public void setUserTransaction(WorkTransaction userTransaction) {
- this.userTransaction = userTransaction;
- }
-
- public void addUserDirectory(UserDirectory userDirectory, Map<String, String> properties) {
- userDirectories.put(userDirectory, new Hashtable<>(properties));
- }
-
- public void removeUserDirectory(UserDirectory userDirectory, Map<String, String> properties) {
- userDirectories.remove(userDirectory);
- }
-
- // public void setUserAdminServiceReference(
- // ServiceReference<UserAdmin> userAdminServiceReference) {
- // this.userAdminServiceReference = userAdminServiceReference;
- // }
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.cms.e4.users.providers.CommonNameLP;
-import org.argeo.cms.e4.users.providers.DomainNameLP;
-import org.argeo.cms.e4.users.providers.MailLP;
-import org.argeo.cms.e4.users.providers.UserNameLP;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.parts.LdifUsersTable;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
-import org.argeo.util.transaction.WorkTransaction;
-import org.eclipse.jface.dialogs.IPageChangeProvider;
-import org.eclipse.jface.dialogs.IPageChangedListener;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.dialogs.PageChangedEvent;
-import org.eclipse.jface.wizard.IWizardContainer;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdminEvent;
-
-/** Wizard to update users */
-public class UserBatchUpdateWizard extends Wizard {
-
- private final static CmsLog log = CmsLog.getLog(UserBatchUpdateWizard.class);
- private UserAdminWrapper userAdminWrapper;
-
- // pages
- private ChooseCommandWizardPage chooseCommandPage;
- private ChooseUsersWizardPage userListPage;
- private ValidateAndLaunchWizardPage validatePage;
-
- // Various implemented commands keys
- private final static String CMD_UPDATE_PASSWORD = "resetPassword";
- private final static String CMD_UPDATE_EMAIL = "resetEmail";
- private final static String CMD_GROUP_MEMBERSHIP = "groupMembership";
-
- private final Map<String, String> commands = new HashMap<String, String>() {
- private static final long serialVersionUID = 1L;
- {
- put("Reset password(s)", CMD_UPDATE_PASSWORD);
- put("Reset email(s)", CMD_UPDATE_EMAIL);
- // TODO implement role / group management
- // put("Add/Remove from group", CMD_GROUP_MEMBERSHIP);
- }
- };
-
- public UserBatchUpdateWizard(UserAdminWrapper userAdminWrapper) {
- this.userAdminWrapper = userAdminWrapper;
- }
-
- @Override
- public void addPages() {
- chooseCommandPage = new ChooseCommandWizardPage();
- addPage(chooseCommandPage);
- userListPage = new ChooseUsersWizardPage();
- addPage(userListPage);
- validatePage = new ValidateAndLaunchWizardPage();
- addPage(validatePage);
- }
-
- @Override
- public boolean performFinish() {
- if (!canFinish())
- return false;
- WorkTransaction ut = userAdminWrapper.getUserTransaction();
- if (!ut.isNoTransactionStatus() && !MessageDialog.openConfirm(getShell(), "Existing Transaction",
- "A user transaction is already existing, " + "are you sure you want to proceed ?"))
- return false;
-
- // We cannot use jobs, user modifications are still meant to be done in
- // the UIThread
- // UpdateJob job = null;
- // if (job != null)
- // job.schedule();
-
- if (CMD_UPDATE_PASSWORD.equals(chooseCommandPage.getCommand())) {
- char[] newValue = chooseCommandPage.getPwdValue();
- if (newValue == null)
- throw new CmsException("Password cannot be null or an empty string");
- ResetPassword job = new ResetPassword(userAdminWrapper, userListPage.getSelectedUsers(), newValue);
- job.doUpdate();
- } else if (CMD_UPDATE_EMAIL.equals(chooseCommandPage.getCommand())) {
- String newValue = chooseCommandPage.getEmailValue();
- if (newValue == null)
- throw new CmsException("Password cannot be null or an empty string");
- ResetEmail job = new ResetEmail(userAdminWrapper, userListPage.getSelectedUsers(), newValue);
- job.doUpdate();
- }
- return true;
- }
-
- public boolean canFinish() {
- if (this.getContainer().getCurrentPage() == validatePage)
- return true;
- return false;
- }
-
- private class ResetPassword {
- private char[] newPwd;
- private UserAdminWrapper userAdminWrapper;
- private List<User> usersToUpdate;
-
- public ResetPassword(UserAdminWrapper userAdminWrapper, List<User> usersToUpdate, char[] newPwd) {
- this.newPwd = newPwd;
- this.usersToUpdate = usersToUpdate;
- this.userAdminWrapper = userAdminWrapper;
- }
-
- @SuppressWarnings("unchecked")
- protected void doUpdate() {
- userAdminWrapper.beginTransactionIfNeeded();
- try {
- for (User user : usersToUpdate) {
- // the char array is emptied after being used.
- user.getCredentials().put(null, newPwd.clone());
- }
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- } catch (Exception e) {
- throw new CmsException("Cannot perform batch update on users", e);
- } finally {
- WorkTransaction ut = userAdminWrapper.getUserTransaction();
- if (!ut.isNoTransactionStatus())
- ut.rollback();
- }
- }
- }
-
- private class ResetEmail {
- private String newEmail;
- private UserAdminWrapper userAdminWrapper;
- private List<User> usersToUpdate;
-
- public ResetEmail(UserAdminWrapper userAdminWrapper, List<User> usersToUpdate, String newEmail) {
- this.newEmail = newEmail;
- this.usersToUpdate = usersToUpdate;
- this.userAdminWrapper = userAdminWrapper;
- }
-
- @SuppressWarnings("unchecked")
- protected void doUpdate() {
- userAdminWrapper.beginTransactionIfNeeded();
- try {
- for (User user : usersToUpdate) {
- // the char array is emptied after being used.
- user.getProperties().put(LdapAttrs.mail.name(), newEmail);
- }
-
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- if (!usersToUpdate.isEmpty())
- userAdminWrapper.notifyListeners(
- new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, usersToUpdate.get(0)));
- } catch (Exception e) {
- throw new CmsException("Cannot perform batch update on users", e);
- } finally {
- WorkTransaction ut = userAdminWrapper.getUserTransaction();
- if (!ut.isNoTransactionStatus())
- ut.rollback();
- }
- }
- }
-
- // @SuppressWarnings("unused")
- // private class AddToGroup extends UpdateJob {
- // private String groupID;
- // private Session session;
- //
- // public AddToGroup(Session session, List<Node> nodesToUpdate,
- // String groupID) {
- // super(session, nodesToUpdate);
- // this.session = session;
- // this.groupID = groupID;
- // }
- //
- // protected void doUpdate(Node node) {
- // log.info("Add/Remove to group actions are not yet implemented");
- // // TODO implement this
- // // try {
- // // throw new CmsException("Not yet implemented");
- // // } catch (RepositoryException re) {
- // // throw new CmsException(
- // // "Unable to update boolean value for node " + node, re);
- // // }
- // }
- // }
-
- // /**
- // * Base privileged job that will be run asynchronously to perform the
- // batch
- // * update
- // */
- // private abstract class UpdateJob extends PrivilegedJob {
- //
- // private final UserAdminWrapper userAdminWrapper;
- // private final List<User> usersToUpdate;
- //
- // protected abstract void doUpdate(User user);
- //
- // public UpdateJob(UserAdminWrapper userAdminWrapper,
- // List<User> usersToUpdate) {
- // super("Perform update");
- // this.usersToUpdate = usersToUpdate;
- // this.userAdminWrapper = userAdminWrapper;
- // }
- //
- // @Override
- // protected IStatus doRun(IProgressMonitor progressMonitor) {
- // try {
- // JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor);
- // int total = usersToUpdate.size();
- // monitor.beginTask("Performing change", total);
- // userAdminWrapper.beginTransactionIfNeeded();
- // for (User user : usersToUpdate) {
- // doUpdate(user);
- // monitor.worked(1);
- // }
- // userAdminWrapper.getUserTransaction().commit();
- // } catch (Exception e) {
- // throw new CmsException(
- // "Cannot perform batch update on users", e);
- // } finally {
- // UserTransaction ut = userAdminWrapper.getUserTransaction();
- // try {
- // if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION)
- // ut.rollback();
- // } catch (IllegalStateException | SecurityException
- // | SystemException e) {
- // log.error("Unable to rollback session in 'finally', "
- // + "the system might be in a dirty state");
- // e.printStackTrace();
- // }
- // }
- // return Status.OK_STATUS;
- // }
- // }
-
- // PAGES
- /**
- * Displays a combo box that enables user to choose which action to perform
- */
- private class ChooseCommandWizardPage extends WizardPage {
- private static final long serialVersionUID = -8069434295293996633L;
- private Combo chooseCommandCmb;
- private Button trueChk;
- private Text valueTxt;
- private Text pwdTxt;
- private Text pwd2Txt;
-
- public ChooseCommandWizardPage() {
- super("Choose a command to run.");
- setTitle("Choose a command to run.");
- }
-
- @Override
- public void createControl(Composite parent) {
- GridLayout gl = new GridLayout();
- Composite container = new Composite(parent, SWT.NO_FOCUS);
- container.setLayout(gl);
-
- chooseCommandCmb = new Combo(container, SWT.READ_ONLY);
- chooseCommandCmb.setLayoutData(EclipseUiUtils.fillWidth());
- String[] values = commands.keySet().toArray(new String[0]);
- chooseCommandCmb.setItems(values);
-
- final Composite bottomPart = new Composite(container, SWT.NO_FOCUS);
- bottomPart.setLayoutData(EclipseUiUtils.fillAll());
- bottomPart.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
- chooseCommandCmb.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- if (getCommand().equals(CMD_UPDATE_PASSWORD))
- populatePasswordCmp(bottomPart);
- else if (getCommand().equals(CMD_UPDATE_EMAIL))
- populateEmailCmp(bottomPart);
- else if (getCommand().equals(CMD_GROUP_MEMBERSHIP))
- populateGroupCmp(bottomPart);
- else
- populateBooleanFlagCmp(bottomPart);
- checkPageComplete();
- bottomPart.layout(true, true);
- }
- });
- setControl(container);
- }
-
- private void populateBooleanFlagCmp(Composite parent) {
- EclipseUiUtils.clear(parent);
- trueChk = new Button(parent, SWT.CHECK);
- trueChk.setText("Do it. (It will to the contrary if unchecked)");
- trueChk.setSelection(true);
- trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
- }
-
- private void populatePasswordCmp(Composite parent) {
- EclipseUiUtils.clear(parent);
- Composite body = new Composite(parent, SWT.NO_FOCUS);
-
- ModifyListener ml = new ModifyListener() {
- private static final long serialVersionUID = -1558726363536729634L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- checkPageComplete();
- }
- };
-
- body.setLayout(new GridLayout(2, false));
- body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- pwdTxt = EclipseUiUtils.createGridLP(body, "New password", ml);
- pwd2Txt = EclipseUiUtils.createGridLP(body, "Repeat password", ml);
- }
-
- private void populateEmailCmp(Composite parent) {
- EclipseUiUtils.clear(parent);
- Composite body = new Composite(parent, SWT.NO_FOCUS);
-
- ModifyListener ml = new ModifyListener() {
- private static final long serialVersionUID = 2147704227294268317L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- checkPageComplete();
- }
- };
-
- body.setLayout(new GridLayout(2, false));
- body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- valueTxt = EclipseUiUtils.createGridLT(body, "New e-mail", ml);
- }
-
- private void checkPageComplete() {
- String errorMsg = null;
- if (chooseCommandCmb.getSelectionIndex() < 0)
- errorMsg = "Please select an action";
- else if (CMD_UPDATE_EMAIL.equals(getCommand())) {
- if (!valueTxt.getText().matches(UiAdminUtils.EMAIL_PATTERN))
- errorMsg = "Not a valid e-mail address";
- } else if (CMD_UPDATE_PASSWORD.equals(getCommand())) {
- if (EclipseUiUtils.isEmpty(pwdTxt.getText()) || pwdTxt.getText().length() < 4)
- errorMsg = "Please enter a password that is at least 4 character long";
- else if (!pwdTxt.getText().equals(pwd2Txt.getText()))
- errorMsg = "Passwords are different";
- }
- if (EclipseUiUtils.notEmpty(errorMsg)) {
- setMessage(errorMsg, WizardPage.ERROR);
- setPageComplete(false);
- } else {
- setMessage("Page complete, you can proceed to user choice", WizardPage.INFORMATION);
- setPageComplete(true);
- }
-
- getContainer().updateButtons();
- }
-
- private void populateGroupCmp(Composite parent) {
- EclipseUiUtils.clear(parent);
- trueChk = new Button(parent, SWT.CHECK);
- trueChk.setText("Add to group. (It will remove user(s) from the " + "corresponding group if unchecked)");
- trueChk.setSelection(true);
- trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
- }
-
- protected String getCommand() {
- return commands.get(chooseCommandCmb.getItem(chooseCommandCmb.getSelectionIndex()));
- }
-
- protected String getCommandLbl() {
- return chooseCommandCmb.getItem(chooseCommandCmb.getSelectionIndex());
- }
-
- @SuppressWarnings("unused")
- protected boolean getBoleanValue() {
- // FIXME this is not consistent and will lead to errors.
- if ("argeo:enabled".equals(getCommand()))
- return trueChk.getSelection();
- else
- return !trueChk.getSelection();
- }
-
- @SuppressWarnings("unused")
- protected String getStringValue() {
- String value = null;
- if (valueTxt != null) {
- value = valueTxt.getText();
- if ("".equals(value.trim()))
- value = null;
- }
- return value;
- }
-
- protected char[] getPwdValue() {
- // We do not directly reset the password text fields: There is no
- // need to over secure this process: setting a pwd to multi users
- // at the same time is anyhow a bad practice and should be used only
- // in test environment or for temporary access
- if (pwdTxt == null || pwdTxt.isDisposed())
- return null;
- else
- return pwdTxt.getText().toCharArray();
- }
-
- protected String getEmailValue() {
- // We do not directly reset the password text fields: There is no
- // need to over secure this process: setting a pwd to multi users
- // at the same time is anyhow a bad practice and should be used only
- // in test environment or for temporary access
- if (valueTxt == null || valueTxt.isDisposed())
- return null;
- else
- return valueTxt.getText();
- }
- }
-
- /**
- * Displays a list of users with a check box to be able to choose some of them
- */
- private class ChooseUsersWizardPage extends WizardPage implements IPageChangedListener {
- private static final long serialVersionUID = 7651807402211214274L;
- private ChooseUserTableViewer userTableCmp;
-
- public ChooseUsersWizardPage() {
- super("Choose Users");
- setTitle("Select users who will be impacted");
- }
-
- @Override
- public void createControl(Composite parent) {
- Composite pageCmp = new Composite(parent, SWT.NONE);
- pageCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
- // Define the displayed columns
- List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
- columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
- columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
- columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
-
- // Only show technical DN to admin
- if (CurrentUser.isInRole(CmsConstants.ROLE_ADMIN))
- columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
-
- userTableCmp = new ChooseUserTableViewer(pageCmp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
- userTableCmp.setLayoutData(EclipseUiUtils.fillAll());
- userTableCmp.setColumnDefinitions(columnDefs);
- userTableCmp.populate(true, true);
- userTableCmp.refresh();
-
- setControl(pageCmp);
-
- // Add listener to update message when shown
- final IWizardContainer wContainer = this.getContainer();
- if (wContainer instanceof IPageChangeProvider) {
- ((IPageChangeProvider) wContainer).addPageChangedListener(this);
- }
-
- }
-
- @Override
- public void pageChanged(PageChangedEvent event) {
- if (event.getSelectedPage() == this) {
- String msg = "Chosen batch action: " + chooseCommandPage.getCommandLbl();
- ((WizardPage) event.getSelectedPage()).setMessage(msg);
- }
- }
-
- protected List<User> getSelectedUsers() {
- return userTableCmp.getSelectedUsers();
- }
-
- private class ChooseUserTableViewer extends LdifUsersTable {
- private static final long serialVersionUID = 5080437561015853124L;
- private final String[] knownProps = { LdapAttrs.uid.name(), LdapAttrs.DN, LdapAttrs.cn.name(),
- LdapAttrs.givenName.name(), LdapAttrs.sn.name(), LdapAttrs.mail.name() };
-
- public ChooseUserTableViewer(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected List<User> listFilteredElements(String filter) {
- Role[] roles;
-
- try {
- StringBuilder builder = new StringBuilder();
-
- StringBuilder tmpBuilder = new StringBuilder();
- if (EclipseUiUtils.notEmpty(filter))
- for (String prop : knownProps) {
- tmpBuilder.append("(");
- tmpBuilder.append(prop);
- tmpBuilder.append("=*");
- tmpBuilder.append(filter);
- tmpBuilder.append("*)");
- }
- if (tmpBuilder.length() > 1) {
- builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
- .append(LdapObjs.inetOrgPerson.name()).append(")(|");
- builder.append(tmpBuilder.toString());
- builder.append("))");
- } else
- builder.append("(").append(LdapAttrs.objectClass.name()).append("=")
- .append(LdapObjs.inetOrgPerson.name()).append(")");
- roles = userAdminWrapper.getUserAdmin().getRoles(builder.toString());
- } catch (InvalidSyntaxException e) {
- throw new CmsException("Unable to get roles with filter: " + filter, e);
- }
- List<User> users = new ArrayList<User>();
- for (Role role : roles)
- // Prevent current logged in user to perform batch on
- // himself
- if (!UserAdminUtils.isCurrentUser((User) role))
- users.add((User) role);
- return users;
- }
- }
- }
-
- /** Summary of input data before launching the process */
- private class ValidateAndLaunchWizardPage extends WizardPage implements IPageChangedListener {
- private static final long serialVersionUID = 7098918351451743853L;
- private ChosenUsersTableViewer userTableCmp;
-
- public ValidateAndLaunchWizardPage() {
- super("Validate and launch");
- setTitle("Validate and launch");
- }
-
- @Override
- public void createControl(Composite parent) {
- Composite pageCmp = new Composite(parent, SWT.NO_FOCUS);
- pageCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
- List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
- columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
- columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
- columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
- // Only show technical DN to admin
- if (CurrentUser.isInRole(CmsConstants.ROLE_ADMIN))
- columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
- userTableCmp = new ChosenUsersTableViewer(pageCmp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
- userTableCmp.setLayoutData(EclipseUiUtils.fillAll());
- userTableCmp.setColumnDefinitions(columnDefs);
- userTableCmp.populate(false, false);
- userTableCmp.refresh();
- setControl(pageCmp);
- // Add listener to update message when shown
- final IWizardContainer wContainer = this.getContainer();
- if (wContainer instanceof IPageChangeProvider) {
- ((IPageChangeProvider) wContainer).addPageChangedListener(this);
- }
- }
-
- @Override
- public void pageChanged(PageChangedEvent event) {
- if (event.getSelectedPage() == this) {
- @SuppressWarnings({ "unchecked", "rawtypes" })
- Object[] values = ((ArrayList) userListPage.getSelectedUsers())
- .toArray(new Object[userListPage.getSelectedUsers().size()]);
- userTableCmp.getTableViewer().setInput(values);
- String msg = "Following batch action: [" + chooseCommandPage.getCommandLbl()
- + "] will be perfomed on the users listed below.\n";
- // + "Are you sure you want to proceed?";
- setMessage(msg);
- }
- }
-
- private class ChosenUsersTableViewer extends LdifUsersTable {
- private static final long serialVersionUID = 7814764735794270541L;
-
- public ChosenUsersTableViewer(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected List<User> listFilteredElements(String filter) {
- return userListPage.getSelectedUsers();
- }
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import static org.argeo.cms.auth.UserAdminUtils.getProperty;
-import static org.argeo.util.naming.LdapAttrs.cn;
-import static org.argeo.util.naming.LdapAttrs.givenName;
-import static org.argeo.util.naming.LdapAttrs.mail;
-import static org.argeo.util.naming.LdapAttrs.sn;
-import static org.argeo.util.naming.LdapAttrs.uid;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.auth.UserAdminUtils;
-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.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.parts.LdifUsersTable;
-import org.argeo.util.naming.LdapAttrs;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.ToolBarManager;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.dialogs.TrayDialog;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerDropAdapter;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.dnd.DND;
-import org.eclipse.swt.dnd.DropTargetEvent;
-import org.eclipse.swt.dnd.TextTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.dnd.TransferData;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Link;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolBar;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-import org.osgi.service.useradmin.UserAdminEvent;
-
-/** Display/edit the properties of a given user */
-public class UserEditor extends AbstractRoleEditor {
- // final static String ID = "UserEditor.mainPage";
-
- @Inject
- private EPartService partService;
-
- // private final UserEditor editor;
- // private UserAdminWrapper userAdminWrapper;
-
- // Local configuration
- // private final int PRE_TITLE_INDENT = 10;
-
- // public UserMainPage(FormEditor editor, UserAdminWrapper userAdminWrapper) {
- // super(editor, ID, "Main");
- // this.editor = (UserEditor) editor;
- // this.userAdminWrapper = userAdminWrapper;
- // }
-
- // protected void createFormContent(final IManagedForm mf) {
- // ScrolledForm form = mf.getForm();
- // Composite body = form.getBody();
- // GridLayout mainLayout = new GridLayout();
- // // mainLayout.marginRight = 10;
- // body.setLayout(mainLayout);
- // User user = editor.getDisplayedUser();
- // appendOverviewPart(body, user);
- // // Remove to ability to force the password for his own user. The user
- // // must then use the change pwd feature
- // appendMemberOfPart(body, user);
- // }
-
- @Override
- protected void createUi(Composite body) {
- // Composite body = new Composite(parent, SWT.BORDER);
- GridLayout mainLayout = new GridLayout();
- // mainLayout.marginRight = 10;
- body.setLayout(mainLayout);
- // body.getParent().setLayout(new GridLayout());
- // body.setLayoutData(CmsUiUtils.fillAll());
- User user = getDisplayedUser();
- appendOverviewPart(body, user);
- // Remove to ability to force the password for his own user. The user
- // must then use the change pwd feature
- appendMemberOfPart(body, user);
- }
-
- /** Creates the general section */
- private void appendOverviewPart(final Composite parent, final User user) {
- // FormToolkit tk = getManagedForm().getToolkit();
-
- // Section section = tk.createSection(parent, SWT.NO_FOCUS);
- // GridData gd = EclipseUiUtils.fillWidth();
- // // gd.verticalAlignment = PRE_TITLE_INDENT;
- // section.setLayoutData(gd);
- Composite body = new Composite(parent, SWT.NONE);
- body.setLayoutData(EclipseUiUtils.fillWidth());
- // section.setClient(body);
- // body.setLayout(new GridLayout(6, false));
- body.setLayout(new GridLayout(2, false));
-
- Text commonName = createReadOnlyLT(body, "Name", getProperty(user, cn));
- Text distinguishedName = createReadOnlyLT(body, "Login", getProperty(user, uid));
- Text firstName = createLT(body, "First name", getProperty(user, givenName));
- Text lastName = createLT(body, "Last name", getProperty(user, sn));
- Text email = createLT(body, "Email", getProperty(user, mail));
-
- Link resetPwdLk = new Link(body, SWT.NONE);
- if (!UserAdminUtils.isCurrentUser(user)) {
- resetPwdLk.setText("<a>Reset password</a>");
- }
- resetPwdLk.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
-
- // create form part (controller)
- AbstractFormPart part = new AbstractFormPart() {
- private MainInfoListener listener;
-
- @Override
- public void initialize(IManagedForm form) {
- super.initialize(form);
- listener = new MainInfoListener(parent.getDisplay(), this);
- userAdminWrapper.addListener(listener);
- }
-
- @Override
- public void dispose() {
- userAdminWrapper.removeListener(listener);
- super.dispose();
- }
-
- @SuppressWarnings("unchecked")
- public void commit(boolean onSave) {
- // TODO Sanity checks (mail validity...)
- user.getProperties().put(LdapAttrs.givenName.name(), firstName.getText());
- user.getProperties().put(LdapAttrs.sn.name(), lastName.getText());
- user.getProperties().put(LdapAttrs.cn.name(), commonName.getText());
- user.getProperties().put(LdapAttrs.mail.name(), email.getText());
- super.commit(onSave);
- }
-
- @Override
- public void refresh() {
- distinguishedName.setText(UserAdminUtils.getProperty(user, LdapAttrs.uid.name()));
- commonName.setText(UserAdminUtils.getProperty(user, LdapAttrs.cn.name()));
- firstName.setText(UserAdminUtils.getProperty(user, LdapAttrs.givenName.name()));
- lastName.setText(UserAdminUtils.getProperty(user, LdapAttrs.sn.name()));
- email.setText(UserAdminUtils.getProperty(user, LdapAttrs.mail.name()));
- refreshFormTitle(user);
- super.refresh();
- }
- };
-
- // Improve this: automatically generate CN when first or last name
- // changes
- ModifyListener cnML = new ModifyListener() {
- private static final long serialVersionUID = 4298649222869835486L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- String first = firstName.getText();
- String last = lastName.getText();
- String cn = first.trim() + " " + last.trim() + " ";
- cn = cn.trim();
- commonName.setText(cn);
- // getManagedForm().getForm().setText(cn);
- updateEditorTitle(cn);
- }
- };
- firstName.addModifyListener(cnML);
- lastName.addModifyListener(cnML);
-
- ModifyListener defaultListener = new FormPartML(part);
- firstName.addModifyListener(defaultListener);
- lastName.addModifyListener(defaultListener);
- email.addModifyListener(defaultListener);
-
- if (!UserAdminUtils.isCurrentUser(user))
- resetPwdLk.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = 5881800534589073787L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- new ChangePasswordDialog(user, "Reset password").open();
- }
- });
-
- getManagedForm().addPart(part);
- }
-
- private class ChangePasswordDialog extends TrayDialog {
- private static final long serialVersionUID = 2843538207460082349L;
-
- private User user;
- private Text password1;
- private Text password2;
- private String title;
- // private FormToolkit tk;
-
- public ChangePasswordDialog(User user, String title) {
- super(Display.getDefault().getActiveShell());
- // this.tk = tk;
- this.user = user;
- this.title = title;
- }
-
- protected Control createDialogArea(Composite parent) {
- Composite dialogarea = (Composite) super.createDialogArea(parent);
- dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- Composite body = new Composite(dialogarea, SWT.NO_FOCUS);
- body.setLayoutData(EclipseUiUtils.fillAll());
- GridLayout layout = new GridLayout(2, false);
- body.setLayout(layout);
-
- password1 = createLP(body, "New password", "");
- password2 = createLP(body, "Repeat password", "");
- parent.pack();
- return body;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected void okPressed() {
- String msg = null;
-
- if (password1.getText().equals(""))
- msg = "Password cannot be empty";
- else if (password1.getText().equals(password2.getText())) {
- char[] newPassword = password1.getText().toCharArray();
- // userAdminWrapper.beginTransactionIfNeeded();
- userAdminWrapper.beginTransactionIfNeeded();
- user.getCredentials().put(null, newPassword);
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- super.okPressed();
- } else {
- msg = "Passwords are not equals";
- }
-
- if (EclipseUiUtils.notEmpty(msg))
- MessageDialog.openError(getParentShell(), "Cannot reset pasword", msg);
- }
-
- protected void configureShell(Shell shell) {
- super.configureShell(shell);
- shell.setText(title);
- }
- }
-
- private LdifUsersTable appendMemberOfPart(final Composite parent, User user) {
- // Section section = addSection(tk, parent, "Roles");
- // Composite body = (Composite) section.getClient();
- // Composite body= parent;
- Composite body = new Composite(parent, SWT.BORDER);
- body.setLayout(new GridLayout());
- body.setLayoutData(CmsSwtUtils.fillAll());
-
- // boolean isAdmin = CurrentUser.isInRole(NodeConstants.ROLE_ADMIN);
-
- // Displayed columns
- List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
- columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
- columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
- columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 100));
- // Only show technical DN to administrators
- // if (isAdmin)
- // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name",
- // 300));
-
- // Create and configure the table
- final LdifUsersTable userViewerCmp = new MyUserTableViewer(body, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL, user);
-
- userViewerCmp.setColumnDefinitions(columnDefs);
- // if (isAdmin)
- // userViewerCmp.populateWithStaticFilters(false, false);
- // else
- userViewerCmp.populate(true, false);
- GridData gd = EclipseUiUtils.fillAll();
- gd.heightHint = 500;
- userViewerCmp.setLayoutData(gd);
-
- // Controllers
- TableViewer userViewer = userViewerCmp.getTableViewer();
- userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
- int operations = DND.DROP_COPY | DND.DROP_MOVE;
- Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
- GroupDropListener dropL = new GroupDropListener(userAdminWrapper, userViewer, user);
- userViewer.addDropSupport(operations, tt, dropL);
-
- AbstractFormPart part = new AbstractFormPart() {
-
- private GroupChangeListener listener;
-
- @Override
- public void initialize(IManagedForm form) {
- super.initialize(form);
- listener = new GroupChangeListener(parent.getDisplay(), this);
- userAdminWrapper.addListener(listener);
- }
-
- public void commit(boolean onSave) {
- super.commit(onSave);
- }
-
- @Override
- public void dispose() {
- userAdminWrapper.removeListener(listener);
- super.dispose();
- }
-
- @Override
- public void refresh() {
- userViewerCmp.refresh();
- super.refresh();
- }
- };
- getManagedForm().addPart(part);
- // addRemoveAbitily(body, userViewer, user);
- // userViewerCmp.refresh();
- String tooltip = "Remove " + UserAdminUtils.getUserLocalId(user.getName()) + " from the below selected groups";
- Action action = new RemoveMembershipAction(userViewer, user, tooltip, SecurityAdminImages.ICON_REMOVE_DESC);
- ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
- ToolBar toolBar = toolBarManager.createControl(body);
- toolBar.setLayoutData(CmsSwtUtils.fillWidth());
- toolBarManager.add(action);
- toolBarManager.update(true);
- return userViewerCmp;
- }
-
- private class MyUserTableViewer extends LdifUsersTable {
- private static final long serialVersionUID = 2653790051461237329L;
-
- private Button showSystemRoleBtn;
-
- private final User user;
- private final UserFilter userFilter;
-
- public MyUserTableViewer(Composite parent, int style, User user) {
- super(parent, style, true);
- this.user = user;
- userFilter = new UserFilter();
- }
-
- protected void populateStaticFilters(Composite staticFilterCmp) {
- staticFilterCmp.setLayout(new GridLayout());
- showSystemRoleBtn = new Button(staticFilterCmp, SWT.CHECK);
- showSystemRoleBtn.setText("Show system roles");
- boolean showSysRole = CurrentUser.isInRole(CmsConstants.ROLE_ADMIN);
- showSystemRoleBtn.setSelection(showSysRole);
- userFilter.setShowSystemRole(showSysRole);
- showSystemRoleBtn.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -7033424592697691676L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- userFilter.setShowSystemRole(showSystemRoleBtn.getSelection());
- refresh();
- }
- });
- }
-
- @Override
- protected List<User> listFilteredElements(String filter) {
- List<User> users = (List<User>) getFlatGroups(null);
- List<User> filteredUsers = new ArrayList<User>();
- if (users.contains(user))
- users.remove(user);
- userFilter.setSearchText(filter);
- for (User user : users)
- if (userFilter.select(null, null, user))
- filteredUsers.add(user);
- return filteredUsers;
- }
- }
-
- // private void addRemoveAbility(Composite parent, TableViewer userViewer, User
- // user) {
- // // Section section = sectionPart.getSection();
- // ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
- // ToolBar toolbar = toolBarManager.createControl(parent);
- // final Cursor handCursor = new Cursor(Display.getCurrent(), SWT.CURSOR_HAND);
- // toolbar.setCursor(handCursor);
- // toolbar.addDisposeListener(new DisposeListener() {
- // private static final long serialVersionUID = 3882131405820522925L;
- //
- // public void widgetDisposed(DisposeEvent e) {
- // if ((handCursor != null) && (handCursor.isDisposed() == false)) {
- // handCursor.dispose();
- // }
- // }
- // });
- //
- // String tooltip = "Remove " + UserAdminUtils.getUserLocalId(user.getName()) +
- // " from the below selected groups";
- // Action action = new RemoveMembershipAction(userViewer, user, tooltip,
- // SecurityAdminImages.ICON_REMOVE_DESC);
- // toolBarManager.add(action);
- // toolBarManager.update(true);
- // // section.setTextClient(toolbar);
- // }
-
- private class RemoveMembershipAction extends Action {
- private static final long serialVersionUID = -1337713097184522588L;
-
- private final TableViewer userViewer;
- private final User user;
-
- RemoveMembershipAction(TableViewer userViewer, User user, String name, ImageDescriptor img) {
- super(name, img);
- this.userViewer = userViewer;
- this.user = user;
- }
-
- @Override
- public void run() {
- ISelection selection = userViewer.getSelection();
- if (selection.isEmpty())
- return;
-
- @SuppressWarnings("unchecked")
- Iterator<Group> it = ((IStructuredSelection) selection).iterator();
- List<Group> groups = new ArrayList<Group>();
- while (it.hasNext()) {
- Group currGroup = it.next();
- groups.add(currGroup);
- }
-
- userAdminWrapper.beginTransactionIfNeeded();
- for (Group group : groups) {
- group.removeMember(user);
- }
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- for (Group group : groups) {
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
- }
- }
- }
-
- /**
- * Defines the table as being a potential target to add group memberships
- * (roles) to this user
- */
- private class GroupDropListener extends ViewerDropAdapter {
- private static final long serialVersionUID = 2893468717831451621L;
-
- private final UserAdminWrapper myUserAdminWrapper;
- private final User myUser;
-
- public GroupDropListener(UserAdminWrapper userAdminWrapper, Viewer userViewer, User user) {
- super(userViewer);
- this.myUserAdminWrapper = userAdminWrapper;
- this.myUser = user;
- }
-
- @Override
- public boolean validateDrop(Object target, int operation, TransferData transferType) {
- // Target is always OK in a list only view
- // TODO check if not a string
- boolean validDrop = true;
- return validDrop;
- }
-
- @Override
- public void drop(DropTargetEvent event) {
- String name = (String) event.data;
- UserAdmin myUserAdmin = myUserAdminWrapper.getUserAdmin();
- Role role = myUserAdmin.getRole(name);
- // TODO this check should be done before.
- if (role.getType() == Role.GROUP) {
- // TODO check if the user is already member of this group
-
- myUserAdminWrapper.beginTransactionIfNeeded();
- Group group = (Group) role;
- group.addMember(myUser);
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- myUserAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
- }
- super.drop(event);
- }
-
- @Override
- public boolean performDrop(Object data) {
- // userTableViewerCmp.refresh();
- return true;
- }
- }
-
- // LOCAL HELPERS
- private void refreshFormTitle(User group) {
- // getManagedForm().getForm().setText(UserAdminUtils.getProperty(group,
- // LdapAttrs.cn.name()));
- }
-
- /** Appends a section with a title */
- // private Section addSection(FormToolkit tk, Composite parent, String title) {
- // Section section = tk.createSection(parent, Section.TITLE_BAR);
- // GridData gd = EclipseUiUtils.fillWidth();
- // gd.verticalAlignment = PRE_TITLE_INDENT;
- // section.setLayoutData(gd);
- // section.setText(title);
- // // section.getMenu().setVisible(true);
- //
- // Composite body = tk.createComposite(section, SWT.WRAP);
- // body.setLayoutData(EclipseUiUtils.fillAll());
- // section.setClient(body);
- //
- // return section;
- // }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import org.argeo.cms.e4.CmsE4Utils;
-import org.argeo.util.naming.LdapAttrs;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.User;
-
-/**
- * Default double click listener for the various user tables, will open the
- * clicked item in the editor
- */
-public class UserTableDefaultDClickListener implements IDoubleClickListener {
- private final EPartService partService;
-
- public UserTableDefaultDClickListener(EPartService partService) {
- this.partService = partService;
- }
-
- public void doubleClick(DoubleClickEvent evt) {
- if (evt.getSelection().isEmpty())
- return;
- Object obj = ((IStructuredSelection) evt.getSelection()).getFirstElement();
- User user = (User) obj;
-
- String editorId = getEditorId(user);
- CmsE4Utils.openEditor(partService, editorId, LdapAttrs.uid.name(), user.getName());
- }
-
- protected String getEditorId(User user) {
- if (user instanceof Group)
- return "org.argeo.cms.e4.partdescriptor.groupEditor";
- else
- return "org.argeo.cms.e4.partdescriptor.userEditor";
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.e4.users.providers.CommonNameLP;
-import org.argeo.cms.e4.users.providers.DomainNameLP;
-import org.argeo.cms.e4.users.providers.MailLP;
-import org.argeo.cms.e4.users.providers.UserDragListener;
-import org.argeo.cms.e4.users.providers.UserNameLP;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.parts.LdifUsersTable;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-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.dnd.DND;
-import org.eclipse.swt.dnd.TextTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdminEvent;
-import org.osgi.service.useradmin.UserAdminListener;
-
-/** List all users with filter - based on Ldif userAdmin */
-public class UsersView {
- // private final static Log log = LogFactory.getLog(UsersView.class);
-
- // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".usersView";
-
- @Inject
- private UserAdminWrapper userAdminWrapper;
- @Inject
- private EPartService partService;
-
- // UI Objects
- private LdifUsersTable userTableViewerCmp;
- private TableViewer userViewer;
- private List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
-
- private UserAdminListener listener;
-
- @PostConstruct
- public void createPartControl(Composite parent, ESelectionService selectionService) {
-
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
- // Define the displayed columns
- columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
- columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
- columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
- // Only show technical DN to admin
- if (CurrentUser.isInRole(CmsConstants.ROLE_ADMIN))
- columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
-
- // Create and configure the table
- userTableViewerCmp = new MyUserTableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
- userTableViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
- userTableViewerCmp.setColumnDefinitions(columnDefs);
- userTableViewerCmp.populate(true, false);
-
- // Links
- userViewer = userTableViewerCmp.getTableViewer();
- userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
- userViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- IStructuredSelection selection = (IStructuredSelection) event.getSelection();
- selectionService.setSelection(selection.toList());
- }
- });
- // getViewSite().setSelectionProvider(userViewer);
-
- // Really?
- userTableViewerCmp.refresh();
-
- // Drag and drop
- int operations = DND.DROP_COPY | DND.DROP_MOVE;
- Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
- userViewer.addDragSupport(operations, tt, new UserDragListener(userViewer));
-
- // Register a useradmin listener
- listener = new MyUiUAListener(parent.getDisplay());
- userAdminWrapper.addListener(listener);
- }
-
- private class MyUiUAListener extends UiUserAdminListener {
- public MyUiUAListener(Display display) {
- super(display);
- }
-
- @Override
- public void roleChangedToUiThread(UserAdminEvent event) {
- if (userViewer != null && !userViewer.getTable().isDisposed())
- refresh();
- }
- }
-
- private class MyUserTableViewer extends LdifUsersTable {
- private static final long serialVersionUID = 8467999509931900367L;
-
- private final String[] knownProps = { LdapAttrs.DN, LdapAttrs.uid.name(), LdapAttrs.cn.name(),
- LdapAttrs.givenName.name(), LdapAttrs.sn.name(), LdapAttrs.mail.name() };
-
- public MyUserTableViewer(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- protected List<User> listFilteredElements(String filter) {
- Role[] roles;
-
- try {
- StringBuilder builder = new StringBuilder();
-
- StringBuilder tmpBuilder = new StringBuilder();
- if (EclipseUiUtils.notEmpty(filter))
- for (String prop : knownProps) {
- tmpBuilder.append("(");
- tmpBuilder.append(prop);
- tmpBuilder.append("=*");
- tmpBuilder.append(filter);
- tmpBuilder.append("*)");
- }
- if (tmpBuilder.length() > 1) {
- builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
- .append(LdapObjs.inetOrgPerson.name()).append(")(|");
- builder.append(tmpBuilder.toString());
- builder.append("))");
- } else
- builder.append("(").append(LdapAttrs.objectClass.name()).append("=")
- .append(LdapObjs.inetOrgPerson.name()).append(")");
- roles = userAdminWrapper.getUserAdmin().getRoles(builder.toString());
- } catch (InvalidSyntaxException e) {
- throw new CmsException("Unable to get roles with filter: " + filter, e);
- }
- List<User> users = new ArrayList<User>();
- for (Role role : roles)
- // if (role.getType() == Role.USER && role.getType() !=
- // Role.GROUP)
- users.add((User) role);
- return users;
- }
- }
-
- public void refresh() {
- userTableViewerCmp.refresh();
- }
-
- // Override generic view methods
- @PreDestroy
- public void dispose() {
- userAdminWrapper.removeListener(listener);
- }
-
- @Focus
- public void setFocus() {
- userTableViewerCmp.setFocus();
- }
-
- /* DEPENDENCY INJECTION */
- public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
- this.userAdminWrapper = userAdminWrapper;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.handlers;
-
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.cms.e4.users.GroupsView;
-import org.argeo.cms.e4.users.UserAdminWrapper;
-import org.eclipse.e4.core.di.annotations.CanExecute;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.services.IServiceConstants;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.UserAdmin;
-import org.osgi.service.useradmin.UserAdminEvent;
-
-/** Delete the selected groups */
-public class DeleteGroups {
- // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID +
- // ".deleteGroups";
-
- /* DEPENDENCY INJECTION */
- @Inject
- private UserAdminWrapper userAdminWrapper;
-
- @Inject
- ESelectionService selectionService;
-
- @SuppressWarnings("unchecked")
- @Execute
- public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
- // ISelection selection = null;// HandlerUtil.getCurrentSelection(event);
- // if (selection.isEmpty())
- // return null;
- //
- // List<Group> groups = new ArrayList<Group>();
- // Iterator<Group> it = ((IStructuredSelection) selection).iterator();
-
- List<Group> selection = (List<Group>) selectionService.getSelection();
- if (selection == null)
- return;
-
- StringBuilder builder = new StringBuilder();
- for (Group group : selection) {
- Group currGroup = group;
- String groupName = UserAdminUtils.getUserLocalId(currGroup.getName());
- // TODO add checks
- builder.append(groupName).append("; ");
- // groups.add(currGroup);
- }
-
- if (!MessageDialog.openQuestion(Display.getCurrent().getActiveShell(), "Delete Groups", "Are you sure that you "
- + "want to delete these groups?\n" + builder.substring(0, builder.length() - 2)))
- return;
-
- userAdminWrapper.beginTransactionIfNeeded();
- UserAdmin userAdmin = userAdminWrapper.getUserAdmin();
- // IWorkbenchPage iwp =
- // HandlerUtil.getActiveWorkbenchWindow(event).getActivePage();
- for (Group group : selection) {
- String groupName = group.getName();
- // TODO find a way to close the editor cleanly if opened. Cannot be
- // done through the UserAdminListeners, it causes a
- // java.util.ConcurrentModificationException because disposing the
- // editor unregisters and disposes the listener
- // IEditorPart part = iwp.findEditor(new UserEditorInput(groupName));
- // if (part != null)
- // iwp.closeEditor(part, false);
- userAdmin.removeRole(groupName);
- }
- userAdminWrapper.commitOrNotifyTransactionStateChange();
-
- // Update the view
- for (Group group : selection) {
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_REMOVED, group));
- }
-
- // return null;
- }
-
- @CanExecute
- public boolean canExecute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
- return part.getObject() instanceof GroupsView && selectionService.getSelection() != null;
- }
-
- /* DEPENDENCY INJECTION */
- // public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
- // this.userAdminWrapper = userAdminWrapper;
- // }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.handlers;
-
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.cms.e4.users.UserAdminWrapper;
-import org.argeo.cms.e4.users.UsersView;
-import org.eclipse.e4.core.di.annotations.CanExecute;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.e4.ui.services.IServiceConstants;
-import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-import org.osgi.service.useradmin.UserAdminEvent;
-
-/** Delete the selected users */
-public class DeleteUsers {
- // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".deleteUsers";
-
- /* DEPENDENCY INJECTION */
- @Inject
- private UserAdminWrapper userAdminWrapper;
-
- @SuppressWarnings("unchecked")
- @Execute
- public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
- // ISelection selection = null;// HandlerUtil.getCurrentSelection(event);
- // if (selection.isEmpty())
- // return null;
- List<User> selection = (List<User>) selectionService.getSelection();
- if (selection == null)
- return;
-
-// Iterator<User> it = ((IStructuredSelection) selection).iterator();
-// List<User> users = new ArrayList<User>();
- StringBuilder builder = new StringBuilder();
-
- for(User user:selection) {
- User currUser = user;
-// User currUser = it.next();
- String userName = UserAdminUtils.getUserLocalId(currUser.getName());
- if (UserAdminUtils.isCurrentUser(currUser)) {
- MessageDialog.openError(Display.getCurrent().getActiveShell(), "Deletion forbidden",
- "You cannot delete your own user this way.");
- return;
- }
- builder.append(userName).append("; ");
-// users.add(currUser);
- }
-
- if (!MessageDialog.openQuestion(Display.getCurrent().getActiveShell(), "Delete Users",
- "Are you sure that you want to delete these users?\n" + builder.substring(0, builder.length() - 2)))
- return;
-
- userAdminWrapper.beginTransactionIfNeeded();
- UserAdmin userAdmin = userAdminWrapper.getUserAdmin();
- // IWorkbenchPage iwp =
- // HandlerUtil.getActiveWorkbenchWindow(event).getActivePage();
-
- for (User user : selection) {
- String userName = user.getName();
- // TODO find a way to close the editor cleanly if opened. Cannot be
- // done through the UserAdminListeners, it causes a
- // java.util.ConcurrentModificationException because disposing the
- // editor unregisters and disposes the listener
- // IEditorPart part = iwp.findEditor(new UserEditorInput(userName));
- // if (part != null)
- // iwp.closeEditor(part, false);
- userAdmin.removeRole(userName);
- }
- userAdminWrapper.commitOrNotifyTransactionStateChange();
-
- for (User user : selection) {
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_REMOVED, user));
- }
- }
-
- @CanExecute
- public boolean canExecute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
- return part.getObject() instanceof UsersView && selectionService.getSelection() != null;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.handlers;
-
-import java.util.Dictionary;
-import java.util.Map;
-
-import javax.inject.Inject;
-
-import org.argeo.cms.e4.users.UserAdminWrapper;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.naming.LdapAttrs;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.jface.wizard.WizardDialog;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.UserAdminEvent;
-
-/** Create a new group */
-public class NewGroup {
- // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".newGroup";
-
- /* DEPENDENCY INJECTION */
- @Inject
- private UserAdminWrapper userAdminWrapper;
-
- @Execute
- public Object execute() {
- NewGroupWizard newGroupWizard = new NewGroupWizard();
- newGroupWizard.setWindowTitle("Group creation");
- WizardDialog dialog = new WizardDialog(Display.getCurrent().getActiveShell(), newGroupWizard);
- dialog.open();
- return null;
- }
-
- private class NewGroupWizard extends Wizard {
-
- // Pages
- private MainGroupInfoWizardPage mainGroupInfo;
-
- // UI fields
- private Text dNameTxt, commonNameTxt, descriptionTxt;
- private Combo baseDnCmb;
-
- public NewGroupWizard() {
- }
-
- @Override
- public void addPages() {
- mainGroupInfo = new MainGroupInfoWizardPage();
- addPage(mainGroupInfo);
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- @Override
- public boolean performFinish() {
- if (!canFinish())
- return false;
- String commonName = commonNameTxt.getText();
- try {
- userAdminWrapper.beginTransactionIfNeeded();
- String dn = getDn(commonName);
- Group group = (Group) userAdminWrapper.getUserAdmin().createRole(dn, Role.GROUP);
- Dictionary props = group.getProperties();
- String descStr = descriptionTxt.getText();
- if (EclipseUiUtils.notEmpty(descStr))
- props.put(LdapAttrs.description.name(), descStr);
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CREATED, group));
- return true;
- } catch (Exception e) {
- ErrorFeedback.show("Cannot create new group " + commonName, e);
- return false;
- }
- }
-
- private class MainGroupInfoWizardPage extends WizardPage implements FocusListener {
- private static final long serialVersionUID = -3150193365151601807L;
-
- public MainGroupInfoWizardPage() {
- super("Main");
- setTitle("General information");
- setMessage("Please choose a domain, provide a common name " + "and a free description");
- }
-
- @Override
- public void createControl(Composite parent) {
- Composite bodyCmp = new Composite(parent, SWT.NONE);
- setControl(bodyCmp);
- bodyCmp.setLayout(new GridLayout(2, false));
-
- dNameTxt = EclipseUiUtils.createGridLT(bodyCmp, "Distinguished name");
- dNameTxt.setEnabled(false);
-
- baseDnCmb = createGridLC(bodyCmp, "Base DN");
- // Initialise before adding the listener to avoid NPE
- initialiseDnCmb(baseDnCmb);
- baseDnCmb.addFocusListener(this);
-
- commonNameTxt = EclipseUiUtils.createGridLT(bodyCmp, "Common name");
- commonNameTxt.addFocusListener(this);
-
- Label descLbl = new Label(bodyCmp, SWT.LEAD);
- descLbl.setText("Description");
- descLbl.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
- descriptionTxt = new Text(bodyCmp, SWT.LEAD | SWT.MULTI | SWT.WRAP | SWT.BORDER);
- descriptionTxt.setLayoutData(EclipseUiUtils.fillAll());
- descriptionTxt.addFocusListener(this);
-
- // Initialize buttons
- setPageComplete(false);
- getContainer().updateButtons();
- }
-
- @Override
- public void focusLost(FocusEvent event) {
- String name = commonNameTxt.getText();
- if (EclipseUiUtils.isEmpty(name))
- dNameTxt.setText("");
- else
- dNameTxt.setText(getDn(name));
-
- String message = checkComplete();
- if (message != null) {
- setMessage(message, WizardPage.ERROR);
- setPageComplete(false);
- } else {
- setMessage("Complete", WizardPage.INFORMATION);
- setPageComplete(true);
- }
- getContainer().updateButtons();
- }
-
- @Override
- public void focusGained(FocusEvent event) {
- }
-
- /** @return the error message or null if complete */
- protected String checkComplete() {
- String name = commonNameTxt.getText();
-
- if (name.trim().equals(""))
- return "Common name must not be empty";
- Role role = userAdminWrapper.getUserAdmin().getRole(getDn(name));
- if (role != null)
- return "Group " + name + " already exists";
- return null;
- }
-
- @Override
- public void setVisible(boolean visible) {
- super.setVisible(visible);
- if (visible)
- if (baseDnCmb.getSelectionIndex() == -1)
- baseDnCmb.setFocus();
- else
- commonNameTxt.setFocus();
- }
- }
-
- private Map<String, String> getDns() {
- return userAdminWrapper.getKnownBaseDns(true);
- }
-
- private String getDn(String cn) {
- Map<String, String> dns = getDns();
- String bdn = baseDnCmb.getText();
- if (EclipseUiUtils.notEmpty(bdn)) {
- Dictionary<String, ?> props = DirectoryConf.uriAsProperties(dns.get(bdn));
- String dn = LdapAttrs.cn.name() + "=" + cn + "," + DirectoryConf.groupBase.getValue(props) + "," + bdn;
- return dn;
- }
- return null;
- }
-
- private void initialiseDnCmb(Combo combo) {
- Map<String, String> dns = userAdminWrapper.getKnownBaseDns(true);
- if (dns.isEmpty())
- throw new CmsException("No writable base dn found. Cannot create group");
- combo.setItems(dns.keySet().toArray(new String[0]));
- if (dns.size() == 1)
- combo.select(0);
- }
- }
-
- private Combo createGridLC(Composite parent, String label) {
- Label lbl = new Label(parent, SWT.LEAD);
- lbl.setText(label);
- lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
- Combo combo = new Combo(parent, SWT.LEAD | SWT.BORDER | SWT.READ_ONLY);
- combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- return combo;
- }
-
- /* DEPENDENCY INJECTION */
- public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
- this.userAdminWrapper = userAdminWrapper;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.handlers;
-
-import java.util.Dictionary;
-import java.util.List;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.cms.e4.users.UiAdminUtils;
-import org.argeo.cms.e4.users.UserAdminWrapper;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.naming.LdapAttrs;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.jface.wizard.WizardDialog;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdminEvent;
-
-/** Open a wizard that enables creation of a new user. */
-public class NewUser {
- // private final static Log log = LogFactory.getLog(NewUser.class);
- // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".newUser";
-
- /* DEPENDENCY INJECTION */
- @Inject
- private UserAdminWrapper userAdminWrapper;
-
- @Execute
- public Object execute() {
- NewUserWizard newUserWizard = new NewUserWizard();
- newUserWizard.setWindowTitle("User creation");
- WizardDialog dialog = new WizardDialog(Display.getCurrent().getActiveShell(), newUserWizard);
- dialog.open();
- return null;
- }
-
- private class NewUserWizard extends Wizard {
-
- // pages
- private MainUserInfoWizardPage mainUserInfo;
-
- // End user fields
- private Text dNameTxt, usernameTxt, firstNameTxt, lastNameTxt, primaryMailTxt, pwd1Txt, pwd2Txt;
- private Combo baseDnCmb;
-
- public NewUserWizard() {
-
- }
-
- @Override
- public void addPages() {
- mainUserInfo = new MainUserInfoWizardPage();
- addPage(mainUserInfo);
- String message = "Default wizard that also eases user creation tests:\n "
- + "Mail and last name are automatically "
- + "generated form the uid. Password are defauted to 'demo'.";
- mainUserInfo.setMessage(message, WizardPage.WARNING);
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- @Override
- public boolean performFinish() {
- if (!canFinish())
- return false;
- String username = mainUserInfo.getUsername();
- userAdminWrapper.beginTransactionIfNeeded();
- try {
- User user = (User) userAdminWrapper.getUserAdmin().createRole(getDn(username), Role.USER);
-
- Dictionary props = user.getProperties();
-
- String lastNameStr = lastNameTxt.getText();
- if (EclipseUiUtils.notEmpty(lastNameStr))
- props.put(LdapAttrs.sn.name(), lastNameStr);
-
- String firstNameStr = firstNameTxt.getText();
- if (EclipseUiUtils.notEmpty(firstNameStr))
- props.put(LdapAttrs.givenName.name(), firstNameStr);
-
- String cn = UserAdminUtils.buildDefaultCn(firstNameStr, lastNameStr);
- if (EclipseUiUtils.notEmpty(cn))
- props.put(LdapAttrs.cn.name(), cn);
-
- String mailStr = primaryMailTxt.getText();
- if (EclipseUiUtils.notEmpty(mailStr))
- props.put(LdapAttrs.mail.name(), mailStr);
-
- char[] password = mainUserInfo.getPassword();
- user.getCredentials().put(null, password);
- userAdminWrapper.commitOrNotifyTransactionStateChange();
- userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CREATED, user));
- return true;
- } catch (Exception e) {
- ErrorFeedback.show("Cannot create new user " + username, e);
- return false;
- }
- }
-
- private class MainUserInfoWizardPage extends WizardPage implements ModifyListener {
- private static final long serialVersionUID = -3150193365151601807L;
-
- public MainUserInfoWizardPage() {
- super("Main");
- setTitle("Required Information");
- }
-
- @Override
- public void createControl(Composite parent) {
- Composite composite = new Composite(parent, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
- dNameTxt = EclipseUiUtils.createGridLT(composite, "Distinguished name", this);
- dNameTxt.setEnabled(false);
-
- baseDnCmb = createGridLC(composite, "Base DN");
- initialiseDnCmb(baseDnCmb);
- baseDnCmb.addModifyListener(this);
- baseDnCmb.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = -1435351236582736843L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- String name = usernameTxt.getText();
- dNameTxt.setText(getDn(name));
- }
- });
-
- usernameTxt = EclipseUiUtils.createGridLT(composite, "Local ID", this);
- usernameTxt.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = -1435351236582736843L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- String name = usernameTxt.getText();
- if (name.trim().equals("")) {
- dNameTxt.setText("");
- lastNameTxt.setText("");
- primaryMailTxt.setText("");
- pwd1Txt.setText("");
- pwd2Txt.setText("");
- } else {
- dNameTxt.setText(getDn(name));
- lastNameTxt.setText(name.toUpperCase());
- primaryMailTxt.setText(getMail(name));
- pwd1Txt.setText("demo");
- pwd2Txt.setText("demo");
- }
- }
- });
-
- primaryMailTxt = EclipseUiUtils.createGridLT(composite, "Email", this);
- firstNameTxt = EclipseUiUtils.createGridLT(composite, "First name", this);
- lastNameTxt = EclipseUiUtils.createGridLT(composite, "Last name", this);
- pwd1Txt = EclipseUiUtils.createGridLP(composite, "Password", this);
- pwd2Txt = EclipseUiUtils.createGridLP(composite, "Repeat password", this);
- setControl(composite);
-
- // Initialize buttons
- setPageComplete(false);
- getContainer().updateButtons();
- }
-
- @Override
- public void modifyText(ModifyEvent event) {
- String message = checkComplete();
- if (message != null) {
- setMessage(message, WizardPage.ERROR);
- setPageComplete(false);
- } else {
- setMessage("Complete", WizardPage.INFORMATION);
- setPageComplete(true);
- }
- getContainer().updateButtons();
- }
-
- /** @return error message or null if complete */
- protected String checkComplete() {
- String name = usernameTxt.getText();
-
- if (name.trim().equals(""))
- return "User name must not be empty";
- Role role = userAdminWrapper.getUserAdmin().getRole(getDn(name));
- if (role != null)
- return "User " + name + " already exists";
- if (!primaryMailTxt.getText().matches(UiAdminUtils.EMAIL_PATTERN))
- return "Not a valid email address";
- if (lastNameTxt.getText().trim().equals(""))
- return "Specify a last name";
- if (pwd1Txt.getText().trim().equals(""))
- return "Specify a password";
- if (pwd2Txt.getText().trim().equals(""))
- return "Repeat the password";
- if (!pwd2Txt.getText().equals(pwd1Txt.getText()))
- return "Passwords are different";
- return null;
- }
-
- @Override
- public void setVisible(boolean visible) {
- super.setVisible(visible);
- if (visible)
- if (baseDnCmb.getSelectionIndex() == -1)
- baseDnCmb.setFocus();
- else
- usernameTxt.setFocus();
- }
-
- public String getUsername() {
- return usernameTxt.getText();
- }
-
- public char[] getPassword() {
- return pwd1Txt.getTextChars();
- }
-
- }
-
- private Map<String, String> getDns() {
- return userAdminWrapper.getKnownBaseDns(true);
- }
-
- private String getDn(String uid) {
- Map<String, String> dns = getDns();
- String bdn = baseDnCmb.getText();
- if (EclipseUiUtils.notEmpty(bdn)) {
- Dictionary<String, ?> props = DirectoryConf.uriAsProperties(dns.get(bdn));
- String dn = LdapAttrs.uid.name() + "=" + uid + "," + DirectoryConf.userBase.getValue(props) + "," + bdn;
- return dn;
- }
- return null;
- }
-
- private void initialiseDnCmb(Combo combo) {
- Map<String, String> dns = userAdminWrapper.getKnownBaseDns(true);
- if (dns.isEmpty())
- throw new CmsException("No writable base dn found. Cannot create user");
- combo.setItems(dns.keySet().toArray(new String[0]));
- if (dns.size() == 1)
- combo.select(0);
- }
-
- private String getMail(String username) {
- if (baseDnCmb.getSelectionIndex() == -1)
- return null;
- String baseDn = baseDnCmb.getText();
- try {
- LdapName name = new LdapName(baseDn);
- List<Rdn> rdns = name.getRdns();
- return username + "@" + (String) rdns.get(1).getValue() + '.' + (String) rdns.get(0).getValue();
- } catch (InvalidNameException e) {
- throw new CmsException("Unable to generate mail for " + username + " with base dn " + baseDn, e);
- }
- }
- }
-
- private Combo createGridLC(Composite parent, String label) {
- Label lbl = new Label(parent, SWT.LEAD);
- lbl.setText(label);
- lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
- Combo combo = new Combo(parent, SWT.LEAD | SWT.BORDER | SWT.READ_ONLY);
- combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- return combo;
- }
-
- /* DEPENDENCY INJECTION */
- public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
- this.userAdminWrapper = userAdminWrapper;
- }
-}
+++ /dev/null
-/** Users management handlers. */
-package org.argeo.cms.e4.users.handlers;
\ No newline at end of file
+++ /dev/null
-/** Users management perspective. */
-package org.argeo.cms.e4.users;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.e4.users.providers;
-
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.util.naming.LdapAttrs;
-import org.osgi.service.useradmin.User;
-
-/** Simply declare a label provider that returns the common name of a user */
-public class CommonNameLP extends UserAdminAbstractLP {
- private static final long serialVersionUID = 5256703081044911941L;
-
- @Override
- public String getText(User user) {
- return UserAdminUtils.getProperty(user, LdapAttrs.cn.name());
- }
-
- @Override
- public String getToolTipText(Object element) {
- return UserAdminUtils.getProperty((User) element, LdapAttrs.DN);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.users.providers;
-
-import org.argeo.cms.auth.UserAdminUtils;
-import org.osgi.service.useradmin.User;
-
-/** The human friendly domain name for the corresponding user. */
-public class DomainNameLP extends UserAdminAbstractLP {
- private static final long serialVersionUID = 5256703081044911941L;
-
- @Override
- public String getText(User user) {
- return UserAdminUtils.getDomainName(user);
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.providers;
-
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.util.naming.LdapAttrs;
-import org.osgi.service.useradmin.User;
-
-/** Simply declare a label provider that returns the Primary Mail of a user */
-public class MailLP extends UserAdminAbstractLP {
- private static final long serialVersionUID = 8329764452141982707L;
-
- @Override
- public String getText(User user) {
- return UserAdminUtils.getProperty(user, LdapAttrs.mail.name());
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.providers;
-
-import org.argeo.api.cms.CmsContext;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.cms.e4.users.SecurityAdminImages;
-import org.argeo.util.naming.LdapAttrs;
-import org.eclipse.swt.graphics.Image;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-
-/** Provide a bundle specific image depending on the current user type */
-public class RoleIconLP extends UserAdminAbstractLP {
- private static final long serialVersionUID = 6550449442061090388L;
-
- @Override
- public String getText(User user) {
- return "";
- }
-
- @Override
- public Image getImage(Object element) {
- User user = (User) element;
- String dn = user.getName();
- if (dn.endsWith(CmsConstants.ROLES_BASEDN))
- return SecurityAdminImages.ICON_ROLE;
- else if (user.getType() == Role.GROUP) {
- String businessCategory = UserAdminUtils.getProperty(user, LdapAttrs.businessCategory);
- if (businessCategory != null && businessCategory.equals(CmsContext.WORKGROUP))
- return SecurityAdminImages.ICON_WORKGROUP;
- return SecurityAdminImages.ICON_GROUP;
- } else
- return SecurityAdminImages.ICON_USER;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.providers;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.cms.swt.CmsException;
-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.widgets.Display;
-import org.osgi.service.useradmin.User;
-
-/**
- * Utility class that add font modifications to a column label provider
- * depending on the given user properties
- */
-public abstract class UserAdminAbstractLP extends ColumnLabelProvider {
- private static final long serialVersionUID = 137336765024922368L;
-
- // private Font italic;
- private Font bold;
-
- @Override
- public Font getFont(Object element) {
- // Self as bold
- try {
- LdapName selfUserName = UserAdminUtils.getCurrentUserLdapName();
- String userName = ((User) element).getName();
- LdapName userLdapName = new LdapName(userName);
- if (userLdapName.equals(selfUserName)) {
- if (bold == null)
- bold = JFaceResources.getFontRegistry()
- .defaultFontDescriptor().setStyle(SWT.BOLD)
- .createFont(Display.getCurrent());
- return bold;
- }
- } catch (InvalidNameException e) {
- throw new CmsException("cannot parse dn for " + element, e);
- }
-
- // Disabled as Italic
- // Node userProfile = (Node) elem;
- // if (!userProfile.getProperty(ARGEO_ENABLED).getBoolean())
- // return italic;
-
- return null;
- // return super.getFont(element);
- }
-
- @Override
- public String getText(Object element) {
- User user = (User) element;
- return getText(user);
- }
-
- public void setDisplay(Display display) {
- // italic = JFaceResources.getFontRegistry().defaultFontDescriptor()
- // .setStyle(SWT.ITALIC).createFont(display);
- bold = JFaceResources.getFontRegistry().defaultFontDescriptor()
- .setStyle(SWT.BOLD).createFont(Display.getCurrent());
- }
-
- public abstract String getText(User user);
-}
+++ /dev/null
-package org.argeo.cms.e4.users.providers;
-
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.dnd.DragSourceEvent;
-import org.eclipse.swt.dnd.DragSourceListener;
-import org.osgi.service.useradmin.User;
-
-/** Default drag listener to modify group and users via the UI */
-public class UserDragListener implements DragSourceListener {
- private static final long serialVersionUID = -2074337775033781454L;
- private final Viewer viewer;
-
- public UserDragListener(Viewer viewer) {
- this.viewer = viewer;
- }
-
- public void dragStart(DragSourceEvent event) {
- // TODO implement finer checks
- IStructuredSelection selection = (IStructuredSelection) viewer
- .getSelection();
- if (selection.isEmpty() || selection.size() > 1)
- event.doit = false;
- else
- event.doit = true;
- }
-
- public void dragSetData(DragSourceEvent event) {
- // TODO Support multiple selection
- Object obj = ((IStructuredSelection) viewer.getSelection())
- .getFirstElement();
- if (obj != null) {
- User user = (User) obj;
- event.data = user.getName();
- }
- }
-
- public void dragFinished(DragSourceEvent event) {
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.providers;
-
-import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.util.naming.LdapAttrs;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerFilter;
-import org.osgi.service.useradmin.User;
-
-/**
- * Filter user list using JFace mechanism on the client (yet on the server) side
- * rather than having the UserAdmin to process the search
- */
-public class UserFilter extends ViewerFilter {
- private static final long serialVersionUID = 5082509381672880568L;
-
- private String searchString;
- private boolean showSystemRole = true;
-
- private final String[] knownProps = { LdapAttrs.DN, LdapAttrs.cn.name(), LdapAttrs.givenName.name(),
- LdapAttrs.sn.name(), LdapAttrs.uid.name(), LdapAttrs.description.name(), LdapAttrs.mail.name() };
-
- public void setSearchText(String s) {
- // ensure that the value can be used for matching
- if (notEmpty(s))
- searchString = ".*" + s.toLowerCase() + ".*";
- else
- searchString = ".*";
- }
-
- public void setShowSystemRole(boolean showSystemRole) {
- this.showSystemRole = showSystemRole;
- }
-
- @Override
- public boolean select(Viewer viewer, Object parentElement, Object element) {
- User user = (User) element;
- if (!showSystemRole && user.getName().matches(".*(" + CmsConstants.ROLES_BASEDN + ")"))
- // UserAdminUtils.getProperty(user, LdifName.dn.name())
- // .toLowerCase().endsWith(AuthConstants.ROLES_BASEDN))
- return false;
-
- if (searchString == null || searchString.length() == 0)
- return true;
-
- if (user.getName().matches(searchString))
- return true;
-
- for (String key : knownProps) {
- String currVal = UserAdminUtils.getProperty(user, key);
- if (notEmpty(currVal) && currVal.toLowerCase().matches(searchString))
- return true;
- }
- return false;
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.users.providers;
-
-import org.osgi.service.useradmin.User;
-
-/** Simply declare a label provider that returns the username of a user */
-public class UserNameLP extends UserAdminAbstractLP {
- private static final long serialVersionUID = 6550449442061090388L;
-
- @Override
- public String getText(User user) {
- return user.getName();
- }
-}
+++ /dev/null
-/** Users management content providers. */
-package org.argeo.cms.e4.users.providers;
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src" />
- <classpathentry kind="con"
- path="org.eclipse.pde.core.requiredPlugins" />
- <classpathentry kind="con"
- path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11" />
- <classpathentry kind="output" path="bin" />
-</classpath>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.cms.swt</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="CMS User App">
- <implementation class="org.argeo.cms.swt.app.CmsUserApp"/>
- <property name="argeo.cms.app.contextName" type="String" value="cms/user"/>
- <service>
- <provide interface="org.argeo.api.cms.CmsApp"/>
- </service>
- <reference bind="setCmsContext" cardinality="1..1" interface="org.argeo.api.cms.CmsContext" name="CmsContext" policy="static"/>
- <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.ContentRepository" name="ContentRepository" policy="static"/>
-</scr:component>
+++ /dev/null
-Import-Package: org.eclipse.swt,\
-org.eclipse.jface.window,\
-org.eclipse.core.commands.common,\
-javax.servlet.*;version="[3,5)",\
-*
-
-Bundle-ActivationPolicy: lazy
-
-Service-Component: \
-OSGI-INF/cmsUserApp.xml
-
\ No newline at end of file
+++ /dev/null
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- OSGI-INF/cmsUserApp.xml
-source.. = src/
+++ /dev/null
-package org.argeo.cms.jface.dialog;
-
-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.cms.swt.dialogs.LightweightDialog;
-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 {
- // FIXME it creates a dependency to Eclipse Core Runtime
- // 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);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt;
-
-/** @deprecated Use standard Java {@link RuntimeException} instead. */
-@Deprecated
-public class CmsException extends RuntimeException {
- private static final long serialVersionUID = -5341764743356771313L;
-
- public CmsException(String message) {
- super(message);
- }
-
- public CmsException(String message, Throwable e) {
- super(message, e);
- }
-
-}
+++ /dev/null
-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";
-}
+++ /dev/null
-package org.argeo.cms.swt;
-
-import org.argeo.api.cms.ux.CmsIcon;
-import org.argeo.api.cms.ux.CmsTheme;
-import org.eclipse.swt.graphics.Image;
-
-/** SWT specific {@link CmsTheme}. */
-public interface CmsSwtTheme extends CmsTheme {
-// /** The image registered at this path, or <code>null</code> 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 <code>null</code> if not found.
- *
- * @param name An icon file name without path and extension.
- * @param preferredSize the preferred size, if <code>null</code>,
- * {@link #getDefaultIconSize()} will be tried.
- */
- Image getIcon(String name, Integer preferredSize);
-
- Image getSmallIcon(CmsIcon icon);
-
- Image getBigIcon(CmsIcon icon);
-}
+++ /dev/null
-package org.argeo.cms.swt;
-
-import org.argeo.api.cms.ux.CmsUi;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** A basic {@link CmsUi}, based on an SWT {@link Composite}. */
-public class CmsSwtUi extends Composite implements CmsUi {
-
- private static final long serialVersionUID = -107939076610406448L;
-
- public CmsSwtUi(Composite parent, int style) {
- super(parent, style);
- setLayout(new GridLayout());
- }
-
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.swt;
-
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-import org.argeo.api.cms.ux.CmsIcon;
-import org.argeo.api.cms.ux.CmsStyle;
-import org.argeo.api.cms.ux.CmsTheme;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.layout.FormAttachment;
-import org.eclipse.swt.layout.FormData;
-import org.eclipse.swt.layout.FormLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.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.Layout;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.Widget;
-
-/** SWT utilities. */
-public class CmsSwtUtils {
- /*
- * THEME AND VIEW
- */
-
- public static CmsSwtTheme getCmsTheme(Composite parent) {
- CmsSwtTheme theme = (CmsSwtTheme) parent.getData(CmsTheme.class.getName());
- if (theme == null) {
- // find parent shell
- Shell topShell = parent.getShell();
- while (topShell.getParent() != null)
- topShell = (Shell) topShell.getParent();
- theme = (CmsSwtTheme) 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);
- }
-
- /*
- * EVENTS
- */
-
- /** Sends an event via {@link CmsView#sendEvent(String, Map)}. */
- public static void sendEventOnSelect(Control control, String topic, Map<String, Object> 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<String, Object> properties = new HashMap<>();
- properties.put(key, value);
- sendEventOnSelect(control, topic, properties);
- }
-
- /*
- * ICONS
- */
- /** Get a small icon from this theme. */
- public static Image getSmallIcon(CmsTheme theme, CmsIcon icon) {
- return ((CmsSwtTheme) theme).getSmallIcon(icon);
- }
-
- /** Get a big icon from this theme. */
- public static Image getBigIcon(CmsTheme theme, CmsIcon icon) {
- return ((CmsSwtTheme) theme).getBigIcon(icon);
- }
-
- /*
- * LAYOUT INDEPENDENT
- */
- /** Takes the most space possible, depending on parent layout. */
- public static void fill(Control control) {
- Layout parentLayout = control.getParent().getLayout();
- if (parentLayout == null)
- throw new IllegalStateException("Parent layout is not set");
- if (parentLayout instanceof GridLayout) {
- control.setLayoutData(fillAll());
- } else if (parentLayout instanceof FormLayout) {
- control.setLayoutData(coverAll());
- } else {
- throw new IllegalArgumentException("Unsupported parent layout " + parentLayout.getClass().getName());
- }
- }
-
- /*
- * GRID LAYOUT
- */
- /** A {@link GridLayout} without any spacing and one column. */
- public static GridLayout noSpaceGridLayout() {
- return noSpaceGridLayout(new GridLayout());
- }
-
- /**
- * A {@link GridLayout} without any spacing and multiple columns of unequal
- * width.
- */
- 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 extends Widget> 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 extends Widget> T style(T widget, CmsStyle style) {
- return style(widget, style.style());
- }
-
- /** Enable markups on widget */
- public static <T extends Widget> T markup(T widget) {
- EclipseUiSpecificUtils.setMarkupData(widget);
- return widget;
- }
-
- /** Disable markup validation. */
- public static <T extends Widget> 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 <code>toString()</code> method.
- * This argument should not be null, but if it is null and
- * assertions are disabled "<null>" is displayed instead; if
- * assertions are enabled the call will fail.
- *
- * @see markup
- */
- public static <T extends Widget> T text(T widget, Object txt) {
- assert txt != null;
- String str = txt != null ? txt.toString() : "<null>";
- 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();
- }
-
- /** Clean reserved URL characters for use in HTTP links. */
- public static String cleanPathForUrl(String path) {
- StringTokenizer st = new StringTokenizer(path, "/");
- StringBuilder sb = new StringBuilder();
- while (st.hasMoreElements()) {
- sb.append('/');
- String encoded = URLEncoder.encode(st.nextToken(), StandardCharsets.UTF_8);
- encoded = encoded.replace("+", "%20");
- sb.append(encoded);
-
- }
- return sb.toString();
- }
-
- /** Singleton. */
- private CmsSwtUtils() {
- }
-
-}
+++ /dev/null
-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
- }
-}
+++ /dev/null
-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
- }
-}
+++ /dev/null
-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
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt;
-
-import org.argeo.api.cms.ux.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;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt;
-
-import org.argeo.cms.ux.widgets.EditablePart;
-import org.eclipse.swt.widgets.Control;
-
-/** Manages whether an editable or non editable control is shown. */
-public interface SwtEditablePart extends EditablePart {
- public Control getControl();
-}
+++ /dev/null
-package org.argeo.cms.swt.acr;
-
-import org.argeo.api.acr.Content;
-import org.argeo.api.acr.spi.ProvidedContent;
-import org.eclipse.swt.widgets.Composite;
-
-/** A composite which can (optionally) manage a content. */
-public class ContentComposite extends Composite {
- private static final long serialVersionUID = -1447009015451153367L;
-
- public ContentComposite(Composite parent, int style, Content item) {
- super(parent, style);
- setData(item);
- }
-
- public Content getContent() {
- return (Content) getData();
- }
-
- @Deprecated
- public Content getNode() {
- return getContent();
- }
-
- protected ProvidedContent getProvidedContent() {
- return (ProvidedContent) getContent();
- }
-
- public String getSessionLocalId() {
- return getProvidedContent().getSessionLocalId();
- }
-
- protected void itemUpdated() {
- layout();
- }
-
- public void setContent(Content content) {
- setData(content);
- itemUpdated();
- }
-}
+++ /dev/null
-package org.argeo.cms.swt.acr;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.argeo.api.acr.Content;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ux.widgets.EditablePart;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** A structured UI related to a JCR context. */
-public class SwtSection extends ContentComposite {
- private static final long serialVersionUID = -5933796173755739207L;
-
- private final SwtSection parentSection;
- private Composite sectionHeader;
- private final Integer relativeDepth;
-
- public SwtSection(Composite parent, int style, Content node) {
- this(parent, findSection(parent), style, node);
- }
-
- public SwtSection(SwtSection section, int style, Content node) {
- this(section, section, style, node);
- }
-
- protected SwtSection(Composite parent, SwtSection parentSection, int style, Content node) {
- super(parent, style, node);
- this.parentSection = parentSection;
- if (parentSection != null) {
- relativeDepth = getProvidedContent().getDepth() - parentSection.getProvidedContent().getDepth();
- } else {
- relativeDepth = 0;
- }
- setLayout(CmsSwtUtils.noSpaceGridLayout());
- }
-
- public Map<String, SwtSection> getSubSections() {
- LinkedHashMap<String, SwtSection> result = new LinkedHashMap<String, SwtSection>();
- for (Control child : getChildren()) {
- if (child instanceof Composite) {
- collectDirectSubSections((Composite) child, result);
- }
- }
- return Collections.unmodifiableMap(result);
- }
-
- private void collectDirectSubSections(Composite composite, LinkedHashMap<String, SwtSection> subSections) {
- if (composite == sectionHeader || composite instanceof EditablePart)
- return;
- if (composite instanceof SwtSection) {
- SwtSection section = (SwtSection) composite;
- subSections.put(section.getProvidedContent().getSessionLocalId(), section);
- return;
- }
-
- for (Control child : composite.getChildren())
- if (child instanceof Composite)
- collectDirectSubSections((Composite) child, subSections);
- }
-
- public Composite createHeader() {
- return createHeader(this);
- }
-
- public Composite createHeader(Composite parent) {
- if (sectionHeader != null)
- sectionHeader.dispose();
-
- sectionHeader = new Composite(parent, SWT.NONE);
- sectionHeader.setLayoutData(CmsSwtUtils.fillWidth());
- sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout());
- // sectionHeader.moveAbove(null);
- // layout();
- return sectionHeader;
- }
-
- public Composite getHeader() {
- if (sectionHeader != null && sectionHeader.isDisposed())
- sectionHeader = null;
- return sectionHeader;
- }
-
- // SECTION PARTS
- public SwtSectionPart getSectionPart(String partId) {
- for (Control child : getChildren()) {
- if (child instanceof SwtSectionPart) {
- SwtSectionPart sectionPart = (SwtSectionPart) child;
- if (sectionPart.getPartId().equals(partId))
- return sectionPart;
- }
- }
- return null;
- }
-
- public SwtSectionPart nextSectionPart(SwtSectionPart sectionPart) {
- Control[] children = getChildren();
- for (int i = 0; i < children.length; i++) {
- if (sectionPart == children[i]) {
- for (int j = i + 1; j < children.length; j++) {
- if (children[i + 1] instanceof SwtSectionPart) {
- return (SwtSectionPart) children[i + 1];
- }
- }
-
-// if (i + 1 < children.length) {
-// Composite next = (Composite) children[i + 1];
-// return (SectionPart) next;
-// } else {
-// // next section
-// }
- }
- }
- return null;
- }
-
- public SwtSectionPart previousSectionPart(SwtSectionPart sectionPart) {
- Control[] children = getChildren();
- for (int i = 0; i < children.length; i++) {
- if (sectionPart == children[i])
- if (i != 0) {
- Composite previous = (Composite) children[i - 1];
- return (SwtSectionPart) previous;
- } else {
- // previous section
- }
- }
- return null;
- }
-
- @Override
- public String toString() {
- if (parentSection == null)
- return "Main section " + getContent();
- return "Section " + getContent();
- }
-
- public SwtSection getParentSection() {
- return parentSection;
- }
-
- public Integer getRelativeDepth() {
- return relativeDepth;
- }
-
- /** Recursively finds the related section in the parents (can be itself) */
- public static SwtSection findSection(Control control) {
- if (control == null)
- return null;
- if (control instanceof SwtSection)
- return (SwtSection) control;
- else
- return findSection(control.getParent());
- }
-}
+++ /dev/null
-package org.argeo.cms.swt.acr;
-
-import org.argeo.cms.ux.acr.ContentPart;
-import org.argeo.cms.ux.widgets.EditablePart;
-
-/** An editable part dynamically related to a Section */
-public interface SwtSectionPart extends EditablePart, ContentPart {
- public String getPartId();
-
- public SwtSection getSection();
-}
+++ /dev/null
-package org.argeo.cms.swt.acr;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.api.acr.Content;
-import org.argeo.api.acr.spi.ProvidedContent;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.Selected;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.StackLayout;
-import org.eclipse.swt.graphics.Image;
-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.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** Manages {@link SwtSection} in a tab-like structure. */
-public class SwtTabbedArea extends Composite {
- private static final long serialVersionUID = 8659669229482033444L;
-
- private Composite headers;
- private Composite body;
-
- private List<SwtSection> sections = new ArrayList<>();
-
- private ProvidedContent previousNode;
- private SwtUiProvider previousUiProvider;
- private SwtUiProvider currentUiProvider;
-
- private String tabStyle;
- private String tabSelectedStyle;
- private String bodyStyle;
- private Image closeIcon;
-
- private StackLayout stackLayout;
-
- private boolean singleTab = false;
-
- public SwtTabbedArea(Composite parent, int style) {
- super(parent, SWT.NONE);
- CmsSwtUtils.style(parent, bodyStyle);
-
- setLayout(CmsSwtUtils.noSpaceGridLayout());
-
- // TODO manage tabs at bottom or sides
- headers = new Composite(this, SWT.NONE);
- headers.setLayoutData(CmsSwtUtils.fillWidth());
- body = new Composite(this, SWT.NONE);
- body.setLayoutData(CmsSwtUtils.fillAll());
- // body.setLayout(new FormLayout());
- stackLayout = new StackLayout();
- body.setLayout(stackLayout);
- emptyState();
- }
-
- protected void refreshTabHeaders() {
- int tabCount = sections.size() > 0 ? sections.size() : 1;
- for (Control tab : headers.getChildren())
- tab.dispose();
-
- headers.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(tabCount, true)));
-
- if (sections.size() == 0) {
- Composite emptyHeader = new Composite(headers, SWT.NONE);
- emptyHeader.setLayoutData(CmsSwtUtils.fillAll());
- emptyHeader.setLayout(new GridLayout());
- Label lbl = new Label(emptyHeader, SWT.NONE);
- lbl.setText("");
- lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
-
- }
-
- SwtSection currentSection = getCurrentSection();
- for (SwtSection section : sections) {
- boolean selected = section == currentSection;
- Composite sectionHeader = section.createHeader(headers);
- CmsSwtUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle);
- int headerColumns = singleTab ? 1 : 2;
- sectionHeader.setLayout(new GridLayout(headerColumns, false));
- sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout(headerColumns));
- Button title = new Button(sectionHeader, SWT.FLAT);
- CmsSwtUtils.style(title, selected ? tabSelectedStyle : tabStyle);
- title.setLayoutData(CmsSwtUtils.fillWidth());
- title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode())));
- Content node = section.getContent();
-
- // FIXME find a standard way to display titles
- String titleStr = node.getName().getLocalPart();
-
- // TODO internationalize
- title.setText(titleStr);
- if (!singleTab) {
- ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
- ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT);
- if (closeIcon != null)
- closeItem.setImage(closeIcon);
- else
- closeItem.setText("X");
- CmsSwtUtils.style(closeItem, selected ? tabSelectedStyle : tabStyle);
- closeItem.addSelectionListener((Selected) (e) -> closeTab(section));
- }
- }
-
- }
-
- public void view(SwtUiProvider uiProvider, Content context) {
- if (body.isDisposed())
- return;
- int index = tabIndex(context);
- if (index >= 0) {
- showTab(index);
- previousNode = (ProvidedContent) context;
- previousUiProvider = uiProvider;
- return;
- }
- SwtSection section = (SwtSection) body.getChildren()[0];
- previousNode = (ProvidedContent) section.getNode();
- if (previousNode == null) {// empty state
- previousNode = (ProvidedContent) context;
- previousUiProvider = uiProvider;
- } else {
- previousUiProvider = currentUiProvider;
- }
- currentUiProvider = uiProvider;
- section.setContent(context);
- // section.setLayoutData(CmsUiUtils.coverAll());
- build(section, uiProvider, context);
- if (sections.size() == 0)
- sections.add(section);
- refreshTabHeaders();
- index = tabIndex(context);
- showTab(index);
- layout(true, true);
- }
-
- public void open(SwtUiProvider uiProvider, Content context) {
- if (singleTab)
- throw new UnsupportedOperationException("Open is not supported in single tab mode.");
-
- if (previousNode != null
- && previousNode.getSessionLocalId().equals(((ProvidedContent) context).getSessionLocalId())) {
- // does nothing
- return;
- }
- if (sections.size() == 0)
- CmsSwtUtils.clear(body);
- SwtSection currentSection = getCurrentSection();
- int currentIndex = sections.indexOf(currentSection);
- SwtSection previousSection = new SwtSection(body, SWT.NONE, context);
- build(previousSection, previousUiProvider, previousNode);
- // previousSection.setLayoutData(CmsUiUtils.coverAll());
- int newIndex = currentIndex + 1;
- sections.add(currentIndex, previousSection);
-// sections.add(newIndex, previousSection);
- showTab(newIndex);
- refreshTabHeaders();
- layout(true, true);
- }
-
- public void showTab(int index) {
- SwtSection sectionToShow = sections.get(index);
- // sectionToShow.moveAbove(null);
- stackLayout.topControl = sectionToShow;
- refreshTabHeaders();
- layout(true, true);
- }
-
- protected void build(SwtSection section, SwtUiProvider uiProvider, Content context) {
- for (Control child : section.getChildren())
- child.dispose();
- CmsSwtUtils.style(section, bodyStyle);
- section.setContent(context);
- uiProvider.createUiPart(section, context);
-
- }
-
- private int tabIndex(Content context) {
- for (int i = 0; i < sections.size(); i++) {
- SwtSection section = sections.get(i);
- if (section.getSessionLocalId().equals(((ProvidedContent) context).getSessionLocalId()))
- return i;
- }
- return -1;
- }
-
- public void closeTab(SwtSection section) {
- int currentIndex = sections.indexOf(section);
- int nextIndex = currentIndex == 0 ? 0 : currentIndex - 1;
- sections.remove(section);
- section.dispose();
- if (sections.size() == 0) {
- emptyState();
- refreshTabHeaders();
- layout(true, true);
- return;
- }
- refreshTabHeaders();
- showTab(nextIndex);
- }
-
- public void closeAllTabs() {
- for (SwtSection section : sections) {
- section.dispose();
- }
- sections.clear();
- emptyState();
- refreshTabHeaders();
- layout(true, true);
- }
-
- protected void emptyState() {
- new SwtSection(body, SWT.NONE, null);
- refreshTabHeaders();
- }
-
- public Composite getCurrent() {
- return getCurrentSection();
- }
-
- protected SwtSection getCurrentSection() {
- return (SwtSection) stackLayout.topControl;
- }
-
- public Content getCurrentContext() {
- SwtSection section = getCurrentSection();
- if (section != null) {
- return section.getNode();
- } else {
- return null;
- }
- }
-
- public void setTabStyle(String tabStyle) {
- this.tabStyle = tabStyle;
- }
-
- public void setTabSelectedStyle(String tabSelectedStyle) {
- this.tabSelectedStyle = tabSelectedStyle;
- }
-
- public void setBodyStyle(String bodyStyle) {
- this.bodyStyle = bodyStyle;
- }
-
- public void setCloseIcon(Image closeIcon) {
- this.closeIcon = closeIcon;
- }
-
- public void setSingleTab(boolean singleTab) {
- this.singleTab = singleTab;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.acr;
-
-import org.argeo.api.acr.Content;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-@FunctionalInterface
-public interface SwtUiProvider {
- Control createUiPart(Composite parent, Content context);
-}
+++ /dev/null
-package org.argeo.cms.swt.app;
-
-import static org.argeo.api.acr.NamespaceUtils.toPrefixedName;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.namespace.QName;
-
-import org.argeo.api.acr.Content;
-import org.argeo.api.acr.NamespaceUtils;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.widgets.SwtHierarchicalPart;
-import org.argeo.cms.swt.widgets.SwtTabularPart;
-import org.argeo.cms.ux.acr.ContentHierarchicalPart;
-import org.argeo.cms.ux.widgets.Column;
-import org.argeo.cms.ux.widgets.DefaultTabularPart;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.widgets.Composite;
-
-public class AcrContentTreeView extends Composite {
- private static final long serialVersionUID = -3707881216246077323L;
-
- private Content rootContent;
-
-// private Content selected;
-
- public AcrContentTreeView(Composite parent, int style, Content content) {
- super(parent, style);
- this.rootContent = content;
- // this.selected = rootContent;
- setLayout(CmsSwtUtils.noSpaceGridLayout());
-
- SashForm split = new SashForm(this, SWT.HORIZONTAL);
- split.setLayoutData(CmsSwtUtils.fillAll());
-
- ContentHierarchicalPart contentPart = new ContentHierarchicalPart();
- contentPart.setInput(rootContent);
-
- SwtHierarchicalPart<Content> hPart = new SwtHierarchicalPart<>(split, getStyle(), contentPart);
-
- Composite area = new Composite(split, SWT.BORDER);
- area.setLayout(CmsSwtUtils.noSpaceGridLayout(2));
- split.setWeights(new int[] { 30, 70 });
-
- // attributes
- DefaultTabularPart<Content, QName> attributesPart = new DefaultTabularPart<>() {
-
- @Override
- protected List<QName> asList(Content input) {
- return new ArrayList<>(input.keySet());
- }
- };
-
- attributesPart.addColumn(new Column<QName>() {
-
- @Override
- public String getText(QName model) {
- try {
- return NamespaceUtils.toPrefixedName(model);
- } catch (IllegalStateException e) {
- return model.toString();
- }
- }
- });
- attributesPart.addColumn(new Column<QName>() {
-
- @Override
- public String getText(QName model) {
- return attributesPart.getInput().get(model).toString();
- }
-
- @Override
- public int getWidth() {
- return 400;
- }
-
- });
- // attributesPart.setInput(selected);
-
- SwtTabularPart<Content, QName> attributeTable = new SwtTabularPart<>(area, style, attributesPart);
- attributeTable.setLayoutData(CmsSwtUtils.fillAll());
-
- // types
- DefaultTabularPart<Content, QName> typesPart = new DefaultTabularPart<>() {
-
- @Override
- protected List<QName> asList(Content input) {
- return input.getContentClasses();
- }
- };
- typesPart.addColumn(new Column<QName>() {
-
- @Override
- public String getText(QName model) {
- return toPrefixedName(model);
- }
-
- });
-
- // typesPart.setInput(selected);
-
- SwtTabularPart<Content, QName> typesTable = new SwtTabularPart<>(area, style, typesPart);
- typesTable.setLayoutData(CmsSwtUtils.fillAll());
-
- // controller
- contentPart.setInput(rootContent);
- contentPart.onSelected((o) -> {
- Content c = (Content) o;
-// selected = c;
- attributesPart.setInput(c);
- typesPart.setInput(c);
- });
-
- attributesPart.refresh();
- typesPart.refresh();
- }
-
-// protected void refreshTable() {
-// for (TableItem item : table.getItems()) {
-// item.dispose();
-// }
-// for (QName key : selected.keySet()) {
-// TableItem item = new TableItem(table, 0);
-// item.setText(0, key.toString());
-// Object value = selected.get(key);
-// item.setText(1, value.toString());
-// }
-// table.getColumn(0).pack();
-// table.getColumn(1).pack();
-// }
-
-// public static void main(String[] args) {
-// Path basePath;
-// if (args.length > 0) {
-// basePath = Paths.get(args[0]);
-// } else {
-// basePath = Paths.get(System.getProperty("user.home"));
-// }
-//
-// final Display display = new Display();
-// final Shell shell = new Shell(display);
-// shell.setText(basePath.toString());
-// shell.setLayout(new FillLayout());
-//
-// FsContentProvider contentSession = new FsContentProvider("/", basePath);
-//// GcrContentTreeView treeView = new GcrContentTreeView(shell, 0, contentSession.get("/"));
-//
-// shell.setSize(shell.computeSize(800, 600));
-// shell.open();
-// while (!shell.isDisposed()) {
-// if (!display.readAndDispatch())
-// display.sleep();
-// }
-// display.dispose();
-// }
-}
+++ /dev/null
-package org.argeo.cms.swt.app;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.argeo.api.acr.Content;
-import org.argeo.api.acr.ContentRepository;
-import org.argeo.api.cms.CmsContext;
-import org.argeo.api.cms.ux.CmsUi;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.cms.AbstractCmsApp;
-import org.argeo.cms.swt.CmsSwtUi;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.auth.CmsLogin;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-
-public class CmsUserApp extends AbstractCmsApp {
- private ContentRepository contentRepository;
-
- @Override
- public Set<String> getUiNames() {
- Set<String> uiNames = new HashSet<>();
- uiNames.add("login");
- uiNames.add("data");
- return uiNames;
- }
-
- @Override
- public CmsUi initUi(Object uiParent) {
- Composite parent = (Composite) uiParent;
- String uiName = parent.getData(UI_NAME_PROPERTY) != null ? parent.getData(UI_NAME_PROPERTY).toString() : null;
- CmsSwtUi cmsUi = new CmsSwtUi(parent, SWT.NONE);
- if ("login".equals(uiName)) {
- CmsView cmsView = CmsSwtUtils.getCmsView(cmsUi);
- CmsLogin cmsLogin = new CmsLogin(cmsView, getCmsContext());
- cmsLogin.createUi(cmsUi);
-
- } else if ("data".equals(uiName)) {
- Content rootContent = contentRepository.get().get("/");
- AcrContentTreeView view = new AcrContentTreeView(cmsUi, 0, rootContent);
- view.setLayoutData(CmsSwtUtils.fillAll());
-
- }
- return cmsUi;
- }
-
- @Override
- public void refreshUi(CmsUi cmsUi, String state) {
- }
-
- @Override
- public void setState(CmsUi cmsUi, String state) {
- // TODO Auto-generated method stub
-
- }
-
- public void setContentRepository(ContentRepository contentRepository) {
- this.contentRepository = contentRepository;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-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 org.argeo.api.cms.CmsAuth;
-import org.argeo.api.cms.CmsContext;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.cms.CmsMsg;
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.auth.RemoteAuthCallback;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.cms.servlet.ServletHttpResponse;
-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 CmsLog log = CmsLog.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;
-
- private CmsContext cmsContext;
-
- public CmsLogin(CmsView cmsView, CmsContext cmsContext) {
- this.cmsView = cmsView;
- this.cmsContext = cmsContext;
- if (this.cmsContext != null) {
- defaultLocale = this.cmsContext.getDefaultLocale();
- List<Locale> locales = this.cmsContext.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<Locale> 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(CmsAuth.LOGIN_CONTEXT_USER, this);
- else
- loginContext = new LoginContext(CmsAuth.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 RemoteAuthCallback) {
- ((RemoteAuthCallback) callback).setRequest(new ServletHttpRequest(UiContext.getHttpRequest()));
- ((RemoteAuthCallback) callback).setResponse(new ServletHttpResponse(UiContext.getHttpResponse()));
- } else if (callback instanceof LanguageCallback) {
- Locale toUse = null;
- if (localeChoice != null)
- toUse = localeChoice.getSelectedLocale();
- else if (defaultLocale != null)
- toUse = defaultLocale;
-
- if (toUse != null) {
- ((LanguageCallback) callback).setLocale(toUse);
- UiContext.setLocale(toUse);
- }
-
- }
- }
- }
-
- public void setSubject(Subject subject) {
- this.subject = subject;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.auth;
-
-import org.argeo.api.cms.CmsContext;
-import org.argeo.api.cms.ux.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, CmsContext cmsContext) {
- super(cmsView, cmsContext);
- 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);
- }
-}
+++ /dev/null
-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:<br>
- * <ul>
- * <li>{@link PasswordCallback}</li>
- * <li>{@link NameCallback}</li>
- * <li>{@link TextOutputCallback}</li>
- * </ul>
- * Supported Argeo {@link Callback}s are:<br>
- * <ul>
- * <li>{@link LocaleChoice}</li>
- * </ul>
- */
-public class CompositeCallbackHandler extends Composite implements CallbackHandler {
- private static final long serialVersionUID = -928223893722723777L;
-
- private boolean wasUsedAlready = false;
- private boolean isSubmitted = false;
- private boolean isCanceled = false;
-
- public CompositeCallbackHandler(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- public synchronized void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- // reset
- if (wasUsedAlready && !isSubmitted() && !isCanceled()) {
- cancel();
- for (Control control : getChildren())
- control.dispose();
- isSubmitted = false;
- isCanceled = false;
- }
-
- for (Callback callback : callbacks)
- checkCallbackSupported(callback);
- // create controls synchronously in the UI thread
- getDisplay().syncExec(new Runnable() {
-
- @Override
- public void run() {
- createCallbackHandlers(callbacks);
- }
- });
-
- if (!wasUsedAlready)
- wasUsedAlready = true;
-
- // while (!isSubmitted() && !isCanceled()) {
- // try {
- // wait(1000l);
- // } catch (InterruptedException e) {
- // // silent
- // }
- // }
-
- // cleanCallbacksAfterCancel(callbacks);
- }
-
- public void checkCallbackSupported(Callback callback) throws UnsupportedCallbackException {
- if (callback instanceof TextOutputCallback || callback instanceof NameCallback
- || callback instanceof PasswordCallback || callback instanceof LocaleChoice) {
- return;
- } else {
- throw new UnsupportedCallbackException(callback);
- }
- }
-
- /**
- * Set writable callbacks to null if the handle is canceled (check is done
- * by the method)
- */
- public void cleanCallbacksAfterCancel(Callback[] callbacks) {
- if (isCanceled()) {
- for (Callback callback : callbacks) {
- if (callback instanceof NameCallback) {
- ((NameCallback) callback).setName(null);
- } else if (callback instanceof PasswordCallback) {
- PasswordCallback pCallback = (PasswordCallback) callback;
- char[] arr = pCallback.getPassword();
- if (arr != null) {
- Arrays.fill(arr, '*');
- pCallback.setPassword(null);
- }
- }
- }
- }
- }
-
- public void createCallbackHandlers(Callback[] callbacks) {
- Composite composite = this;
- for (int i = 0; i < callbacks.length; i++) {
- Callback callback = callbacks[i];
- if (callback instanceof TextOutputCallback) {
- createLabelTextoutputHandler(composite, (TextOutputCallback) callback);
- } else if (callback instanceof NameCallback) {
- createNameHandler(composite, (NameCallback) callback);
- } else if (callback instanceof PasswordCallback) {
- createPasswordHandler(composite, (PasswordCallback) callback);
- } else if (callback instanceof LocaleChoice) {
- createLocaleHandler(composite, (LocaleChoice) callback);
- }
- }
- }
-
- protected Text createNameHandler(Composite composite, final NameCallback callback) {
- Label label = new Label(composite, SWT.NONE);
- label.setText(callback.getPrompt());
- final Text text = new Text(composite, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
- if (callback.getDefaultName() != null) {
- // set default value, if provided
- text.setText(callback.getDefaultName());
- callback.setName(callback.getDefaultName());
- }
- text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- text.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = 7300032545287292973L;
-
- public void modifyText(ModifyEvent event) {
- callback.setName(text.getText());
- }
- });
- text.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = 1820530045857665111L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- submit();
- }
- });
-
- text.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -8698107785092095713L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- }
- });
- return text;
- }
-
- protected Text createPasswordHandler(Composite composite, final PasswordCallback callback) {
- Label label = new Label(composite, SWT.NONE);
- label.setText(callback.getPrompt());
- final Text passwordText = new Text(composite, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD | SWT.BORDER);
- passwordText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- passwordText.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = -7099363995047686732L;
-
- public void modifyText(ModifyEvent event) {
- callback.setPassword(passwordText.getTextChars());
- }
- });
- passwordText.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = 1820530045857665111L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- submit();
- }
- });
- return passwordText;
- }
-
- protected Combo createLocaleHandler(Composite composite, final LocaleChoice callback) {
- String[] labels = callback.getSupportedLocalesLabels();
- if (labels.length == 0)
- return null;
- Label label = new Label(composite, SWT.NONE);
- label.setText("Language");
-
- final Combo combo = new Combo(composite, SWT.READ_ONLY);
- combo.setItems(labels);
- combo.select(callback.getDefaultIndex());
- combo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- combo.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = 38678989091946277L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- callback.setSelectedIndex(combo.getSelectionIndex());
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- }
- });
- return combo;
- }
-
- protected Label createLabelTextoutputHandler(Composite composite, final TextOutputCallback callback) {
- Label label = new Label(composite, SWT.NONE);
- label.setText(callback.getMessage());
- GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
- data.horizontalSpan = 2;
- label.setLayoutData(data);
- return label;
- // TODO: find a way to pass this information
- // int messageType = callback.getMessageType();
- // int dialogMessageType = IMessageProvider.NONE;
- // switch (messageType) {
- // case TextOutputCallback.INFORMATION:
- // dialogMessageType = IMessageProvider.INFORMATION;
- // break;
- // case TextOutputCallback.WARNING:
- // dialogMessageType = IMessageProvider.WARNING;
- // break;
- // case TextOutputCallback.ERROR:
- // dialogMessageType = IMessageProvider.ERROR;
- // break;
- // }
- // setMessage(callback.getMessage(), dialogMessageType);
- }
-
- synchronized boolean isSubmitted() {
- return isSubmitted;
- }
-
- synchronized boolean isCanceled() {
- return isCanceled;
- }
-
- protected synchronized void submit() {
- isSubmitted = true;
- notifyAll();
- }
-
- protected synchronized void cancel() {
- isCanceled = true;
- notifyAll();
- }
-}
+++ /dev/null
-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();
- }
-
-}
+++ /dev/null
-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.swt.CmsException;
-
-/** Choose in a list of locales. TODO: replace with {@link LanguageCallback} */
-@Deprecated
-public class LocaleChoice {
- private final List<Locale> locales;
-
- private Integer selectedIndex = null;
- private final Integer defaultIndex;
-
- public LocaleChoice(List<Locale> locales, Locale defaultLocale) {
- Integer defaultIndex = null;
- this.locales = Collections.unmodifiableList(locales);
- for (int i = 0; i < locales.size(); i++)
- if (locales.get(i).equals(defaultLocale))
- defaultIndex = i;
-
- // based on language only
- if (defaultIndex == null)
- for (int i = 0; i < locales.size(); i++)
- if (locales.get(i).getLanguage().equals(defaultLocale.getLanguage()))
- defaultIndex = i;
-
- if (defaultIndex == null)
- throw new CmsException("Default locale " + defaultLocale + " is not in available locales " + locales);
- this.defaultIndex = defaultIndex;
-
- this.selectedIndex = defaultIndex;
- }
-
-// /**
-// * Convenience constructor based on a comma separated list of iso codes (en,
-// * en_US, fr_CA, etc.). Default selection is default locale.
-// */
-// public LocaleChoice(String locales, Locale defaultLocale) {
-// this(LocaleUtils.asLocaleList(locales), defaultLocale);
-// }
-
- public String[] getSupportedLocalesLabels() {
- String[] labels = new String[locales.size()];
- for (int i = 0; i < locales.size(); i++) {
- Locale locale = locales.get(i);
- if (locale.getCountry().equals(""))
- labels[i] = locale.getDisplayLanguage(locale) + " [" + locale.getLanguage() + "]";
- else
- labels[i] = locale.getDisplayLanguage(locale) + " (" + locale.getDisplayCountry(locale) + ") ["
- + locale.getLanguage() + "_" + locale.getCountry() + "]";
-
- }
- return labels;
- }
-
- public Locale getSelectedLocale() {
- if (selectedIndex == null)
- return null;
- return locales.get(selectedIndex);
- }
-
- public void setSelectedIndex(Integer selectedIndex) {
- this.selectedIndex = selectedIndex;
- }
-
- public Integer getSelectedIndex() {
- return selectedIndex;
- }
-
- public Integer getDefaultIndex() {
- return defaultIndex;
- }
-
- public List<Locale> getLocales() {
- return locales;
- }
-
- public Locale getDefaultLocale() {
- return locales.get(getDefaultIndex());
- }
-}
+++ /dev/null
-/** Argeo CMS authentication widgets, based on SWT. */
-package org.argeo.cms.swt.auth;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.swt.dialogs;
-
-import java.security.PrivilegedAction;
-import java.util.Arrays;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.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 CmsLog log = CmsLog.getLog(ChangePasswordDialog.class);
-
- private CmsUserManager cmsUserManager;
- private CmsView cmsView;
-
- private PrivilegedAction<Integer> 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;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.dialogs;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-import org.argeo.api.cms.CmsLog;
-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 CmsLog log = CmsLog.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;
- }
-
-}
+++ /dev/null
-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);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.dialogs;
-
-import org.argeo.api.cms.CmsLog;
-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 CmsLog log = CmsLog.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
+++ /dev/null
-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;
- }
-
-}
+++ /dev/null
-/** SWT/JFace dialogs. */
-package org.argeo.cms.swt.dialogs;
\ No newline at end of file
+++ /dev/null
-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.api.cms.ux.CmsIcon;
-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<String, ImageData> imageCache = new HashMap<>();
-
- private Map<String, Map<Integer, String>> iconPaths = new HashMap<>();
-
- protected 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 <code>null</code> if not found.
- *
- * @param name An icon file name without path and extension.
- * @param preferredSize the preferred size, if <code>null</code>,
- * {@link #getSmallIconSize()} will be tried.
- */
- public Image getIcon(String name, Integer preferredSize) {
- if (preferredSize == null)
- preferredSize = getSmallIconSize();
- Map<Integer, String> 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;
- String ext = "";
- if (lastSlash >= 0)
- fileName = p.substring(lastSlash + 1);
- int lastDot = fileName.lastIndexOf('.');
- if (lastDot >= 0) {
- ext = fileName.substring(lastDot + 1);
- fileName = fileName.substring(0, lastDot);
- }
-
- if ("svg".equals(ext))
- continue paths;
-
- 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 Image getSmallIcon(CmsIcon icon) {
- return getIcon(icon.name(), getSmallIconSize());
- }
-
- @Override
- public Image getBigIcon(CmsIcon icon) {
- return getIcon(icon.name(), getBigIconSize());
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.osgi;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.batik.transcoder.TranscoderException;
-import org.apache.batik.transcoder.TranscoderInput;
-import org.apache.batik.transcoder.TranscoderOutput;
-import org.apache.batik.transcoder.image.ImageTranscoder;
-import org.apache.batik.transcoder.image.PNGTranscoder;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.framework.BundleContext;
-
-/** Theme which can dynamically create icons from SVG data. */
-public class BundleSvgTheme extends BundleCmsSwtTheme {
- private final static Logger logger = System.getLogger(BundleSvgTheme.class.getName());
-
- private Map<String, Map<Integer, Image>> imageCache = Collections.synchronizedMap(new HashMap<>());
-
- private Map<Integer, ImageTranscoder> transcoders = Collections.synchronizedMap(new HashMap<>());
-
- @Override
- public Image getIcon(String name, Integer preferredSize) {
- String path = "icons/types/svg/" + name + ".svg";
- return createImageFromSvg(path, preferredSize);
- }
-
- protected Image createImageFromSvg(String path, Integer preferredSize) {
- Image image = null;
- if (imageCache.containsKey(path)) {
- image = imageCache.get(path).get(preferredSize);
- }
- if (image != null)
- return image;
- ImageData imageData = loadFromSvg(path, preferredSize);
- image = new Image(Display.getDefault(), imageData);
- if (!imageCache.containsKey(path))
- imageCache.put(path, Collections.synchronizedMap(new HashMap<>()));
- imageCache.get(path).put(preferredSize, image);
- return image;
- }
-
- protected ImageData loadFromSvg(String path, int size) {
- ImageTranscoder transcoder = null;
- synchronized (this) {
- transcoder = transcoders.get(size);
- if (transcoder == null) {
- transcoder = new PNGTranscoder();
- transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) size);
- transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) size);
- transcoders.put(size, transcoder);
- }
- }
- ImageData imageData;
- try (InputStream in = getResourceAsStream(path); ByteArrayOutputStream out = new ByteArrayOutputStream();) {
- if (in == null)
- throw new IllegalArgumentException(path + " not found");
- TranscoderInput input = new TranscoderInput(in);
- TranscoderOutput output = new TranscoderOutput(out);
- transcoder.transcode(input, output);
- try (InputStream imageIn = new ByteArrayInputStream(out.toByteArray())) {
- imageData = new ImageData(imageIn);
- }
- logger.log(Level.DEBUG, () -> "Generated " + size + "x" + size + " PNG icon from " + path);
- } catch (IOException | TranscoderException e) {
- throw new RuntimeException("Cannot transcode SVG " + path, e);
- }
-
- return imageData;
- }
-
- @Override
- public void init(BundleContext bundleContext, Map<String, String> properties) {
- super.init(bundleContext, properties);
-
- // preload all icons
-// paths: for (String p : getImagesPaths()) {
-// if (!p.endsWith(".svg"))
-// continue paths;
-// createImageFromSvg(p, getDefaultIconSize());
-// }
- }
-
- @Override
- public void destroy(BundleContext bundleContext, Map<String, String> properties) {
- Display display = Display.getDefault();
- if (display != null)
- for (String path : imageCache.keySet()) {
- for (Image image : imageCache.get(path).values()) {
- display.syncExec(() -> image.dispose());
- }
- }
- super.destroy(bundleContext, properties);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.useradmin;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.api.cms.CmsConstants;
-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.util.naming.LdapAttrs;
-import org.argeo.util.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<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
-
- /**
- * 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<ColumnDefinition> 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<User> 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 + "=*"
- + CmsConstants.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<User> users = new ArrayList<User>();
- 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());
- }
-}
+++ /dev/null
-package org.argeo.cms.swt.useradmin;
-
-import org.argeo.api.cms.CmsConstants;
-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(CmsConstants.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 "";
- }
-}
+++ /dev/null
-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");
-}
+++ /dev/null
-/** SWT/JFace users management components. */
-package org.argeo.cms.swt.useradmin;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.swt.widgets;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ux.widgets.DataPart;
-import org.argeo.cms.ux.widgets.DataView;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Composite;
-
-public abstract class AbstractSwtPart<INPUT, TYPE> extends Composite implements DataView<INPUT, TYPE> {
- private static final long serialVersionUID = -1999179054267812170L;
-
- protected DataPart<INPUT, TYPE> dataPart;
-
- protected final SelectionListener selectionListener;
-
- public AbstractSwtPart(Composite parent, int style, DataPart<INPUT, TYPE> dataPart) {
- super(parent, style);
- setLayout(CmsSwtUtils.noSpaceGridLayout());
-
- this.dataPart = dataPart;
-
- selectionListener = new SelectionListener() {
-
- private static final long serialVersionUID = 4334785560035009330L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- if (dataPart.getOnSelected() != null)
- dataPart.getOnSelected().accept((TYPE) e.item.getData());
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- if (dataPart.getOnAction() != null)
- dataPart.getOnAction().accept((TYPE) e.item.getData());
- }
- };
-
- dataPart.addView(this);
- addDisposeListener((e) -> dataPart.removeView(this));
- }
-
- public abstract void refresh();
-}
+++ /dev/null
-package org.argeo.cms.swt.widgets;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Shell;
-
-/**
- * Manages a lightweight shell which is related to a {@link Control}, typically
- * in order to reproduce a dropdown semantic, but with more flexibility.
- */
-public class ContextOverlay extends ScrolledPage {
- private static final long serialVersionUID = 6702077429573324009L;
-
-// private Shell shell;
- private Control control;
-
- private int maxHeight = 400;
-
- public ContextOverlay(Control control, int style) {
- super(createShell(control, style), SWT.NONE);
- Shell shell = getShell();
- setLayoutData(CmsSwtUtils.fillAll());
- // TODO make autohide configurable?
- //shell.addShellListener(new AutoHideShellListener());
- this.control = control;
- control.addDisposeListener((e) -> {
- dispose();
- shell.dispose();
- });
- }
-
- private static Composite createShell(Control control, int style) {
- if (control == null)
- throw new IllegalArgumentException("Control cannot be null");
- if (control.isDisposed())
- throw new IllegalArgumentException("Control is disposed");
- Shell shell = new Shell(control.getShell(), SWT.NO_TRIM);
- shell.setLayout(CmsSwtUtils.noSpaceGridLayout());
- Composite placeholder = new Composite(shell, SWT.BORDER);
- placeholder.setLayoutData(CmsSwtUtils.fillAll());
- placeholder.setLayout(CmsSwtUtils.noSpaceGridLayout());
- return placeholder;
- }
-
- public void show() {
- Point relativeControlLocation = control.getLocation();
- Point controlLocation = control.toDisplay(relativeControlLocation.x, relativeControlLocation.y);
-
- int controlWidth = control.getBounds().width;
-
- Shell shell = getShell();
-
- layout(true, true);
- shell.pack();
- shell.layout(true, true);
- int targetShellWidth = shell.getSize().x < controlWidth ? controlWidth : shell.getSize().x;
- if (shell.getSize().y > maxHeight) {
- shell.setSize(targetShellWidth, maxHeight);
- } else {
- shell.setSize(targetShellWidth, shell.getSize().y);
- }
-
- int shellHeight = shell.getSize().y;
- int controlHeight = control.getBounds().height;
- Point shellLocation = new Point(controlLocation.x, controlLocation.y + controlHeight);
- int displayHeight = shell.getDisplay().getBounds().height;
- if (shellLocation.y + shellHeight > displayHeight) {// bottom of page
- shellLocation = new Point(controlLocation.x, controlLocation.y - shellHeight);
- }
- shell.setLocation(shellLocation);
-
- if (getChildren().length != 0)
- shell.open();
- if (!control.isDisposed())
- control.setFocus();
- }
-
- public void hide() {
- getShell().setVisible(false);
- onHide();
- }
-
- public boolean isShellVisible() {
- if (isDisposed())
- return false;
- return getShell().isVisible();
- }
-
- /** to be overridden */
- protected void onHide() {
- // does nothing by default.
- }
-
- private class AutoHideShellListener extends ShellAdapter {
- private static final long serialVersionUID = 7743287433907938099L;
-
- @Override
- public void shellDeactivated(ShellEvent e) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e1) {
- // silent
- }
- if (!control.isDisposed() && !control.isFocusControl())
- hide();
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.swt.widgets;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Editable text part displaying styled text. */
-public class EditableText extends StyledControl {
- private static final long serialVersionUID = -6372283442330912755L;
-
- private boolean editable = true;
- private boolean multiLine = true;
-
- private Color highlightColor;
- private Composite highlight;
-
- private boolean useTextAsLabel = false;
-
- public EditableText(Composite parent, int style) {
- super(parent, style);
- editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
- multiLine = !(SWT.SINGLE == (style & SWT.SINGLE));
- highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
- useTextAsLabel = SWT.FLAT == (style & SWT.FLAT);
- }
-
- @Override
- protected Control createControl(Composite box, String style) {
- if (isEditing() && getEditable()) {
- return createText(box, style, true);
- } else {
- if (useTextAsLabel) {
- return createTextLabel(box, style);
- } else {
- return createLabel(box, style);
- }
- }
- }
-
- protected Label createLabel(Composite box, String style) {
- Label lbl = new Label(box, getStyle() | SWT.WRAP);
- lbl.setLayoutData(CmsSwtUtils.fillWidth());
- if (style != null)
- CmsSwtUtils.style(lbl, style);
- CmsSwtUtils.markup(lbl);
- if (mouseListener != null)
- lbl.addMouseListener(mouseListener);
- return lbl;
- }
-
- protected Text createTextLabel(Composite box, String style) {
- Text lbl = new Text(box, getStyle() | (multiLine ? SWT.MULTI : SWT.SINGLE));
- lbl.setEditable(false);
- lbl.setLayoutData(CmsSwtUtils.fillWidth());
- if (style != null)
- CmsSwtUtils.style(lbl, style);
- CmsSwtUtils.markup(lbl);
- if (mouseListener != null)
- lbl.addMouseListener(mouseListener);
- return lbl;
- }
-
- protected Text createText(Composite box, String style, boolean editable) {
- highlight = new Composite(box, SWT.NONE);
- highlight.setBackground(highlightColor);
- GridData highlightGd = new GridData(SWT.FILL, SWT.FILL, false, false);
- highlightGd.widthHint = 5;
- highlightGd.heightHint = 3;
- highlight.setLayoutData(highlightGd);
-
- final Text text = new Text(box, getStyle() | (multiLine ? SWT.MULTI : SWT.SINGLE) | SWT.WRAP);
- text.setEditable(editable);
- GridData textLayoutData = CmsSwtUtils.fillWidth();
- // textLayoutData.heightHint = preferredHeight;
- text.setLayoutData(textLayoutData);
- if (style != null)
- CmsSwtUtils.style(text, style);
- text.setFocus();
- return text;
- }
-
- @Override
- protected void clear(boolean deep) {
- if (highlight != null)
- highlight.dispose();
- super.clear(deep);
- }
-
- public void setText(String text) {
- Control child = getControl();
- if (child instanceof Label)
- ((Label) child).setText(text);
- else if (child instanceof Text)
- ((Text) child).setText(text);
- }
-
- public Text getAsText() {
- return (Text) getControl();
- }
-
- public Label getAsLabel() {
- return (Label) getControl();
- }
-
- public String getText() {
- Control child = getControl();
-
- if (child instanceof Label)
- return ((Label) child).getText();
- else if (child instanceof Text)
- return ((Text) child).getText();
- else
- throw new IllegalStateException("Unsupported control " + child.getClass());
- }
-
- /** @deprecated Use {@link #isEditable()} instead. */
- @Deprecated
- public boolean getEditable() {
- return isEditable();
- }
-
- public boolean isEditable() {
- return editable;
- }
-
- public void setUseTextAsLabel(boolean useTextAsLabel) {
- this.useTextAsLabel = useTextAsLabel;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.widgets;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/**
- * A composite that can be scrolled vertically. It wraps a
- * {@link ScrolledComposite} (and is being wrapped by it), simplifying its
- * configuration.
- */
-public class ScrolledPage extends Composite {
- private static final long serialVersionUID = 1593536965663574437L;
-
- private ScrolledComposite scrolledComposite;
-
- public ScrolledPage(Composite parent, int style) {
- this(parent, style, false);
- }
-
- public ScrolledPage(Composite parent, int style, boolean alwaysShowScroll) {
- super(createScrolledComposite(parent, alwaysShowScroll), style);
- scrolledComposite = (ScrolledComposite) getParent();
- scrolledComposite.setContent(this);
-
- scrolledComposite.setExpandVertical(true);
- scrolledComposite.setExpandHorizontal(true);
- scrolledComposite.addControlListener(new ScrollControlListener());
- }
-
- private static ScrolledComposite createScrolledComposite(Composite parent, boolean alwaysShowScroll) {
- ScrolledComposite scrolledComposite = new ScrolledComposite(parent, SWT.V_SCROLL);
- scrolledComposite.setAlwaysShowScrollBars(alwaysShowScroll);
- return scrolledComposite;
- }
-
- @Override
- public void layout(boolean changed, boolean all) {
- updateScroll();
- super.layout(changed, all);
- }
-
- public void showControl(Control control) {
- scrolledComposite.showControl(control);
- }
-
- protected void updateScroll() {
- Rectangle r = scrolledComposite.getClientArea();
- Point preferredSize = computeSize(r.width, SWT.DEFAULT);
- scrolledComposite.setMinHeight(preferredSize.y);
- }
-
- // public ScrolledComposite getScrolledComposite() {
- // return this.scrolledComposite;
- // }
-
- /** Set it on the wrapping scrolled composite */
- @Override
- public void setLayoutData(Object layoutData) {
- scrolledComposite.setLayoutData(layoutData);
- }
-
- private class ScrollControlListener extends org.eclipse.swt.events.ControlAdapter {
- private static final long serialVersionUID = -3586986238567483316L;
-
- public void controlResized(ControlEvent e) {
- updateScroll();
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.swt.widgets;
-
-import org.argeo.api.cms.ux.CmsStyle;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.SwtEditablePart;
-import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Editable text part displaying styled text. */
-public abstract class StyledControl extends Composite implements SwtEditablePart {
- private static final long serialVersionUID = -6372283442330912755L;
- private Control control;
-
- private Composite container;
- private Composite box;
-
- protected MouseListener mouseListener;
- protected FocusListener focusListener;
-
- private Boolean editing = Boolean.FALSE;
-
- private Composite ancestorToLayout;
-
- public StyledControl(Composite parent, int swtStyle) {
- super(parent, swtStyle);
- setLayout(CmsSwtUtils.noSpaceGridLayout());
- }
-
- protected abstract Control createControl(Composite box, String style);
-
- protected Composite createBox() {
- Composite box = new Composite(container, SWT.INHERIT_DEFAULT);
- setContainerLayoutData(box);
- box.setLayout(CmsSwtUtils.noSpaceGridLayout(3));
- return box;
- }
-
- protected Composite createContainer() {
- Composite container = new Composite(this, SWT.INHERIT_DEFAULT);
- setContainerLayoutData(container);
- container.setLayout(CmsSwtUtils.noSpaceGridLayout());
- return container;
- }
-
- @Override
- public Control getControl() {
- return control;
- }
-
- protected synchronized Boolean isEditing() {
- return editing;
- }
-
- @Override
- public synchronized void startEditing() {
- assert !isEditing();
- editing = true;
- // int height = control.getSize().y;
- String style = (String) EclipseUiSpecificUtils.getStyleData(control);
- clear(false);
- refreshControl(style);
-
- // add the focus listener to the newly created edition control
- if (focusListener != null)
- control.addFocusListener(focusListener);
- }
-
- @Override
- public synchronized void stopEditing() {
- assert isEditing();
- editing = false;
- String style = (String) EclipseUiSpecificUtils.getStyleData(control);
- clear(false);
- refreshControl(style);
- }
-
- protected void refreshControl(String style) {
- control = createControl(box, style);
- setControlLayoutData(control);
- if (ancestorToLayout != null)
- ancestorToLayout.layout(true, true);
- else
- getParent().layout(true, true);
- }
-
- public void setStyle(CmsStyle style) {
- setStyle(style.style());
- }
-
- public void setStyle(String style) {
- Object currentStyle = null;
- if (control != null)
- currentStyle = EclipseUiSpecificUtils.getStyleData(control);
- if (currentStyle != null && currentStyle.equals(style))
- return;
-
- clear(true);
- refreshControl(style);
-
- if (style != null) {
- CmsSwtUtils.style(box, style + "_box");
- CmsSwtUtils.style(container, style + "_container");
- }
- }
-
- /** To be overridden */
- protected void setControlLayoutData(Control control) {
- control.setLayoutData(CmsSwtUtils.fillWidth());
- }
-
- /** To be overridden */
- protected void setContainerLayoutData(Composite composite) {
- composite.setLayoutData(CmsSwtUtils.fillWidth());
- }
-
- protected void clear(boolean deep) {
- if (deep) {
- for (Control control : getChildren())
- control.dispose();
- container = createContainer();
- box = createBox();
- } else {
- control.dispose();
- }
- }
-
- public void setMouseListener(MouseListener mouseListener) {
- if (this.mouseListener != null && control != null)
- control.removeMouseListener(this.mouseListener);
- this.mouseListener = mouseListener;
- if (control != null && this.mouseListener != null)
- control.addMouseListener(mouseListener);
- }
-
- public void setFocusListener(FocusListener focusListener) {
- if (this.focusListener != null && control != null)
- control.removeFocusListener(this.focusListener);
- this.focusListener = focusListener;
- if (control != null && this.focusListener != null)
- control.addFocusListener(focusListener);
- }
-
- public void setAncestorToLayout(Composite ancestorToLayout) {
- this.ancestorToLayout = ancestorToLayout;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.widgets;
-
-import java.util.List;
-
-import org.argeo.api.cms.ux.CmsIcon;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ux.widgets.HierarchicalPart;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeItem;
-
-/** {@link HierarchicalPart} implementation based on a {@link Tree}. */
-public class SwtHierarchicalPart<T> extends AbstractSwtPart<T, T> {
- private static final long serialVersionUID = -6247710601465713047L;
-
- private final Tree tree;
-
- private HierarchicalPart<T> hierarchicalPart;
-
- public SwtHierarchicalPart(Composite parent, int style, HierarchicalPart<T> hierarchicalPart) {
- super(parent, style, hierarchicalPart);
- tree = new Tree(this, SWT.BORDER);
- tree.setLayoutData(CmsSwtUtils.fillAll());
- this.hierarchicalPart = hierarchicalPart;
-
- tree.addSelectionListener(selectionListener);
- }
-
- @Override
- public void refresh() {
- // TODO optimise
- // tree.clearAll(true);
-
- for (TreeItem rootItem : tree.getItems()) {
- rootItem.dispose();
- }
-
- List<T> rootItems = hierarchicalPart.getChildren(hierarchicalPart.getInput());
- for (T child : rootItems) {
- TreeItem childItem = addTreeItem(null, child);
-// List<T> grandChildren = hierarchicalPart.getChildren(child);
-// for (T grandChild : grandChildren) {
-// addTreeItem(childItem, grandChild);
-// }
- }
-// tree.addListener(SWT.SetData, event -> {
-// TreeItem item = (TreeItem) event.item;
-// TreeItem parentItem = item.getParentItem();
-// if (parentItem == null) {
-// refreshRootItem(item);
-// } else {
-// refreshItem(parentItem, item);
-// }
-// });
-// tree.setItemCount(getRootItemCount());
-
- tree.addListener(SWT.Expand, event -> {
- final TreeItem root = (TreeItem) event.item;
- TreeItem[] items = root.getItems();
- for (TreeItem item : items) {
- if (item.getData() != null) {
-// List<T> grandChildren = hierarchicalPart.getChildren((T) item.getData());
-// for (T grandChild : grandChildren) {
-// addTreeItem(item, grandChild);
-// }
- return;
- }
- item.dispose();
- }
-
- List<T> children = hierarchicalPart.getChildren((T) root.getData());
- for (T child : children) {
- TreeItem childItem = addTreeItem(root, child);
-// List<T> grandChildren = hierarchicalPart.getChildren(child);
-// for (T grandChild : grandChildren) {
-// addTreeItem(childItem, grandChild);
-// }
- }
- });
-
- CmsSwtUtils.fill(tree);
-
- }
-
- protected TreeItem addTreeItem(TreeItem parent, T data) {
- TreeItem item = parent == null ? new TreeItem(tree, SWT.NONE) : new TreeItem(parent, SWT.NONE);
- item.setData(data);
- String txt = hierarchicalPart.getText(data);
- if (txt != null)
- item.setText(hierarchicalPart.getText(data));
- CmsIcon icon = hierarchicalPart.getIcon(data);
- // TODO optimize
- List<T> grandChildren = hierarchicalPart.getChildren(data);
- if (grandChildren.size() != 0)
- new TreeItem(item, SWT.NONE);
- return item;
-//if(icon!=null)
-// item.setImage(null);
- }
-
- protected Tree getTree() {
- return tree;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.swt.widgets;
-
-import org.argeo.api.cms.ux.CmsIcon;
-import org.argeo.cms.swt.CmsSwtTheme;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ux.widgets.Column;
-import org.argeo.cms.ux.widgets.TabularPart;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.TableItem;
-
-/** {@link TabularPart} implementation based on a {@link Table}. */
-public class SwtTabularPart<INPUT, T> extends AbstractSwtPart<INPUT, T> {
- private static final long serialVersionUID = -1114155772446357750L;
- private final Table table;
- private TabularPart<INPUT, T> tabularPart;
-
- private CmsSwtTheme theme;
-
- public SwtTabularPart(Composite parent, int style, TabularPart<INPUT, T> tabularPart) {
- super(parent, style, tabularPart);
- theme = CmsSwtUtils.getCmsTheme(parent);
-
- table = new Table(this, SWT.VIRTUAL | SWT.BORDER);
- table.setLinesVisible(true);
- table.setLayoutData(CmsSwtUtils.fillAll());
-
- this.tabularPart = tabularPart;
- }
-
- @Override
- public void refresh() {
- // TODO optimise
- table.clearAll();
- table.addListener(SWT.SetData, event -> {
- TableItem item = (TableItem) event.item;
- refreshItem(item);
- });
- table.setItemCount(tabularPart.getItemCount());
- for (int i = 0; i < tabularPart.getColumnCount(); i++) {
- TableColumn swtColumn = new TableColumn(table, SWT.NONE);
- swtColumn.setWidth(tabularPart.getColumn(i).getWidth());
- }
- CmsSwtUtils.fill(table);
-
- table.addSelectionListener(selectionListener);
-
- }
-
- protected Object getDataFromEvent(SelectionEvent e) {
- Object data = e.item.getData();
- if (data == null)
- data = tabularPart.getData(getTable().indexOf((TableItem) e.item));
- return data;
- }
-
- protected void refreshItem(TableItem item) {
- int row = getTable().indexOf(item);
- for (int i = 0; i < tabularPart.getColumnCount(); i++) {
- Column<T> column = tabularPart.getColumn(i);
- T data = tabularPart.getData(row);
- item.setData(data);
- String text = data != null ? column.getText(data) : "";
- if (text != null)
- item.setText(i, text);
- CmsIcon icon = column.getIcon(data);
- if (icon != null) {
- Image image = theme.getSmallIcon(icon);
- item.setImage(i, image);
- }
- }
- }
-
- protected Table getTable() {
- return table;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.theme;
-
-import java.net.URL;
-
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-
-public class CmsImages {
- private static BundleContext themeBc = FrameworkUtil.getBundle(CmsImages.class).getBundleContext();
-
- final public static String ICONS_BASE = "icons/";
- final public static String TYPES_BASE = ICONS_BASE + "types/";
- final public static String ACTIONS_BASE = ICONS_BASE + "actions/";
-
- public static Image createIcon(String name) {
- return createImg(CmsImages.ICONS_BASE + name);
- }
-
- public static Image createAction(String name) {
- return createImg(CmsImages.ACTIONS_BASE + name);
- }
-
- public static Image createType(String name) {
- return createImg(CmsImages.TYPES_BASE + name);
- }
-
- public static Image createImg(String name) {
- return CmsImages.createDesc(name).createImage(Display.getDefault());
- }
-
- public static ImageDescriptor createDesc(String name) {
- return createDesc(themeBc, name);
- }
-
- public static ImageDescriptor createDesc(BundleContext bc, String name) {
- URL url = bc.getBundle().getResource(name);
- if (url == null)
- return ImageDescriptor.getMissingImageDescriptor();
- return ImageDescriptor.createFromURL(url);
- }
-
- public static Image createImg(BundleContext bc, String name) {
- return createDesc(bc, name).createImage(Display.getDefault());
- }
-
-}
+++ /dev/null
-/** Argeo CMS core theme images. */
-package org.argeo.cms.ui.theme;
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-
-/**
- * Tree content provider dealing with tree objects and providing reasonable
- * defaults.
- */
-public abstract class AbstractTreeContentProvider implements
- ITreeContentProvider {
- private static final long serialVersionUID = 8246126401957763868L;
-
- /** Does nothing */
- public void dispose() {
- }
-
- /** Does nothing */
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
-
- public Object[] getChildren(Object element) {
- if (element instanceof TreeParent) {
- return ((TreeParent) element).getChildren();
- }
- return new Object[0];
- }
-
- public Object getParent(Object element) {
- if (element instanceof TreeParent) {
- return ((TreeParent) element).getParent();
- }
- return null;
- }
-
- public boolean hasChildren(Object element) {
- if (element instanceof TreeParent) {
- return ((TreeParent) element).hasChildren();
- }
- return false;
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui;
-
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-
-/**
- * Wraps the definition of a column to be used in the various JFace viewers
- * (typically tree and table). It enables definition of generic viewers which
- * column can be then defined externally. Also used to generate export.
- */
-public class ColumnDefinition {
- private ColumnLabelProvider labelProvider;
- private String label;
- private int weight = 0;
- private int minWidth = 120;
-
- public ColumnDefinition(ColumnLabelProvider labelProvider, String label) {
- this.labelProvider = labelProvider;
- this.label = label;
- }
-
- public ColumnDefinition(ColumnLabelProvider labelProvider, String label,
- int weight) {
- this.labelProvider = labelProvider;
- this.label = label;
- this.weight = weight;
- this.minWidth = weight;
- }
-
- public ColumnDefinition(ColumnLabelProvider labelProvider, String label,
- int weight, int minimumWidth) {
- this.labelProvider = labelProvider;
- this.label = label;
- this.weight = weight;
- this.minWidth = minimumWidth;
- }
-
- public ColumnLabelProvider getLabelProvider() {
- return labelProvider;
- }
-
- public void setLabelProvider(ColumnLabelProvider labelProvider) {
- this.labelProvider = labelProvider;
- }
-
- public String getLabel() {
- return label;
- }
-
- public void setLabel(String label) {
- this.label = label;
- }
-
- public int getWeight() {
- return weight;
- }
-
- public void setWeight(int weight) {
- this.weight = weight;
- }
-
- public int getMinWidth() {
- return minWidth;
- }
-
- public void setMinWidth(int minWidth) {
- this.minWidth = minWidth;
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui;
-
-import org.eclipse.jface.viewers.ColumnViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerComparator;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-
-/** Generic column viewer sorter */
-public class ColumnViewerComparator extends ViewerComparator {
- private static final long serialVersionUID = -2266218906355859909L;
-
- public static final int ASC = 1;
-
- public static final int NONE = 0;
-
- public static final int DESC = -1;
-
- private int direction = 0;
-
- private TableViewerColumn column;
-
- private ColumnViewer viewer;
-
- public ColumnViewerComparator(TableViewerColumn column) {
- super(null);
- this.column = column;
- this.viewer = column.getViewer();
- this.column.getColumn().addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = 7586796298965472189L;
-
- public void widgetSelected(SelectionEvent e) {
- if (ColumnViewerComparator.this.viewer.getComparator() != null) {
- if (ColumnViewerComparator.this.viewer.getComparator() == ColumnViewerComparator.this) {
- int tdirection = ColumnViewerComparator.this.direction;
-
- if (tdirection == ASC) {
- setSortDirection(DESC);
- } else if (tdirection == DESC) {
- setSortDirection(NONE);
- }
- } else {
- setSortDirection(ASC);
- }
- } else {
- setSortDirection(ASC);
- }
- }
- });
- }
-
- private void setSortDirection(int direction) {
- if (direction == NONE) {
- column.getColumn().getParent().setSortColumn(null);
- column.getColumn().getParent().setSortDirection(SWT.NONE);
- viewer.setComparator(null);
- } else {
- column.getColumn().getParent().setSortColumn(column.getColumn());
- this.direction = direction;
-
- if (direction == ASC) {
- column.getColumn().getParent().setSortDirection(SWT.DOWN);
- } else {
- column.getColumn().getParent().setSortDirection(SWT.UP);
- }
-
- if (viewer.getComparator() == this) {
- viewer.refresh();
- } else {
- viewer.setComparator(this);
- }
-
- }
- }
-
- public int compare(Viewer viewer, Object e1, Object e2) {
- return direction * super.compare(viewer, e1, e2);
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui;
-
-/** CMS specific exceptions. */
-public class EclipseUiException extends RuntimeException {
- private static final long serialVersionUID = -5341764743356771313L;
-
- public EclipseUiException(String message) {
- super(message);
- }
-
- public EclipseUiException(String message, Throwable e) {
- super(message, e);
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui;
-
-import org.eclipse.jface.resource.JFaceResources;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.graphics.Font;
-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.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Utilities to simplify UI development. */
-public class EclipseUiUtils {
-
- /** Dispose all children of a Composite */
- public static void clear(Composite composite) {
- for (Control child : composite.getChildren())
- child.dispose();
- }
-
- /**
- * Enables efficient call to the layout method of a composite, refreshing only
- * some of the children controls.
- */
- public static void layout(Composite parent, Control... toUpdateControls) {
- parent.layout(toUpdateControls);
- }
-
- //
- // FONTS
- //
- /** Shortcut to retrieve default italic font from display */
- public static Font getItalicFont(Composite parent) {
- return JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.ITALIC)
- .createFont(parent.getDisplay());
- }
-
- /** Shortcut to retrieve default bold font from display */
- public static Font getBoldFont(Composite parent) {
- return JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.BOLD)
- .createFont(parent.getDisplay());
- }
-
- /** Shortcut to retrieve default bold italic font from display */
- public static Font getBoldItalicFont(Composite parent) {
- return JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.BOLD | SWT.ITALIC)
- .createFont(parent.getDisplay());
- }
-
- //
- // Simplify grid layouts management
- //
- public static GridLayout noSpaceGridLayout() {
- return noSpaceGridLayout(new GridLayout());
- }
-
- public static GridLayout noSpaceGridLayout(int columns) {
- return noSpaceGridLayout(new GridLayout(columns, false));
- }
-
- public static GridLayout noSpaceGridLayout(GridLayout layout) {
- layout.horizontalSpacing = 0;
- layout.verticalSpacing = 0;
- layout.marginWidth = 0;
- layout.marginHeight = 0;
- return layout;
- }
-
- public static GridData fillWidth() {
- return grabWidth(SWT.FILL, SWT.FILL);
- }
-
- public static GridData fillWidth(int colSpan) {
- GridData gd = grabWidth(SWT.FILL, SWT.FILL);
- gd.horizontalSpan = colSpan;
- return gd;
- }
-
- public static GridData fillAll() {
- return new GridData(SWT.FILL, SWT.FILL, true, true);
- }
-
- public static GridData fillAll(int colSpan, int rowSpan) {
- return new GridData(SWT.FILL, SWT.FILL, true, true, colSpan, rowSpan);
- }
-
- public static GridData grabWidth(int horizontalAlignment, int verticalAlignment) {
- return new GridData(horizontalAlignment, horizontalAlignment, true, false);
- }
-
- //
- // Simplify Form layout management
- //
-
- /**
- * Creates a basic form data that is attached to the 4 corners of the parent
- * composite
- */
- public static FormData fillFormData() {
- FormData formData = new FormData();
- formData.top = new FormAttachment(0, 0);
- formData.left = new FormAttachment(0, 0);
- formData.right = new FormAttachment(100, 0);
- formData.bottom = new FormAttachment(100, 0);
- return formData;
- }
-
- /**
- * Create a label and a text field for a grid layout, the text field grabbing
- * excess horizontal
- *
- * @param parent
- * the parent composite
- * @param label
- * the label to display
- * @param modifyListener
- * a {@link ModifyListener} to listen on events on the text, can be
- * null
- * @return the created text
- *
- */
- // FIXME why was this deprecated.
- // * @ deprecated use { @ link #createGridLT(Composite, String)} instead
- // @ Deprecated
- public static Text createGridLT(Composite parent, String label, ModifyListener modifyListener) {
- Label lbl = new Label(parent, SWT.LEAD);
- lbl.setText(label);
- lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
- Text txt = new Text(parent, SWT.LEAD | SWT.BORDER);
- txt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- if (modifyListener != null)
- txt.addModifyListener(modifyListener);
- return txt;
- }
-
- /**
- * Create a label and a text field for a grid layout, the text field grabbing
- * excess horizontal
- */
- public static Text createGridLT(Composite parent, String label) {
- return createGridLT(parent, label, null);
- }
-
- /**
- * Creates one label and a text field not editable with background colour of the
- * parent (like a label but with selectable text)
- */
- public static Text createGridLL(Composite parent, String label, String text) {
- Text txt = createGridLT(parent, label);
- txt.setText(text);
- txt.setEditable(false);
- txt.setBackground(parent.getBackground());
- return txt;
- }
-
- /**
- * Create a label and a text field with password display for a grid layout, the
- * text field grabbing excess horizontal
- */
- public static Text createGridLP(Composite parent, String label) {
- return createGridLP(parent, label, null);
- }
-
- /**
- * Create a label and a text field with password display for a grid layout, the
- * text field grabbing excess horizontal. The given modify listener will be
- * added to the newly created text field if not null.
- */
- public static Text createGridLP(Composite parent, String label, ModifyListener modifyListener) {
- Label lbl = new Label(parent, SWT.LEAD);
- lbl.setText(label);
- lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
- Text txt = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.PASSWORD);
- txt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- if (modifyListener != null)
- txt.addModifyListener(modifyListener);
- return txt;
- }
-
- // MISCELLANEOUS
-
- /** Simply checks if a string is not null nor empty */
- public static boolean notEmpty(String stringToTest) {
- return !(stringToTest == null || "".equals(stringToTest.trim()));
- }
-
- /** Simply checks if a string is null or empty */
- public static boolean isEmpty(String stringToTest) {
- return stringToTest == null || "".equals(stringToTest.trim());
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui;
-
-import java.io.InputStream;
-
-/**
- * Used for file download : subclasses must implement model specific methods to
- * get a byte array representing a file given is ID.
- */
-@Deprecated
-public interface FileProvider {
-
- public byte[] getByteArrayFileFromId(String fileId);
-
- public InputStream getInputStreamFromFileId(String fileId);
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui;
-
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerComparator;
-
-public abstract class GenericTableComparator extends ViewerComparator {
- private static final long serialVersionUID = -1175894935075325810L;
- protected int propertyIndex;
- public static final int ASCENDING = 0, DESCENDING = 1;
- protected int direction = DESCENDING;
-
- /**
- * Creates an instance of a sorter for TableViewer.
- *
- * @param defaultColumnIndex
- * the default sorter column
- */
-
- public GenericTableComparator(int defaultColumnIndex, int direction) {
- propertyIndex = defaultColumnIndex;
- this.direction = direction;
- }
-
- public void setColumn(int column) {
- if (column == this.propertyIndex) {
- // Same column as last sort; toggle the direction
- direction = 1 - direction;
- } else {
- // New column; do a descending sort
- this.propertyIndex = column;
- direction = DESCENDING;
- }
- }
-
- /**
- * Must be Overriden in each view.
- */
- public abstract int compare(Viewer viewer, Object e1, Object e2);
-}
+++ /dev/null
-package org.argeo.eclipse.ui;
-
-import java.util.List;
-
-/**
- * Views and editors can implement this interface so that one of the list that
- * is displayed in the part (For instance in a Table or a Tree Viewer) can be
- * rebuilt externally. Typically to generate csv or calc extract.
- */
-public interface IListProvider {
- /**
- * Returns an array of current and relevant elements
- */
- public Object[] getElements(String extractId);
-
- /**
- * Returns the column definition for passed ID
- */
- public List<ColumnDefinition> getColumnDefinition(String extractId);
-}
+++ /dev/null
-package org.argeo.eclipse.ui.dialogs;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-import org.argeo.api.cms.CmsLog;
-import org.eclipse.jface.dialogs.IMessageProvider;
-import org.eclipse.jface.dialogs.TitleAreaDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Point;
-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;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Generic error dialog to be used in try/catch blocks.
- *
- * @deprecated Use CMS dialogs instead.
- */
-@Deprecated
-public class ErrorFeedback extends TitleAreaDialog {
- private static final long serialVersionUID = -8918084784628179044L;
-
- private final static CmsLog log = CmsLog.getLog(ErrorFeedback.class);
-
- private final String message;
- private final Throwable exception;
-
- public static void 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;
-
- new ErrorFeedback(newShell(), message, e).open();
- }
-
- public static void show(String message) {
- new ErrorFeedback(newShell(), message, null).open();
- }
-
- private static Shell newShell() {
- return new Shell(getDisplay(), SWT.NO_TRIM);
- }
-
- /** 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 ErrorFeedback(Shell parentShell, String message, Throwable e) {
- super(parentShell);
- setShellStyle(SWT.NO_TRIM);
- this.message = message;
- this.exception = e;
- log.error(message, e);
- }
-
- protected Point getInitialSize() {
- if (exception != null)
- return new Point(800, 600);
- else
- return new Point(400, 300);
- }
-
- @Override
- protected Control createDialogArea(Composite parent) {
- Composite dialogarea = (Composite) super.createDialogArea(parent);
- dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- Composite composite = new Composite(dialogarea, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
- composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
- setMessage(message != null ? message + (exception != null ? ": " + exception.getMessage() : "")
- : exception != null ? exception.getMessage() : "Unkown Error", IMessageProvider.ERROR);
-
- if (exception != null) {
- Text stack = new Text(composite, 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));
- StringWriter sw = new StringWriter();
- exception.printStackTrace(new PrintWriter(sw));
- stack.setText(sw.toString());
- }
-
- parent.pack();
- return composite;
- }
-
- protected void configureShell(Shell shell) {
- super.configureShell(shell);
- shell.setText("Error");
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui.dialogs;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.swt.SWT;
-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.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Generic lightweight dialog, not based on JFace.
- *
- * @deprecated Use CMS dialogs instead.
- */
-@Deprecated
-public class FeedbackDialog extends LightweightDialog {
- private final static CmsLog log = CmsLog.getLog(FeedbackDialog.class);
-
- private String message;
- private Throwable exception;
-
-// private Shell parentShell;
- private Shell shell;
-
- public static void 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;
-
- new FeedbackDialog(getDisplay().getActiveShell(), message, e).open();
- }
-
- public static void show(String message) {
- new FeedbackDialog(getDisplay().getActiveShell(), message, null).open();
- }
-
- /** 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 FeedbackDialog(Shell parentShell, String message, Throwable e) {
- super(parentShell);
- this.message = message;
- this.exception = e;
- log.error(message, e);
- }
-
- public int open() {
- if (shell != null)
- throw new EclipseUiException("There is already a shell");
- shell = new Shell(getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
- shell.setLayout(new GridLayout());
- // shell.setText("Error");
- shell.setSize(getInitialSize());
- createDialogArea(shell);
- // shell.pack();
- // shell.layout();
-
- Rectangle shellBounds = Display.getCurrent().getBounds();// RAP
- Point dialogSize = shell.getSize();
- int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2;
- int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2;
- shell.setLocation(x, y);
-
- shell.addShellListener(new ShellAdapter() {
- private static final long serialVersionUID = -2701270481953688763L;
-
- @Override
- public void shellDeactivated(ShellEvent e) {
- closeShell();
- }
- });
-
- shell.open();
- return OK;
- }
-
- protected void closeShell() {
- shell.close();
- shell.dispose();
- shell = null;
- }
-
- protected Point getInitialSize() {
- // if (exception != null)
- // return new Point(800, 600);
- // else
- return new Point(400, 300);
- }
-
- protected Control createDialogArea(Composite parent) {
- Composite dialogarea = new Composite(parent, SWT.NONE);
- dialogarea.setLayout(new GridLayout());
- // Composite dialogarea = (Composite) super.createDialogArea(parent);
- dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
- Label messageLbl = new Label(dialogarea, SWT.NONE);
- if (message != null)
- messageLbl.setText(message);
- else if (exception != null)
- messageLbl.setText(exception.getLocalizedMessage());
-
- 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(composite, 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));
- StringWriter sw = new StringWriter();
- exception.printStackTrace(new PrintWriter(sw));
- stack.setText(sw.toString());
- }
-
- // parent.pack();
- return composite;
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui.dialogs;
-
-import org.argeo.api.cms.CmsLog;
-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. */
-@Deprecated
-public class LightweightDialog {
- private final static CmsLog log = CmsLog.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
+++ /dev/null
-package org.argeo.eclipse.ui.dialogs;
-
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.dialogs.IMessageProvider;
-import org.eclipse.jface.dialogs.TitleAreaDialog;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Point;
-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.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Dialog to retrieve a single value.
- *
- * @deprecated Use CMS dialogs instead.
- */
-@Deprecated
-public class SingleValue extends TitleAreaDialog {
- private static final long serialVersionUID = 2843538207460082349L;
-
- private Text valueT;
- private String value;
- private final String title, message, label;
- private final Boolean multiline;
-
- public static String ask(String label, String message) {
- SingleValue svd = new SingleValue(label, message);
- if (svd.open() == Window.OK)
- return svd.getString();
- else
- return null;
- }
-
- public static Long askLong(String label, String message) {
- SingleValue svd = new SingleValue(label, message);
- if (svd.open() == Window.OK)
- return svd.getLong();
- else
- return null;
- }
-
- public static Double askDouble(String label, String message) {
- SingleValue svd = new SingleValue(label, message);
- if (svd.open() == Window.OK)
- return svd.getDouble();
- else
- return null;
- }
-
- public SingleValue(String label, String message) {
- this(Display.getDefault().getActiveShell(), label, message, label, false);
- }
-
- public SingleValue(Shell parentShell, String title, String message, String label, Boolean multiline) {
- super(parentShell);
- this.title = title;
- this.message = message;
- this.label = label;
- this.multiline = multiline;
- }
-
- protected Point getInitialSize() {
- if (multiline)
- return new Point(450, 350);
-
- else
- return new Point(400, 270);
- }
-
- protected Control createDialogArea(Composite parent) {
- Composite dialogarea = (Composite) super.createDialogArea(parent);
- dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- Composite composite = new Composite(dialogarea, SWT.NONE);
- composite.setLayoutData(EclipseUiUtils.fillAll());
- GridLayout layout = new GridLayout(2, false);
- layout.marginWidth = layout.marginHeight = 20;
- composite.setLayout(layout);
-
- valueT = createLT(composite, label);
-
- setMessage(message, IMessageProvider.NONE);
-
- parent.pack();
- valueT.setFocus();
- return composite;
- }
-
- @Override
- protected void okPressed() {
- value = valueT.getText();
- super.okPressed();
- }
-
- /** Creates label and text. */
- protected Text createLT(Composite parent, String label) {
- new Label(parent, SWT.NONE).setText(label);
- Text text;
- if (multiline) {
- text = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.MULTI);
- text.setLayoutData(EclipseUiUtils.fillAll());
- } else {
- text = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.SINGLE);
- text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
- }
- return text;
- }
-
- protected void configureShell(Shell shell) {
- super.configureShell(shell);
- shell.setText(title);
- }
-
- public String getString() {
- return value;
- }
-
- public Long getLong() {
- return Long.valueOf(getString());
- }
-
- public Double getDouble() {
- return Double.valueOf(getString());
- }
-}
+++ /dev/null
-/** Generic SWT/JFace dialogs. */
-package org.argeo.eclipse.ui.dialogs;
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.io.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.LinkedHashMap;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.Text;
-
-/** Simple UI provider that populates a composite parent given a NIO path */
-public class AdvancedFsBrowser {
- private final static CmsLog log = CmsLog.getLog(AdvancedFsBrowser.class);
-
- // Some local constants to experiment. should be cleaned
- // private final static int THUMBNAIL_WIDTH = 400;
- // private Point imageWidth = new Point(250, 0);
- private final static int COLUMN_WIDTH = 160;
-
- private Path initialPath;
- private Path currEdited;
- // Filter
- private Composite displayBoxCmp;
- private Text parentPathTxt;
- private Text filterTxt;
- // Browser columns
- private ScrolledComposite scrolledCmp;
- // Keep a cache of the opened directories
- private LinkedHashMap<Path, FilterEntitiesVirtualTable> browserCols = new LinkedHashMap<>();
- private Composite scrolledCmpBody;
-
- public Control createUi(Composite parent, Path basePath) {
- if (basePath == null)
- throw new IllegalArgumentException("Context cannot be null");
- parent.setLayout(new GridLayout());
-
- // top filter
- Composite filterCmp = new Composite(parent, SWT.NO_FOCUS);
- filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
- addFilterPanel(filterCmp);
-
- // Bottom part a sash with browser on the left
- SashForm form = new SashForm(parent, SWT.HORIZONTAL);
- // form.setLayout(new FillLayout());
- form.setLayoutData(EclipseUiUtils.fillAll());
- Composite leftCmp = new Composite(form, SWT.NO_FOCUS);
- displayBoxCmp = new Composite(form, SWT.NONE);
- form.setWeights(new int[] { 3, 1 });
-
- createBrowserPart(leftCmp, basePath);
- // leftCmp.addControlListener(new ControlAdapter() {
- // @Override
- // public void controlResized(ControlEvent e) {
- // Rectangle r = leftCmp.getClientArea();
- // log.warn("Browser resized: " + r.toString());
- // scrolledCmp.setMinSize(browserCols.size() * (COLUMN_WIDTH + 2),
- // SWT.DEFAULT);
- // // scrolledCmp.setMinSize(scrolledCmpBody.computeSize(SWT.DEFAULT,
- // // r.height));
- // }
- // });
-
- populateCurrEditedDisplay(displayBoxCmp, basePath);
-
- // INIT
- setEdited(basePath);
- initialPath = basePath;
- // form.layout(true, true);
- return parent;
- }
-
- private void createBrowserPart(Composite parent, Path context) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
- // scrolled composite
- scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER | SWT.NO_FOCUS);
- scrolledCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- scrolledCmp.setExpandVertical(true);
- scrolledCmp.setExpandHorizontal(true);
- scrolledCmp.setShowFocusedControl(true);
-
- scrolledCmpBody = new Composite(scrolledCmp, SWT.NO_FOCUS);
- scrolledCmp.setContent(scrolledCmpBody);
- scrolledCmpBody.addControlListener(new ControlAdapter() {
- private static final long serialVersionUID = 183238447102854553L;
-
- @Override
- public void controlResized(ControlEvent e) {
- Rectangle r = scrolledCmp.getClientArea();
- scrolledCmp.setMinSize(scrolledCmpBody.computeSize(SWT.DEFAULT, r.height));
- }
- });
- initExplorer(scrolledCmpBody, context);
- scrolledCmpBody.layout(true, true);
- scrolledCmp.layout();
-
- }
-
- private Control initExplorer(Composite parent, Path context) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
- return createBrowserColumn(parent, context);
- }
-
- private Control createBrowserColumn(Composite parent, Path context) {
- // TODO style is not correctly managed.
- FilterEntitiesVirtualTable table = new FilterEntitiesVirtualTable(parent, SWT.BORDER | SWT.NO_FOCUS, context);
- // CmsUtils.style(table, ArgeoOrgStyle.browserColumn.style());
- table.filterList("*");
- table.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true));
- browserCols.put(context, table);
- parent.layout(true, true);
- return table;
- }
-
- public void addFilterPanel(Composite parent) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false)));
-
- 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(EclipseUiUtils.fillWidth());
- filterTxt.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = 1L;
-
- public void modifyText(ModifyEvent event) {
- modifyFilter(false);
- }
- });
- filterTxt.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = 2533535233583035527L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
- // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
- FilterEntitiesVirtualTable currTable = null;
- if (currEdited != null) {
- FilterEntitiesVirtualTable table = browserCols.get(currEdited);
- if (table != null && !table.isDisposed())
- currTable = table;
- }
-
- if (e.keyCode == SWT.ARROW_DOWN)
- currTable.setFocus();
- else if (e.keyCode == SWT.BS) {
- if (filterTxt.getText().equals("")
- && !(currEdited.getNameCount() == 1 || currEdited.equals(initialPath))) {
- Path oldEdited = currEdited;
- Path parentPath = currEdited.getParent();
- setEdited(parentPath);
- if (browserCols.containsKey(parentPath))
- browserCols.get(parentPath).setSelected(oldEdited);
- filterTxt.setFocus();
- e.doit = false;
- }
- } else if (e.keyCode == SWT.TAB && !shiftPressed) {
- Path uniqueChild = getOnlyChild(currEdited, filterTxt.getText());
- if (uniqueChild != null) {
- // Highlight the unique chosen child
- currTable.setSelected(uniqueChild);
- setEdited(uniqueChild);
- }
- filterTxt.setFocus();
- e.doit = false;
- }
- }
- });
- }
-
- private Path getOnlyChild(Path parent, String filter) {
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(currEdited, filter + "*")) {
- Path uniqueChild = null;
- boolean moreThanOne = false;
- loop: for (Path entry : stream) {
- if (uniqueChild == null) {
- uniqueChild = entry;
- } else {
- moreThanOne = true;
- break loop;
- }
- }
- if (!moreThanOne)
- return uniqueChild;
- return null;
- } catch (IOException ioe) {
- throw new FsUiException(
- "Unable to determine unique child existence and get it under " + parent + " with filter " + filter,
- ioe);
- }
- }
-
- private void setEdited(Path path) {
- currEdited = path;
- EclipseUiUtils.clear(displayBoxCmp);
- populateCurrEditedDisplay(displayBoxCmp, currEdited);
- refreshFilters(path);
- refreshBrowser(path);
- }
-
- private void refreshFilters(Path path) {
- parentPathTxt.setText(path.toUri().toString());
- filterTxt.setText("");
- filterTxt.getParent().layout();
- }
-
- private void refreshBrowser(Path currPath) {
- Path currParPath = currPath.getParent();
- Object[][] colMatrix = new Object[browserCols.size()][2];
-
- int i = 0, currPathIndex = -1, lastLeftOpenedIndex = -1;
- for (Path path : browserCols.keySet()) {
- colMatrix[i][0] = path;
- colMatrix[i][1] = browserCols.get(path);
- if (currPathIndex >= 0 && lastLeftOpenedIndex < 0 && currParPath != null) {
- boolean leaveOpened = path.startsWith(currPath);
- if (!leaveOpened)
- lastLeftOpenedIndex = i;
- }
- if (currParPath.equals(path))
- currPathIndex = i;
- i++;
- }
-
- if (currPathIndex >= 0 && lastLeftOpenedIndex >= 0) {
- // dispose and remove useless cols
- for (int l = i - 1; l >= lastLeftOpenedIndex; l--) {
- ((FilterEntitiesVirtualTable) colMatrix[l][1]).dispose();
- browserCols.remove(colMatrix[l][0]);
- }
- }
-
- if (browserCols.containsKey(currPath)) {
- FilterEntitiesVirtualTable currCol = browserCols.get(currPath);
- if (currCol.isDisposed()) {
- // Does it still happen ?
- log.warn(currPath + " browser column was disposed and still listed");
- browserCols.remove(currPath);
- }
- }
-
- if (!browserCols.containsKey(currPath) && Files.isDirectory(currPath))
- createBrowserColumn(scrolledCmpBody, currPath);
-
- scrolledCmpBody.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false)));
- scrolledCmpBody.layout(true, true);
- // also resize the scrolled composite
- scrolledCmp.layout();
- }
-
- private void modifyFilter(boolean fromOutside) {
- if (!fromOutside)
- if (currEdited != null) {
- String filter = filterTxt.getText() + "*";
- FilterEntitiesVirtualTable table = browserCols.get(currEdited);
- if (table != null && !table.isDisposed())
- table.filterList(filter);
- }
- }
-
- /**
- * Recreates the content of the box that displays information about the current
- * selected node.
- */
- private void populateCurrEditedDisplay(Composite parent, Path context) {
- parent.setLayout(new GridLayout());
-
- // if (isImg(context)) {
- // EditableImage image = new Img(parent, RIGHT, context, imageWidth);
- // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false,
- // 2, 1));
- // }
-
- try {
- Label contextL = new Label(parent, SWT.NONE);
- contextL.setText(context.getFileName().toString());
- contextL.setFont(EclipseUiUtils.getBoldFont(parent));
- addProperty(parent, "Last modified", Files.getLastModifiedTime(context).toString());
- addProperty(parent, "Owner", Files.getOwner(context).getName());
- if (Files.isDirectory(context)) {
- addProperty(parent, "Type", "Folder");
- } else {
- String mimeType = Files.probeContentType(context);
- if (EclipseUiUtils.isEmpty(mimeType))
- mimeType = "<i>Unknown</i>";
- addProperty(parent, "Type", mimeType);
- addProperty(parent, "Size", FsUiUtils.humanReadableByteCount(Files.size(context), false));
- }
- parent.layout(true, true);
- } catch (IOException e) {
- throw new FsUiException("Cannot display details for " + context, e);
- }
- }
-
- private void addProperty(Composite parent, String propName, String value) {
- Label contextL = new Label(parent, SWT.NONE);
- contextL.setText(propName + ": " + value);
- }
-
- /**
- * Almost canonical implementation of a table that displays the content of a
- * directory
- */
- private class FilterEntitiesVirtualTable extends Composite {
- private static final long serialVersionUID = 2223410043691844875L;
-
- // Context
- private Path context;
- private Path currSelected = null;
-
- // UI Objects
- private FsTableViewer viewer;
-
- @Override
- public boolean setFocus() {
- if (viewer.getTable().isDisposed())
- return false;
- if (currSelected != null)
- viewer.setSelection(new StructuredSelection(currSelected), true);
- else if (viewer.getSelection().isEmpty()) {
- Object first = viewer.getElementAt(0);
- if (first != null)
- viewer.setSelection(new StructuredSelection(first), true);
- }
- return viewer.getTable().setFocus();
- }
-
- /**
- * Enable highlighting the correct element in the table when externally browsing
- * (typically via the command-line-like Text field)
- */
- void setSelected(Path selected) {
- // to prevent change selection event to be thrown
- currSelected = selected;
- viewer.setSelection(new StructuredSelection(currSelected), true);
- }
-
- void filterList(String filter) {
- viewer.setInput(context, filter);
- }
-
- public FilterEntitiesVirtualTable(Composite parent, int style, Path context) {
- super(parent, SWT.NO_FOCUS);
- this.context = context;
- createTableViewer(this);
- }
-
- private void createTableViewer(final Composite parent) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
- // We must limit the size of the table otherwise the full list is
- // loaded before the layout happens
- // Composite listCmp = new Composite(parent, SWT.NO_FOCUS);
- // GridData gd = new GridData(SWT.LEFT, SWT.FILL, false, true);
- // gd.widthHint = COLUMN_WIDTH;
- // listCmp.setLayoutData(gd);
- // listCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
- // viewer = new TableViewer(listCmp, SWT.VIRTUAL | SWT.MULTI |
- // SWT.V_SCROLL);
- // Table table = viewer.getTable();
- // table.setLayoutData(EclipseUiUtils.fillAll());
-
- viewer = new FsTableViewer(parent, SWT.MULTI);
- Table table = viewer.configureDefaultSingleColumnTable(COLUMN_WIDTH);
-
- viewer.addSelectionChangedListener(new ISelectionChangedListener() {
-
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
- if (selection.isEmpty())
- return;
- Object obj = selection.getFirstElement();
- Path newSelected;
- if (obj instanceof Path)
- newSelected = (Path) obj;
- else if (obj instanceof ParentDir)
- newSelected = ((ParentDir) obj).getPath();
- else
- return;
- if (newSelected.equals(currSelected))
- return;
- currSelected = newSelected;
- setEdited(newSelected);
-
- }
- });
-
- table.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -8083424284436715709L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
- Path selected = null;
- if (!selection.isEmpty())
- selected = ((Path) selection.getFirstElement());
- if (e.keyCode == SWT.ARROW_RIGHT) {
- if (!Files.isDirectory(selected))
- return;
- if (selected != null) {
- setEdited(selected);
- browserCols.get(selected).setFocus();
- }
- } else if (e.keyCode == SWT.ARROW_LEFT) {
- if (context.equals(initialPath))
- return;
- Path parent = context.getParent();
- if (parent == null)
- return;
-
- setEdited(parent);
- browserCols.get(parent).setFocus();
- }
- }
- });
- }
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.graphics.Image;
-
-/** Basic label provider with icon for NIO file viewers */
-public class FileIconNameLabelProvider extends ColumnLabelProvider {
- private static final long serialVersionUID = 8187902187946523148L;
-
- private Image folderIcon;
- private Image fileIcon;
-
- public FileIconNameLabelProvider() {
- // if (!PlatformUI.isWorkbenchRunning()) {
- folderIcon = ImageDescriptor.createFromFile(getClass(), "folder.png").createImage();
- fileIcon = ImageDescriptor.createFromFile(getClass(), "file.png").createImage();
- // }
- }
-
- @Override
- public void dispose() {
- if (folderIcon != null)
- folderIcon.dispose();
- if (fileIcon != null)
- fileIcon.dispose();
- super.dispose();
- }
-
- @Override
- public String getText(Object element) {
- if (element instanceof Path) {
- Path curr = ((Path) element);
- Path name = curr.getFileName();
- if (name == null)
- return "[No name]";
- else
- return name.toString();
- } else if (element instanceof ParentDir) {
- return "..";
- }
- return null;
- }
-
- @Override
- public Image getImage(Object element) {
- if (element instanceof Path) {
- Path curr = ((Path) element);
- if (Files.isDirectory(curr))
- // if (folderIcon != null)
- return folderIcon;
- // else
- // return
- // PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
- // else if (fileIcon != null)
- return fileIcon;
- // else
- // return
- // PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE);
- } else if (element instanceof ParentDir) {
- return folderIcon;
- }
- return null;
- }
-
- @Override
- public String getToolTipText(Object element) {
- if (element instanceof Path) {
- Path curr = ((Path) element);
- Path name = curr.getFileName();
- if (name == null)
- return "[No name]";
- else
- return name.toAbsolutePath().toString();
- } else if (element instanceof ParentDir) {
- return ((ParentDir) element).getPath().toAbsolutePath().toString();
- }
- return null;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.nio.file.Path;
-import java.util.List;
-
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.eclipse.jface.viewers.CellLabelProvider;
-import org.eclipse.jface.viewers.ILazyContentProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-
-/**
- * Canonical implementation of a JFace table viewer to display the content of a
- * file folder
- */
-public class FsTableViewer extends TableViewer {
- private static final long serialVersionUID = -5632407542678477234L;
-
- private boolean showHiddenItems = false;
- private boolean folderFirst = true;
- private boolean reverseOrder = false;
- private String orderProperty = FsUiConstants.PROPERTY_NAME;
-
- private Path initialPath = null;
-
- public FsTableViewer(Composite parent, int style) {
- super(parent, style | SWT.VIRTUAL);
- }
-
- public Table configureDefaultSingleColumnTable(int tableWidthHint) {
-
- return configureDefaultSingleColumnTable(tableWidthHint, new FileIconNameLabelProvider());
- }
-
- public Table configureDefaultSingleColumnTable(int tableWidthHint, CellLabelProvider labelProvider) {
- Table table = this.getTable();
- table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
- table.setLinesVisible(false);
- table.setHeaderVisible(false);
- // CmsUtils.markup(table);
- // CmsUtils.style(table, MaintenanceStyles.BROWSER_COLUMN);
-
- TableViewerColumn column = new TableViewerColumn(this, SWT.NONE);
- TableColumn tcol = column.getColumn();
- tcol.setWidth(tableWidthHint);
- column.setLabelProvider(labelProvider);
- this.setContentProvider(new MyLazyCP());
- return table;
- }
-
- public Table configureDefaultTable(List<ColumnDefinition> columns) {
- this.setContentProvider(new MyLazyCP());
- Table table = this.getTable();
- table.setLinesVisible(true);
- table.setHeaderVisible(true);
- // CmsUtils.markup(table);
- // CmsUtils.style(table, MaintenanceStyles.BROWSER_COLUMN);
- for (ColumnDefinition colDef : columns) {
- TableViewerColumn column = new TableViewerColumn(this, SWT.NONE);
- column.setLabelProvider(colDef.getLabelProvider());
- TableColumn tcol = column.getColumn();
- tcol.setResizable(true);
- tcol.setText(colDef.getLabel());
- tcol.setWidth(colDef.getMinWidth());
- }
- return table;
- }
-
- public void setInput(Path dir, String filter) {
- Path[] rows = FsUiUtils.getChildren(dir, filter, showHiddenItems, folderFirst, orderProperty, reverseOrder);
- if (rows == null) {
- this.setInput(null);
- this.setItemCount(0);
- return;
- }
- boolean isRoot;
- try {
- isRoot = dir.getRoot().equals(dir);
- } catch (Exception e) {
- // FIXME Workaround for JCR root node access
- isRoot = dir.toString().equals("/");
- }
- final Object[] res;
- if (isRoot)
- res = rows;
- else if (initialPath != null && initialPath.equals(dir))
- res = rows;
- else {
- res = new Object[rows.length + 1];
- res[0] = new ParentDir(dir.getParent());
- for (int i = 1; i < res.length; i++) {
- res[i] = rows[i - 1];
- }
- }
- this.setInput(res);
- int length = res.length;
- this.setItemCount(length);
- this.refresh();
- }
-
- /** Directly displays bookmarks **/
- public void setPathsInput(Path... paths) {
- this.setInput((Object[]) paths);
- this.setItemCount(paths.length);
- this.refresh();
- }
-
- /**
- * A path which is to be considered as root (and thus provide no link to a
- * parent directory)
- */
- public void setInitialPath(Path initialPath) {
- this.initialPath = initialPath;
- }
-
- private class MyLazyCP implements ILazyContentProvider {
- private static final long serialVersionUID = 9096550041395433128L;
- private Object[] elements;
-
- public void dispose() {
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- // IMPORTANT: don't forget this: an exception will be thrown if
- // a selected object is not part of the results anymore.
- viewer.setSelection(null);
- this.elements = (Object[]) newInput;
- }
-
- public void updateElement(int index) {
- if (index < elements.length)
- FsTableViewer.this.replace(elements[index], index);
- }
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.io.IOException;
-import java.nio.file.DirectoryIteratorException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.TreeViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeColumn;
-
-/**
- * Canonical implementation of a JFace TreeViewer to display the content of a
- * repository
- */
-public class FsTreeViewer extends TreeViewer {
- private static final long serialVersionUID = -5632407542678477234L;
-
- private boolean showHiddenItems = false;
- private boolean showDirectoryFirst = true;
- private String orderingProperty = FsUiConstants.PROPERTY_NAME;
-
- public FsTreeViewer(Composite parent, int style) {
- super(parent, style | SWT.VIRTUAL);
- }
-
- public Tree configureDefaultSingleColumnTable(int tableWidthHint) {
- Tree tree = this.getTree();
- tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
- tree.setLinesVisible(true);
- tree.setHeaderVisible(false);
-// CmsUtils.markup(tree);
-
- TreeViewerColumn column = new TreeViewerColumn(this, SWT.NONE);
- TreeColumn tcol = column.getColumn();
- tcol.setWidth(tableWidthHint);
- column.setLabelProvider(new FileIconNameLabelProvider());
-
- this.setContentProvider(new MyCP());
- return tree;
- }
-
- public Tree configureDefaultTable(List<ColumnDefinition> columns) {
- this.setContentProvider(new MyCP());
- Tree tree = this.getTree();
- tree.setLinesVisible(true);
- tree.setHeaderVisible(true);
-// CmsUtils.markup(tree);
-// CmsUtils.style(tree, MaintenanceStyles.BROWSER_COLUMN);
- for (ColumnDefinition colDef : columns) {
- TreeViewerColumn column = new TreeViewerColumn(this, SWT.NONE);
- column.setLabelProvider(colDef.getLabelProvider());
- TreeColumn tcol = column.getColumn();
- tcol.setResizable(true);
- tcol.setText(colDef.getLabel());
- tcol.setWidth(colDef.getMinWidth());
- }
- return tree;
- }
-
- public void setInput(Path dir, String filter) {
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
- // TODO make this lazy
- List<Path> paths = new ArrayList<>();
- for (Path entry : stream) {
- paths.add(entry);
- }
- Object[] rows = paths.toArray(new Object[0]);
- this.setInput(rows);
- // this.setItemCount(rows.length);
- this.refresh();
- } catch (IOException | DirectoryIteratorException e) {
- throw new FsUiException("Unable to filter " + dir + " children with filter " + filter, e);
- }
- }
-
- /** Directly displays bookmarks **/
- public void setPathsInput(Path... paths) {
- this.setInput((Object[]) paths);
- // this.setItemCount(paths.length);
- this.refresh();
- }
-
- private class MyCP implements ITreeContentProvider {
- private static final long serialVersionUID = 9096550041395433128L;
- private Object[] elements;
-
- public void dispose() {
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- // IMPORTANT: don't forget this: an exception will be thrown if
- // a selected object is not part of the results anymore.
- viewer.setSelection(null);
- this.elements = (Object[]) newInput;
- }
-
- @Override
- public Object[] getElements(Object inputElement) {
- return elements;
- }
-
- @Override
- public Object[] getChildren(Object parentElement) {
- Path path = (Path) parentElement;
- if (!Files.isDirectory(path))
- return null;
- else
- return FsUiUtils.getChildren(path, "*", showHiddenItems, showDirectoryFirst, orderingProperty, false);
- }
-
- @Override
- public Object getParent(Object element) {
- Path path = (Path) element;
- return path.getParent();
- }
-
- @Override
- public boolean hasChildren(Object element) {
- Path path = (Path) element;
- try {
- if (!Files.isDirectory(path))
- return false;
- else
- try (DirectoryStream<Path> children = Files.newDirectoryStream(path, "*")) {
- return children.iterator().hasNext();
- }
- } catch (IOException e) {
- throw new FsUiException("Unable to check child existence on " + path, e);
- }
- }
-
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-/** Centralize constants used by the Nio FS UI parts */
-public interface FsUiConstants {
-
- // TODO use standard properties
- String PROPERTY_NAME = "name";
- String PROPERTY_SIZE = "size";
- String PROPERTY_LAST_MODIFIED = "last-modified";
- String PROPERTY_TYPE = "type";
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-/** Files specific exception */
-public class FsUiException extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- public FsUiException(String message) {
- super(message);
- }
-
- public FsUiException(String message, Throwable e) {
- super(message, e);
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.io.IOException;
-import java.nio.file.DirectoryIteratorException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/** Centralise additional utilitary methods to manage Java7 NIO files */
-public class FsUiUtils {
-
- /**
- * thanks to
- * http://programming.guide/java/formatting-byte-size-to-human-readable-format.html
- */
- public static String humanReadableByteCount(long bytes, boolean si) {
- int unit = si ? 1000 : 1024;
- if (bytes < unit)
- return bytes + " B";
- int exp = (int) (Math.log(bytes) / Math.log(unit));
- String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
- return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
- }
-
- public static Path[] getChildren(Path parent, String filter, boolean showHiddenItems, boolean folderFirst,
- String orderProperty, boolean reverseOrder) {
- if (!Files.isDirectory(parent))
- return null;
- List<Pair> pairs = new ArrayList<>();
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(parent, filter)) {
- loop: for (Path entry : stream) {
- if (!showHiddenItems)
- if (Files.isHidden(entry))
- continue loop;
- switch (orderProperty) {
- case FsUiConstants.PROPERTY_SIZE:
- if (folderFirst)
- pairs.add(new LPair(entry, Files.size(entry), Files.isDirectory(entry)));
- else
- pairs.add(new LPair(entry, Files.size(entry)));
- break;
- case FsUiConstants.PROPERTY_LAST_MODIFIED:
- if (folderFirst)
- pairs.add(new LPair(entry, Files.getLastModifiedTime(entry).toMillis(),
- Files.isDirectory(entry)));
- else
- pairs.add(new LPair(entry, Files.getLastModifiedTime(entry).toMillis()));
- break;
- case FsUiConstants.PROPERTY_NAME:
- if (folderFirst)
- pairs.add(new SPair(entry, entry.getFileName().toString(), Files.isDirectory(entry)));
- else
- pairs.add(new SPair(entry, entry.getFileName().toString()));
- break;
- default:
- throw new FsUiException("Unable to prepare sort for property " + orderProperty);
- }
- }
- Pair[] rows = pairs.toArray(new Pair[0]);
- Arrays.sort(rows);
- Path[] results = new Path[rows.length];
- if (reverseOrder) {
- int j = rows.length - 1;
- for (int i = 0; i < rows.length; i++)
- results[i] = rows[j - i].p;
- } else
- for (int i = 0; i < rows.length; i++)
- results[i] = rows[i].p;
- return results;
- } catch (IOException | DirectoryIteratorException e) {
- throw new FsUiException("Unable to filter " + parent + " children with filter " + filter, e);
- }
- }
-
- static abstract class Pair implements Comparable<Object> {
- Path p;
- Boolean i;
- };
-
- static class LPair extends Pair {
- long v;
-
- public LPair(Path path, long propValue) {
- p = path;
- v = propValue;
- }
-
- public LPair(Path path, long propValue, boolean isDir) {
- p = path;
- v = propValue;
- i = isDir;
- }
-
- public int compareTo(Object o) {
- if (i != null) {
- Boolean j = ((LPair) o).i;
- if (i.booleanValue() != j.booleanValue())
- return i.booleanValue() ? -1 : 1;
- }
- long u = ((LPair) o).v;
- return v < u ? -1 : v == u ? 0 : 1;
- }
- };
-
- static class SPair extends Pair {
- String v;
-
- public SPair(Path path, String propValue) {
- p = path;
- v = propValue;
- }
-
- public SPair(Path path, String propValue, boolean isDir) {
- p = path;
- v = propValue;
- i = isDir;
- }
-
- public int compareTo(Object o) {
- if (i != null) {
- Boolean j = ((SPair) o).i;
- if (i.booleanValue() != j.booleanValue())
- return i.booleanValue() ? -1 : 1;
- }
- String u = ((SPair) o).v;
- return v.compareTo(u);
- }
- };
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.attribute.FileTime;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-
-/** Expect a {@link Path} as input element */
-public class NioFileLabelProvider extends ColumnLabelProvider {
- private final static FileTime EPOCH = FileTime.fromMillis(0);
- private static final long serialVersionUID = 2160026425187796930L;
- private final String propName;
- private DateFormat dateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm");
-
- // TODO use new formatting
- // DateTimeFormatter formatter =
- // DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
- // .withLocale( Locale.UK )
- // .withZone( ZoneId.systemDefault() );
- public NioFileLabelProvider(String propName) {
- this.propName = propName;
- }
-
- @Override
- public String getText(Object element) {
- try {
- Path path;
- if (element instanceof ParentDir) {
-// switch (propName) {
-// case FsUiConstants.PROPERTY_SIZE:
-// return "-";
-// case FsUiConstants.PROPERTY_LAST_MODIFIED:
-// return "-";
-// // return Files.getLastModifiedTime(((ParentDir) element).getPath()).toString();
-// case FsUiConstants.PROPERTY_TYPE:
-// return "Folder";
-// }
- path = ((ParentDir) element).getPath();
- } else
- path = (Path) element;
- switch (propName) {
- case FsUiConstants.PROPERTY_SIZE:
- if (Files.isDirectory(path))
- return "-";
- else
- return FsUiUtils.humanReadableByteCount(Files.size(path), false);
- case FsUiConstants.PROPERTY_LAST_MODIFIED:
- if (Files.isDirectory(path))
- return "-";
- FileTime time = Files.getLastModifiedTime(path);
- if (time.equals(EPOCH))
- return "-";
- else
- return dateFormat.format(new Date(time.toMillis()));
- case FsUiConstants.PROPERTY_TYPE:
- if (Files.isDirectory(path))
- return "Folder";
- else {
- String mimeType = Files.probeContentType(path);
- if (EclipseUiUtils.isEmpty(mimeType))
- return "Unknown";
- else
- return mimeType;
- }
- default:
- throw new IllegalArgumentException("Unsupported property " + propName);
- }
- } catch (IOException ioe) {
- throw new FsUiException("Cannot get property " + propName + " on " + element);
- }
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.nio.file.Path;
-
-/** A parent directory (..) reference. */
-public class ParentDir {
- Path path;
-
- public ParentDir(Path path) {
- super();
- this.path = path;
- }
-
- public Path getPath() {
- return path;
- }
-
- @Override
- public int hashCode() {
- return path.hashCode();
- }
-
- @Override
- public String toString() {
- return "Parent dir " + path;
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-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.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Table;
-
-/**
- * Experimental UI upon Java 7 nio files api: SashForm layout with bookmarks on
- * the left hand side and a simple table on the right hand side.
- */
-public class SimpleFsBrowser extends Composite {
- private final static CmsLog log = CmsLog.getLog(SimpleFsBrowser.class);
- private static final long serialVersionUID = -40347919096946585L;
-
- private Path currSelected;
- private FsTableViewer bookmarksViewer;
- private FsTableViewer directoryDisplayViewer;
-
- public SimpleFsBrowser(Composite parent, int style) {
- super(parent, style);
- createContent(this);
- // parent.layout(true, true);
- }
-
- public Viewer getViewer() {
- return directoryDisplayViewer;
- }
-
- private void createContent(Composite parent) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
- SashForm form = new SashForm(parent, SWT.HORIZONTAL);
- Composite leftCmp = new Composite(form, SWT.NONE);
- populateBookmarks(leftCmp);
-
- Composite rightCmp = new Composite(form, SWT.BORDER);
- populateDisplay(rightCmp);
- form.setLayoutData(EclipseUiUtils.fillAll());
- form.setWeights(new int[] { 1, 3 });
- }
-
- public void setInput(Path... paths) {
- bookmarksViewer.setPathsInput(paths);
- bookmarksViewer.getTable().getParent().layout(true, true);
- }
-
- private void populateBookmarks(final Composite parent) {
- // GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
- // layout.verticalSpacing = 5;
- parent.setLayout(new GridLayout());
-
- ISelectionChangedListener selList = new MySelectionChangedListener();
-
- appendTitle(parent, "My bookmarks");
- bookmarksViewer = new FsTableViewer(parent, SWT.MULTI | SWT.NO_SCROLL);
- Table table = bookmarksViewer.configureDefaultSingleColumnTable(500);
- GridData gd = EclipseUiUtils.fillWidth();
- gd.horizontalIndent = 10;
- table.setLayoutData(gd);
- bookmarksViewer.addSelectionChangedListener(selList);
-
- appendTitle(parent, "Jcr + File");
-
- FsTableViewer jcrFilesViewers = new FsTableViewer(parent, SWT.MULTI | SWT.NO_SCROLL);
- table = jcrFilesViewers.configureDefaultSingleColumnTable(500);
- gd = EclipseUiUtils.fillWidth();
- gd.horizontalIndent = 10;
- table.setLayoutData(gd);
- jcrFilesViewers.addSelectionChangedListener(selList);
-
- // FileSystemProvider fsProvider = new JackrabbitMemoryFsProvider();
- // try {
- // Path testPath = fsProvider.getPath(new URI("jcr+memory:/"));
- // jcrFilesViewers.setPathsInput(testPath);
- // } catch (URISyntaxException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
- }
-
- private Label appendTitle(Composite parent, String value) {
- Label titleLbl = new Label(parent, SWT.NONE);
- titleLbl.setText(value);
- titleLbl.setFont(EclipseUiUtils.getBoldFont(parent));
- GridData gd = EclipseUiUtils.fillWidth();
- gd.horizontalIndent = 5;
- gd.verticalIndent = 5;
- titleLbl.setLayoutData(gd);
- return titleLbl;
- }
-
- private class MySelectionChangedListener implements ISelectionChangedListener {
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- IStructuredSelection selection = (IStructuredSelection) bookmarksViewer.getSelection();
- if (selection.isEmpty())
- return;
- else {
- Path newSelected = (Path) selection.getFirstElement();
- if (newSelected.equals(currSelected))
- return;
- currSelected = newSelected;
- directoryDisplayViewer.setInput(currSelected, "*");
- }
- }
- }
-
- private void populateDisplay(final Composite parent) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
- directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
- List<ColumnDefinition> colDefs = new ArrayList<>();
- colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), "Name", 200));
- colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100));
- colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 250));
- colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
- "Last modified", 200));
- Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
- table.setLayoutData(EclipseUiUtils.fillAll());
-
- table.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -8083424284436715709L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- log.debug("Key event received: " + e.keyCode);
- IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
- Path selected = null;
- if (!selection.isEmpty())
- selected = ((Path) selection.getFirstElement());
- if (e.keyCode == SWT.CR) {
- if (!Files.isDirectory(selected))
- return;
- if (selected != null) {
- currSelected = selected;
- directoryDisplayViewer.setInput(currSelected, "*");
- }
- } else if (e.keyCode == SWT.BS) {
- currSelected = currSelected.getParent();
- directoryDisplayViewer.setInput(currSelected, "*");
- directoryDisplayViewer.getTable().setFocus();
- }
- }
- });
-
-// directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
-// @Override
-// public void doubleClick(DoubleClickEvent event) {
-// IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
-// Path selected = null;
-// if (!selection.isEmpty()) {
-// Object obj = selection.getFirstElement();
-// if (obj instanceof Path)
-// selected = (Path) obj;
-// else if (obj instanceof ParentDir)
-// selected = ((ParentDir) obj).getPath();
-// }
-// if (selected != null) {
-// if (!Files.isDirectory(selected))
-// return;
-// currSelected = selected;
-// directoryDisplayViewer.setInput(currSelected, "*");
-// }
-// }
-// });
-
- directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
- @Override
- public void doubleClick(DoubleClickEvent event) {
- IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
- Path selected = null;
- if (!selection.isEmpty()) {
- Object obj = selection.getFirstElement();
- if (obj instanceof Path)
- selected = (Path) obj;
- else if (obj instanceof ParentDir)
- selected = ((ParentDir) obj).getPath();
- }
- if (selected != null) {
- if (!Files.isDirectory(selected))
- return;
- currSelected = selected;
- directoryDisplayViewer.setInput(currSelected, "*");
- }
- }
- });
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui.fs;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.Tree;
-
-/** A simple Java 7 nio files browser with a tree */
-public class SimpleFsTreeBrowser extends Composite {
- private final static CmsLog log = CmsLog.getLog(SimpleFsTreeBrowser.class);
- private static final long serialVersionUID = -40347919096946585L;
-
- private Path currSelected;
- private FsTreeViewer treeViewer;
- private FsTableViewer directoryDisplayViewer;
-
- public SimpleFsTreeBrowser(Composite parent, int style) {
- super(parent, style);
- createContent(this);
- // parent.layout(true, true);
- }
-
- private void createContent(Composite parent) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
- SashForm form = new SashForm(parent, SWT.HORIZONTAL);
- Composite child1 = new Composite(form, SWT.NONE);
- populateTree(child1);
- Composite child2 = new Composite(form, SWT.BORDER);
- populateDisplay(child2);
- form.setLayoutData(EclipseUiUtils.fillAll());
- form.setWeights(new int[] { 1, 3 });
- }
-
- public void setInput(Path... paths) {
- treeViewer.setPathsInput(paths);
- treeViewer.getControl().getParent().layout(true, true);
- }
-
- private void populateTree(final Composite parent) {
- // GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
- // layout.verticalSpacing = 5;
- parent.setLayout(new GridLayout());
-
- ISelectionChangedListener selList = new MySelectionChangedListener();
-
- treeViewer = new FsTreeViewer(parent, SWT.MULTI);
- Tree tree = treeViewer.configureDefaultSingleColumnTable(500);
- GridData gd = EclipseUiUtils.fillAll();
- // gd.horizontalIndent = 10;
- tree.setLayoutData(gd);
- treeViewer.addSelectionChangedListener(selList);
- }
-
- private class MySelectionChangedListener implements ISelectionChangedListener {
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();
- if (selection.isEmpty())
- return;
- else {
- Path newSelected = (Path) selection.getFirstElement();
- if (newSelected.equals(currSelected))
- return;
- currSelected = newSelected;
- if (Files.isDirectory(currSelected))
- directoryDisplayViewer.setInput(currSelected, "*");
- }
- }
- }
-
- private void populateDisplay(final Composite parent) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
- directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
- List<ColumnDefinition> colDefs = new ArrayList<>();
- colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), "Name", 200, 200));
- colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100, 100));
- colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 300, 300));
- colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
- "Last modified", 100, 100));
- Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
- table.setLayoutData(EclipseUiUtils.fillAll());
-
- table.addKeyListener(new KeyListener() {
- private static final long serialVersionUID = -8083424284436715709L;
-
- @Override
- public void keyReleased(KeyEvent e) {
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- log.debug("Key event received: " + e.keyCode);
- IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
- Path selected = null;
- if (!selection.isEmpty())
- selected = ((Path) selection.getFirstElement());
- if (e.keyCode == SWT.CR) {
- if (!Files.isDirectory(selected))
- return;
- if (selected != null) {
- currSelected = selected;
- directoryDisplayViewer.setInput(currSelected, "*");
- }
- } else if (e.keyCode == SWT.BS) {
- currSelected = currSelected.getParent();
- directoryDisplayViewer.setInput(currSelected, "*");
- directoryDisplayViewer.getTable().setFocus();
- }
- }
- });
- }
-}
+++ /dev/null
-/** Generic SWT/JFace file system utilities. */
-package org.argeo.eclipse.ui.fs;
\ No newline at end of file
+++ /dev/null
-/** Generic SWT/JFace utilities. */
-package org.argeo.eclipse.ui;
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui.parts;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.util.ViewerUtils;
-import org.eclipse.jface.layout.TableColumnLayout;
-import org.eclipse.jface.viewers.CheckboxTableViewer;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ColumnWeightData;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Link;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.useradmin.User;
-
-/**
- * Generic composite that display a filter and a table viewer to display users
- * (can also be groups)
- *
- * Warning: this class does not extends <code>TableViewer</code>. Use the
- * getTableViewer method to access it.
- *
- */
-public abstract class LdifUsersTable extends Composite {
- private static final long serialVersionUID = -7385959046279360420L;
-
- // Context
- // private UserAdmin userAdmin;
-
- // Configuration
- private List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
- private boolean hasFilter;
- private boolean preventTableLayout = false;
- private boolean hasSelectionColumn;
- private int tableStyle;
-
- // Local UI Objects
- private TableViewer usersViewer;
- private Text filterTxt;
-
- /* EXPOSED METHODS */
-
- /**
- * @param parent
- * @param style
- */
- public LdifUsersTable(Composite parent, int style) {
- super(parent, SWT.NO_FOCUS);
- this.tableStyle = style;
- }
-
- // TODO workaround the bug of the table layout in the Form
- public LdifUsersTable(Composite parent, int style, boolean preventTableLayout) {
- super(parent, SWT.NO_FOCUS);
- this.tableStyle = style;
- this.preventTableLayout = preventTableLayout;
- }
-
- /** This must be called before the call to populate method */
- public void setColumnDefinitions(List<ColumnDefinition> columnDefinitions) {
- this.columnDefs = columnDefinitions;
- }
-
- /**
- *
- * @param addFilter
- * choose to add a field to filter results or not
- * @param addSelection
- * choose to add a column to select some of the displayed results or
- * not
- */
- public void populate(boolean addFilter, boolean addSelection) {
- // initialization
- Composite parent = this;
- hasFilter = addFilter;
- hasSelectionColumn = addSelection;
-
- // Main Layout
- GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
- layout.verticalSpacing = 5;
- this.setLayout(layout);
- if (hasFilter)
- createFilterPart(parent);
-
- Composite tableComp = new Composite(parent, SWT.NO_FOCUS);
- tableComp.setLayoutData(EclipseUiUtils.fillAll());
- usersViewer = createTableViewer(tableComp);
- usersViewer.setContentProvider(new UsersContentProvider());
- }
-
- /**
- *
- * @param showMore
- * display static filters on creation
- * @param addSelection
- * choose to add a column to select some of the displayed results or
- * not
- */
- public void populateWithStaticFilters(boolean showMore, boolean addSelection) {
- // initialization
- Composite parent = this;
- hasFilter = true;
- hasSelectionColumn = addSelection;
-
- // Main Layout
- GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
- layout.verticalSpacing = 5;
- this.setLayout(layout);
- createStaticFilterPart(parent, showMore);
-
- Composite tableComp = new Composite(parent, SWT.NO_FOCUS);
- tableComp.setLayoutData(EclipseUiUtils.fillAll());
- usersViewer = createTableViewer(tableComp);
- usersViewer.setContentProvider(new UsersContentProvider());
- }
-
- /** Enable access to the selected users or groups */
- public List<User> getSelectedUsers() {
- if (hasSelectionColumn) {
- Object[] elements = ((CheckboxTableViewer) usersViewer).getCheckedElements();
-
- List<User> result = new ArrayList<User>();
- for (Object obj : elements) {
- result.add((User) obj);
- }
- return result;
- } else
- throw new EclipseUiException(
- "Unvalid request: no selection column " + "has been created for the current table");
- }
-
- /** Returns the User table viewer, typically to add doubleclick listener */
- public TableViewer getTableViewer() {
- return usersViewer;
- }
-
- /**
- * Force the refresh of the underlying table using the current filter string if
- * relevant
- */
- public void refresh() {
- String filter = hasFilter ? filterTxt.getText().trim() : null;
- if ("".equals(filter))
- filter = null;
- refreshFilteredList(filter);
- }
-
- /** Effective repository request: caller must implement this method */
- abstract protected List<User> listFilteredElements(String filter);
-
- // protected List<User> listFilteredElements(String filter) {
- // List<User> users = new ArrayList<User>();
- // try {
- // Role[] roles = userAdmin.getRoles(filter);
- // // Display all users and groups
- // for (Role role : roles)
- // users.add((User) role);
- // } catch (InvalidSyntaxException e) {
- // throw new EclipseUiException("Unable to get roles with filter: "
- // + filter, e);
- // }
- // return users;
- // }
-
- /* GENERIC COMPOSITE METHODS */
- @Override
- public boolean setFocus() {
- if (hasFilter)
- return filterTxt.setFocus();
- else
- return usersViewer.getTable().setFocus();
- }
-
- @Override
- public void dispose() {
- super.dispose();
- }
-
- /* LOCAL CLASSES AND METHODS */
- // Will be usefull to rather use a virtual table viewer
- private void refreshFilteredList(String filter) {
- List<User> users = listFilteredElements(filter);
- usersViewer.setInput(users.toArray());
- }
-
- private class UsersContentProvider implements IStructuredContentProvider {
- private static final long serialVersionUID = 1L;
-
- public Object[] getElements(Object inputElement) {
- return (Object[]) inputElement;
- }
-
- public void dispose() {
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
- }
-
- /* MANAGE FILTER */
- private void createFilterPart(Composite parent) {
- // Text Area for the filter
- filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
- filterTxt.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
- filterTxt.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = 1L;
-
- public void modifyText(ModifyEvent event) {
- refreshFilteredList(filterTxt.getText());
- }
- });
- }
-
- private void createStaticFilterPart(Composite parent, boolean showMore) {
- Composite filterComp = new Composite(parent, SWT.NO_FOCUS);
- filterComp.setLayout(new GridLayout(2, false));
- filterComp.setLayoutData(EclipseUiUtils.fillWidth());
- // generic search
- filterTxt = new Text(filterComp, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
- filterTxt.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
- // filterTxt.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL |
- // GridData.HORIZONTAL_ALIGN_FILL));
- filterTxt.addModifyListener(new ModifyListener() {
- private static final long serialVersionUID = 1L;
-
- public void modifyText(ModifyEvent event) {
- refreshFilteredList(filterTxt.getText());
- }
- });
-
- // add static filter abilities
- Link moreLk = new Link(filterComp, SWT.NONE);
- Composite staticFilterCmp = new Composite(filterComp, SWT.NO_FOCUS);
- staticFilterCmp.setLayoutData(EclipseUiUtils.fillWidth(2));
- populateStaticFilters(staticFilterCmp);
-
- MoreLinkListener listener = new MoreLinkListener(moreLk, staticFilterCmp, showMore);
- // initialise the layout
- listener.refresh();
- moreLk.addSelectionListener(listener);
- }
-
- /** Overwrite to add static filters */
- protected void populateStaticFilters(Composite staticFilterCmp) {
- }
-
- // private void addMoreSL(final Link more) {
- // more.addSelectionListener( }
-
- private class MoreLinkListener extends SelectionAdapter {
- private static final long serialVersionUID = -524987616510893463L;
- private boolean isShown;
- private final Composite staticFilterCmp;
- private final Link moreLk;
-
- public MoreLinkListener(Link moreLk, Composite staticFilterCmp, boolean isShown) {
- this.moreLk = moreLk;
- this.staticFilterCmp = staticFilterCmp;
- this.isShown = isShown;
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- isShown = !isShown;
- refresh();
- }
-
- public void refresh() {
- GridData gd = (GridData) staticFilterCmp.getLayoutData();
- if (isShown) {
- moreLk.setText("<a> Less... </a>");
- gd.heightHint = SWT.DEFAULT;
- } else {
- moreLk.setText("<a> More... </a>");
- gd.heightHint = 0;
- }
- forceLayout();
- }
- }
-
- private void forceLayout() {
- LdifUsersTable.this.getParent().layout(true, true);
- }
-
- private TableViewer createTableViewer(final Composite parent) {
-
- int style = tableStyle | SWT.H_SCROLL | SWT.V_SCROLL;
- if (hasSelectionColumn)
- style = style | SWT.CHECK;
- Table table = new Table(parent, style);
- TableColumnLayout layout = new TableColumnLayout();
-
- // TODO the table layout does not works with the scrolled form
-
- if (preventTableLayout) {
- parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
- table.setLayoutData(EclipseUiUtils.fillAll());
- } else
- parent.setLayout(layout);
-
- TableViewer viewer;
- if (hasSelectionColumn)
- viewer = new CheckboxTableViewer(table);
- else
- viewer = new TableViewer(table);
- table.setLinesVisible(true);
- table.setHeaderVisible(true);
-
- TableViewerColumn column;
- // int offset = 0;
- if (hasSelectionColumn) {
- // offset = 1;
- column = ViewerUtils.createTableViewerColumn(viewer, "", SWT.NONE, 25);
- column.setLabelProvider(new ColumnLabelProvider() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public String getText(Object element) {
- return null;
- }
- });
- layout.setColumnData(column.getColumn(), new ColumnWeightData(25, 25, false));
-
- SelectionAdapter selectionAdapter = new SelectionAdapter() {
- private static final long serialVersionUID = 1L;
-
- boolean allSelected = false;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- allSelected = !allSelected;
- ((CheckboxTableViewer) usersViewer).setAllChecked(allSelected);
- }
- };
- column.getColumn().addSelectionListener(selectionAdapter);
- }
-
- // NodeViewerComparator comparator = new NodeViewerComparator();
- // TODO enable the sort by click on the header
- // int i = offset;
- for (ColumnDefinition colDef : columnDefs)
- createTableColumn(viewer, layout, colDef);
-
- // column = ViewerUtils.createTableViewerColumn(viewer,
- // colDef.getHeaderLabel(), SWT.NONE, colDef.getColumnSize());
- // column.setLabelProvider(new CLProvider(colDef.getPropertyName()));
- // column.getColumn().addSelectionListener(
- // JcrUiUtils.getNodeSelectionAdapter(i,
- // colDef.getPropertyType(), colDef.getPropertyName(),
- // comparator, viewer));
- // i++;
- // }
-
- // IMPORTANT: initialize comparator before setting it
- // JcrColumnDefinition firstCol = colDefs.get(0);
- // comparator.setColumn(firstCol.getPropertyType(),
- // firstCol.getPropertyName());
- // viewer.setComparator(comparator);
-
- return viewer;
- }
-
- /** Default creation of a column for a user table */
- private TableViewerColumn createTableColumn(TableViewer tableViewer, TableColumnLayout layout,
- ColumnDefinition columnDef) {
-
- boolean resizable = true;
- TableViewerColumn tvc = new TableViewerColumn(tableViewer, SWT.NONE);
- TableColumn column = tvc.getColumn();
-
- column.setText(columnDef.getLabel());
- column.setWidth(columnDef.getMinWidth());
- column.setResizable(resizable);
-
- ColumnLabelProvider lp = columnDef.getLabelProvider();
- // add a reference to the display to enable font management
- // if (lp instanceof UserAdminAbstractLP)
- // ((UserAdminAbstractLP) lp).setDisplay(tableViewer.getTable()
- // .getDisplay());
- tvc.setLabelProvider(lp);
-
- layout.setColumnData(column, new ColumnWeightData(columnDef.getWeight(), columnDef.getMinWidth(), resizable));
-
- return tvc;
- }
-}
+++ /dev/null
-/** Generic SWT/JFace composites. */
-package org.argeo.eclipse.ui.parts;
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui.util;
-
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.TreeViewerColumn;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.TreeColumn;
-
-/**
- * Centralise useful methods to manage JFace Table, Tree and TreeColumn viewers.
- */
-public class ViewerUtils {
-
- /**
- * Creates a basic column for the given table. For the time being, we do not
- * support movable columns.
- */
- public static TableColumn createColumn(Table parent, String name, int style, int width) {
- TableColumn result = new TableColumn(parent, style);
- result.setText(name);
- result.setWidth(width);
- result.setResizable(true);
- return result;
- }
-
- /**
- * Creates a TableViewerColumn for the given viewer. For the time being, we do
- * not support movable columns.
- */
- public static TableViewerColumn createTableViewerColumn(TableViewer parent, String name, int style, int width) {
- TableViewerColumn tvc = new TableViewerColumn(parent, style);
- TableColumn column = tvc.getColumn();
- column.setText(name);
- column.setWidth(width);
- column.setResizable(true);
- return tvc;
- }
-
- // public static TableViewerColumn createTableViewerColumn(TableViewer parent,
- // Localized name, int style, int width) {
- // return createTableViewerColumn(parent, name.lead(), style, width);
- // }
-
- /**
- * Creates a TreeViewerColumn for the given viewer. For the time being, we do
- * not support movable columns.
- */
- public static TreeViewerColumn createTreeViewerColumn(TreeViewer parent, String name, int style, int width) {
- TreeViewerColumn tvc = new TreeViewerColumn(parent, style);
- TreeColumn column = tvc.getColumn();
- column.setText(name);
- column.setWidth(width);
- column.setResizable(true);
- return tvc;
- }
-}
+++ /dev/null
-/** Generic SWT/JFace JCR helpers. */
-package org.argeo.eclipse.ui.util;
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.api.cli</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+package org.argeo.api.cli;
+
+public class CommandArgsException extends IllegalArgumentException {
+ private static final long serialVersionUID = -7271050747105253935L;
+ private String commandName;
+ private volatile CommandsCli commandsCli;
+
+ public CommandArgsException(Exception cause) {
+ super(cause.getMessage(), cause);
+ }
+
+ public CommandArgsException(String message) {
+ super(message);
+ }
+
+ public String getCommandName() {
+ return commandName;
+ }
+
+ public void setCommandName(String commandName) {
+ this.commandName = commandName;
+ }
+
+ public CommandsCli getCommandsCli() {
+ return commandsCli;
+ }
+
+ public void setCommandsCli(CommandsCli commandsCli) {
+ this.commandsCli = commandsCli;
+ }
+
+}
--- /dev/null
+package org.argeo.api.cli;
+
+import java.util.List;
+
+/** {@link RuntimeException} referring during a command run. */
+public class CommandRuntimeException extends RuntimeException {
+ private static final long serialVersionUID = 5595999301269377128L;
+
+ private final DescribedCommand<?> command;
+ private final List<String> arguments;
+
+ public CommandRuntimeException(Throwable e, DescribedCommand<?> command, List<String> arguments) {
+ this(null, e, command, arguments);
+ }
+
+ public CommandRuntimeException(String message, DescribedCommand<?> command, List<String> arguments) {
+ this(message, null, command, arguments);
+ }
+
+ public CommandRuntimeException(String message, Throwable e, DescribedCommand<?> command, List<String> arguments) {
+ super(message == null ? "(" + command.getClass().getName() + " " + arguments.toString() + ")"
+ : message + " (" + command.getClass().getName() + " " + arguments.toString() + ")", e);
+ this.command = command;
+ this.arguments = arguments;
+ }
+
+ public DescribedCommand<?> getCommand() {
+ return command;
+ }
+
+ public List<String> getArguments() {
+ return arguments;
+ }
+
+}
--- /dev/null
+package org.argeo.api.cli;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.function.Function;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.MissingOptionException;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/** Base class for a CLI managing sub commands. */
+public abstract class CommandsCli implements DescribedCommand<Object> {
+ public final static String HELP = "help";
+
+ private final String commandName;
+ private Map<String, Function<List<String>, ?>> commands = new TreeMap<>();
+
+ protected final Options options = new Options();
+
+ public CommandsCli(String commandName) {
+ this.commandName = commandName;
+ }
+
+ @Override
+ public Object apply(List<String> args) {
+ String cmd = null;
+ List<String> newArgs = new ArrayList<>();
+ try {
+ CommandLineParser clParser = new DefaultParser();
+ CommandLine commonCl = clParser.parse(getOptions(), args.toArray(new String[args.size()]), true);
+ List<String> leftOvers = commonCl.getArgList();
+ for (String arg : leftOvers) {
+ if (!arg.startsWith("-") && cmd == null) {
+ cmd = arg;
+ } else {
+ newArgs.add(arg);
+ }
+ }
+ } catch (ParseException e) {
+ CommandArgsException cae = new CommandArgsException(e);
+ throw cae;
+ }
+
+ Function<List<String>, ?> function = cmd != null ? getCommand(cmd) : getDefaultCommand();
+ if (function == null)
+ throw new IllegalArgumentException("Uknown command " + cmd);
+ try {
+ Object value = function.apply(newArgs);
+ return value != null ? value.toString() : null;
+ } catch (CommandArgsException e) {
+ if (e.getCommandName() == null) {
+ e.setCommandName(cmd);
+ e.setCommandsCli(this);
+ }
+ throw e;
+ } catch (IllegalArgumentException e) {
+ CommandArgsException cae = new CommandArgsException(e);
+ cae.setCommandName(cmd);
+ throw cae;
+ }
+ }
+
+ @Override
+ public Options getOptions() {
+ return options;
+ }
+
+ protected void addCommand(String cmd, Function<List<String>, ?> function) {
+ commands.put(cmd, function);
+
+ }
+
+ @Override
+ public String getUsage() {
+ return "[command]";
+ }
+
+ protected void addCommandsCli(CommandsCli commandsCli) {
+ addCommand(commandsCli.getCommandName(), commandsCli);
+ commandsCli.addCommand(HELP, new HelpCommand(this, commandsCli));
+ }
+
+ public String getCommandName() {
+ return commandName;
+ }
+
+ public Set<String> getSubCommands() {
+ return commands.keySet();
+ }
+
+ public Function<List<String>, ?> getCommand(String command) {
+ return commands.get(command);
+ }
+
+ public HelpCommand getHelpCommand() {
+ return (HelpCommand) getCommand(HELP);
+ }
+
+ public Function<List<String>, String> getDefaultCommand() {
+ return getHelpCommand();
+ }
+
+ /** In order to implement quickly a main method. */
+ public static void mainImpl(CommandsCli cli, String[] args) {
+ try {
+ cli.addCommand(CommandsCli.HELP, new HelpCommand(null, cli));
+ Object output = cli.apply(Arrays.asList(args));
+ System.out.println(output);
+ System.exit(0);
+ } catch (CommandArgsException e) {
+ System.err.println("Wrong arguments " + Arrays.toString(args) + ": " + e.getMessage());
+ Throwable cause = e.getCause();
+ if (!(cause instanceof MissingOptionException))
+ e.printStackTrace();
+ if (e.getCommandName() != null) {
+ StringWriter out = new StringWriter();
+ HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out);
+ System.err.println(out.toString());
+ } else {
+ e.printStackTrace();
+ }
+ System.exit(1);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
--- /dev/null
+package org.argeo.api.cli;
+
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/** A command that can be described. */
+public interface DescribedCommand<T> extends Function<List<String>, T> {
+ default Options getOptions() {
+ return new Options();
+ }
+
+ String getDescription();
+
+ default String getUsage() {
+ return null;
+ }
+
+ default String getExamples() {
+ return null;
+ }
+
+ default CommandLine toCommandLine(List<String> args) {
+ try {
+ DefaultParser parser = new DefaultParser();
+ return parser.parse(getOptions(), args.toArray(new String[args.size()]));
+ } catch (ParseException e) {
+ throw new CommandArgsException(e);
+ }
+ }
+
+ /** In order to implement quickly a main method. */
+ public static void mainImpl(DescribedCommand<?> command, String[] args) {
+ try {
+ Object output = command.apply(Arrays.asList(args));
+ System.out.println(output);
+ System.exit(0);
+ } catch (IllegalArgumentException e) {
+ StringWriter out = new StringWriter();
+ HelpCommand.printHelp(command, out);
+ System.err.println(out.toString());
+ System.exit(1);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.api.cli;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+
+/** A special command that can describe {@link DescribedCommand}. */
+public class HelpCommand implements DescribedCommand<String> {
+ private CommandsCli commandsCli;
+ private CommandsCli parentCommandsCli;
+
+ // Help formatting
+ private static int helpWidth = 80;
+ private static int helpLeftPad = 4;
+ private static int helpDescPad = 20;
+
+ public HelpCommand(CommandsCli parentCommandsCli, CommandsCli commandsCli) {
+ super();
+ this.parentCommandsCli = parentCommandsCli;
+ this.commandsCli = commandsCli;
+ }
+
+ @Override
+ public String apply(List<String> args) {
+ StringWriter out = new StringWriter();
+
+ if (args.size() == 0) {// overview
+ printHelp(commandsCli, out);
+ } else {
+ String cmd = args.get(0);
+ Function<List<String>, ?> function = commandsCli.getCommand(cmd);
+ if (function == null)
+ return "Command " + cmd + " not found.";
+ Options options;
+ String examples;
+ DescribedCommand<?> command = null;
+ if (function instanceof DescribedCommand) {
+ command = (DescribedCommand<?>) function;
+ options = command.getOptions();
+ examples = command.getExamples();
+ } else {
+ options = new Options();
+ examples = null;
+ }
+ String description = getShortDescription(function);
+ String commandCall = getCommandUsage(cmd, command);
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp(new PrintWriter(out), helpWidth, commandCall, description, options, helpLeftPad,
+ helpDescPad, examples, false);
+ }
+ return out.toString();
+ }
+
+ private static String getShortDescription(Function<List<String>, ?> function) {
+ if (function instanceof DescribedCommand) {
+ return ((DescribedCommand<?>) function).getDescription();
+ } else {
+ return function.toString();
+ }
+ }
+
+ public String getCommandUsage(String cmd, DescribedCommand<?> command) {
+ String commandCall = getCommandCall(commandsCli) + " " + cmd;
+ assert command != null;
+ if (command != null && command.getUsage() != null) {
+ commandCall = commandCall + " " + command.getUsage();
+ }
+ return commandCall;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Shows this help or describes a command";
+ }
+
+ @Override
+ public String getUsage() {
+ return "[command]";
+ }
+
+ public CommandsCli getParentCommandsCli() {
+ return parentCommandsCli;
+ }
+
+ protected String getCommandCall(CommandsCli commandsCli) {
+ HelpCommand hc = commandsCli.getHelpCommand();
+ if (hc.getParentCommandsCli() != null) {
+ return getCommandCall(hc.getParentCommandsCli()) + " " + commandsCli.getCommandName();
+ } else {
+ return commandsCli.getCommandName();
+ }
+ }
+
+ public static void printHelp(DescribedCommand<?> command, StringWriter out) {
+ String usage = "java " + command.getClass().getName()
+ + (command.getUsage() != null ? " " + command.getUsage() : "");
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
+ helpLeftPad, helpDescPad, command.getExamples(), false);
+
+ }
+
+ public static void printHelp(CommandsCli commandsCli, String commandName, StringWriter out) {
+ DescribedCommand<?> command = (DescribedCommand<?>) commandsCli.getCommand(commandName);
+ String usage = commandsCli.getHelpCommand().getCommandUsage(commandName, command);
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
+ helpLeftPad, helpDescPad, command.getExamples(), false);
+
+ }
+
+ public static void printHelp(CommandsCli commandsCli, StringWriter out) {
+ out.append(commandsCli.getDescription()).append('\n');
+ String leftPad = spaces(helpLeftPad);
+ for (String cmd : commandsCli.getSubCommands()) {
+ Function<List<String>, ?> function = commandsCli.getCommand(cmd);
+ assert function != null;
+ out.append(leftPad);
+ out.append(cmd);
+ // TODO deal with long commands
+ out.append(spaces(helpDescPad - cmd.length()));
+ out.append(getShortDescription(function));
+ out.append('\n');
+ }
+ }
+
+ private static String spaces(int count) {
+ // Java 11
+ // return " ".repeat(count);
+ if (count <= 0)
+ return "";
+ else {
+ StringBuilder sb = new StringBuilder(count);
+ for (int i = 0; i < count; i++)
+ sb.append(' ');
+ return sb.toString();
+ }
+ }
+}
--- /dev/null
+/** Command line API. */
+package org.argeo.api.cli;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ssh.cli;
+
+import org.argeo.api.cli.CommandsCli;
+
+public class SshCli extends CommandsCli {
+ public SshCli(String commandName) {
+ super(commandName);
+ addCommand("shell", new SshShell());
+ }
+
+ @Override
+ public String getDescription() {
+ return "SSH utilities.";
+ }
+
+
+}
--- /dev/null
+package org.argeo.cms.ssh.cli;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.agent.SshAgentFactory;
+import org.apache.sshd.agent.local.LocalAgentFactory;
+import org.apache.sshd.agent.unix.UnixAgentFactory;
+import org.apache.sshd.client.config.keys.ClientIdentityLoader;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.argeo.api.cli.DescribedCommand;
+import org.argeo.cms.ssh.AbstractSsh;
+import org.argeo.cms.ssh.Ssh;
+
+public class SshShell implements DescribedCommand<String> {
+ private Option portOption;
+
+ @Override
+ public Options getOptions() {
+ Options options = new Options();
+ portOption = Option.builder().option("p").longOpt("port").hasArg().desc("port to connect to").build();
+ options.addOption(portOption);
+ return options;
+ }
+
+ @Override
+ public String apply(List<String> args) {
+ CommandLine cl = toCommandLine(args);
+ String portStr = cl.getOptionValue(portOption);
+ if (portStr == null)
+ portStr = "22";
+
+ String host = cl.getArgList().get(0);
+
+ String uriStr = "ssh://" + host + ":" + portStr + "/";
+ // System.out.println(uriStr);
+ URI uri = URI.create(uriStr);
+
+ Ssh ssh = null;
+ try {
+ ssh = new Ssh(uri);
+ boolean osAgent;
+ SshAgent sshAgent;
+ try {
+ String sshAuthSockentEnv = System.getenv(SshAgent.SSH_AUTHSOCKET_ENV_NAME);
+ if (sshAuthSockentEnv != null) {
+ ssh.getSshClient().getProperties().put(SshAgent.SSH_AUTHSOCKET_ENV_NAME, sshAuthSockentEnv);
+ SshAgentFactory agentFactory = new UnixAgentFactory();
+ ssh.getSshClient().setAgentFactory(agentFactory);
+ sshAgent = agentFactory.createClient(null, ssh.getSshClient());
+ osAgent = true;
+ } else {
+ osAgent = false;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ osAgent = false;
+ }
+
+ if (!osAgent) {
+ SshAgentFactory agentFactory = new LocalAgentFactory();
+ ssh.getSshClient().setAgentFactory(agentFactory);
+ sshAgent = agentFactory.createClient(null, ssh.getSshClient());
+ String keyPath = System.getProperty("user.home") + "/.ssh/id_rsa";
+
+ char[] keyPassword = AbstractSsh.readPassword();
+ NamedResource namedResource = new NamedResource() {
+
+ @Override
+ public String getName() {
+ return keyPath;
+ }
+ };
+ KeyPair keyPair = ClientIdentityLoader.DEFAULT
+ .loadClientIdentities(null, namedResource, FilePasswordProvider.of(new String(keyPassword)))
+ .iterator().next();
+ sshAgent.addIdentity(keyPair, "NO COMMENT");
+ }
+
+// char[] keyPassword = AbstractSsh.readPassword();
+// SshKeyPair keyPair = SshKeyPair.loadDefault(keyPassword);
+// Arrays.fill(keyPassword, '*');
+// ssh.setSshKeyPair(keyPair);
+// ssh.authenticate();
+ ssh.verifyAuth();
+
+ long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
+ System.out.println("Ssh available in " + jvmUptime + " ms.");
+
+ AbstractSsh.openShell(ssh);
+ } catch (IOException | GeneralSecurityException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } finally {
+ if (ssh != null)
+ ssh.closeSession();
+ }
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Launch a static CMS.";
+ }
+
+ }
\ No newline at end of file
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
-import org.argeo.cms.cli.CommandArgsException;
-import org.argeo.cms.cli.DescribedCommand;
+import org.argeo.api.cli.CommandArgsException;
+import org.argeo.api.cli.DescribedCommand;
public class FileSync implements DescribedCommand<SyncResult<Path>> {
final static Option deleteOption = Option.builder().longOpt("delete").desc("delete from target").build();
package org.argeo.cms.acr.fs;
-import org.argeo.cms.cli.CommandsCli;
+import org.argeo.api.cli.CommandsCli;
/** File utilities. */
public class FsCommands extends CommandsCli {
import javax.security.auth.spi.LoginModule;
import org.argeo.api.cms.CmsLog;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
+import org.argeo.cms.internal.runtime.CmsContextImpl;
import org.osgi.service.useradmin.Authorization;
import org.osgi.service.useradmin.UserAdmin;
private Map<String, Object> sharedState = null;
// private state
- private BundleContext bc;
+// private BundleContext bc;
@SuppressWarnings("unchecked")
@Override
Map<String, ?> options) {
this.subject = subject;
this.sharedState = (Map<String, Object>) sharedState;
- try {
- bc = FrameworkUtil.getBundle(AnonymousLoginModule.class).getBundleContext();
- assert bc != null;
- } catch (Exception e) {
- throw new IllegalStateException("Cannot initialize login module", e);
- }
+// try {
+// bc = FrameworkUtil.getBundle(AnonymousLoginModule.class).getBundleContext();
+// assert bc != null;
+// } catch (Exception e) {
+// throw new IllegalStateException("Cannot initialize login module", e);
+// }
}
@Override
@Override
public boolean commit() throws LoginException {
- UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
+ UserAdmin userAdmin = CmsContextImpl.getCmsContext().getUserAdmin();
Authorization authorization = userAdmin.getAuthorization(null);
RemoteAuthRequest request = (RemoteAuthRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
Locale locale = Locale.getDefault();
+++ /dev/null
-package org.argeo.cms.cli;
-
-public class CommandArgsException extends IllegalArgumentException {
- private static final long serialVersionUID = -7271050747105253935L;
- private String commandName;
- private volatile CommandsCli commandsCli;
-
- public CommandArgsException(Exception cause) {
- super(cause.getMessage(), cause);
- }
-
- public CommandArgsException(String message) {
- super(message);
- }
-
- public String getCommandName() {
- return commandName;
- }
-
- public void setCommandName(String commandName) {
- this.commandName = commandName;
- }
-
- public CommandsCli getCommandsCli() {
- return commandsCli;
- }
-
- public void setCommandsCli(CommandsCli commandsCli) {
- this.commandsCli = commandsCli;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.cli;
-
-import java.util.List;
-
-/** {@link RuntimeException} referring during a command run. */
-public class CommandRuntimeException extends RuntimeException {
- private static final long serialVersionUID = 5595999301269377128L;
-
- private final DescribedCommand<?> command;
- private final List<String> arguments;
-
- public CommandRuntimeException(Throwable e, DescribedCommand<?> command, List<String> arguments) {
- this(null, e, command, arguments);
- }
-
- public CommandRuntimeException(String message, DescribedCommand<?> command, List<String> arguments) {
- this(message, null, command, arguments);
- }
-
- public CommandRuntimeException(String message, Throwable e, DescribedCommand<?> command, List<String> arguments) {
- super(message == null ? "(" + command.getClass().getName() + " " + arguments.toString() + ")"
- : message + " (" + command.getClass().getName() + " " + arguments.toString() + ")", e);
- this.command = command;
- this.arguments = arguments;
- }
-
- public DescribedCommand<?> getCommand() {
- return command;
- }
-
- public List<String> getArguments() {
- return arguments;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.cli;
-
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.function.Function;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.MissingOptionException;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-
-/** Base class for a CLI managing sub commands. */
-public abstract class CommandsCli implements DescribedCommand<Object> {
- public final static String HELP = "help";
-
- private final String commandName;
- private Map<String, Function<List<String>, ?>> commands = new TreeMap<>();
-
- protected final Options options = new Options();
-
- public CommandsCli(String commandName) {
- this.commandName = commandName;
- }
-
- @Override
- public Object apply(List<String> args) {
- String cmd = null;
- List<String> newArgs = new ArrayList<>();
- try {
- CommandLineParser clParser = new DefaultParser();
- CommandLine commonCl = clParser.parse(getOptions(), args.toArray(new String[args.size()]), true);
- List<String> leftOvers = commonCl.getArgList();
- for (String arg : leftOvers) {
- if (!arg.startsWith("-") && cmd == null) {
- cmd = arg;
- } else {
- newArgs.add(arg);
- }
- }
- } catch (ParseException e) {
- CommandArgsException cae = new CommandArgsException(e);
- throw cae;
- }
-
- Function<List<String>, ?> function = cmd != null ? getCommand(cmd) : getDefaultCommand();
- if (function == null)
- throw new IllegalArgumentException("Uknown command " + cmd);
- try {
- Object value = function.apply(newArgs);
- return value != null ? value.toString() : null;
- } catch (CommandArgsException e) {
- if (e.getCommandName() == null) {
- e.setCommandName(cmd);
- e.setCommandsCli(this);
- }
- throw e;
- } catch (IllegalArgumentException e) {
- CommandArgsException cae = new CommandArgsException(e);
- cae.setCommandName(cmd);
- throw cae;
- }
- }
-
- @Override
- public Options getOptions() {
- return options;
- }
-
- protected void addCommand(String cmd, Function<List<String>, ?> function) {
- commands.put(cmd, function);
-
- }
-
- @Override
- public String getUsage() {
- return "[command]";
- }
-
- protected void addCommandsCli(CommandsCli commandsCli) {
- addCommand(commandsCli.getCommandName(), commandsCli);
- commandsCli.addCommand(HELP, new HelpCommand(this, commandsCli));
- }
-
- public String getCommandName() {
- return commandName;
- }
-
- public Set<String> getSubCommands() {
- return commands.keySet();
- }
-
- public Function<List<String>, ?> getCommand(String command) {
- return commands.get(command);
- }
-
- public HelpCommand getHelpCommand() {
- return (HelpCommand) getCommand(HELP);
- }
-
- public Function<List<String>, String> getDefaultCommand() {
- return getHelpCommand();
- }
-
- /** In order to implement quickly a main method. */
- public static void mainImpl(CommandsCli cli, String[] args) {
- try {
- cli.addCommand(CommandsCli.HELP, new HelpCommand(null, cli));
- Object output = cli.apply(Arrays.asList(args));
- System.out.println(output);
- System.exit(0);
- } catch (CommandArgsException e) {
- System.err.println("Wrong arguments " + Arrays.toString(args) + ": " + e.getMessage());
- Throwable cause = e.getCause();
- if (!(cause instanceof MissingOptionException))
- e.printStackTrace();
- if (e.getCommandName() != null) {
- StringWriter out = new StringWriter();
- HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out);
- System.err.println(out.toString());
- } else {
- e.printStackTrace();
- }
- System.exit(1);
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
-}
+++ /dev/null
-package org.argeo.cms.cli;
-
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Function;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-
-/** A command that can be described. */
-public interface DescribedCommand<T> extends Function<List<String>, T> {
- default Options getOptions() {
- return new Options();
- }
-
- String getDescription();
-
- default String getUsage() {
- return null;
- }
-
- default String getExamples() {
- return null;
- }
-
- default CommandLine toCommandLine(List<String> args) {
- try {
- DefaultParser parser = new DefaultParser();
- return parser.parse(getOptions(), args.toArray(new String[args.size()]));
- } catch (ParseException e) {
- throw new CommandArgsException(e);
- }
- }
-
- /** In order to implement quickly a main method. */
- public static void mainImpl(DescribedCommand<?> command, String[] args) {
- try {
- Object output = command.apply(Arrays.asList(args));
- System.out.println(output);
- System.exit(0);
- } catch (IllegalArgumentException e) {
- StringWriter out = new StringWriter();
- HelpCommand.printHelp(command, out);
- System.err.println(out.toString());
- System.exit(1);
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
-
-}
+++ /dev/null
-package org.argeo.cms.cli;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.List;
-import java.util.function.Function;
-
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Options;
-
-/** A special command that can describe {@link DescribedCommand}. */
-public class HelpCommand implements DescribedCommand<String> {
- private CommandsCli commandsCli;
- private CommandsCli parentCommandsCli;
-
- // Help formatting
- private static int helpWidth = 80;
- private static int helpLeftPad = 4;
- private static int helpDescPad = 20;
-
- public HelpCommand(CommandsCli parentCommandsCli, CommandsCli commandsCli) {
- super();
- this.parentCommandsCli = parentCommandsCli;
- this.commandsCli = commandsCli;
- }
-
- @Override
- public String apply(List<String> args) {
- StringWriter out = new StringWriter();
-
- if (args.size() == 0) {// overview
- printHelp(commandsCli, out);
- } else {
- String cmd = args.get(0);
- Function<List<String>, ?> function = commandsCli.getCommand(cmd);
- if (function == null)
- return "Command " + cmd + " not found.";
- Options options;
- String examples;
- DescribedCommand<?> command = null;
- if (function instanceof DescribedCommand) {
- command = (DescribedCommand<?>) function;
- options = command.getOptions();
- examples = command.getExamples();
- } else {
- options = new Options();
- examples = null;
- }
- String description = getShortDescription(function);
- String commandCall = getCommandUsage(cmd, command);
- HelpFormatter formatter = new HelpFormatter();
- formatter.printHelp(new PrintWriter(out), helpWidth, commandCall, description, options, helpLeftPad,
- helpDescPad, examples, false);
- }
- return out.toString();
- }
-
- private static String getShortDescription(Function<List<String>, ?> function) {
- if (function instanceof DescribedCommand) {
- return ((DescribedCommand<?>) function).getDescription();
- } else {
- return function.toString();
- }
- }
-
- public String getCommandUsage(String cmd, DescribedCommand<?> command) {
- String commandCall = getCommandCall(commandsCli) + " " + cmd;
- assert command != null;
- if (command != null && command.getUsage() != null) {
- commandCall = commandCall + " " + command.getUsage();
- }
- return commandCall;
- }
-
- @Override
- public String getDescription() {
- return "Shows this help or describes a command";
- }
-
- @Override
- public String getUsage() {
- return "[command]";
- }
-
- public CommandsCli getParentCommandsCli() {
- return parentCommandsCli;
- }
-
- protected String getCommandCall(CommandsCli commandsCli) {
- HelpCommand hc = commandsCli.getHelpCommand();
- if (hc.getParentCommandsCli() != null) {
- return getCommandCall(hc.getParentCommandsCli()) + " " + commandsCli.getCommandName();
- } else {
- return commandsCli.getCommandName();
- }
- }
-
- public static void printHelp(DescribedCommand<?> command, StringWriter out) {
- String usage = "java " + command.getClass().getName()
- + (command.getUsage() != null ? " " + command.getUsage() : "");
- HelpFormatter formatter = new HelpFormatter();
- formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
- helpLeftPad, helpDescPad, command.getExamples(), false);
-
- }
-
- public static void printHelp(CommandsCli commandsCli, String commandName, StringWriter out) {
- DescribedCommand<?> command = (DescribedCommand<?>) commandsCli.getCommand(commandName);
- String usage = commandsCli.getHelpCommand().getCommandUsage(commandName, command);
- HelpFormatter formatter = new HelpFormatter();
- formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
- helpLeftPad, helpDescPad, command.getExamples(), false);
-
- }
-
- public static void printHelp(CommandsCli commandsCli, StringWriter out) {
- out.append(commandsCli.getDescription()).append('\n');
- String leftPad = spaces(helpLeftPad);
- for (String cmd : commandsCli.getSubCommands()) {
- Function<List<String>, ?> function = commandsCli.getCommand(cmd);
- assert function != null;
- out.append(leftPad);
- out.append(cmd);
- // TODO deal with long commands
- out.append(spaces(helpDescPad - cmd.length()));
- out.append(getShortDescription(function));
- out.append('\n');
- }
- }
-
- private static String spaces(int count) {
- // Java 11
- // return " ".repeat(count);
- if (count <= 0)
- return "";
- else {
- StringBuilder sb = new StringBuilder(count);
- for (int i = 0; i < count; i++)
- sb.append(' ');
- return sb.toString();
- }
- }
-}
+++ /dev/null
-/** Command line API. */
-package org.argeo.cms.cli;
\ No newline at end of file
import org.argeo.cms.internal.runtime.CmsUserAdmin;
import org.argeo.cms.internal.runtime.DeployedContentRepository;
import org.argeo.util.register.Component;
+import org.argeo.util.register.ComponentRegister;
import org.argeo.util.register.SimpleRegister;
import org.argeo.util.transaction.SimpleTransactionManager;
import org.argeo.util.transaction.WorkControl;
import org.osgi.service.useradmin.UserAdmin;
/**
- * A CMS assembly which is programatically defined, as an alternative to OSGi
+ * A CMS assembly which is programmatically defined, as an alternative to OSGi
* deployment. Useful for testing or AOT compilation.
*/
public class StaticCms {
postActivation(register);
}
- protected void addComponents(SimpleRegister register) {
+ protected void addComponents(ComponentRegister register) {
}
- protected void postActivation(SimpleRegister register) {
+ protected void postActivation(ComponentRegister register) {
}
+ public ComponentRegister getComponentRegister() {
+ return register;
+ }
+
public void stop() {
if (register.isActive()) {
register.deactivate();
<T> SortedSet<Component<? extends T>> find(Class<T> clss, Predicate<Map<String, Object>> filter);
+ default <T> Component.PublishedType<T> getSingleton(Class<T> type) {
+ SortedSet<Component<? extends T>> found = find(type, null);
+ if (found.size() == 0)
+ throw new IllegalStateException("No component found for " + type);
+ return found.first().getType(type);
+ }
+
+ default <T> T getObject(Class<T> clss) {
+ SortedSet<Component<? extends T>> found = find(clss, null);
+ if (found.size() == 0)
+ return null;
+ return found.first().get();
+ }
+
Component<?> get(Object instance);
// default <T> PublishedType<T> getType(Class<T> clss) {
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.cms.e4.rap</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" configuration-policy="optional" name="CMS Admin RAP">
- <implementation class="org.argeo.cms.e4.rap.CmsE4AdminApp"/>
- <service>
- <provide interface="org.eclipse.rap.rwt.application.ApplicationConfiguration"/>
- <property name="contextName" type="String" value="cms"/>
- </service>
-</scr:component>
+++ /dev/null
-Bundle-ActivationPolicy: lazy
-Service-Component: OSGI-INF/cms-admin-rap.xml
-
-Import-Package: org.eclipse.swt,\
-org.eclipse.swt.graphics,\
-org.eclipse.e4.ui.workbench,\
-org.eclipse.rap.rwt.client,\
-org.eclipse.nebula.widgets.richtext;resolution:=optional,\
-*
+++ /dev/null
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- OSGI-INF/
+++ /dev/null
-package org.argeo.cms.e4.rap;
-
-import java.util.HashMap;
-import java.util.Map;
-
-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;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.osgi.framework.BundleContext;
-
-/** Base class for CMS RAP applications. */
-public abstract class AbstractRapE4App implements ApplicationConfiguration {
- private String e4Xmi;
- private String path;
- private String lifeCycleUri = "bundleclass://org.argeo.cms.e4.rap/org.argeo.cms.e4.rap.CmsLoginLifecycle";
-
- private Map<String, String> baseProperties = new HashMap<String, String>();
-
- private BundleContext bundleContext;
- public final static String CONTEXT_NAME_PROPERTY = "contextName";
- private String contextName;
-
- /**
- * To be overridden in order to add multiple entry points, directly or using
- * {@link #addE4EntryPoint(Application, String, String, Map)}.
- */
- protected void addEntryPoints(Application application) {
- }
-
- public void configure(Application application) {
- application.setExceptionHandler(new ExceptionHandler() {
-
- @Override
- public void handleException(Throwable throwable) {
- CmsFeedback.show("Unexpected RWT exception", throwable);
- }
- });
-
- if (e4Xmi != null) {// backward compatibility
- addE4EntryPoint(application, path, e4Xmi, getBaseProperties());
- } else {
- addEntryPoints(application);
- }
- }
-
- protected Map<String, String> getBaseProperties() {
- return baseProperties;
- }
-
-// protected void addEntryPoint(Application application, E4ApplicationConfig config, Map<String, String> properties) {
-// CmsE4EntryPointFactory entryPointFactory = new CmsE4EntryPointFactory(config);
-// application.addEntryPoint(path, entryPointFactory, properties);
-// application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
-// }
-
- protected void addE4EntryPoint(Application application, String path, String e4Xmi, Map<String, String> properties) {
- E4ApplicationConfig config = createE4ApplicationConfig(e4Xmi);
- CmsE4EntryPointFactory entryPointFactory = new CmsE4EntryPointFactory(config);
- application.addEntryPoint(path, entryPointFactory, properties);
- application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
- }
-
- /**
- * To be overridden for further configuration.
- *
- * @see E4ApplicationConfig
- */
- protected E4ApplicationConfig createE4ApplicationConfig(String e4Xmi) {
- return new E4ApplicationConfig(e4Xmi, lifeCycleUri, null, null, false, true, true);
- }
-
- @Deprecated
- public void setPageTitle(String pageTitle) {
- if (pageTitle != null)
- baseProperties.put(WebClient.PAGE_TITLE, pageTitle);
- }
-
- /** Returns a new map used to customise and entry point. */
- public Map<String, String> customise(String pageTitle) {
- Map<String, String> custom = new HashMap<>(getBaseProperties());
- if (pageTitle != null)
- custom.put(WebClient.PAGE_TITLE, pageTitle);
- return custom;
- }
-
- @Deprecated
- public void setE4Xmi(String e4Xmi) {
- this.e4Xmi = e4Xmi;
- }
-
- @Deprecated
- public void setPath(String path) {
- this.path = path;
- }
-
- public void setLifeCycleUri(String lifeCycleUri) {
- this.lifeCycleUri = lifeCycleUri;
- }
-
- protected BundleContext getBundleContext() {
- return bundleContext;
- }
-
- protected void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- public String getContextName() {
- return contextName;
- }
-
- public void setContextName(String contextName) {
- this.contextName = contextName;
- }
-
- public void init(BundleContext bundleContext, Map<String, Object> properties) {
- this.bundleContext = bundleContext;
- for (String key : properties.keySet()) {
- Object value = properties.get(key);
- if (value != null)
- baseProperties.put(key, value.toString());
- }
-
- if (properties.containsKey(CONTEXT_NAME_PROPERTY)) {
- assert properties.get(CONTEXT_NAME_PROPERTY) != null;
- contextName = properties.get(CONTEXT_NAME_PROPERTY).toString();
- } else {
- contextName = "<unknown context>";
- }
- }
-
- public void destroy(Map<String, Object> properties) {
-
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.rap;
-
-import org.eclipse.rap.rwt.application.Application;
-
-/**
- * Access to canonical views of the core CMS concepts, useful for devleopers and
- * operators.
- */
-public class CmsE4AdminApp extends AbstractRapE4App {
- @Override
- protected void addEntryPoints(Application application) {
- addE4EntryPoint(application, "/devops", "org.argeo.cms.e4/e4xmi/cms-devops.e4xmi",
- customise("Argeo CMS DevOps"));
- addE4EntryPoint(application, "/ego", "org.argeo.cms.e4/e4xmi/cms-ego.e4xmi", customise("Argeo CMS Ego"));
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.rap;
-
-import java.security.PrivilegedAction;
-
-import javax.security.auth.Subject;
-
-import org.eclipse.rap.e4.E4ApplicationConfig;
-import org.eclipse.rap.e4.E4EntryPointFactory;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-
-public class CmsE4EntryPointFactory extends E4EntryPointFactory {
- public final static String DEFAULT_LIFECYCLE_URI = "bundleclass://org.argeo.cms.e4.rap/org.argeo.cms.e4.rap.CmsLoginLifecycle";
-
- public CmsE4EntryPointFactory(E4ApplicationConfig config) {
- super(config);
- }
-
- public CmsE4EntryPointFactory(String e4Xmi, String lifeCycleUri) {
- super(defaultConfig(e4Xmi, lifeCycleUri));
- }
-
- public CmsE4EntryPointFactory(String e4Xmi) {
- this(e4Xmi, DEFAULT_LIFECYCLE_URI);
- }
-
- public static E4ApplicationConfig defaultConfig(String e4Xmi, String lifeCycleUri) {
- E4ApplicationConfig config = new E4ApplicationConfig(e4Xmi, lifeCycleUri, null, null, false, true, true);
- return config;
- }
-
- @Override
- public EntryPoint create() {
- EntryPoint ep = createEntryPoint();
- EntryPoint authEp = new EntryPoint() {
-
- @Override
- public int createUI() {
- Subject subject = new Subject();
- return Subject.doAs(subject, new PrivilegedAction<Integer>() {
-
- @Override
- public Integer run() {
- // SPNEGO
- // 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");
- // }
-
- JavaScriptExecutor jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
- Integer exitCode = ep.createUI();
- jsExecutor.execute("location.reload()");
- return exitCode;
- }
-
- });
- }
- };
- return authEp;
- }
-
- protected EntryPoint createEntryPoint() {
- return super.create();
- }
-}
+++ /dev/null
-package org.argeo.cms.e4.rap;
-
-import java.security.AccessController;
-import java.util.UUID;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-import org.argeo.api.cms.CmsAuth;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.auth.CurrentUser;
-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.eclipse.e4.core.services.events.IEventBroker;
-import org.eclipse.e4.ui.workbench.UIEvents;
-import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
-import org.eclipse.e4.ui.workbench.lifecycle.PreSave;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.client.service.BrowserNavigation;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
-
-@SuppressWarnings("restriction")
-public class CmsLoginLifecycle implements CmsView {
- private final static CmsLog log = CmsLog.getLog(CmsLoginLifecycle.class);
-
- private UxContext uxContext;
- private CmsImageManager imageManager;
-
- private LoginContext loginContext;
- private BrowserNavigation browserNavigation;
-
- private String state = null;
- private String uid;
-
- @PostContextCreate
- boolean login(final IEventBroker eventBroker) {
- uid = UUID.randomUUID().toString();
- browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
- if (browserNavigation != null)
- browserNavigation.addBrowserNavigationListener(new BrowserNavigationListener() {
- private static final long serialVersionUID = -3668136623771902865L;
-
- @Override
- public void navigated(BrowserNavigationEvent event) {
- state = event.getState();
- if (uxContext != null)// is logged in
- stateChanged();
- }
- });
-
- Subject subject = Subject.getSubject(AccessController.getContext());
- Display display = Display.getCurrent();
-// UiContext.setData(CmsView.KEY, this);
- // FIXME get CMS context
- CmsLoginShell loginShell = new CmsLoginShell(this, null);
- CmsSwtUtils.registerCmsView(loginShell.getShell(), this);
- loginShell.setSubject(subject);
- try {
- // try pre-auth
- loginContext = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER, subject, loginShell);
- loginContext.login();
- } catch (LoginException e) {
- loginShell.createUi();
- loginShell.open();
-
- while (!loginShell.getShell().isDisposed()) {
- if (!display.readAndDispatch())
- display.sleep();
- }
- }
- if (CurrentUser.getUsername(getSubject()) == null)
- return false;
- uxContext = new SimpleSwtUxContext();
- imageManager = new SimpleImageManager();
-
- eventBroker.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE, new EventHandler() {
- @Override
- public void handleEvent(Event event) {
- startupComplete();
- eventBroker.unsubscribe(this);
- }
- });
-
- // lcs.changeApplicationLocale(Locale.FRENCH);
- return true;
- }
-
- @PreSave
- void destroy() {
- // logout();
- }
-
- @Override
- public UxContext getUxContext() {
- return uxContext;
- }
-
- @Override
- public void navigateTo(String state) {
- browserNavigation.pushState(state, state);
- }
-
- @Override
- public void authChange(LoginContext loginContext) {
- if (loginContext == null)
- throw new IllegalArgumentException("Login context cannot be null");
- // logout previous login context
- // if (this.loginContext != null)
- // try {
- // this.loginContext.logout();
- // } catch (LoginException e1) {
- // System.err.println("Could not log out: " + e1);
- // }
- this.loginContext = loginContext;
- }
-
- @Override
- public void logout() {
- if (loginContext == null)
- throw new IllegalStateException("Login context should not be null");
- try {
- CurrentUser.logoutCmsSession(loginContext.getSubject());
- loginContext.logout();
- } catch (LoginException e) {
- throw new IllegalStateException("Cannot log out", e);
- }
- }
-
- @Override
- public void exception(Throwable e) {
- String msg = "Unexpected exception in Eclipse 4 RAP";
- log.error(msg, e);
- CmsFeedback.show(msg, e);
- }
-
- @Override
- public CmsImageManager getImageManager() {
- return imageManager;
- }
-
- protected Subject getSubject() {
- return loginContext.getSubject();
- }
-
- @Override
- public boolean isAnonymous() {
- return CurrentUser.isAnonymous(getSubject());
- }
-
- @Override
- public String getUid() {
- return uid;
- }
-
- // CALLBACKS
- protected void startupComplete() {
- }
-
- protected void stateChanged() {
-
- }
-
- // GETTERS
- protected BrowserNavigation getBrowserNavigation() {
- return browserNavigation;
- }
-
- protected String getState() {
- return state;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.rap;
-
-import java.util.Enumeration;
-
-import org.apache.commons.io.FilenameUtils;
-import org.argeo.api.cms.CmsLog;
-import org.eclipse.rap.rwt.application.Application;
-import org.osgi.framework.Bundle;
-
-/** Simple RAP app which loads all e4xmi files. */
-public class SimpleRapE4App extends AbstractRapE4App {
- private final static CmsLog log = CmsLog.getLog(SimpleRapE4App.class);
-
- private String baseE4xmi = "/e4xmi";
-
- @Override
- protected void addEntryPoints(Application application) {
- Bundle bundle = getBundleContext().getBundle();
- Enumeration<String> paths = bundle.getEntryPaths(baseE4xmi);
- while (paths.hasMoreElements()) {
- String p = paths.nextElement();
- if (p.endsWith(".e4xmi")) {
- String e4xmiPath = bundle.getSymbolicName() + '/' + p;
- String name = '/' + FilenameUtils.removeExtension(FilenameUtils.getName(p));
- addE4EntryPoint(application, name, e4xmiPath, getBaseProperties());
- if (log.isDebugEnabled())
- log.debug("Registered " + e4xmiPath + " as " + getContextName() + name);
- }
- }
- }
-
-}
+++ /dev/null
-/** Eclipse 4 RAP specific extensions. */
-package org.argeo.cms.e4.rap;
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.cms.ui.rap</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="CMS Web App Factory">
- <implementation class="org.argeo.cms.web.osgi.CmsWebAppFactory"/>
- <reference bind="addCmsApp" cardinality="0..n" interface="org.argeo.api.cms.CmsApp" name="CmsApp" policy="dynamic" unbind="removeCmsApp"/>
- <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
-</scr:component>
+++ /dev/null
-Import-Package:\
-org.argeo.api.acr,\
-org.eclipse.swt,\
-org.argeo.eclipse.ui,\
-javax.jcr.nodetype,\
-javax.jcr.security,\
-org.eclipse.swt.graphics,\
-org.eclipse.jetty.util.component;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.http;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.io;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.security;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.server.handler;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.*;version="[9.4,12)";resolution:=optional,\
-javax.servlet.*;version="[3,5)",\
-*
-
-Service-Component: OSGI-INF/cmsWebAppFactory.xml
-
+++ /dev/null
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- OSGI-INF/cmsWebAppFactory.xml
-source.. = src/
-additional.bundles = org.argeo.ext.slf4j,\
- org.slf4j.api
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.script.Invocable;
-import javax.script.ScriptException;
-
-import org.argeo.api.cms.CmsConstants;
-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.web.SimpleErgonomics;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.application.EntryPointFactory;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.BundleContext;
-
-public class AppUi implements CmsUiProvider, Branding {
- private final CmsScriptApp app;
-
- private CmsUiProvider ui;
- private String createUi;
- private Object impl;
- private String script;
- // private Branding branding = new Branding();
-
- private EntryPointFactory factory;
-
- // Branding
- private String themeId;
- private String additionalHeaders;
- private String bodyHtml;
- private String pageTitle;
- private String pageOverflow;
- private String favicon;
-
- public AppUi(CmsScriptApp app) {
- this.app = app;
- }
-
- public AppUi(CmsScriptApp app, String scriptPath) {
- this.app = app;
- this.ui = new ScriptUi((BundleContext) app.getScriptEngine().get(CmsScriptRwtApplication.BC),
- app.getScriptEngine(), scriptPath);
- }
-
- public AppUi(CmsScriptApp app, CmsUiProvider uiProvider) {
- this.app = app;
- this.ui = uiProvider;
- }
-
- public AppUi(CmsScriptApp app, EntryPointFactory factory) {
- this.app = app;
- this.factory = factory;
- }
-
- public void apply(Repository repository, Application application, Branding appBranding, String path) {
- Map<String, String> factoryProperties = new HashMap<>();
- if (appBranding != null)
- appBranding.applyBranding(factoryProperties);
- applyBranding(factoryProperties);
- if (factory != null) {
- application.addEntryPoint("/" + path, factory, factoryProperties);
- } else {
- EntryPointFactory entryPointFactory = new EntryPointFactory() {
- @Override
- public EntryPoint create() {
- SimpleErgonomics ergonomics = new SimpleErgonomics(repository, CmsConstants.SYS_WORKSPACE,
- "/home/root/argeo:keyring", AppUi.this, factoryProperties);
-// CmsUiProvider header = app.getHeader();
-// if (header != null)
-// ergonomics.setHeader(header);
- app.applySides(ergonomics);
- Integer headerHeight = app.getHeaderHeight();
- if (headerHeight != null)
- ergonomics.setHeaderHeight(headerHeight);
- return ergonomics;
- }
- };
- application.addEntryPoint("/" + path, entryPointFactory, factoryProperties);
- }
- }
-
- public void setUi(CmsUiProvider uiProvider) {
- this.ui = uiProvider;
- }
-
- public void applyBranding(Map<String, String> properties) {
- if (themeId != null)
- properties.put(WebClient.THEME_ID, themeId);
- if (additionalHeaders != null)
- properties.put(WebClient.HEAD_HTML, additionalHeaders);
- if (bodyHtml != null)
- properties.put(WebClient.BODY_HTML, bodyHtml);
- if (pageTitle != null)
- properties.put(WebClient.PAGE_TITLE, pageTitle);
- if (pageOverflow != null)
- properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
- if (favicon != null)
- properties.put(WebClient.FAVICON, favicon);
- }
-
- // public Branding getBranding() {
- // return branding;
- // }
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- CmsPane cmsPane = new CmsPane(parent, SWT.NONE);
-
- if (false) {
- // QA
- CmsSwtUtils.style(cmsPane.getQaArea(), "qa");
- Button reload = new Button(cmsPane.getQaArea(), SWT.FLAT);
- CmsSwtUtils.style(reload, "qa");
- reload.setText("Reload");
- reload.addSelectionListener(new Selected() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- new Thread() {
- @Override
- public void run() {
- app.reload();
- }
- }.start();
- RWT.getClient().getService(JavaScriptExecutor.class)
- .execute("setTimeout('location.reload()',1000)");
- }
- });
-
- // Support
- CmsSwtUtils.style(cmsPane.getSupportArea(), "support");
- Label msg = new Label(cmsPane.getSupportArea(), SWT.NONE);
- CmsSwtUtils.style(msg, "support");
- msg.setText("UNSUPPORTED DEVELOPMENT VERSION");
- }
-
- if (ui != null) {
- ui.createUi(cmsPane.getMainArea(), context);
- }
- if (createUi != null) {
- Invocable invocable = (Invocable) app.getScriptEngine();
- try {
- invocable.invokeFunction(createUi, cmsPane.getMainArea(), context);
-
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- if (impl != null) {
- Invocable invocable = (Invocable) app.getScriptEngine();
- try {
- invocable.invokeMethod(impl, "createUi", cmsPane.getMainArea(), context);
-
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- // Invocable invocable = (Invocable) app.getScriptEngine();
- // try {
- // invocable.invokeMethod(AppUi.this, "initUi", parent, context);
- //
- // } catch (NoSuchMethodException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // } catch (ScriptException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
-
- return null;
- }
-
- public void setCreateUi(String createUi) {
- this.createUi = createUi;
- }
-
- public void setImpl(Object impl) {
- this.impl = impl;
- }
-
- public Object getImpl() {
- return impl;
- }
-
- public String getScript() {
- return script;
- }
-
- public void setScript(String script) {
- this.script = script;
- }
-
- // Branding
- public String getThemeId() {
- return themeId;
- }
-
- public void setThemeId(String themeId) {
- this.themeId = themeId;
- }
-
- public String getAdditionalHeaders() {
- return additionalHeaders;
- }
-
- public void setAdditionalHeaders(String additionalHeaders) {
- this.additionalHeaders = additionalHeaders;
- }
-
- public String getBodyHtml() {
- return bodyHtml;
- }
-
- public void setBodyHtml(String bodyHtml) {
- this.bodyHtml = bodyHtml;
- }
-
- public String getPageTitle() {
- return pageTitle;
- }
-
- public void setPageTitle(String pageTitle) {
- this.pageTitle = pageTitle;
- }
-
- public String getPageOverflow() {
- return pageOverflow;
- }
-
- public void setPageOverflow(String pageOverflow) {
- this.pageOverflow = pageOverflow;
- }
-
- public String getFavicon() {
- return favicon;
- }
-
- public void setFavicon(String favicon) {
- this.favicon = favicon;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.util.Map;
-
-public interface Branding {
- public void applyBranding(Map<String, String> properties);
-
- public String getThemeId();
-
- public String getAdditionalHeaders();
-
- public String getBodyHtml();
-
- public String getPageTitle();
-
- public String getPageOverflow();
-
- public String getFavicon();
-
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.script.ScriptEngine;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsTheme;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.ui.CmsUiConstants;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.web.BundleResourceLoader;
-import org.argeo.cms.web.SimpleErgonomics;
-import org.argeo.cms.web.WebThemeUtils;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.Application.OperationMode;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.http.NamespaceException;
-
-public class CmsScriptApp implements Branding {
- public final static String CONTEXT_NAME = "contextName";
-
- ServiceRegistration<ApplicationConfiguration> appConfigReg;
-
- private ScriptEngine scriptEngine;
-
- private final static CmsLog log = CmsLog.getLog(CmsScriptApp.class);
-
- private String webPath;
- private String repo = "(cn=node)";
-
- // private Branding branding = new Branding();
- private CmsTheme theme;
-
- private List<String> resources = new ArrayList<>();
-
- private Map<String, AppUi> ui = new HashMap<>();
-
- private CmsUiProvider header;
- private Integer headerHeight = null;
- private CmsUiProvider lead;
- private CmsUiProvider end;
- private CmsUiProvider footer;
-
- // Branding
- private String themeId;
- private String additionalHeaders;
- private String bodyHtml;
- private String pageTitle;
- private String pageOverflow;
- private String favicon;
-
- public CmsScriptApp(ScriptEngine scriptEngine) {
- super();
- this.scriptEngine = scriptEngine;
- }
-
- public void apply(BundleContext bundleContext, Repository repository, Application application) {
- BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
-
- application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
- // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
-
- application.setExceptionHandler(new CmsExceptionHandler());
-
- // loading animated gif
- application.addResource(CmsUiConstants.LOADING_IMAGE, createResourceLoader(CmsUiConstants.LOADING_IMAGE));
- // empty image
- application.addResource(CmsUiConstants.NO_IMAGE, createResourceLoader(CmsUiConstants.NO_IMAGE));
-
- for (String resource : resources) {
- application.addResource(resource, bundleRL);
- if (log.isTraceEnabled())
- log.trace("Resource " + resource);
- }
-
- if (theme != null) {
- WebThemeUtils.apply(application, theme);
- String themeHeaders = theme.getHtmlHeaders();
- if (themeHeaders != null) {
- if (additionalHeaders == null)
- additionalHeaders = themeHeaders;
- else
- additionalHeaders = themeHeaders + "\n" + additionalHeaders;
- }
- themeId = theme.getThemeId();
- }
-
- // client JavaScript
- Bundle appBundle = bundleRL.getBundle();
- BundleContext bc = appBundle.getBundleContext();
- HttpService httpService = bc.getService(bc.getServiceReference(HttpService.class));
- HttpContext httpContext = new BundleHttpContext(bc);
- Enumeration<URL> themeResources = appBundle.findEntries("/js/", "*", true);
- if (themeResources != null)
- bundleResources: while (themeResources.hasMoreElements()) {
- try {
- String name = themeResources.nextElement().getPath();
- if (name.endsWith("/"))
- continue bundleResources;
- String alias = "/" + getWebPath() + name;
-
- httpService.registerResources(alias, name, httpContext);
- if (log.isDebugEnabled())
- log.debug("Mapped " + name + " to alias " + alias);
-
- } catch (NamespaceException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- // App UIs
- for (String appUiName : ui.keySet()) {
- AppUi appUi = ui.get(appUiName);
- appUi.apply(repository, application, this, appUiName);
-
- }
-
- }
-
- public void applySides(SimpleErgonomics simpleErgonomics) {
- simpleErgonomics.setHeader(header);
- simpleErgonomics.setLead(lead);
- simpleErgonomics.setEnd(end);
- simpleErgonomics.setFooter(footer);
- }
-
- public void register(BundleContext bundleContext, ApplicationConfiguration appConfig) {
- Hashtable<String, String> props = new Hashtable<>();
- props.put(CONTEXT_NAME, webPath);
- appConfigReg = bundleContext.registerService(ApplicationConfiguration.class, appConfig, props);
- }
-
- public void reload() {
- BundleContext bundleContext = appConfigReg.getReference().getBundle().getBundleContext();
- ApplicationConfiguration appConfig = bundleContext.getService(appConfigReg.getReference());
- appConfigReg.unregister();
- register(bundleContext, appConfig);
-
- // BundleContext bundleContext = (BundleContext)
- // getScriptEngine().get("bundleContext");
- // try {
- // Bundle bundle = bundleContext.getBundle();
- // bundle.stop();
- // bundle.start();
- // } catch (BundleException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
- }
-
- private static ResourceLoader createResourceLoader(final String resourceName) {
- return new ResourceLoader() {
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- return getClass().getClassLoader().getResourceAsStream(resourceName);
- }
- };
- }
-
- public List<String> getResources() {
- return resources;
- }
-
- public AppUi newUi(String name) {
- if (ui.containsKey(name))
- throw new IllegalArgumentException("There is already an UI named " + name);
- AppUi appUi = new AppUi(this);
- // appUi.setApp(this);
- ui.put(name, appUi);
- return appUi;
- }
-
- public void addUi(String name, AppUi appUi) {
- if (ui.containsKey(name))
- throw new IllegalArgumentException("There is already an UI named " + name);
- // appUi.setApp(this);
- ui.put(name, appUi);
- }
-
- public void applyBranding(Map<String, String> properties) {
- if (themeId != null)
- properties.put(WebClient.THEME_ID, themeId);
- if (additionalHeaders != null)
- properties.put(WebClient.HEAD_HTML, additionalHeaders);
- if (bodyHtml != null)
- properties.put(WebClient.BODY_HTML, bodyHtml);
- if (pageTitle != null)
- properties.put(WebClient.PAGE_TITLE, pageTitle);
- if (pageOverflow != null)
- properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
- if (favicon != null)
- properties.put(WebClient.FAVICON, favicon);
- }
-
- class CmsExceptionHandler implements ExceptionHandler {
-
- @Override
- public void handleException(Throwable throwable) {
- // TODO be smarter
- CmsUiUtils.getCmsView().exception(throwable);
- }
-
- }
-
- // public Branding getBranding() {
- // return branding;
- // }
-
- ScriptEngine getScriptEngine() {
- return scriptEngine;
- }
-
- public static String toJson(Node node) {
- try {
- StringBuilder sb = new StringBuilder();
- sb.append('{');
- PropertyIterator pit = node.getProperties();
- int count = 0;
- while (pit.hasNext()) {
- Property p = pit.nextProperty();
- int type = p.getType();
- if (type == PropertyType.REFERENCE || type == PropertyType.WEAKREFERENCE || type == PropertyType.PATH) {
- Node ref = p.getNode();
- if (count != 0)
- sb.append(',');
- // TODO limit depth?
- sb.append(toJson(ref));
- count++;
- } else if (!p.isMultiple()) {
- if (count != 0)
- sb.append(',');
- sb.append('\"').append(p.getName()).append("\":\"").append(p.getString()).append('\"');
- count++;
- }
- }
- sb.append('}');
- return sb.toString();
- } catch (RepositoryException e) {
- throw new CmsException("Cannot convert " + node + " to JSON", e);
- }
- }
-
- public void fromJson(Node node, String json) {
- // TODO
- }
-
- public CmsTheme getTheme() {
- return theme;
- }
-
- public void setTheme(CmsTheme theme) {
- this.theme = theme;
- }
-
- public String getWebPath() {
- return webPath;
- }
-
- public void setWebPath(String context) {
- this.webPath = context;
- }
-
- public String getRepo() {
- return repo;
- }
-
- public void setRepo(String repo) {
- this.repo = repo;
- }
-
- public Map<String, AppUi> getUi() {
- return ui;
- }
-
- public void setUi(Map<String, AppUi> ui) {
- this.ui = ui;
- }
-
- // Branding
- public String getThemeId() {
- return themeId;
- }
-
- public void setThemeId(String themeId) {
- this.themeId = themeId;
- }
-
- public String getAdditionalHeaders() {
- return additionalHeaders;
- }
-
- public void setAdditionalHeaders(String additionalHeaders) {
- this.additionalHeaders = additionalHeaders;
- }
-
- public String getBodyHtml() {
- return bodyHtml;
- }
-
- public void setBodyHtml(String bodyHtml) {
- this.bodyHtml = bodyHtml;
- }
-
- public String getPageTitle() {
- return pageTitle;
- }
-
- public void setPageTitle(String pageTitle) {
- this.pageTitle = pageTitle;
- }
-
- public String getPageOverflow() {
- return pageOverflow;
- }
-
- public void setPageOverflow(String pageOverflow) {
- this.pageOverflow = pageOverflow;
- }
-
- public String getFavicon() {
- return favicon;
- }
-
- public void setFavicon(String favicon) {
- this.favicon = favicon;
- }
-
- public CmsUiProvider getHeader() {
- return header;
- }
-
- public void setHeader(CmsUiProvider header) {
- this.header = header;
- }
-
- public Integer getHeaderHeight() {
- return headerHeight;
- }
-
- public void setHeaderHeight(Integer headerHeight) {
- this.headerHeight = headerHeight;
- }
-
- public CmsUiProvider getLead() {
- return lead;
- }
-
- public void setLead(CmsUiProvider lead) {
- this.lead = lead;
- }
-
- public CmsUiProvider getEnd() {
- return end;
- }
-
- public void setEnd(CmsUiProvider end) {
- this.end = end;
- }
-
- public CmsUiProvider getFooter() {
- return footer;
- }
-
- public void setFooter(CmsUiProvider footer) {
- this.footer = footer;
- }
-
- static class BundleHttpContext implements HttpContext {
- private BundleContext bundleContext;
-
- public BundleHttpContext(BundleContext bundleContext) {
- super();
- this.bundleContext = bundleContext;
- }
-
- @Override
- public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
- // TODO Auto-generated method stub
- return true;
- }
-
- @Override
- public URL getResource(String name) {
-
- return bundleContext.getBundle().getEntry(name);
- }
-
- @Override
- public String getMimeType(String name) {
- return null;
- }
-
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.URL;
-
-import javax.jcr.Repository;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.swt.CmsException;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.wiring.BundleWiring;
-
-public class CmsScriptRwtApplication implements ApplicationConfiguration {
- public final static String APP = "APP";
- public final static String BC = "BC";
-
- private final CmsLog log = CmsLog.getLog(CmsScriptRwtApplication.class);
-
- BundleContext bundleContext;
- Repository repository;
-
- ScriptEngine engine;
-
- public void init(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
- ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
- try {
-// Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
-// ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
-// engine = scriptEngineManager.getEngineByName("JavaScript");
-// if (engine == null) {// Nashorn
-// Thread.currentThread().setContextClassLoader(originalCcl);
-// scriptEngineManager = new ScriptEngineManager();
-// Thread.currentThread().setContextClassLoader(bundleCl);
-// engine = scriptEngineManager.getEngineByName("JavaScript");
-// }
- engine = loadScriptEngine(originalCcl, bundleCl);
-
- // Load script
- URL appUrl = bundleContext.getBundle().getEntry("cms/app.js");
- // System.out.println("Loading " + appUrl);
- // System.out.println("Loading " + appUrl.getHost());
- // System.out.println("Loading " + appUrl.getPath());
-
- CmsScriptApp app = new CmsScriptApp(engine);
- engine.put(APP, app);
- engine.put(BC, bundleContext);
- try (Reader reader = new InputStreamReader(appUrl.openStream())) {
- engine.eval(reader);
- } catch (IOException | ScriptException e) {
- throw new CmsException("Cannot execute " + appUrl, e);
- }
-
- if (log.isDebugEnabled())
- log.debug("CMS script app initialized from " + appUrl);
-
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- Thread.currentThread().setContextClassLoader(originalCcl);
- }
- }
-
- public void destroy(BundleContext bundleContext) {
- engine = null;
- }
-
- @Override
- public void configure(Application application) {
- load(application);
- }
-
- void load(Application application) {
- CmsScriptApp app = getApp();
- app.apply(bundleContext, repository, application);
- if (log.isDebugEnabled())
- log.debug("CMS script app loaded to " + app.getWebPath());
- }
-
- CmsScriptApp getApp() {
- if (engine == null)
- throw new IllegalStateException("CMS script app is not initialized");
- return (CmsScriptApp) engine.get(APP);
- }
-
- void update() {
-
- try {
- bundleContext.getBundle().update();
- } catch (BundleException e) {
- e.printStackTrace();
- }
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- private static ScriptEngine loadScriptEngine(ClassLoader originalCcl, ClassLoader bundleCl) {
- Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
- ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
- ScriptEngine engine = scriptEngineManager.getEngineByName("JavaScript");
- if (engine == null) {// Nashorn
- Thread.currentThread().setContextClassLoader(originalCcl);
- scriptEngineManager = new ScriptEngineManager();
- Thread.currentThread().setContextClassLoader(bundleCl);
- engine = scriptEngineManager.getEngineByName("JavaScript");
- }
- return engine;
- }
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import javax.jcr.Repository;
-
-import org.argeo.api.cms.CmsLog;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class ScriptAppActivator implements BundleActivator {
- private final static CmsLog log = CmsLog.getLog(ScriptAppActivator.class);
-
- @Override
- public void start(BundleContext context) throws Exception {
- try {
- CmsScriptRwtApplication appConfig = new CmsScriptRwtApplication();
- appConfig.init(context);
- CmsScriptApp app = appConfig.getApp();
- ServiceTracker<Repository, Repository> repoSt = new ServiceTracker<Repository, Repository>(context,
- FrameworkUtil.createFilter("(&" + app.getRepo() + "(objectClass=javax.jcr.Repository))"), null) {
-
- @Override
- public Repository addingService(ServiceReference<Repository> reference) {
- Repository repository = super.addingService(reference);
- appConfig.setRepository(repository);
- CmsScriptApp app = appConfig.getApp();
- app.register(context, appConfig);
- return repository;
- }
-
- };
- repoSt.open();
- } catch (Exception e) {
- log.error("Cannot initialise script bundle " + context.getBundle().getSymbolicName(), e);
- throw e;
- }
- }
-
- @Override
- public void stop(BundleContext context) throws Exception {
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.script.Invocable;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.BundleContext;
-
-class ScriptUi implements CmsUiProvider {
- private final static CmsLog log = CmsLog.getLog(ScriptUi.class);
-
- private boolean development = true;
- private ScriptEngine scriptEngine;
-
- private URL appUrl;
- // private BundleContext bundleContext;
- // private String path;
-
- // private Bindings bindings;
- // private String script;
-
- public ScriptUi(BundleContext bundleContext,ScriptEngine scriptEngine, String path) {
- this.scriptEngine = scriptEngine;
-//// ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
-// ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
-// ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
-// try {
-//// Thread.currentThread().setContextClassLoader(bundleCl);
-//// scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
-//// scriptEngine.put(CmsScriptRwtApplication.BC, bundleContext);
-// scriptEngine = CmsScriptRwtApplication.loadScriptEngine(originalCcl, bundleCl);
-//
-// } catch (Exception e) {
-// e.printStackTrace();
-// } finally {
-// Thread.currentThread().setContextClassLoader(originalCcl);
-// }
- this.appUrl = bundleContext.getBundle().getEntry(path);
- load();
- }
-
- private void load() {
-// try (Reader reader = new InputStreamReader(appUrl.openStream())) {
-// scriptEngine.eval(reader);
-// } catch (IOException | ScriptException e) {
-// log.warn("Cannot execute " + appUrl, e);
-// }
-
- try {
- scriptEngine.eval("load('" + appUrl + "')");
- } catch (ScriptException e) {
- log.warn("Cannot execute " + appUrl, e);
- }
-
- }
-
- // public ScriptUiProvider(ScriptEngine scriptEngine, String script) throws
- // ScriptException {
- // super();
- // this.scriptEngine = scriptEngine;
- // this.script = script;
- // bindings = scriptEngine.createBindings();
- // scriptEngine.eval(script, bindings);
- // }
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- long begin = System.currentTimeMillis();
- // if (bindings == null) {
- // bindings = scriptEngine.createBindings();
- // try {
- // scriptEngine.eval(script, bindings);
- // } catch (ScriptException e) {
- // log.warn("Cannot evaluate script", e);
- // }
- // }
- // Bindings bindings = scriptEngine.createBindings();
- // bindings.put("parent", parent);
- // bindings.put("context", context);
- // URL appUrl = bundleContext.getBundle().getEntry(path);
- // try (Reader reader = new InputStreamReader(appUrl.openStream())) {
- // scriptEngine.eval(reader,bindings);
- // } catch (IOException | ScriptException e) {
- // log.warn("Cannot execute " + appUrl, e);
- // }
-
- if (development)
- load();
-
- Invocable invocable = (Invocable) scriptEngine;
- try {
- invocable.invokeFunction("createUi", parent, context);
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- long duration = System.currentTimeMillis() - begin;
- if (log.isTraceEnabled())
- log.trace(appUrl + " UI in " + duration + " ms");
- return null;
- }
-
-}
+++ /dev/null
-// CMS
-var ScrolledPage = Java.type('org.argeo.cms.ui.widgets.ScrolledPage');
-
-var CmsScriptApp = Java.type('org.argeo.cms.ui.script.CmsScriptApp');
-var AppUi = Java.type('org.argeo.cms.ui.script.AppUi');
-var Theme = Java.type('org.argeo.cms.ui.script.Theme');
-var ScriptUi = Java.type('org.argeo.cms.ui.script.ScriptUi');
-var CmsUtils = Java.type('org.argeo.cms.ui.util.CmsUiUtils');
-var SimpleCmsHeader = Java.type('org.argeo.cms.ui.util.SimpleCmsHeader');
-var CmsLink = Java.type('org.argeo.cms.ui.util.CmsLink');
-var MenuLink = Java.type('org.argeo.cms.ui.util.MenuLink');
-var UserMenuLink = Java.type('org.argeo.cms.ui.util.UserMenuLink');
-
-// SWT
-var SWT = Java.type('org.eclipse.swt.SWT');
-var Composite = Java.type('org.eclipse.swt.widgets.Composite');
-var Label = Java.type('org.eclipse.swt.widgets.Label');
-var Button = Java.type('org.eclipse.swt.widgets.Button');
-var Text = Java.type('org.eclipse.swt.widgets.Text');
-var Browser = Java.type('org.eclipse.swt.browser.Browser');
-
-var FillLayout = Java.type('org.eclipse.swt.layout.FillLayout');
-var GridLayout = Java.type('org.eclipse.swt.layout.GridLayout');
-var RowLayout = Java.type('org.eclipse.swt.layout.RowLayout');
-var FormLayout = Java.type('org.eclipse.swt.layout.FormLayout');
-var GridData = Java.type('org.eclipse.swt.layout.GridData');
-
-function loadNode(node) {
- var json = CmsScriptApp.toJson(node)
- var fromJson = JSON.parse(json)
- return fromJson
-}
-
-function newArea(parent, style, layout) {
- var control = new Composite(parent, SWT.NONE)
- control.setLayout(layout)
- CmsUtils.style(control, style)
- return control
-}
-
-function newLabel(parent, style, text) {
- var control = new Label(parent, SWT.WRAP)
- control.setText(text)
- CmsUtils.style(control, style)
- CmsUtils.markup(control)
- return control
-}
-
-function newButton(parent, style, text) {
- var control = new Button(parent, SWT.FLAT)
- control.setText(text)
- CmsUtils.style(control, style)
- CmsUtils.markup(control)
- return control
-}
-
-function newFormLabel(parent, style, text) {
- return newLabel(parent, style, '<b>' + text + '</b>')
-}
-
-function newText(parent, style, msg) {
- var control = new Text(parent, SWT.NONE)
- control.setMessage(msg)
- CmsUtils.style(control, style)
- return control
-}
-
-function newScrolledPage(parent) {
- var scrolled = new ScrolledPage(parent, SWT.NONE)
- scrolled.setLayoutData(CmsUtils.fillAll())
- scrolled.setLayout(CmsUtils.noSpaceGridLayout())
- var page = new Composite(scrolled, SWT.NONE)
- page.setLayout(CmsUtils.noSpaceGridLayout())
- page.setBackgroundMode(SWT.INHERIT_NONE)
- return page
-}
-
-function gridData(control) {
- var gridData = new GridData()
- control.setLayoutData(gridData)
- return gridData
-}
-
-function gridData(control, hAlign, vAlign) {
- var gridData = new GridData(hAlign, vAlign, false, false)
- control.setLayoutData(gridData)
- return gridData
-}
-
-// print(__FILE__, __LINE__, __DIR__)
+++ /dev/null
-/** Argeo CMS user interface scripting. */
-package org.argeo.cms.ui.script;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.web;
-
-import static org.argeo.util.directory.ldap.SharedSecret.X_SHARED_SECRET;
-
-import java.io.IOException;
-import java.security.PrivilegedAction;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-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.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.api.cms.CmsAuth;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.auth.RemoteAuthCallback;
-import org.argeo.cms.auth.RemoteAuthCallbackHandler;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.cms.servlet.ServletHttpResponse;
-import org.argeo.cms.swt.CmsException;
-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.util.directory.ldap.AuthPassword;
-import org.argeo.util.directory.ldap.SharedSecret;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.AbstractEntryPoint;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.BrowserNavigation;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-/** Manages history and navigation */
-@Deprecated
-public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implements CmsView {
- private static final long serialVersionUID = 906558779562569784L;
-
- private final CmsLog log = CmsLog.getLog(AbstractCmsEntryPoint.class);
-
- // private final Subject subject;
- private LoginContext loginContext;
-
- private final Repository repository;
- private final String workspace;
- private final String defaultPath;
- private final Map<String, String> factoryProperties;
-
- // Current state
- private Session session;
- private Node node;
- private String nodePath;// useful when changing auth
- private String state;
- private Throwable exception;
-
- // Client services
- private final JavaScriptExecutor jsExecutor;
- private final BrowserNavigation browserNavigation;
-
- public AbstractCmsEntryPoint(Repository repository, String workspace, String defaultPath,
- Map<String, String> factoryProperties) {
- this.repository = repository;
- this.workspace = workspace;
- this.defaultPath = defaultPath;
- this.factoryProperties = new HashMap<String, String>(factoryProperties);
- // subject = new Subject();
-
- // Initial login
- LoginContext lc;
- try {
- lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER,
- new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
- new ServletHttpResponse(UiContext.getHttpResponse())));
- lc.login();
- } catch (LoginException e) {
- try {
- lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS);
- lc.login();
- } catch (LoginException e1) {
- throw new CmsException("Cannot log in as anonymous", e1);
- }
- }
- authChange(lc);
-
- jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
- browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
- if (browserNavigation != null)
- browserNavigation.addBrowserNavigationListener(new CmsNavigationListener());
- }
-
- @Override
- protected Shell createShell(Display display) {
- Shell shell = super.createShell(display);
- shell.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_SHELL);
- display.disposeExec(new Runnable() {
-
- @Override
- public void run() {
- if (log.isTraceEnabled())
- log.trace("Logging out " + session);
- JcrUtils.logoutQuietly(session);
- }
- });
- return shell;
- }
-
- @Override
- protected final void createContents(final Composite parent) {
- // UiContext.setData(CmsView.KEY, this);
- CmsSwtUtils.registerCmsView(parent.getShell(), this);
- Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- try {
- initUi(parent);
- } catch (Exception e) {
- throw new CmsException("Cannot create entrypoint contents", e);
- }
- return null;
- }
- });
- }
-
- /** Create UI */
- protected abstract void initUi(Composite parent);
-
- /** Recreate UI after navigation or auth change */
- protected abstract void refresh();
-
- /**
- * The node to return when no node was found (for authenticated users and
- * anonymous)
- */
-// private Node getDefaultNode(Session session) throws RepositoryException {
-// if (!session.hasPermission(defaultPath, "read")) {
-// String userId = session.getUserID();
-// if (userId.equals(NodeConstants.ROLE_ANONYMOUS))
-// // TODO throw a special exception
-// throw new CmsException("Login required");
-// else
-// throw new CmsException("Unauthorized");
-// }
-// return session.getNode(defaultPath);
-// }
-
- protected String getBaseTitle() {
- return factoryProperties.get(WebClient.PAGE_TITLE);
- }
-
- public void navigateTo(String state) {
- exception = null;
- String title = setState(state);
- doRefresh();
- if (browserNavigation != null)
- browserNavigation.pushState(state, title);
- }
-
- // @Override
- // public synchronized Subject getSubject() {
- // return subject;
- // }
-
- // @Override
- // public LoginContext getLoginContext() {
- // return loginContext;
- // }
- protected Subject getSubject() {
- return loginContext.getSubject();
- }
-
- @Override
- public boolean isAnonymous() {
- return CurrentUser.isAnonymous(getSubject());
- }
-
- @Override
- public synchronized void logout() {
- if (loginContext == null)
- throw new CmsException("Login context should not be null");
- try {
- CurrentUser.logoutCmsSession(loginContext.getSubject());
- loginContext.logout();
- LoginContext anonymousLc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS);
- anonymousLc.login();
- authChange(anonymousLc);
- } catch (LoginException e) {
- log.error("Cannot logout", e);
- }
- }
-
- @Override
- public synchronized void authChange(LoginContext lc) {
- if (lc == 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 = lc;
- Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
-
- @Override
- public Void run() {
- try {
- JcrUtils.logoutQuietly(session);
- session = repository.login(workspace);
- if (nodePath != null)
- try {
- node = session.getNode(nodePath);
- } catch (PathNotFoundException e) {
- navigateTo("~");
- }
-
- // refresh UI
- doRefresh();
- } catch (RepositoryException e) {
- throw new CmsException("Cannot perform auth change", e);
- }
- return null;
- }
-
- });
- }
-
- @Override
- public void exception(final Throwable e) {
- AbstractCmsEntryPoint.this.exception = e;
- log.error("Unexpected exception in CMS", e);
- doRefresh();
- }
-
- protected synchronized void doRefresh() {
- Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- refresh();
- return null;
- }
- });
- }
-
- /** Sets the state of the entry point and retrieve the related JCR node. */
- protected synchronized String setState(String newState) {
- String previousState = this.state;
-
- String newNodePath = null;
- String prefix = null;
- this.state = newState;
- if (newState.equals("~"))
- this.state = "";
-
- try {
- int firstSlash = state.indexOf('/');
- if (firstSlash == 0) {
- newNodePath = state;
- prefix = "";
- } else if (firstSlash > 0) {
- prefix = state.substring(0, firstSlash);
- newNodePath = state.substring(firstSlash);
- } else {
- newNodePath = defaultPath;
- prefix = state;
-
- }
-
- // auth
- int colonIndex = prefix.indexOf('$');
- if (colonIndex > 0) {
- SharedSecret token = new SharedSecret(new AuthPassword(X_SHARED_SECRET + '$' + prefix)) {
-
- @Override
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- super.handle(callbacks);
- // handle HTTP context
- for (Callback callback : callbacks) {
- if (callback instanceof RemoteAuthCallback) {
- ((RemoteAuthCallback) callback)
- .setRequest(new ServletHttpRequest(UiContext.getHttpRequest()));
- ((RemoteAuthCallback) callback)
- .setResponse(new ServletHttpResponse(UiContext.getHttpResponse()));
- }
- }
- }
- };
- LoginContext lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER, token);
- lc.login();
- authChange(lc);// sets the node as well
- // } else {
- // // TODO check consistency
- // }
- } else {
- Node newNode = null;
- if (session.nodeExists(newNodePath))
- newNode = session.getNode(newNodePath);
- else {
-// throw new CmsException("Data " + newNodePath + " does not exist");
- newNode = null;
- }
- setNode(newNode);
- }
- String title = publishMetaData(getNode());
-
- if (log.isTraceEnabled())
- log.trace("node=" + newNodePath + ", state=" + state + " (prefix=" + prefix + ")");
-
- return title;
- } catch (Exception e) {
- log.error("Cannot set state '" + state + "'", e);
- if (state.equals("") || newState.equals("~") || newState.equals(previousState))
- return "Unrecoverable exception : " + e.getClass().getSimpleName();
- if (previousState.equals(""))
- previousState = "~";
- navigateTo(previousState);
- throw new CmsException("Unexpected issue when accessing #" + newState, e);
- }
- }
-
- private String publishMetaData(Node node) throws RepositoryException {
- // Title
- String title;
- if (node != null && node.isNodeType(NodeType.MIX_TITLE) && node.hasProperty(Property.JCR_TITLE))
- title = node.getProperty(Property.JCR_TITLE).getString() + " - " + getBaseTitle();
- else
- title = getBaseTitle();
-
- HttpServletRequest request = UiContext.getHttpRequest();
- if (request == null)
- return null;
-
- StringBuilder js = new StringBuilder();
- if (title == null)
- title = "";
- title = title.replace("'", "\\'");// sanitize
- js.append("document.title = '" + title + "';");
- jsExecutor.execute(js.toString());
- return title;
- }
-
- // Simply remove some illegal character
- // private String clean(String stringToClean) {
- // return stringToClean.replaceAll("'", "").replaceAll("\\n", "")
- // .replaceAll("\\t", "");
- // }
-
- protected synchronized Node getNode() {
- return node;
- }
-
- private synchronized void setNode(Node node) throws RepositoryException {
- this.node = node;
- this.nodePath = node == null ? null : node.getPath();
- }
-
- protected String getState() {
- return state;
- }
-
- protected Throwable getException() {
- return exception;
- }
-
- protected void resetException() {
- exception = null;
- }
-
- protected Session getSession() {
- return session;
- }
-
- private class CmsNavigationListener implements BrowserNavigationListener {
- private static final long serialVersionUID = -3591018803430389270L;
-
- @Override
- public void navigated(BrowserNavigationEvent event) {
- setState(event.getState());
- doRefresh();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-
-/** {@link ResourceLoader} implementation wrapping an {@link Bundle}. */
-public class BundleResourceLoader implements ResourceLoader {
- private final Bundle bundle;
-
- public BundleResourceLoader(Bundle bundle) {
- this.bundle = bundle;
- }
-
- @Override
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- URL res = bundle.getEntry(resourceName);
- if (res == null) {
- res = bundle.getResource(resourceName);
- if (res == null)
- throw new IllegalArgumentException(
- "Resource " + resourceName + " not found in bundle " + bundle.getSymbolicName());
- }
- return res.openStream();
- }
-
- public Bundle getBundle() {
- return bundle;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.argeo.api.cms.ux.CmsTheme;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-
-/** A RAP {@link ResourceLoader} based on a {@link CmsTheme}. */
-public class CmsThemeResourceLoader implements ResourceLoader {
- private final CmsTheme theme;
-
- public CmsThemeResourceLoader(CmsTheme theme) {
- super();
- this.theme = theme;
- }
-
- @Override
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- return theme.getResourceAsStream(resourceName);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.api.cms.CmsAppListener;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsTheme;
-import org.argeo.api.cms.ux.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;
-import org.eclipse.rap.rwt.application.Application.OperationMode;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.event.EventAdmin;
-
-/** An RWT web app integrating with a {@link CmsApp}. */
-public class CmsWebApp implements ApplicationConfiguration, ExceptionHandler, CmsAppListener {
- private final static CmsLog log = CmsLog.getLog(CmsWebApp.class);
-
- private BundleContext bundleContext;
- private CmsApp cmsApp;
-// private String cmsAppId;
- private EventAdmin eventAdmin;
-
- private ServiceRegistration<ApplicationConfiguration> rwtAppReg;
-
- private final static String CONTEXT_NAME = "contextName";
- private String contextName;
-
- private final static String FAVICON_PNG = "favicon.png";
-
- public void init(BundleContext bundleContext, Map<String, String> properties) {
- this.bundleContext = bundleContext;
- contextName = properties.get(CONTEXT_NAME);
- if (cmsApp != null) {
- if (cmsApp.allThemesAvailable())
- publishWebApp();
- }
- }
-
- public void destroy(BundleContext bundleContext, Map<String, String> properties) {
- if (cmsApp != null) {
- cmsApp.removeCmsAppListener(this);
- cmsApp = null;
- }
- }
-
- @Override
- public void configure(Application application) {
- // TODO make it configurable?
- // SWT compatibility is required for:
- // - Browser.execute()
- // - blocking dialogs
- application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
- for (String uiName : cmsApp.getUiNames()) {
- CmsTheme theme = cmsApp.getTheme(uiName);
- if (theme != null)
- WebThemeUtils.apply(application, theme);
- }
-
- Map<String, String> properties = new HashMap<>();
- addEntryPoints(application, properties);
- application.setExceptionHandler(this);
- }
-
- @Override
- public void handleException(Throwable throwable) {
- Display display = Display.getCurrent();
- if (display != null && !display.isDisposed()) {
- CmsView cmsView = CmsSwtUtils.getCmsView(display.getActiveShell());
- cmsView.exception(throwable);
- } else {
- log.error("Unexpected exception outside an UI thread", throwable);
- }
-
- }
-
- protected void addEntryPoints(Application application, Map<String, String> commonProperties) {
- for (String uiName : cmsApp.getUiNames()) {
- Map<String, String> properties = new HashMap<>(commonProperties);
- CmsTheme theme = cmsApp.getTheme(uiName);
- if (theme != null) {
- properties.put(WebClient.THEME_ID, theme.getThemeId());
- properties.put(WebClient.HEAD_HTML, theme.getHtmlHeaders());
- properties.put(WebClient.BODY_HTML, theme.getBodyHtml());
- Set<String> imagePaths = theme.getImagesPaths();
- if (imagePaths.contains(FAVICON_PNG)) {
- properties.put(WebClient.FAVICON, FAVICON_PNG);
- }
- } else {
- properties.put(WebClient.THEME_ID, RWT.DEFAULT_THEME_ID);
- }
- String entryPointName = !uiName.equals("") ? "/" + uiName : "/";
- application.addEntryPoint(entryPointName, () -> {
- CmsWebEntryPoint entryPoint = new CmsWebEntryPoint(this, uiName);
- entryPoint.setEventAdmin(eventAdmin);
- return entryPoint;
- }, properties);
- if (log.isDebugEnabled())
- log.info("Added web entry point " + (contextName != null ? "/" + contextName : "") + entryPointName);
- }
-// if (log.isDebugEnabled())
-// log.debug("Published CMS web app /" + (contextName != null ? contextName : ""));
- }
-
- CmsApp getCmsApp() {
- return cmsApp;
- }
-
- BundleContext getBundleContext() {
- return bundleContext;
- }
-
- public void setCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- this.cmsApp = cmsApp;
-// this.cmsAppId = properties.get(Constants.SERVICE_PID);
- this.cmsApp.addCmsAppListener(this);
- }
-
- public void unsetCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
- if (!contextName.equals(this.contextName))
- return;
- if (this.cmsApp != null) {
- this.cmsApp.removeCmsAppListener(this);
- }
- if (rwtAppReg != null)
- rwtAppReg.unregister();
- this.cmsApp = null;
- }
-
- @Override
- public void themingUpdated() {
- if (cmsApp != null && cmsApp.allThemesAvailable())
- publishWebApp();
- }
-
- protected void publishWebApp() {
- Dictionary<String, Object> regProps = LangUtils.dict(CONTEXT_NAME, contextName);
- if (rwtAppReg != null)
- rwtAppReg.unregister();
- if (bundleContext != null) {
- rwtAppReg = bundleContext.registerService(ApplicationConfiguration.class, this, regProps);
- if (log.isDebugEnabled())
- log.debug("Publishing CMS web app /" + (contextName != null ? contextName : "") + " ...");
- }
- }
-
- public void setEventAdmin(EventAdmin eventAdmin) {
- this.eventAdmin = eventAdmin;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
-
-import java.security.PrivilegedAction;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.api.cms.CmsAuth;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.CmsSession;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.api.cms.ux.CmsUi;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.auth.RemoteAuthCallbackHandler;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.cms.servlet.ServletHttpResponse;
-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.eclipse.ui.specific.UiContext;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.client.service.BrowserNavigation;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
-import org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.SWTError;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventAdmin;
-
-/** The {@link CmsView} for a {@link CmsWebApp}. */
-@SuppressWarnings("restriction")
-public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationListener {
- private static final long serialVersionUID = 7733510691684570402L;
- private final static CmsLog log = CmsLog.getLog(CmsWebEntryPoint.class);
-
- private EventAdmin eventAdmin;
-
- private final CmsWebApp cmsWebApp;
- private final String uiName;
-
- private LoginContext loginContext;
- private String state;
- private Throwable exception;
- private UxContext uxContext;
- private CmsImageManager imageManager;
-
- private Display display;
- private CmsUi ui;
-
- private String uid;
-
- // Client services
- // private final JavaScriptExecutor jsExecutor;
- private final BrowserNavigation browserNavigation;
-
- /** Experimental OS-like multi windows. */
- private boolean multipleShells = false;
-
- public CmsWebEntryPoint(CmsWebApp cmsWebApp, String uiName) {
- assert cmsWebApp != null;
- assert uiName != null;
- this.cmsWebApp = cmsWebApp;
- this.uiName = uiName;
- uid = UUID.randomUUID().toString();
-
- // Initial login
- LoginContext lc;
- try {
- lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER,
- new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
- new ServletHttpResponse(UiContext.getHttpResponse())));
- lc.login();
- } catch (LoginException e) {
- try {
- lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS,
- new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
- new ServletHttpResponse(UiContext.getHttpResponse())));
- lc.login();
- } catch (LoginException e1) {
- throw new IllegalStateException("Cannot log in as anonymous", e1);
- }
- }
- authChange(lc);
-
- // jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
- browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
- if (browserNavigation != null)
- browserNavigation.addBrowserNavigationListener(this);
- }
-
- protected void createContents(Composite parent) {
- Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- try {
- uxContext = new SimpleSwtUxContext();
- imageManager = new DefaultImageManager();
- CmsSession cmsSession = getCmsSession();
- if (cmsSession != null) {
- UiContext.setLocale(cmsSession.getLocale());
- LocaleUtils.setThreadLocale(cmsSession.getLocale());
- } else {
- Locale rwtLocale = RWT.getUISession().getLocale();
- LocaleUtils.setThreadLocale(rwtLocale);
- }
- parent.setData(CmsApp.UI_NAME_PROPERTY, uiName);
- display = parent.getDisplay();
- ui = cmsWebApp.getCmsApp().initUi(parent);
- 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);
- } catch (Exception e) {
- throw new IllegalStateException("Cannot create entrypoint contents", e);
- }
- return null;
- }
- });
- }
-
- protected Subject getSubject() {
- return loginContext.getSubject();
- }
-
- public <T> T doAs(PrivilegedAction<T> action) {
- return Subject.doAs(getSubject(), action);
- }
-
- @Override
- public boolean isAnonymous() {
- return CurrentUser.isAnonymous(getSubject());
- }
-
- @Override
- public synchronized void logout() {
- if (loginContext == null)
- throw new IllegalArgumentException("Login context should not be null");
- try {
- CurrentUser.logoutCmsSession(loginContext.getSubject());
- loginContext.logout();
- LoginContext anonymousLc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS,
- new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
- new ServletHttpResponse(UiContext.getHttpResponse())));
- anonymousLc.login();
- authChange(anonymousLc);
- } catch (LoginException e) {
- log.error("Cannot logout", e);
- }
- }
-
- @Override
- public synchronized void authChange(LoginContext lc) {
- if (lc == null)
- throw new IllegalArgumentException("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 = lc;
- doRefresh();
- }
-
- @Override
- public void exception(final Throwable e) {
- if (e instanceof SWTError) {
- SWTError swtError = (SWTError) e;
- if (swtError.code == SWT.ERROR_FUNCTION_DISPOSED)
- return;
- }
- display.syncExec(() -> {
-// CmsFeedback.show("Unexpected exception in CMS", e);
- exception = e;
- log.error("Unexpected exception in CMS", e);
- doRefresh();
- });
- }
-
- protected synchronized void doRefresh() {
- if (ui != null)
- Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- if (exception != null) {
- // TODO internationalise
- CmsFeedback.show("Unexpected exception", exception);
- exception = null;
- // TODO report
- }
- cmsWebApp.getCmsApp().refreshUi(ui, state);
- return null;
- }
- });
- }
-
- /** Sets the state of the entry point and retrieve the related JCR node. */
- protected String setState(String newState) {
- cmsWebApp.getCmsApp().setState(ui, newState);
- state = newState;
- return null;
- }
-
- @Override
- public UxContext getUxContext() {
- return uxContext;
- }
-
- @Override
- public String getUid() {
- return uid;
- }
-
- @Override
- public void navigateTo(String state) {
- exception = null;
- String title = setState(state);
- if (title != null)
- doRefresh();
- if (browserNavigation != null)
- browserNavigation.pushState(state, title);
- }
-
- public CmsImageManager getImageManager() {
- return imageManager;
- }
-
- @Override
- public void navigated(BrowserNavigationEvent event) {
- setState(event.getState());
- // doRefresh();
- }
-
- @Override
- public void sendEvent(String topic, Map<String, Object> properties) {
- if (properties == null)
- properties = new HashMap<>();
- if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
- throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
- + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
- properties.put(CMS_VIEW_UID_PROPERTY, uid);
- eventAdmin.sendEvent(new Event(topic, properties));
- }
-
- @Override
- public void stateChanged(String state, String title) {
- browserNavigation.pushState(state, title);
- }
-
- @Override
- public CmsSession getCmsSession() {
- CmsSession cmsSession = cmsWebApp.getCmsApp().getCmsContext().getCmsSession(getSubject());
- if (cmsSession == null)
- throw new IllegalStateException("No CMS session available for " + getSubject());
- return cmsSession;
- }
-
- @Override
- public Object getData(String key) {
- if (ui != null) {
- return ui.getData(key);
- } else {
- throw new IllegalStateException("UI is not initialized");
- }
- }
-
- @Override
- public void setData(String key, Object value) {
- if (ui != null) {
- ui.setData(key, value);
- } else {
- throw new IllegalStateException("UI is not initialized");
- }
- }
-
- /*
- * EntryPoint IMPLEMENTATION
- */
-
- @Override
- public int createUI() {
- Display display = new Display();
- Shell shell = createShell(display);
- shell.setLayout(CmsSwtUtils.noSpaceGridLayout());
- CmsSwtUtils.registerCmsView(shell, this);
- createContents(shell);
- shell.layout();
-// if (shell.getMaximized()) {
-// shell.layout();
-// } else {
-//// shell.pack();
-// }
- shell.open();
- if (getApplicationContext().getLifeCycleFactory().getLifeCycle() instanceof RWTLifeCycle) {
- eventLoop: while (!shell.isDisposed()) {
- try {
- Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- return null;
- }
- });
- } catch (Throwable e) {
- if (e instanceof SWTError) {
- SWTError swtError = (SWTError) e;
- if (swtError.code == SWT.ERROR_FUNCTION_DISPOSED) {
- log.error("Unexpected SWT error in event loop, ignoring it. " + e.getMessage());
- continue eventLoop;
- } else {
- log.error("Unexpected SWT error in event loop, shutting down...", e);
- break eventLoop;
- }
- } else if (e instanceof ThreadDeath) {
- throw (ThreadDeath) e;
- } else if (e instanceof Error) {
- log.error("Unexpected error in event loop, shutting down...", e);
- break eventLoop;
- } else {
- log.error("Unexpected exception in event loop, ignoring it. " + e.getMessage());
- continue eventLoop;
- }
- }
- }
- if (!display.isDisposed())
- display.dispose();
- }
- return 0;
- }
-
- protected Shell createShell(Display display) {
- Shell shell;
- if (!multipleShells) {
- shell = new Shell(display, SWT.NO_TRIM);
- shell.setMaximized(true);
- } else {
- shell = new Shell(display, SWT.SHELL_TRIM);
- shell.setSize(800, 600);
- }
- return shell;
- }
-
- public void setEventAdmin(EventAdmin eventAdmin) {
- this.eventAdmin = eventAdmin;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import static org.argeo.cms.osgi.BundleCmsTheme.CMS_THEME_BUNDLE_PROPERTY;
-
-import java.util.HashMap;
-import java.util.Map;
-
-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;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.osgi.framework.BundleContext;
-
-/** Lightweight web app using only RWT and not the whole Eclipse platform. */
-public class MinimalWebApp implements ApplicationConfiguration {
-
- private BundleCmsTheme theme;
-
- public void init(BundleContext bundleContext, Map<String, Object> properties) {
- if (properties.containsKey(CMS_THEME_BUNDLE_PROPERTY)) {
- String cmsThemeBundle = properties.get(CMS_THEME_BUNDLE_PROPERTY).toString();
- theme = new BundleCmsTheme(bundleContext, cmsThemeBundle);
- }
- }
-
- public void destroy() {
-
- }
-
- /** To be overridden. Does nothing by default. */
- protected void addEntryPoints(Application application, Map<String, String> properties) {
-
- }
-
- @Override
- public void configure(Application application) {
- if (theme != null)
- WebThemeUtils.apply(application, theme);
-
- Map<String, String> properties = new HashMap<>();
- if (theme != null) {
- properties.put(WebClient.THEME_ID, theme.getThemeId());
- properties.put(WebClient.HEAD_HTML, theme.getHtmlHeaders());
- } else {
- properties.put(WebClient.THEME_ID, RWT.DEFAULT_THEME_ID);
- }
- addEntryPoints(application, properties);
-
- }
-
- public void setTheme(BundleCmsTheme theme) {
- this.theme = theme;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.security.Privilege;
-import javax.jcr.version.VersionManager;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.ui.CmsUiConstants;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.LifeCycleUiProvider;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.util.StyleSheetResourceLoader;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.Application.OperationMode;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.application.EntryPointFactory;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-/** A basic generic app based on {@link SimpleErgonomics}. */
-@Deprecated
-public class SimpleApp implements CmsUiConstants, ApplicationConfiguration {
- private final static CmsLog log = CmsLog.getLog(SimpleApp.class);
-
- private String contextName = null;
-
- private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
- private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
-
- private List<String> resources = new ArrayList<String>();
-
- private BundleContext bundleContext;
-
- private Repository repository;
- private String workspace = null;
- private String jcrBasePath = "/";
- private List<String> roPrincipals = Arrays.asList(CmsConstants.ROLE_ANONYMOUS, CmsConstants.ROLE_USER);
- private List<String> rwPrincipals = Arrays.asList(CmsConstants.ROLE_USER);
-
- private CmsUiProvider header;
- private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
-
- private Integer headerHeight = 40;
-
- private ServiceRegistration<ApplicationConfiguration> appReg;
-
- public void configure(Application application) {
- try {
- BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
-
- application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
- // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
-
- application.setExceptionHandler(new CmsExceptionHandler());
-
- // loading animated gif
- application.addResource(LOADING_IMAGE, createResourceLoader(LOADING_IMAGE));
- // empty image
- application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
-
- for (String resource : resources) {
- application.addResource(resource, bundleRL);
- if (log.isTraceEnabled())
- log.trace("Resource " + resource);
- }
-
- Map<String, String> defaultBranding = null;
- if (branding.containsKey("*"))
- defaultBranding = branding.get("*");
- // String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
-
- // entry points
- for (String page : pages.keySet()) {
- Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(defaultBranding)
- : new HashMap<String, String>();
- if (branding.containsKey(page)) {
- properties.putAll(branding.get(page));
- }
- // favicon
- if (properties.containsKey(WebClient.FAVICON)) {
- String themeId = defaultBranding.get(WebClient.THEME_ID);
- Bundle themeBundle = findThemeBundle(bundleContext, themeId);
- String faviconRelPath = properties.get(WebClient.FAVICON);
- application.addResource(faviconRelPath,
- new BundleResourceLoader(themeBundle != null ? themeBundle : bundleContext.getBundle()));
- if (log.isTraceEnabled())
- log.trace("Favicon " + faviconRelPath);
-
- }
-
- // page title
- if (!properties.containsKey(WebClient.PAGE_TITLE)) {
- if (page.length() > 0)
- properties.put(WebClient.PAGE_TITLE, Character.toUpperCase(page.charAt(0)) + page.substring(1));
- }
-
- // default body HTML
- if (!properties.containsKey(WebClient.BODY_HTML))
- properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
-
- //
- // ADD ENTRY POINT
- //
- application.addEntryPoint("/" + page,
- new CmsEntryPointFactory(pages.get(page), repository, workspace, properties), properties);
- log.info("Page /" + page);
- }
-
- // stylesheets and themes
- Set<Bundle> themeBundles = new HashSet<>();
- for (String themeId : styleSheets.keySet()) {
- Bundle themeBundle = findThemeBundle(bundleContext, themeId);
- StyleSheetResourceLoader styleSheetRL = new StyleSheetResourceLoader(
- themeBundle != null ? themeBundle : bundleContext.getBundle());
- if (themeBundle != null)
- themeBundles.add(themeBundle);
- List<String> cssLst = styleSheets.get(themeId);
- if (log.isDebugEnabled())
- log.debug("Theme " + themeId);
- for (String css : cssLst) {
- application.addStyleSheet(themeId, css, styleSheetRL);
- if (log.isDebugEnabled())
- log.debug(" CSS " + css);
- }
-
- }
- for (Bundle themeBundle : themeBundles) {
- BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
- SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.png");
- SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.gif");
- SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.jpg");
- }
- } catch (RuntimeException e) {
- // Easier access to initialisation errors
- log.error("Unexpected exception when configuring RWT application.", e);
- throw e;
- }
- }
-
- public void init() throws RepositoryException {
- Session session = null;
- try {
- session = CmsJcrUtils.openDataAdminSession(repository, workspace);
- // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
- VersionManager vm = session.getWorkspace().getVersionManager();
- JcrUtils.mkdirs(session, jcrBasePath);
- session.save();
- if (!vm.isCheckedOut(jcrBasePath))
- vm.checkout(jcrBasePath);
- for (String principal : rwPrincipals)
- JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_WRITE);
- for (String principal : roPrincipals)
- JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_READ);
-
- for (String pageName : pages.keySet()) {
- try {
- initPage(session, pages.get(pageName));
- session.save();
- } catch (Exception e) {
- throw new CmsException("Cannot initialize page " + pageName, e);
- }
- }
-
- } finally {
- JcrUtils.logoutQuietly(session);
- }
-
- // publish to OSGi
- register();
- }
-
- protected void initPage(Session adminSession, CmsUiProvider page) throws RepositoryException {
- if (page instanceof LifeCycleUiProvider)
- ((LifeCycleUiProvider) page).init(adminSession);
- }
-
- public void destroy() {
- for (String pageName : pages.keySet()) {
- try {
- CmsUiProvider page = pages.get(pageName);
- if (page instanceof LifeCycleUiProvider)
- ((LifeCycleUiProvider) page).destroy();
- } catch (Exception e) {
- log.error("Cannot destroy page " + pageName, e);
- }
- }
- }
-
- protected void register() {
- Hashtable<String, String> props = new Hashtable<String, String>();
- if (contextName != null)
- props.put("contextName", contextName);
- appReg = bundleContext.registerService(ApplicationConfiguration.class, this, props);
- if (log.isDebugEnabled())
- log.debug("Registered " + (contextName == null ? "/" : contextName));
- }
-
- protected void unregister() {
- appReg.unregister();
- if (log.isDebugEnabled())
- log.debug("Unregistered " + (contextName == null ? "/" : contextName));
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public void setWorkspace(String workspace) {
- this.workspace = workspace;
- }
-
- public void setHeader(CmsUiProvider header) {
- this.header = header;
- }
-
- public void setPages(Map<String, CmsUiProvider> pages) {
- this.pages = pages;
- }
-
- public void setJcrBasePath(String basePath) {
- this.jcrBasePath = basePath;
- }
-
- public void setRoPrincipals(List<String> roPrincipals) {
- this.roPrincipals = roPrincipals;
- }
-
- public void setRwPrincipals(List<String> rwPrincipals) {
- this.rwPrincipals = rwPrincipals;
- }
-
- public void setHeaderHeight(Integer headerHeight) {
- this.headerHeight = headerHeight;
- }
-
- public void setBranding(Map<String, Map<String, String>> branding) {
- this.branding = branding;
- }
-
- public void setStyleSheets(Map<String, List<String>> styleSheets) {
- this.styleSheets = styleSheets;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- public void setResources(List<String> resources) {
- this.resources = resources;
- }
-
- public void setContextName(String contextName) {
- this.contextName = contextName;
- }
-
- private static void addThemeResources(Application application, Bundle themeBundle, BundleResourceLoader themeBRL,
- String pattern) {
- Enumeration<URL> themeResources = themeBundle.findEntries("/", pattern, true);
- if (themeResources == null)
- return;
- while (themeResources.hasMoreElements()) {
- String resource = themeResources.nextElement().getPath();
- // remove first '/' so that RWT registers it
- resource = resource.substring(1);
- if (!resource.endsWith("/")) {
- application.addResource(resource, themeBRL);
- if (log.isTraceEnabled())
- log.trace("Registered " + resource + " from theme " + themeBundle);
- }
-
- }
-
- }
-
- 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;
- }
-
- class CmsExceptionHandler implements ExceptionHandler {
-
- @Override
- public void handleException(Throwable throwable) {
- // TODO be smarter
- CmsUiUtils.getCmsView().exception(throwable);
- }
-
- }
-
- private class CmsEntryPointFactory implements EntryPointFactory {
- private final CmsUiProvider page;
- private final Repository repository;
- private final String workspace;
- private final Map<String, String> properties;
-
- public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace,
- Map<String, String> properties) {
- this.page = page;
- this.repository = repository;
- this.workspace = workspace;
- this.properties = properties;
- }
-
- @Override
- public EntryPoint create() {
- SimpleErgonomics entryPoint = new SimpleErgonomics(repository, workspace, jcrBasePath, page, properties) {
- private static final long serialVersionUID = -637940404865527290L;
-
- @Override
- protected void createAdminArea(Composite parent) {
- Composite adminArea = new Composite(parent, SWT.NONE);
- adminArea.setLayout(new FillLayout());
- Button refresh = new Button(adminArea, SWT.PUSH);
- refresh.setText("Reload App");
- refresh.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -7671999525536351366L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- long timeBeforeReload = 1000;
- RWT.getClient().getService(JavaScriptExecutor.class).execute(
- "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload + ");");
- reloadApp();
- }
- });
- }
- };
- // entryPoint.setState("");
- entryPoint.setHeader(header);
- entryPoint.setHeaderHeight(headerHeight);
- // CmsSession.current.set(entryPoint);
- return entryPoint;
- }
-
- private void reloadApp() {
- new Thread("Refresh app") {
- @Override
- public void run() {
- unregister();
- register();
- }
- }.start();
- }
- }
-
- private static ResourceLoader createResourceLoader(final String resourceName) {
- return new ResourceLoader() {
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- return getClass().getClassLoader().getResourceAsStream(resourceName);
- }
- };
- }
-
- // private static ResourceLoader createUrlResourceLoader(final URL url) {
- // return new ResourceLoader() {
- // public InputStream getResourceAsStream(String resourceName)
- // throws IOException {
- // return url.openStream();
- // }
- // };
- // }
-
- /*
- * TEXTS
- */
- private static String DEFAULT_LOADING_BODY = "<div"
- + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
- + "<img src=\"./rwt-resources/" + LOADING_IMAGE
- + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.util.Map;
-import java.util.UUID;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.swt.CmsException;
-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.util.DefaultImageManager;
-import org.argeo.cms.ui.util.SystemNotifications;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Simple header/body ergonomics. */
-@Deprecated
-public class SimpleErgonomics extends AbstractCmsEntryPoint {
- private static final long serialVersionUID = 8743413921359548523L;
-
- private final static CmsLog log = CmsLog.getLog(SimpleErgonomics.class);
-
- private boolean uiInitialized = false;
- private Composite headerArea;
- private Composite leftArea;
- private Composite rightArea;
- private Composite footerArea;
- private Composite bodyArea;
- private final CmsUiProvider uiProvider;
-
- private CmsUiProvider header;
- private Integer headerHeight = 0;
- private Integer footerHeight = 0;
- private CmsUiProvider lead;
- private CmsUiProvider end;
- private CmsUiProvider footer;
-
- private CmsImageManager imageManager = new DefaultImageManager();
- private UxContext uxContext = null;
- private String uid;
-
- public SimpleErgonomics(Repository repository, String workspace, String defaultPath, CmsUiProvider uiProvider,
- Map<String, String> factoryProperties) {
- super(repository, workspace, defaultPath, factoryProperties);
- this.uiProvider = uiProvider;
- }
-
- @Override
- protected void initUi(Composite parent) {
- uid = UUID.randomUUID().toString();
- parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- parent.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, false)));
-
- uxContext = new SimpleSwtUxContext();
- if (!getUxContext().isMasterData())
- createAdminArea(parent);
- headerArea = new Composite(parent, SWT.NONE);
- headerArea.setLayout(new FillLayout());
- GridData headerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
- headerData.heightHint = headerHeight;
- headerArea.setLayoutData(headerData);
-
- // TODO: bi-directional
- leftArea = new Composite(parent, SWT.NONE);
- leftArea.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
- leftArea.setLayout(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(CmsSwtUtils.noSpaceGridLayout());
-
- // TODO: bi-directional
- rightArea = new Composite(parent, SWT.NONE);
- rightArea.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
- rightArea.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
- footerArea = new Composite(parent, SWT.NONE);
- // footerArea.setLayout(new FillLayout());
- GridData footerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
- footerData.heightHint = footerHeight;
- footerArea.setLayoutData(footerData);
-
- uiInitialized = true;
- refresh();
- }
-
- @Override
- protected void refresh() {
- if (!uiInitialized)
- return;
- if (getState() == null)
- setState("");
- refreshSides();
- refreshBody();
- if (log.isTraceEnabled())
- log.trace("UI refreshed " + getNode());
- }
-
- protected void createAdminArea(Composite parent) {
- }
-
- @Deprecated
- protected void refreshHeader() {
- if (header == null)
- return;
-
- for (Control child : headerArea.getChildren())
- child.dispose();
- try {
- header.createUi(headerArea, getNode());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh header", e);
- }
- headerArea.layout(true, true);
- }
-
- protected void refreshSides() {
- refresh(headerArea, header, CmsStyles.CMS_HEADER);
- refresh(leftArea, lead, CmsStyles.CMS_LEAD);
- refresh(rightArea, end, CmsStyles.CMS_END);
- refresh(footerArea, footer, CmsStyles.CMS_FOOTER);
- }
-
- private void refresh(Composite area, CmsUiProvider uiProvider, String style) {
- if (uiProvider == null)
- return;
-
- for (Control child : area.getChildren())
- child.dispose();
- CmsSwtUtils.style(area, style);
- try {
- uiProvider.createUi(area, getNode());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh header", e);
- }
- area.layout(true, true);
- }
-
- protected void refreshBody() {
- // Exception
- Throwable exception = getException();
- if (exception != null) {
- SystemNotifications systemNotifications = new SystemNotifications(bodyArea);
- systemNotifications.notifyException(exception);
- resetException();
- return;
- // TODO report
- }
-
- // clear
- for (Control child : bodyArea.getChildren())
- child.dispose();
- bodyArea.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
- try {
- Node node = getNode();
-// if (node == null)
-// log.error("Context cannot be null");
-// else
- uiProvider.createUi(bodyArea, node);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh body", e);
- }
-
- bodyArea.layout(true, true);
- }
-
- @Override
- public UxContext getUxContext() {
- return uxContext;
- }
- @Override
- public String getUid() {
- return uid;
- }
-
- public CmsImageManager getImageManager() {
- return imageManager;
- }
-
- public void setHeader(CmsUiProvider header) {
- this.header = header;
- }
-
- public void setHeaderHeight(Integer headerHeight) {
- this.headerHeight = headerHeight;
- }
-
- public void setImageManager(CmsImageManager imageManager) {
- this.imageManager = imageManager;
- }
-
- public CmsUiProvider getLead() {
- return lead;
- }
-
- public void setLead(CmsUiProvider lead) {
- this.lead = lead;
- }
-
- public CmsUiProvider getEnd() {
- return end;
- }
-
- public void setEnd(CmsUiProvider end) {
- this.end = end;
- }
-
- public CmsUiProvider getFooter() {
- return footer;
- }
-
- public void setFooter(CmsUiProvider footer) {
- this.footer = footer;
- }
-
- public CmsUiProvider getHeader() {
- return header;
- }
-
- public void setFooterHeight(Integer footerHeight) {
- this.footerHeight = footerHeight;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsTheme;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-
-/** Web specific utilities around theming. */
-public class WebThemeUtils {
- private final static CmsLog log = CmsLog.getLog(WebThemeUtils.class);
-
- public static void apply(Application application, CmsTheme theme) {
- ResourceLoader resourceLoader = new CmsThemeResourceLoader(theme);
- resources: for (String path : theme.getImagesPaths()) {
- if (path.startsWith("target/"))
- continue resources; // skip maven output
- application.addResource(path, resourceLoader);
- if (log.isTraceEnabled())
- log.trace("Theme " + theme.getThemeId() + ": added resource " + path);
- }
- for (String path : theme.getRapCssPaths()) {
- application.addStyleSheet(theme.getThemeId(), path, resourceLoader);
- if (log.isDebugEnabled())
- log.debug("Theme " + theme.getThemeId() + ": added RAP CSS " + path);
- }
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web.osgi;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.cms.web.CmsWebApp;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.service.event.EventAdmin;
-
-/** Publish a CmsApp as a RAP application. */
-public class CmsWebAppFactory {
- private BundleContext bundleContext = FrameworkUtil.getBundle(CmsWebAppFactory.class).getBundleContext();
- private final static String CONTEXT_NAME = "contextName";
-
- private EventAdmin eventAdmin;
-
- private Map<String, CmsWebApp> registrations = Collections.synchronizedMap(new HashMap<>());
-
- public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
- if (contextName != null) {
- CmsWebApp cmsWebApp = new CmsWebApp();
- cmsWebApp.setEventAdmin(eventAdmin);
- cmsWebApp.setCmsApp(cmsApp, properties);
- Hashtable<String, String> serviceProperties = new Hashtable<>();
- if (!contextName.equals(""))
- serviceProperties.put(CONTEXT_NAME, contextName);
- cmsWebApp.init(bundleContext, serviceProperties);
- registrations.put(contextName, cmsWebApp);
- }
- }
-
- public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
- if (contextName != null) {
- CmsWebApp cmsWebApp = registrations.get(contextName);
- if (cmsWebApp != null) {
- cmsWebApp.destroy(bundleContext, new HashMap<>());
- cmsWebApp.unsetCmsApp(cmsApp, properties);
- } else {
- // TODO log warning
- }
- }
- }
-
- public void setEventAdmin(EventAdmin eventAdmin) {
- this.eventAdmin = eventAdmin;
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.jetty;
-
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.eclipse.rap.rwt.application.AbstractEntryPoint;
-import org.eclipse.rap.rwt.application.ApplicationRunner;
-import org.eclipse.rap.rwt.engine.RWTServlet;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** A minimal RWT runner based on embedded Jetty. */
-public class RwtRunner {
-
- private final Server server;
- private final ServerConnector serverConnector;
- private Path tempDir;
-
- public RwtRunner() {
- server = new Server(new QueuedThreadPool(10, 1));
- serverConnector = new ServerConnector(server);
- serverConnector.setPort(0);
- server.setConnectors(new Connector[] { serverConnector });
- }
-
- protected Control createUi(Composite parent, Object context) {
- return new Label(parent, SWT.NONE);
- }
-
- public void init() {
- ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
- context.setContextPath("/");
- server.setHandler(context);
-
- String entryPoint = "app";
-
- // rwt-resources requires a file system
- try {
- tempDir = Files.createTempDirectory("argeo-rwtRunner");
- context.setBaseResource(Resource.newResource(tempDir.resolve("www").toString()));
- } catch (IOException e) {
- throw new IllegalStateException("Cannot create temporary directory", e);
- }
- context.addEventListener(new ServletContextListener() {
- ApplicationRunner applicationRunner;
-
- @Override
- public void contextInitialized(ServletContextEvent sce) {
- applicationRunner = new ApplicationRunner(
- (application) -> application.addEntryPoint("/" + entryPoint, () -> new AbstractEntryPoint() {
- private static final long serialVersionUID = 5678385921969090733L;
-
- @Override
- protected void createContents(Composite parent) {
- createUi(parent, null);
- }
- }, null), sce.getServletContext());
- applicationRunner.start();
- }
-
- @Override
- public void contextDestroyed(ServletContextEvent sce) {
- applicationRunner.stop();
- }
- });
-
- context.addServlet(new ServletHolder(new RWTServlet()), "/" + entryPoint);
-
- // Required to serve rwt-resources. It is important that this is last.
- ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class);
- context.addServlet(holderPwd, "/");
-
- try {
- server.start();
- } catch (Exception e) {
- throw new IllegalStateException("Cannot start Jetty server", e);
- }
- }
-
- public void destroy() {
- try {
- serverConnector.close();
- server.stop();
- // TODO delete temp dir
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public Integer getEffectivePort() {
- return serverConnector.getLocalPort();
- }
-
- public void waitFor() throws InterruptedException {
- server.join();
- }
-
- public static void main(String[] args) throws Exception {
- RwtRunner rwtRunner = new RwtRunner() {
-
- @Override
- protected Control createUi(Composite parent, Object context) {
- Label label = new Label(parent, SWT.NONE);
- label.setText("Hello world!");
- return label;
- }
- };
- rwtRunner.init();
- Runtime.getRuntime().addShutdownHook(new Thread(() -> rwtRunner.destroy(), "Jetty shutdown"));
-
- long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
- System.out.println("App available in " + jvmUptime + " ms, on port " + rwtRunner.getEffectivePort());
-
- // open browser in app mode
- Thread.sleep(2000);// wait for RWT to be ready
- Runtime.getRuntime().exec("google-chrome --app=http://localhost:" + rwtRunner.getEffectivePort() + "/app");
-
- rwtRunner.waitFor();
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src" />
- <classpathentry kind="con"
- path="org.eclipse.pde.core.requiredPlugins" />
- <classpathentry kind="con"
- path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11" />
- <classpathentry kind="output" path="bin" />
-</classpath>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.swt.specific.rap</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-Import-Package: org.eclipse.swt,\
-org.eclipse.jface.dialogs,\
-org.eclipse.swt.events,\
-javax.servlet.http;version="[3,5)",\
-*
+++ /dev/null
-source.. = src/
-output.. = bin/
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import java.awt.image.BufferedImage;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-
-public class BufferedImageDisplay extends Composite {
- private static final long serialVersionUID = 4541163690514461514L;
- private BufferedImage image;
-
- public BufferedImageDisplay(Composite parent, int style) {
- super(parent, SWT.NO_BACKGROUND);
- }
-
- public void setImage(BufferedImage image) {
- this.image = image;
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Shell;
-
-public class CmsFileDialog extends FileDialog {
- private static final long serialVersionUID = -7540791204102318801L;
-
- public CmsFileDialog(Shell parent, int style) {
- super(parent, style);
- }
-
- public CmsFileDialog(Shell parent) {
- super(parent);
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import org.eclipse.rap.rwt.widgets.FileUpload;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Composite;
-
-public class CmsFileUpload extends FileUpload {
- private static final long serialVersionUID = 8027963992680980549L;
-
- public CmsFileUpload(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- public void setText(String text) {
- super.setText(text);
- }
-
- @Override
- public String getFileName() {
- return super.getFileName();
- }
-
- @Override
- public String[] getFileNames() {
- return super.getFileNames();
- }
-
- @Override
- public void addSelectionListener(SelectionListener listener) {
- super.addSelectionListener(listener);
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import org.eclipse.jface.viewers.AbstractTableViewer;
-import org.eclipse.jface.viewers.ColumnViewer;
-import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.widgets.Widget;
-
-/** Static utilities to bridge differences between RCP and RAP */
-public class EclipseUiSpecificUtils {
-
- public static void setStyleData(Widget widget, Object data) {
- widget.setData(RWT.CUSTOM_VARIANT, data);
- }
-
- public static Object getStyleData(Widget widget) {
- return widget.getData(RWT.CUSTOM_VARIANT);
- }
-
- public static void setMarkupData(Widget widget) {
- widget.setData(RWT.MARKUP_ENABLED, true);
- }
-
- public static void setMarkupValidationDisabledData(Widget widget) {
- widget.setData("org.eclipse.rap.rwt.markupValidationDisabled", Boolean.TRUE);
- }
-
- /**
- * TootlTip support is supported only for {@link AbstractTableViewer} in RAP
- */
- public static void enableToolTipSupport(Viewer viewer) {
- if (viewer instanceof ColumnViewer)
- ColumnViewerToolTipSupport.enableFor((ColumnViewer) viewer);
- }
-
- private EclipseUiSpecificUtils() {
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.eclipse.rap.fileupload.FileDetails;
-import org.eclipse.rap.fileupload.FileUploadHandler;
-import org.eclipse.rap.fileupload.FileUploadReceiver;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.client.ClientFile;
-import org.eclipse.rap.rwt.client.service.ClientFileUploader;
-import org.eclipse.rap.rwt.dnd.ClientFileTransfer;
-import org.eclipse.swt.dnd.DND;
-import org.eclipse.swt.dnd.DropTarget;
-import org.eclipse.swt.dnd.DropTargetAdapter;
-import org.eclipse.swt.dnd.DropTargetEvent;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.widgets.Control;
-
-/** Configures a {@link Control} to receive files drop from the client OS. */
-public class FileDropAdapter {
-
- public void prepareDropTarget(Control control, DropTarget dropTarget) {
- dropTarget.setTransfer(new Transfer[] { ClientFileTransfer.getInstance() });
- dropTarget.addDropListener(new DropTargetAdapter() {
- private static final long serialVersionUID = 5361645765549463168L;
-
- @Override
- public void dropAccept(DropTargetEvent event) {
- if (!ClientFileTransfer.getInstance().isSupportedType(event.currentDataType)) {
- event.detail = DND.DROP_NONE;
- }
- }
-
- @Override
- public void drop(DropTargetEvent event) {
- handleFileDrop(control, event);
- }
- });
- }
-
- public void handleFileDrop(Control control, DropTargetEvent event) {
- ClientFile[] clientFiles = (ClientFile[]) event.data;
- ClientFileUploader service = RWT.getClient().getService(ClientFileUploader.class);
-// DiskFileUploadReceiver receiver = new DiskFileUploadReceiver();
- FileUploadReceiver receiver = new FileUploadReceiver() {
-
- @Override
- public void receive(InputStream stream, FileDetails details) throws IOException {
- control.getDisplay().syncExec(() -> {
- try {
- processUpload(stream, details.getFileName(), details.getContentType());
- } catch (IOException e) {
- throw new IllegalStateException("Cannot process upload of " + details.getFileName(), e);
- }
- });
- }
- };
- FileUploadHandler handler = new FileUploadHandler(receiver);
-// handler.setMaxFileSize( sizeLimit );
-// handler.setUploadTimeLimit( timeLimit );
- service.submit(handler.getUploadUrl(), clientFiles);
-// for (File file : receiver.getTargetFiles()) {
-// paths.add(file.toPath());
-// }
- }
-
- /** Executed in UI thread */
- protected void processUpload(InputStream in, String fileName, String contentType) throws IOException {
-
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import java.util.Locale;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.widgets.Display;
-
-/** Singleton class providing single sources infos about the UI context. */
-public class UiContext {
- /** Can be null, thus indicating that we are not in a web context. */
- public static HttpServletRequest getHttpRequest() {
- return RWT.getRequest();
- }
-
- public static HttpServletResponse getHttpResponse() {
- return RWT.getResponse();
- }
-
- public static Locale getLocale() {
- if (Display.getCurrent() != null)
- return RWT.getUISession().getLocale();
- else
- return Locale.getDefault();
- }
-
- public static void setLocale(Locale locale) {
- if (Display.getCurrent() != null)
- RWT.getUISession().setLocale(locale);
- else
- Locale.setDefault(locale);
- }
-
- /** Can always be null */
- @SuppressWarnings("unchecked")
- public static <T> T getData(String key) {
- Display display = getDisplay();
- if (display == null)
- return null;
- return (T) display.getData(key);
- }
-
- public static void setData(String key, Object value) {
- Display display = getDisplay();
- if (display == null)
- throw new IllegalStateException("Not display available");
- display.setData(key, value);
- }
-
- private static Display getDisplay() {
- return Display.getCurrent();
- }
-
- private UiContext() {
- }
-
-}
+++ /dev/null
-/** Eclipse RAP-specific SWT/JFace utilities, to simplify single-sourcing. */
-package org.argeo.eclipse.ui.specific;
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-/bin/
-/target/
-/exec
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.cms.e4.rcp</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
-org.eclipse.jdt.core.compiler.compliance=1.8
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.8
+++ /dev/null
-eclipse.preferences.version=1
-pluginProject.extensions=false
-resolve.requirebundle=false
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="ASCII"?>
-<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:advanced="http://www.eclipse.org/ui/2010/UIModel/application/ui/advanced" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmi:id="_c4iAgCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.application">
- <children xsi:type="basic:TrimmedWindow" xmi:id="_hSGBwCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.trimmedwindow.argeocompanion" label="Argeo Companion">
- <children xsi:type="advanced:PerspectiveStack" xmi:id="_nxzQICnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.perspectivestack.0">
- <children xsi:type="advanced:Perspective" xmi:id="_oI_oICnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.perspective.cmsadmin" label="CMS Admin">
- <children xsi:type="basic:PartSashContainer" xmi:id="_qc16ECnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.partsashcontainer.0" horizontal="true">
- <children xsi:type="basic:PartStack" xmi:id="_RE87kDsXEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.rcp.partstack.1">
- <children xsi:type="basic:Part" xmi:id="_V1WvgDsXEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.rcp.part.files" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.files.NodeFsBrowserView" label="Files"/>
- <children xsi:type="basic:Part" xmi:id="_vOqDQCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.part.jcr" containerData="4000" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR"/>
- </children>
- <children xsi:type="basic:PartStack" xmi:id="_0eRiwCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.partstack.0" containerData="6000">
- <tags>editorArea</tags>
- </children>
- </children>
- </children>
- </children>
- </children>
- <descriptors xmi:id="__9SDsC8JEeq0koquN4xGyg" elementId="org.argeo.cms.e4.partdescriptor.nodeEditor" allowMultiple="true" category="editorArea" closeable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrNodeEditor"/>
- <addons xmi:id="_c4iAgSnCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
- <addons xmi:id="_c4iAginCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
- <addons xmi:id="_c4iAgynCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
- <addons xmi:id="_c4iAhCnCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
- <addons xmi:id="_c4iAhSnCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
- <addons xmi:id="_c4iAhinCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
- <addons xmi:id="_c4iAhynCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
-</application:Application>
+++ /dev/null
-argeo.osgi.start.2.node=\
-org.eclipse.equinox.http.servlet,\
-org.eclipse.equinox.metatype,\
-org.eclipse.equinox.cm,\
-org.argeo.init
-
-argeo.osgi.start.3.node=\
-org.argeo.cms,\
-org.argeo.cms.jcr,\
-
-applicationXMI=org.argeo.cms.e4.rcp/argeo-companion.e4xmi
-lifeCycleURI=bundleclass://org.argeo.cms.e4.rcp/org.argeo.cms.e4.rcp.CmsRcpLifeCycle
-clearPersistedState=true
-#argeo.cms.desktop.inTray=true
-
-# Remote node:
-#argeo.node.repo.labeledUri=http://root:demo@localhost:7070/jcr/node
-
-# Logging
-log.org.argeo=DEBUG
-
-argeo.node.useradmin.uris=os:///
-eclipse.application=org.argeo.cms.e4.rcp.CmsE4Application
+++ /dev/null
-Bundle-SymbolicName: org.argeo.cms.e4.rcp;singleton=true
-
-Require-Bundle: org.eclipse.core.runtime
-
-Import-Package: !org.eclipse.core.runtime,\
-org.eclipse.swt,\
-*
+++ /dev/null
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- argeo-companion.e4xmi
-source.. = src/
+++ /dev/null
-log4j.rootLogger=WARN, development
-
-## Levels
-log4j.logger.org.argeo=DEBUG
-log4j.logger.org.argeo.jackrabbit.remote.ExtendedDispatcherServlet=WARN
-log4j.logger.org.argeo.server.webextender.TomcatDeployer=INFO
-
-#log4j.logger.org.springframework.security=DEBUG
-#log4j.logger.org.apache.commons.exec=DEBUG
-#log4j.logger.org.apache.jackrabbit.webdav=DEBUG
-#log4j.logger.org.apache.jackrabbit.remote=DEBUG
-#log4j.logger.org.apache.jackrabbit.core.observation=DEBUG
-
-log4j.logger.org.apache.catalina=INFO
-log4j.logger.org.apache.coyote=INFO
-
-log4j.logger.org.apache.directory=INFO
-log4j.logger.org.apache.directory.server=ERROR
-log4j.logger.org.apache.jackrabbit.core.query.lucene=ERROR
-
-## Appenders
-# console is set to be a ConsoleAppender.
-log4j.appender.console=org.apache.log4j.ConsoleAppender
-
-# console uses PatternLayout.
-log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c - [%t]%n
-
-# development appender (slow!)
-log4j.appender.development=org.apache.log4j.ConsoleAppender
-log4j.appender.development.layout=org.apache.log4j.PatternLayout
-log4j.appender.development.layout.ConversionPattern=%d{HH:mm:ss} [%16.16t] %5p %m (%F:%L) %c%n
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<?eclipse version="3.4"?>
-<plugin>
- <extension
- id="CmsE4Application"
- name="CMS E4 Application"
- point="org.eclipse.core.runtime.applications">
- <application
- cardinality="singleton-global"
- thread="main"
- visible="true">
- <run class="org.argeo.cms.e4.rcp.CmsE4Application"></run>
- </application>
- </extension>
-</plugin>
+++ /dev/null
-package org.argeo.cms.e4.rcp;
-
-import java.security.PrivilegedExceptionAction;
-import java.util.UUID;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-import org.argeo.api.cms.CmsAuth;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.SimpleSwtUxContext;
-import org.argeo.cms.swt.auth.CmsLoginShell;
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.IExtension;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.equinox.app.IApplication;
-import org.eclipse.equinox.app.IApplicationContext;
-import org.eclipse.swt.widgets.Display;
-
-public class CmsE4Application implements IApplication, CmsView {
- private LoginContext loginContext;
- private IApplication e4Application;
- private UxContext uxContext;
- private String uid;
-
- @Override
- public Object start(IApplicationContext context) throws Exception {
- // TODO wait for CMS to be ready
- Thread.sleep(5000);
-
- uid = UUID.randomUUID().toString();
- Subject subject = new Subject();
- Display display = createDisplay();
- CmsLoginShell loginShell = new CmsLoginShell(this, null);
- // TODO customize CmsLoginShell to be smaller and centered
- loginShell.setSubject(subject);
- try {
- // try pre-auth
- loginContext = new LoginContext(CmsAuth.LOGIN_CONTEXT_SINGLE_USER, subject, loginShell);
- loginContext.login();
- } catch (LoginException e) {
- e.printStackTrace();
- loginShell.createUi();
- loginShell.open();
-
- while (!loginShell.getShell().isDisposed()) {
- if (!display.readAndDispatch())
- display.sleep();
- }
- }
- if (CurrentUser.getUsername(getSubject()) == null)
- throw new IllegalStateException("Cannot log in");
-
- // try {
- // CallbackHandler callbackHandler = new DefaultLoginDialog(
- // display.getActiveShell());
- // loginContext = new LoginContext(
- // NodeConstants.LOGIN_CONTEXT_SINGLE_USER, subject,
- // callbackHandler);
- // } catch (LoginException e1) {
- // throw new CmsException("Cannot initialize login context", e1);
- // }
- //
- // // login
- // try {
- // loginContext.login();
- // subject = loginContext.getSubject();
- // } catch (LoginException e) {
- // e.printStackTrace();
- // display.dispose();
- // try {
- // Thread.sleep(2000);
- // } catch (InterruptedException e1) {
- // // silent
- // }
- // return null;
- // }
-
- uxContext = new SimpleSwtUxContext();
- // UiContext.setData(CmsView.KEY, this);
- CmsSwtUtils.registerCmsView(loginShell.getShell(), this);
- e4Application = getApplication(null);
- Object res = Subject.doAs(subject, new PrivilegedExceptionAction<Object>() {
-
- @Override
- public Object run() throws Exception {
- return e4Application.start(context);
- }
-
- });
- return res;
- }
-
- @Override
- public void stop() {
- if (e4Application != null)
- e4Application.stop();
- }
-
- static IApplication getApplication(String[] args) {
- IExtension extension = Platform.getExtensionRegistry().getExtension(Platform.PI_RUNTIME,
- Platform.PT_APPLICATIONS, "org.eclipse.e4.ui.workbench.swt.E4Application");
- try {
- IConfigurationElement[] elements = extension.getConfigurationElements();
- if (elements.length > 0) {
- IConfigurationElement[] runs = elements[0].getChildren("run");
- if (runs.length > 0) {
- Object runnable;
- runnable = runs[0].createExecutableExtension("class");
- if (runnable instanceof IApplication)
- return (IApplication) runnable;
- }
- }
- } catch (Exception e) {
- throw new IllegalStateException("Cannot find e4 application", e);
- }
- throw new IllegalStateException("Cannot find e4 application");
- }
-
- public static Display createDisplay() {
- Display.setAppName("Argeo CMS RCP");
-
- // create the display
- Display newDisplay = Display.getCurrent();
- if (newDisplay == null) {
- newDisplay = new Display();
- }
- // Set the priority higher than normal so as to be higher
- // than the JobManager.
- Thread.currentThread().setPriority(Math.min(Thread.MAX_PRIORITY, Thread.NORM_PRIORITY + 1));
- return newDisplay;
- }
-
- //
- // CMS VIEW
- //
-
- @Override
- public UxContext getUxContext() {
- return uxContext;
- }
-
- @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) {
- // System.err.println("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 CmsImageManager getImageManager() {
- // TODO Auto-generated method stub
- return null;
- }
-
- protected Subject getSubject() {
- return loginContext.getSubject();
- }
-
- @Override
- public boolean isAnonymous() {
- return CurrentUser.isAnonymous(getSubject());
- }
-
- @Override
- public String getUid() {
- return uid;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.e4.rcp;
-
-import org.eclipse.e4.core.contexts.IEclipseContext;
-import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
-import org.eclipse.e4.ui.workbench.lifecycle.PreSave;
-import org.eclipse.e4.ui.workbench.lifecycle.ProcessAdditions;
-import org.eclipse.e4.ui.workbench.lifecycle.ProcessRemovals;
-
-@SuppressWarnings("restriction")
-public class CmsRcpLifeCycle {
-
- @PostContextCreate
- void postContextCreate(IEclipseContext workbenchContext) {
- }
-
- @PreSave
- void preSave(IEclipseContext workbenchContext) {
- }
-
- @ProcessAdditions
- void processAdditions(IEclipseContext workbenchContext) {
- }
-
- @ProcessRemovals
- void processRemovals(IEclipseContext workbenchContext) {
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+++ /dev/null
-/bin/
-/target/
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.cms.ui.rcp</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ds.core.builder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="CMS RCP Display Factory">
- <implementation class="org.argeo.cms.ui.rcp.CmsRcpDisplayFactory"/>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="CMS RCP Servlet Factory">
- <implementation class="org.argeo.cms.ui.rcp.servlet.CmsRcpServletFactory"/>
- <reference bind="addCmsApp" cardinality="0..n" interface="org.argeo.api.cms.CmsApp" name="CmsApp" policy="dynamic" unbind="removeCmsApp"/>
- <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
- <reference bind="setHttpService" cardinality="1..1" interface="org.osgi.service.http.HttpService" name="HttpService" policy="static"/>
-</scr:component>
+++ /dev/null
-
-Import-Package:\
-org.argeo.cms.auth,\
-org.eclipse.swt,\
-org.eclipse.swt.graphics,\
-org.w3c.css.sac,\
-*
-
-Service-Component:\
-OSGI-INF/cmsRcpDisplayFactory.xml,\
-OSGI-INF/cmsRcpServletFactory.xml
-
+++ /dev/null
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- OSGI-INF/,\
- OSGI-INF/cmsRcpServletFactory.xml
-source.. = src/
+++ /dev/null
-package org.argeo.cms.ui.rcp;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.PrivilegedAction;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.api.cms.CmsAuth;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.CmsSession;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.api.cms.ux.CmsTheme;
-import org.argeo.api.cms.ux.CmsUi;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.e4.ui.css.core.engine.CSSEngine;
-import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler;
-import org.eclipse.e4.ui.css.swt.engine.CSSSWTEngineImpl;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventAdmin;
-
-/** Runs a {@link CmsApp} as an SWT desktop application. */
-@SuppressWarnings("restriction")
-public class CmsRcpApp implements CmsView {
- private final static CmsLog log = CmsLog.getLog(CmsRcpApp.class);
-
- // private BundleContext bundleContext =
- // FrameworkUtil.getBundle(CmsRcpApp.class).getBundleContext();
-
- private Shell shell;
- private CmsApp cmsApp;
-
- // CMS View
- private String uid;
- private LoginContext loginContext;
-
- private EventAdmin eventAdmin;
-
- private CSSEngine cssEngine;
-
- private CmsUi ui;
- // TODO make it configurable
- private String uiName = "desktop";
-
- public CmsRcpApp(String uiName) {
- uid = UUID.randomUUID().toString();
- this.uiName = uiName;
- }
-
- public void initRcpApp() {
- Display display = Display.getCurrent();
- shell = new Shell(display);
- shell.setText("Argeo CMS");
- Composite parent = shell;
- parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
- CmsSwtUtils.registerCmsView(shell, CmsRcpApp.this);
-
- try {
- loginContext = new LoginContext(CmsAuth.SINGLE_USER.getLoginContextName());
- loginContext.login();
- } catch (LoginException e) {
- throw new IllegalStateException("Could not log in.", e);
- }
- if (log.isDebugEnabled())
- log.debug("Logged in to desktop: " + loginContext.getSubject());
-
- Subject.doAs(loginContext.getSubject(), (PrivilegedAction<Void>) () -> {
-
- // TODO factorise with web app
- parent.setData(CmsApp.UI_NAME_PROPERTY, uiName);
- ui = cmsApp.initUi(parent);
- 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.
- cmsApp.refreshUi(ui, null);
-
- // Styling
- CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
- if (theme != null) {
- cssEngine = new CSSSWTEngineImpl(display);
- for (String path : theme.getSwtCssPaths()) {
- try (InputStream in = theme.loadPath(path)) {
- cssEngine.parseStyleSheet(in);
- } catch (IOException e) {
- throw new IllegalStateException("Cannot load stylesheet " + path, e);
- }
- }
- cssEngine.setErrorHandler(new CSSErrorHandler() {
- public void error(Exception e) {
- log.error("SWT styling error: ", e);
- }
- });
- applyStyles(shell);
- }
- shell.layout(true, true);
-
- shell.open();
- return null;
- });
- }
-
- /*
- * CMS VIEW
- */
-
- @Override
- public String getUid() {
- return uid;
- }
-
- @Override
- public UxContext getUxContext() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void navigateTo(String state) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void authChange(LoginContext loginContext) {
- }
-
- @Override
- public void logout() {
- if (loginContext != null)
- try {
- loginContext.logout();
- } catch (LoginException e) {
- log.error("Cannot log out", e);
- }
- }
-
- @Override
- public void exception(Throwable e) {
- log.error("Unexpected exception in CMS RCP", e);
- }
-
- @Override
- public CmsImageManager getImageManager() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public CmsSession getCmsSession() {
- CmsSession cmsSession = cmsApp.getCmsContext().getCmsSession(getSubject());
- return cmsSession;
- }
-
- @Override
- public Object getData(String key) {
- if (ui != null) {
- return ui.getData(key);
- } else {
- throw new IllegalStateException("UI is not initialized");
- }
- }
-
- @Override
- public void setData(String key, Object value) {
- if (ui != null) {
- ui.setData(key, value);
- } else {
- throw new IllegalStateException("UI is not initialized");
- }
- }
-
- @Override
- public boolean isAnonymous() {
- return false;
- }
-
- @Override
- public void applyStyles(Object node) {
- if (cssEngine != null)
- cssEngine.applyStyles(node, true);
- }
-
- @Override
- public void sendEvent(String topic, Map<String, Object> properties) {
- if (properties == null)
- properties = new HashMap<>();
- if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
- throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
- + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
- properties.put(CMS_VIEW_UID_PROPERTY, uid);
- eventAdmin.sendEvent(new Event(topic, properties));
- }
-
- public <T> T doAs(PrivilegedAction<T> action) {
- return Subject.doAs(getSubject(), action);
- }
-
- protected Subject getSubject() {
- return loginContext.getSubject();
- }
-
- public Shell getShell() {
- return shell;
- }
-
- /*
- * DEPENDENCY INJECTION
- */
- public void setCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- this.cmsApp = cmsApp;
- }
-
- public void unsetCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- this.cmsApp = null;
- }
-
- public void setEventAdmin(EventAdmin eventAdmin) {
- this.eventAdmin = eventAdmin;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.rcp;
-
-import java.nio.file.Path;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.util.OS;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.service.event.EventAdmin;
-import org.eclipse.swt.events.DisposeListener;
-
-/** Creates the SWT {@link Display} in a dedicated thread. */
-public class CmsRcpDisplayFactory {
- /** File name in a run directory */
- private final static String ARGEO_RCP_URL = "argeo.rcp.url";
-
- /** There is only one display in RCP mode */
- private static Display display;
-
- private CmsUiThread uiThread;
-
- private boolean shutdown = false;
-
- public void init() {
- uiThread = new CmsUiThread();
- uiThread.start();
- while (display == null)
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // silent
- }
- }
-
- public void destroy() {
- shutdown = true;
- display.wake();
- try {
- uiThread.join();
- } catch (InterruptedException e) {
- // silent
- } finally {
- uiThread = null;
- }
- }
-
- class CmsUiThread extends Thread {
-
- public CmsUiThread() {
- super("CMS UI");
- }
-
- @Override
- public void run() {
- display = Display.getDefault();
- display.setRuntimeExceptionHandler((e) -> e.printStackTrace());
- display.setErrorHandler((e) -> e.printStackTrace());
-
-// for (String contextName : cmsApps.keySet()) {
-// openCmsApp(contextName);
-// }
-
- while (!shutdown) {
- if (!display.readAndDispatch())
- display.sleep();
- }
- display.dispose();
- display = null;
- }
- }
-
- public static Display getDisplay() {
- return display;
- }
-
- public static void openCmsApp(EventAdmin eventAdmin, CmsApp cmsApp, String uiName,
- DisposeListener disposeListener) {
- CmsRcpDisplayFactory.getDisplay().syncExec(() -> {
- CmsRcpApp cmsRcpApp = new CmsRcpApp(uiName);
- cmsRcpApp.setEventAdmin(eventAdmin);
- cmsRcpApp.setCmsApp(cmsApp, null);
- cmsRcpApp.initRcpApp();
- if (disposeListener != null)
- cmsRcpApp.getShell().addDisposeListener(disposeListener);
- });
- }
-
- public static Path getUrlRunFile() {
- return OS.getRunDir().resolve(CmsRcpDisplayFactory.ARGEO_RCP_URL);
- }
-}
+++ /dev/null
-package org.argeo.cms.ui.rcp.servlet;
-
-import java.io.IOException;
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.util.Objects;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
-import org.osgi.service.event.EventAdmin;
-
-/** Open the related app when called. */
-public class CmsRcpServlet extends HttpServlet {
- private static final long serialVersionUID = -3944472431354848923L;
- private final static Logger logger = System.getLogger(CmsRcpServlet.class.getName());
-
- private CmsApp cmsApp;
- private EventAdmin eventAdmin;
-
- public CmsRcpServlet(EventAdmin eventAdmin, CmsApp cmsApp) {
- Objects.requireNonNull(eventAdmin);
- Objects.requireNonNull(cmsApp);
- this.cmsApp = cmsApp;
- this.eventAdmin = eventAdmin;
- }
-
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String path = req.getPathInfo();
- String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
- CmsRcpDisplayFactory.openCmsApp(eventAdmin, cmsApp, uiName, null);
- logger.log(Level.DEBUG, "Opened RCP UI " + uiName + " of CMS App " + req.getServletPath());
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.rcp.servlet;
-
-import java.io.IOException;
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.net.DatagramSocket;
-import java.net.ServerSocket;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-
-import javax.servlet.Servlet;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.event.EventAdmin;
-import org.osgi.service.http.HttpService;
-
-/** Publishes one {@link CmsRcpServlet} per {@link CmsApp}. */
-public class CmsRcpServletFactory {
- private final static Logger logger = System.getLogger(CmsRcpServletFactory.class.getName());
-
- private BundleContext bundleContext = FrameworkUtil.getBundle(CmsRcpServletFactory.class).getBundleContext();
-
- private CompletableFuture<EventAdmin> eventAdmin = new CompletableFuture<>();
-
- private Map<String, ServiceRegistration<Servlet>> registrations = Collections.synchronizedMap(new HashMap<>());
-
- public void init() {
-
- }
-
- public void destroy() {
- Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
- try {
- if (Files.exists(runFile)) {
- Files.delete(runFile);
- }
- } catch (IOException e) {
- logger.log(Level.ERROR, "Cannot delete " + runFile, e);
- }
- }
-
- public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
- if (contextName != null) {
- eventAdmin.thenAccept((eventAdmin) -> {
- CmsRcpServlet servlet = new CmsRcpServlet(eventAdmin, cmsApp);
- Hashtable<String, String> serviceProperties = new Hashtable<>();
- serviceProperties.put("osgi.http.whiteboard.servlet.pattern", "/" + contextName + "/*");
- ServiceRegistration<Servlet> sr = bundleContext.registerService(Servlet.class, servlet,
- serviceProperties);
- registrations.put(contextName, sr);
- });
- }
- }
-
- public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
- if (contextName != null) {
- ServiceRegistration<Servlet> sr = registrations.get(contextName);
- sr.unregister();
- }
- }
-
- public void setEventAdmin(EventAdmin eventAdmin) {
- this.eventAdmin.complete(eventAdmin);
- }
-
- public void setHttpService(HttpService httpService, Map<String, Object> properties) {
- Integer httpPort = Integer.parseInt(properties.get("http.port").toString());
- String baseUrl = "http://localhost:" + httpPort + "/";
- Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
- try {
- if (!Files.exists(runFile)) {
- Files.createDirectories(runFile.getParent());
- // TODO give read permission only to the owner
- Files.createFile(runFile);
- } else {
- URI uri = URI.create(Files.readString(runFile));
- if (!httpPort.equals(uri.getPort()))
- if (!isPortAvailable(uri.getPort())) {
- throw new IllegalStateException("Another CMS is running on " + runFile);
- } else {
- logger.log(Level.WARNING,
- "Run file " + runFile + " found but port of " + uri + " is available. Overwriting...");
- }
- }
- Files.writeString(runFile, baseUrl, StandardCharsets.UTF_8);
- } catch (IOException e) {
- throw new RuntimeException("Cannot write run file to " + runFile, e);
- }
- logger.log(Level.DEBUG, "RCP available under " + baseUrl + ", written to " + runFile);
- }
-
- protected boolean isPortAvailable(int port) {
- ServerSocket ss = null;
- DatagramSocket ds = null;
- try {
- ss = new ServerSocket(port);
- ss.setReuseAddress(true);
- ds = new DatagramSocket(port);
- ds.setReuseAddress(true);
- return true;
- } catch (IOException e) {
- } finally {
- if (ds != null) {
- ds.close();
- }
-
- if (ss != null) {
- try {
- ss.close();
- } catch (IOException e) {
- /* should not be thrown */
- }
- }
- }
-
- return false;
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src" />
- <classpathentry kind="con"
- path="org.eclipse.pde.core.requiredPlugins" />
- <classpathentry kind="con"
- path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" />
- <classpathentry kind="output" path="bin" />
-</classpath>
+++ /dev/null
-/target/
-/bin/
-*.log
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.swt.specific.rcp</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-/MANIFEST.MF
+++ /dev/null
-Import-Package: \
-!java.*,\
-org.apache.commons.io,\
-org.eclipse.core.commands,\
-!org.eclipse.core.runtime,\
-!org.eclipse.ui.plugin,\
-org.eclipse.swt,\
-javax.servlet.http;version="[3,5)",\
-javax.servlet;version="[3,5)",\
-*
-
-Export-Package: org.argeo.*,\
-org.eclipse.rap.fileupload.*;version="3.10",\
-org.eclipse.rap.rwt.*;version="3.10"
-
-# Was !org.eclipse.core.commands,\ why ?
-
-#Bundle-Activator: org.argeo.eclipse.ui.ArgeoUiPlugin
-#Bundle-ActivationPolicy: lazy
-#Ignore-Package: org.eclipse.core.commands
\ No newline at end of file
+++ /dev/null
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/
+++ /dev/null
-package org.argeo.eclipse.ui.rcp.internal.rwt;
-
-import org.eclipse.rap.rwt.client.Client;
-import org.eclipse.rap.rwt.client.service.BrowserNavigation;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
-import org.eclipse.rap.rwt.client.service.ClientService;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-
-public class RcpClient implements Client {
-
- @Override
- public <T extends ClientService> T getService(Class<T> type) {
- if (type.isAssignableFrom(JavaScriptExecutor.class))
- return (T) javaScriptExecutor;
- else if (type.isAssignableFrom(BrowserNavigation.class))
- return (T) browserNavigation;
- else
- return null;
- }
-
- private JavaScriptExecutor javaScriptExecutor = new JavaScriptExecutor() {
-
- @Override
- public void execute(String code) {
- // TODO Auto-generated method stub
-
- }
- };
- private BrowserNavigation browserNavigation = new BrowserNavigation() {
-
- @Override
- public void pushState(String state, String title) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void addBrowserNavigationListener(
- BrowserNavigationListener listener) {
- // TODO Auto-generated method stub
-
- }
- };
-}
+++ /dev/null
-package org.argeo.eclipse.ui.rcp.internal.rwt;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.apache.commons.io.IOUtils;
-import org.eclipse.rap.rwt.service.ResourceManager;
-
-public class RcpResourceManager implements ResourceManager {
- private Map<String, byte[]> register = Collections
- .synchronizedMap(new TreeMap<String, byte[]>());
-
- @Override
- public void register(String name, InputStream in) {
- try {
- register.put(name, IOUtils.toByteArray(in));
- } catch (IOException e) {
- throw new RuntimeException("Cannot register " + name, e);
- }
- }
-
- @Override
- public boolean unregister(String name) {
- return register.remove(name) != null;
- }
-
- @Override
- public InputStream getRegisteredContent(String name) {
- return new ByteArrayInputStream(register.get(name));
- }
-
- @Override
- public String getLocation(String name) {
- return name;
- }
-
- @Override
- public boolean isRegistered(String name) {
- return register.containsKey(name);
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import java.awt.BorderLayout;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.image.BufferedImage;
-
-import javax.swing.JPanel;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.awt.SWT_AWT;
-import org.eclipse.swt.widgets.Composite;
-
-public class BufferedImageDisplay extends Composite {
- private BufferedImage image;
-
- public BufferedImageDisplay(Composite parent, int style) {
- super(parent, SWT.EMBEDDED | SWT.NO_BACKGROUND);
- Frame frame = SWT_AWT.new_Frame(this);
- frame.setLayout(new BorderLayout());
- frame.add(new JPanel() {
- private static final long serialVersionUID = 8924410573598922364L;
-
- public void paintComponent(Graphics g) {
- super.paintComponent(g);
- if (image != null)
- g.drawImage(image, 0, 0, this);
- }
-
- }, BorderLayout.CENTER);
- frame.setVisible(true);
- }
-
- public void setImage(BufferedImage image) {
- this.image = image;
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Shell;
-
-public class CmsFileDialog extends FileDialog {
- public CmsFileDialog(Shell parent, int style) {
- super(parent, style);
- }
-
- public CmsFileDialog(Shell parent) {
- super(parent);
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import org.eclipse.rap.rwt.widgets.FileUpload;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Composite;
-
-public class CmsFileUpload extends FileUpload {
- public CmsFileUpload(Composite parent, int style) {
- super(parent, style);
- }
-
- @Override
- public void setText(String text) {
- super.setText(text);
- }
-
- @Override
- public String getFileName() {
- return super.getFileName();
- }
-
- @Override
- public String[] getFileNames() {
- return super.getFileNames();
- }
-
- @Override
- public void addSelectionListener(SelectionListener listener) {
- super.addSelectionListener(listener);
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-/** RCP specific {@link NLS} to be extended */
-public class DefaultNLS {// extends NLS {
-// public final static String DEFAULT_BUNDLE_LOCATION = "/properties/plugin";
-//
-// public DefaultNLS() {
-// this(DEFAULT_BUNDLE_LOCATION);
-// }
-//
-// public DefaultNLS(String bundleName) {
-// NLS.initializeMessages(bundleName, getClass());
-// }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-/** Constants which are specific to RWT.*/
-public interface EclipseUiConstants {
- final static String CSS_CLASS = "org.eclipse.e4.ui.css.CssClassName";
- final static String MARKUP_SUPPORT = null;
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import org.eclipse.jface.viewers.ColumnViewer;
-import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.widgets.Widget;
-
-/** Static utilities to bridge differences between RCP and RAP */
-public class EclipseUiSpecificUtils {
- private final static String CSS_CLASS = "org.eclipse.e4.ui.css.CssClassName";
-
- public static void setStyleData(Widget widget, Object data) {
- widget.setData(CSS_CLASS, data);
- }
-
- public static Object getStyleData(Widget widget) {
- return widget.getData(CSS_CLASS);
- }
-
- public static void setMarkupData(Widget widget) {
- // does nothing
- }
-
- public static void setMarkupValidationDisabledData(Widget widget) {
- // does nothing
- }
-
- /**
- * TootlTip support is supported for {@link ColumnViewer} in RCP
- *
- * @see ColumnViewerToolTipSupport#enableFor(Viewer)
- */
- public static void enableToolTipSupport(Viewer viewer) {
- if (viewer instanceof ColumnViewer)
- ColumnViewerToolTipSupport.enableFor((ColumnViewer) viewer);
- }
-
- private EclipseUiSpecificUtils() {
- }
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-
-import org.eclipse.swt.dnd.DND;
-import org.eclipse.swt.dnd.DropTarget;
-import org.eclipse.swt.dnd.DropTargetAdapter;
-import org.eclipse.swt.dnd.DropTargetEvent;
-import org.eclipse.swt.dnd.FileTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.widgets.Control;
-
-public class FileDropAdapter {
-
- public void prepareDropTarget(Control control, DropTarget dropTarget) {
- dropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() });
- dropTarget.addDropListener(new DropTargetAdapter() {
- @Override
- public void dropAccept(DropTargetEvent event) {
- if (!FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
- event.detail = DND.DROP_NONE;
- }
- }
-
- @Override
- public void drop(DropTargetEvent event) {
- handleFileDrop(control, event);
- }
- });
- }
-
- public void handleFileDrop(Control control, DropTargetEvent event) {
- String fileList[] = null;
- FileTransfer ft = FileTransfer.getInstance();
- if (ft.isSupportedType(event.currentDataType)) {
- fileList = (String[]) event.data;
- }
- System.out.println(Arrays.toString(fileList));
- }
-
- /** Executed in UI thread */
- protected void processUpload(InputStream in, String fileName, String contentType) throws IOException {
-
- }
-
-}
+++ /dev/null
-package org.argeo.eclipse.ui.specific;
-
-import java.util.Locale;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.swt.widgets.Display;
-
-/** Singleton class providing single sources infos about the UI context. */
-public class UiContext {
-
- public static HttpServletRequest getHttpRequest() {
- return null;
- }
-
- public static HttpServletResponse getHttpResponse() {
- return null;
- }
-
- public static Locale getLocale() {
- return Locale.getDefault();
- }
-
- public static void setLocale(Locale locale) {
- Locale.setDefault(locale);
- }
-
- /** Can always be null */
- @SuppressWarnings("unchecked")
- public static <T> T getData(String key) {
- Display display = getDisplay();
- if (display == null)
- return null;
- return (T) display.getData(key);
- }
-
- public static void setData(String key, Object value) {
- Display display = getDisplay();
- if (display == null)
- throw new IllegalStateException("Not display available");
- display.setData(key, value);
- }
-
- private static Display getDisplay() {
- return Display.getCurrent();
- }
-
- private UiContext() {
- }
-
-}
+++ /dev/null
-package org.eclipse.rap.fileupload;
-
-public interface FileDetails {
- String getContentType();
-
- long getContentLength();
-
- String getFileName();
-}
+++ /dev/null
-package org.eclipse.rap.fileupload;
-
-import java.util.EventObject;
-
-public abstract class FileUploadEvent extends EventObject {
-
- private static final long serialVersionUID = 1L;
-
- protected FileUploadEvent(FileUploadHandler source) {
- super(source);
- }
-
- public abstract FileDetails[] getFileDetails();
-
- public abstract long getContentLength();
-
- public abstract long getBytesRead();
-
- public abstract Exception getException();
-
-}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2011, 2012 EclipseSource and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * EclipseSource - initial API and implementation
- ******************************************************************************/
-package org.eclipse.rap.fileupload;
-
-/**
- * A file upload handler is used to accept file uploads from a client. After
- * creating a file upload handler, the server will accept file uploads to the
- * URL returned by <code>getUploadUrl()</code>. Upload listeners can be attached
- * to react on progress. When the upload has finished, a FileUploadHandler has
- * to be disposed of by calling its <code>dispose()</code> method.
- *
- * @noextend This class is not intended to be subclassed by clients.
- */
-public class FileUploadHandler {
-
- public FileUploadHandler(FileUploadReceiver fileUploadReceiver) {
- }
-
- public void dispose() {
-
- }
-
- public void addUploadListener(FileUploadListener listener) {
-
- }
-
- public String getUploadUrl() {
- return null;
- }
-}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2011, 2012 EclipseSource and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * EclipseSource - initial API and implementation
- ******************************************************************************/
-package org.eclipse.rap.fileupload;
-
-import org.eclipse.swt.widgets.Display;
-
-
-/**
- * Listener to react on progress and completion of a file upload.
- * <p>
- * <strong>Note:</strong> This listener will be called from a different thread than the UI thread.
- * Implementations must use {@link Display#asyncExec(Runnable)} to access the UI.
- * </p>
- *
- * @see FileUploadEvent
- */
-public interface FileUploadListener {
-
- /**
- * Called when new information about an in-progress upload is available.
- *
- * @param event event object that contains information about the uploaded file
- * @see FileUploadEvent#getBytesRead()
- */
- void uploadProgress( FileUploadEvent event );
-
- /**
- * Called when a file upload has finished successfully.
- *
- * @param event event object that contains information about the uploaded file
- * @see FileUploadEvent
- */
- void uploadFinished( FileUploadEvent event );
-
- /**
- * Called when a file upload failed.
- *
- * @param event event object that contains information about the uploaded file
- * @see FileUploadEvent#getErrorMessage()
- */
- void uploadFailed( FileUploadEvent event );
-
-}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2011, 2013 EclipseSource and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * EclipseSource - initial API and implementation
- ******************************************************************************/
-package org.eclipse.rap.fileupload;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-
-/**
- * Instances of this interface are responsible for reading and processing the data from a file
- * upload.
- */
-public abstract class FileUploadReceiver {
-
- /**
- * Reads and processes all data from the provided input stream.
- *
- * @param stream the stream to read from
- * @param details the details of the uploaded file like file name, content-type and size
- * @throws IOException if an input / output error occurs
- */
- public abstract void receive( InputStream stream, FileDetails details ) throws IOException;
-
-}
+++ /dev/null
-package org.eclipse.rap.rwt;
-
-import java.util.Locale;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.argeo.eclipse.ui.rcp.internal.rwt.RcpClient;
-import org.argeo.eclipse.ui.rcp.internal.rwt.RcpResourceManager;
-import org.eclipse.rap.rwt.client.Client;
-import org.eclipse.rap.rwt.service.ResourceManager;
-
-public class RWT {
- public final static String CUSTOM_VARIANT = "argeo-rcp:CUSTOM_VARIANT";
- public final static String MARKUP_ENABLED = "argeo-rcp:MARKUP_ENABLED";
- public static final String TOOLTIP_MARKUP_ENABLED = "argeo-rcp:TOOLTIP_MARKUP_ENABLED";
- public final static String CUSTOM_ITEM_HEIGHT = "argeo-rcp:CUSTOM_ITEM_HEIGHT";
- public final static String ACTIVE_KEYS = "argeo-rcp:ACTIVE_KEYS";
- public final static String CANCEL_KEYS = "argeo-rcp:CANCEL_KEYS";
- public final static String DEFAULT_THEME_ID = "argeo-rcp:DEFAULT_THEME_ID";
-
- public final static int HYPERLINK = 0;
-
- private static Locale locale = Locale.getDefault();
- private static RcpClient client = new RcpClient();
- private static ResourceManager resourceManager = new RcpResourceManager();
- static {
-
- }
-
- public static Locale getLocale() {
- return locale;
- }
-
- public static HttpServletRequest getRequest() {
- return null;
- }
-
- public static ResourceManager getResourceManager() {
- return resourceManager;
- }
-
- public static Client getClient() {
- return client;
- }
-}
+++ /dev/null
-package org.eclipse.rap.rwt;
-
-public class SingletonUtil {
- public static <T> T getSessionInstance(Class<T> clss) {
- return null;
- }
-}
+++ /dev/null
-package org.eclipse.rap.rwt.application;
-
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-public abstract class AbstractEntryPoint implements EntryPoint {
- private Display display;
- private Shell shell;
-
- protected Shell createShell(Display display) {
- return new Shell(display);
- }
-
- protected void createContents(Composite parent) {
-
- }
-
- public int createUI() {
- display = new Display();
- shell = createShell(display);
- shell.setLayout(new GridLayout(1, false));
- createContents(shell);
- if (shell.getMaximized()) {
- shell.layout();
- } else {
- shell.pack();
- }
- shell.open();
- while (!shell.isDisposed()) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
- display.dispose();
- return 0;
- }
-
- protected Shell getShell() {
- return shell;
- }
-}
+++ /dev/null
-package org.eclipse.rap.rwt.application;
-
-import java.util.Map;
-
-import org.eclipse.rap.rwt.service.ResourceLoader;
-
-public interface Application {
- public static enum OperationMode {
- JEE_COMPATIBILITY, SWT_COMPATIBILITY,
- }
-
- void setOperationMode(OperationMode operationMode);
-
- void addResource(String name, ResourceLoader resourceLoader);
-
- void setExceptionHandler(ExceptionHandler exceptionHandler);
-
- void addEntryPoint(String path, EntryPointFactory entryPointFactory,
- Map<String, String> properties);
-
- void addEntryPoint(String path, Class<? extends EntryPoint> entryPoint,
- Map<String, String> properties);
-
- void addStyleSheet(String themeId, String styleSheetLocation,
- ResourceLoader resourceLoader);
-
-}
+++ /dev/null
-package org.eclipse.rap.rwt.application;
-
-public interface ApplicationConfiguration {
- void configure(Application application);
-}
+++ /dev/null
-package org.eclipse.rap.rwt.application;
-
-public interface EntryPoint {
- int createUI();
-}
+++ /dev/null
-package org.eclipse.rap.rwt.application;
-
-public interface EntryPointFactory {
- public EntryPoint create();
-}
+++ /dev/null
-package org.eclipse.rap.rwt.application;
-
-public interface ExceptionHandler {
- public void handleException(Throwable throwable);
-}
+++ /dev/null
-package org.eclipse.rap.rwt.client;
-
-import java.io.Serializable;
-
-import org.eclipse.rap.rwt.client.service.ClientService;
-
-public interface Client extends Serializable {
-
- /**
- * Returns this client's implementation of a given service, if available.
- *
- * @param type the type of the requested service, must be a subtype of ClientService
- * @return the requested service if provided by this client, otherwise <code>null</code>
- * @see ClientService
- */
- <T extends ClientService> T getService( Class<T> type );
-
-}
\ No newline at end of file
+++ /dev/null
-package org.eclipse.rap.rwt.client;
-
-public interface WebClient {
- public final static String FAVICON = "rcp:FAVICON";
- public final static String PAGE_TITLE = "rcp:PAGE_TITLE";
- public final static String BODY_HTML = "rcp:BODY_HTML";
- public final static String THEME_ID = "rcp:THEME_ID";
- public final static String HEAD_HTML = "rcp:HEAD_HTML";
- public final static String PAGE_OVERFLOW = "rcp:PAGE_OVERFLOW";
-}
+++ /dev/null
-package org.eclipse.rap.rwt.client.service;
-
-public interface BrowserNavigation extends ClientService {
- void pushState(String state, String title);
-
- void addBrowserNavigationListener(BrowserNavigationListener listener);
-}
+++ /dev/null
-package org.eclipse.rap.rwt.client.service;
-
-public class BrowserNavigationEvent {
- private String state;
-
- public String getState() {
- return state;
- }
-
-}
+++ /dev/null
-package org.eclipse.rap.rwt.client.service;
-
-public interface BrowserNavigationListener {
- public void navigated(BrowserNavigationEvent event);
-}
+++ /dev/null
-package org.eclipse.rap.rwt.client.service;
-
-import java.io.Serializable;
-
-public interface ClientService extends Serializable {
-}
+++ /dev/null
-package org.eclipse.rap.rwt.client.service;
-
-public interface JavaScriptExecutor extends ClientService {
- public void execute( String code );
-}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2012 EclipseSource and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * EclipseSource - initial API and implementation
- ******************************************************************************/
-package org.eclipse.rap.rwt.client.service;
-
-/**
- * The UrlLauncher service allows loading an URL in an external window, application or save dialog.
- *
- * @since 2.0
- * @noimplement This interface is not intended to be implemented by clients.
- */
-public interface UrlLauncher extends ClientService {
-
- /**
- * Opens the given URL.
- *
- * Any HTTP URL or relative URL will be opened in a new window.
- * Modern browser may block any attempt to open new windows, but will usually prompt the user to
- * accept or ignore. Even if accepted, the decision may be applied to only this attempt, or only
- * to future attempts. It could also trigger a document reload, causing a session restart.
- *
- * Non-HTTP URLs like "mailto" will not create a new browser window, but require the client
- * to have a matching protocol handler registered.
- *
- * @param url the URL to open
- */
- void openURL( String url );
-
-}
+++ /dev/null
-package org.eclipse.rap.rwt.service;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public interface ResourceLoader {
- public InputStream getResourceAsStream(String resourceName)
- throws IOException;
-}
+++ /dev/null
-package org.eclipse.rap.rwt.service;
-
-import java.io.InputStream;
-
-public interface ResourceManager {
- public void register(String name, InputStream in);
-
- boolean unregister(String name);
-
- public InputStream getRegisteredContent(String name);
-
- public String getLocation(String name);
-
- public boolean isRegistered(String name);
-}
+++ /dev/null
-package org.eclipse.rap.rwt.service;
-
-/** Mock, does nothing as this is irrelevant for RCP. */
-public class ServerPushSession {
- public void start() {
-
- }
-
- public void stop() {
-
- }
-}
+++ /dev/null
-package org.eclipse.rap.rwt.widgets;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Widget;
-
-public class DropDown {
- private boolean visible=false;
-
- public DropDown(Widget parent, int style) {
- // FIXME implement a shell
- }
-
- public DropDown(Widget parent) {
- this(parent, SWT.NONE);
- }
-
- public void setVisible(boolean visible) {
- this.visible = visible;
- }
-
- public boolean isVisible() {
- return visible;
- }
-
- public void setItems( String[] items ) {
-
- }
-
- public void setSelectionIndex( int selection ) {
-
- }
-
-}
+++ /dev/null
-package org.eclipse.rap.rwt.widgets;
-
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-
-public class FileUpload extends Composite {
-
- public FileUpload(Composite parent, int style) {
- super(parent, style);
- }
-
- public void addSelectionListener(SelectionListener listener) {
-
- }
-
- public void submit(String url) {
-
- }
-
- public void setImage(Image image) {
-
- }
-
- public void setText(String text) {
-
- }
-
- public String getFileName() {
- return null;
- }
-
- public String[] getFileNames() {
- return null;
- }
-
-}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.e4</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default CallbackHandler">
+ <implementation class="org.argeo.cms.swt.auth.DynamicCallbackHandler"/>
+ <service>
+ <provide interface="javax.security.auth.callback.CallbackHandler"/>
+ </service>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="Home Repository">
+ <implementation class="org.argeo.cms.e4.OsgiFilterContextFunction"/>
+ <property name="service.context.key" type="String" value="(cn=home)"/>
+ <service>
+ <provide interface="org.eclipse.e4.core.contexts.IContextFunction"/>
+ </service>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="User Admin Wrapper">
+ <implementation class="org.argeo.cms.e4.users.UserAdminWrapper"/>
+ <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.util.transaction.WorkTransaction" name="UserTransaction" policy="static"/>
+ <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
+ <service>
+ <provide interface="org.argeo.cms.e4.users.UserAdminWrapper"/>
+ </service>
+ <reference bind="addUserDirectory" cardinality="0..n" interface="org.argeo.osgi.useradmin.UserDirectory" name="UserDirectory" policy="static" unbind="removeUserDirectory"/>
+</scr:component>
--- /dev/null
+Service-Component: OSGI-INF/homeRepository.xml,\
+OSGI-INF/userAdminWrapper.xml,\
+OSGI-INF/defaultCallbackHandler.xml
+Bundle-ActivationPolicy: lazy
+
+Import-Package: \
+org.argeo.api.acr,\
+org.eclipse.swt,\
+org.eclipse.swt.widgets;version="0.0.0",\
+org.eclipse.e4.ui.model.application.ui,\
+org.eclipse.e4.ui.model.application,\
+javax.jcr.nodetype,\
+org.argeo.cms,\
+org.eclipse.core.commands.common,\
+org.eclipse.jface.window,\
+org.argeo.cms.swt.auth,\
+org.apache.jackrabbit.*;version="[2,3)",\
+javax.servlet.*;version="[3,5)",\
+*
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ OSGI-INF/,\
+ .,\
+ OSGI-INF/homeRepository.xml,\
+ OSGI-INF/userAdminWrapper.xml,\
+ OSGI-INF/defaultCallbackHandler.xml,\
+ e4xmi/cms-demo.e4xmi
+source.. = src/
--- /dev/null
+<?xml version="1.0" encoding="ASCII"?>
+<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:advanced="http://www.eclipse.org/ui/2010/UIModel/application/ui/advanced" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_XqkCQKknEeObFrG_clJBYA" elementId="">
+ <children xsi:type="basic:TrimmedWindow" xmi:id="_Zdy6cKknEeObFrG_clJBYA" elementId="org.argeo.cms.e4.apps.admin.trimmedwindow.0" label="" x="10" y="10" width="500" height="500">
+ <persistedState key="styleOverride" value="8"/>
+ <tags>shellMaximized</tags>
+ <tags>auth.cn=admin,ou=roles,ou=node</tags>
+ <children xsi:type="advanced:PerspectiveStack" xmi:id="_jXVqsCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.perspectivestack.0" selectedElement="_xOVlsDvOEeiF1foPJZSZkw">
+ <children xsi:type="advanced:Perspective" xmi:id="_xOVlsDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.perspective.users" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png">
+ <tags>auth.cn=admin,ou=roles,ou=node</tags>
+ <children xsi:type="basic:PartSashContainer" xmi:id="_1tQoEDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partsashcontainer.2" horizontal="true">
+ <children xsi:type="basic:PartStack" xmi:id="_vtbKkDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.4" containerData="4000" selectedElement="_9gukYDvOEeiF1foPJZSZkw">
+ <children xsi:type="basic:Part" xmi:id="_9gukYDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.part.users" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.UsersView" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/person.png">
+ <handlers xmi:id="_0mN68DvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.4" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.handlers.NewUser" command="_uL5i4DvjEeiF1foPJZSZkw"/>
+ <handlers xmi:id="_ODLdgDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.5" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.handlers.DeleteUsers" command="_xkcMADvjEeiF1foPJZSZkw"/>
+ <toolbar xmi:id="_jLWmkDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.toolbar.1">
+ <children xsi:type="menu:HandledToolItem" xmi:id="_jy_OUDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.new" label="New" iconURI="platform:/plugin/org.argeo.cms.swt/icons/add.png" command="_uL5i4DvjEeiF1foPJZSZkw"/>
+ <children xsi:type="menu:HandledToolItem" xmi:id="_9qszMDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/delete.png" command="_xkcMADvjEeiF1foPJZSZkw"/>
+ </toolbar>
+ </children>
+ </children>
+ <children xsi:type="basic:PartStack" xmi:id="__g1a8DvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.3" containerData="4000">
+ <tags>usersEditorArea</tags>
+ </children>
+ <children xsi:type="basic:PartStack" xmi:id="_-mFn8DvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.5" containerData="2000">
+ <children xsi:type="basic:Part" xmi:id="_6etk4DvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.part.groups" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.GroupsView" label="Groups" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png">
+ <handlers xmi:id="_cmShoDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.6" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.handlers.NewGroup" command="_uL5i4DvjEeiF1foPJZSZkw"/>
+ <handlers xmi:id="_fbYfcDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.7" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.handlers.DeleteGroups" command="_xkcMADvjEeiF1foPJZSZkw"/>
+ <toolbar xmi:id="_Us0rADvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.toolbar.2">
+ <children xsi:type="menu:HandledToolItem" xmi:id="_VQTLgDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.new" label="New" iconURI="platform:/plugin/org.argeo.cms.swt/icons/add.png" command="_uL5i4DvjEeiF1foPJZSZkw"/>
+ <children xsi:type="menu:HandledToolItem" xmi:id="_XfME8DvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/delete.png" command="_xkcMADvjEeiF1foPJZSZkw"/>
+ </toolbar>
+ </children>
+ </children>
+ </children>
+ </children>
+ <children xsi:type="advanced:Perspective" xmi:id="_jvjWYCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.perspective.data" label="Data" iconURI="platform:/plugin/org.argeo.cms.swt/icons/nodes.gif">
+ <children xsi:type="basic:PartSashContainer" xmi:id="_h3tvMCkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partsashcontainer.0" selectedElement="_0B9SECkxEein5vuhpK-Dew" horizontal="true">
+ <children xsi:type="basic:PartStack" xmi:id="_0B9SECkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.0" containerData="4000" selectedElement="_WAjPkCkTEein5vuhpK-Dew">
+ <children xsi:type="basic:Part" xmi:id="_WAjPkCkTEein5vuhpK-Dew" elementId="org.argeo.cms.e4.jcrbrowser" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR" iconURI="platform:/plugin/org.argeo.cms.swt/icons/browser.gif">
+ <menus xsi:type="menu:PopupMenu" xmi:id="_eXiUECqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.popupmenu.nodeViewer">
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_GVeO8CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.swt/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_fU238CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_U4o9cCqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.swt/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_Ncxo0CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.remove" label="Remove" iconURI="platform:/plugin/org.argeo.cms.swt/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
+ </menus>
+ <menus xmi:id="_oRg_ACqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.menu.0">
+ <tags>ViewMenu</tags>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_yJR8ECqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.swt/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_o6HQECqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_5D7aACqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.swt/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_7rR2wCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_XsHLgFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledmenuitem.0" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addRepo.gif" command="_ZWpasFgQEeiknZQLx-vtnA"/>
+ </menus>
+ </children>
+ </children>
+ <children xsi:type="basic:PartStack" xmi:id="_mHrEUCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.1" containerData="6000">
+ <tags>dataExplorer</tags>
+ </children>
+ </children>
+ </children>
+ <children xsi:type="advanced:Perspective" xmi:id="_u5ZakFhJEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.perspective.monitoring" label="Monitoring" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif">
+ <children xsi:type="basic:PartStack" xmi:id="_7i7t8FhJEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.partstack.6">
+ <children xsi:type="basic:Part" xmi:id="_Z-3cMFhbEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.osgiConfigurations" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.OsgiConfigurationsView" label="OSGi Configurations" iconURI="platform:/plugin/org.argeo.cms.swt/icons/node.gif"/>
+ <children xsi:type="basic:Part" xmi:id="_8dM90FhJEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.cmsSessions" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.CmsSessionsView" label="CMS Sessions" iconURI="platform:/plugin/org.argeo.cms.swt/icons/person-logged-in.png"/>
+ <children xsi:type="basic:Part" xmi:id="_KqRZIFhNEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.modules" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.ModulesView" label="Modules" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif"/>
+ <children xsi:type="basic:Part" xmi:id="_dXtIoFhNEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.bundles" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.BundlesView" label="Bundles" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif"/>
+ </children>
+ </children>
+ <children xsi:type="advanced:Perspective" xmi:id="_ABK2ADsNEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.perspective.files" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif">
+ <children xsi:type="basic:PartSashContainer" xmi:id="_FPimEDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.partsashcontainer.1" horizontal="true">
+ <children xsi:type="basic:PartStack" xmi:id="_H93NgDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.partstack.2" containerData="4000">
+ <children xsi:type="basic:Part" xmi:id="_Izxh0DsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.part.files" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.files.NodeFsBrowserView" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif"/>
+ </children>
+ <children xsi:type="basic:Part" xmi:id="_TMqBMDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.part.0" containerData="6000"/>
+ </children>
+ </children>
+ </children>
+ <handlers xmi:id="_Vwax0DvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.8" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.OpenPerspective" command="_AF1UsDvrEeiF1foPJZSZkw"/>
+ <trimBars xmi:id="_euVxMCk2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.trimbar.0" side="Left">
+ <children xsi:type="menu:ToolBar" xmi:id="_fotHsCk2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.toolbar.0">
+ <children xsi:type="menu:HandledToolItem" xmi:id="_jCSQgDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.users" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png" command="_AF1UsDvrEeiF1foPJZSZkw">
+ <tags>auth.cn=admin,ou=roles,ou=node</tags>
+ <parameters xmi:id="_lu_uYDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.2" name="perspectiveId" value="org.argeo.cms.e4.perspective.users"/>
+ </children>
+ <children xsi:type="menu:HandledToolItem" xmi:id="_jfUM4Ck2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.handledtoolitem.test" label="Data" iconURI="platform:/plugin/org.argeo.cms.swt/icons/nodes.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
+ <parameters xmi:id="_KDlXQDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.0" name="perspectiveId" value="org.argeo.cms.e4.perspective.data"/>
+ </children>
+ <children xsi:type="menu:HandledToolItem" xmi:id="_dhv80FhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledtoolitem.monitoring" label="Monitoring" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
+ <parameters xmi:id="_kjN0cFhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.parameter.3" name="perspectiveId" value="org.argeo.cms.e4.perspective.monitoring"/>
+ </children>
+ <children xsi:type="menu:HandledToolItem" xmi:id="_b0OHUDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.files" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
+ <parameters xmi:id="_fXvRYDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.1" name="perspectiveId" value="org.argeo.cms.e4.perspective.files"/>
+ </children>
+ <children xsi:type="menu:ToolBarSeparator" xmi:id="_wuoL8FhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.toolbarseparator.0"/>
+ <children xsi:type="menu:HandledToolItem" xmi:id="_2v8DkFhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledtoolitem.logout" label="Log out" iconURI="platform:/plugin/org.argeo.cms.swt/icons/logout.png" command="_PsWd0FhLEeiknZQLx-vtnA"/>
+ </children>
+ </trimBars>
+ </children>
+ <handlers xmi:id="_Xp-P4CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.0" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.AddFolderNode" command="_RgE5cCqREeidr6NYQH6GbQ"/>
+ <handlers xmi:id="_jbnNwCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.1" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.DeleteNodes" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
+ <handlers xmi:id="_loxB0CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.2" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.Refresh" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
+ <handlers xmi:id="_omPfkCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.3" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.RenameNode" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
+ <handlers xmi:id="_dUg-cFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.9" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.AddRemoteRepository" command="_ZWpasFgQEeiknZQLx-vtnA"/>
+ <handlers xmi:id="_RQyFAFhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.10" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.CloseWorkbench" command="_PsWd0FhLEeiknZQLx-vtnA"/>
+ <descriptors xmi:id="_XzfoMCqlEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.partdescriptor.nodeEditor" label="Node Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/node.gif" allowMultiple="true" category="dataExplorer" closeable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrNodeEditor"/>
+ <descriptors xmi:id="_sAdNwDvdEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partdescriptor.userEditor" label="User Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/person.png" allowMultiple="true" category="usersEditorArea" closeable="true" dirtyable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.UserEditor"/>
+ <descriptors xmi:id="_5nK7EDvdEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partdescriptor.groupEditor" label="Group Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png" allowMultiple="true" category="usersEditorArea" closeable="true" dirtyable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.users.GroupEditor"/>
+ <commands xmi:id="_RgE5cCqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.addFolderNode" commandName="Add folder node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
+ <commands xmi:id="_ChJ-4CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.deleteNodes" commandName="Delete nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
+ <commands xmi:id="_TOKHsCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.refreshNodes" commandName="Refresh nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
+ <commands xmi:id="_ZrcUMCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.renameNode" commandName="Rename node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
+ <commands xmi:id="_uL5i4DvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.add" commandName="Add"/>
+ <commands xmi:id="_xkcMADvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.delete" commandName="Delete"/>
+ <commands xmi:id="_AF1UsDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.openPerspective" commandName="Open Perspective">
+ <parameters xmi:id="_F3WAUDvrEeiF1foPJZSZkw" elementId="perspectiveId" name="Perspective Id" optional="false"/>
+ </commands>
+ <commands xmi:id="_ZWpasFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.addRemoteRepository" commandName="Add Remote Repository"/>
+ <commands xmi:id="_PsWd0FhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.logout" commandName="Log out"/>
+ <addons xmi:id="_XqkCQaknEeObFrG_clJBYA" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
+ <addons xmi:id="_XqkCQqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
+ <addons xmi:id="_XqkCQ6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
+ <addons xmi:id="_XqkCRKknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
+ <addons xmi:id="_XqkCRaknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
+ <addons xmi:id="_XqkCRqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
+ <addons xmi:id="_XqkCR6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
+ <addons xmi:id="_8VnK8OdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.locale" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.LocaleAddon"/>
+ <addons xmi:id="_-xeJYOdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.auth" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.AuthAddon"/>
+ <categories xmi:id="_MDkwUCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.category.jcrBrowser" name="JCR Browser"/>
+</application:Application>
--- /dev/null
+<?xml version="1.0" encoding="ASCII"?>
+<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_XqkCQKknEeObFrG_clJBYA" elementId="">
+ <children xsi:type="basic:TrimmedWindow" xmi:id="_Zdy6cKknEeObFrG_clJBYA" elementId="org.argeo.cms.e4.apps.admin.trimmedwindow.0" label="" x="10" y="10" width="500" height="500">
+ <persistedState key="styleOverride" value="8"/>
+ <tags>shellMaximized</tags>
+ <tags>auth.cn=user,ou=roles,ou=node</tags>
+ <children xsi:type="basic:PartSashContainer" xmi:id="_h3tvMCkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partsashcontainer.0" selectedElement="_0B9SECkxEein5vuhpK-Dew" horizontal="true">
+ <children xsi:type="basic:PartStack" xmi:id="_0B9SECkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.0" containerData="4000" selectedElement="_WAjPkCkTEein5vuhpK-Dew">
+ <children xsi:type="basic:Part" xmi:id="_WAjPkCkTEein5vuhpK-Dew" elementId="org.argeo.cms.e4.jcrbrowser" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/browser.gif">
+ <menus xsi:type="menu:PopupMenu" xmi:id="_eXiUECqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.popupmenu.nodeViewer">
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_GVeO8CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_fU238CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_U4o9cCqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_Ncxo0CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.remove" label="Remove" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
+ </menus>
+ <menus xmi:id="_oRg_ACqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.menu.0">
+ <tags>ViewMenu</tags>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_yJR8ECqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_o6HQECqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_5D7aACqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_7rR2wCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_XsHLgFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledmenuitem.0" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/addRepo.gif" command="_ZWpasFgQEeiknZQLx-vtnA"/>
+ </menus>
+ </children>
+ </children>
+ <children xsi:type="basic:PartStack" xmi:id="_mHrEUCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.1" containerData="6000">
+ <tags>dataExplorer</tags>
+ <children xsi:type="basic:Part" xmi:id="_LyT80MKKEeqaPNgZ5fEKYw" elementId="org.argeo.cms.e4.part.egoDashboard" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.parts.EgoDashboard" label="" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/home.png">
+ <toolbar xmi:id="_Ut8wMMKMEeqaPNgZ5fEKYw" elementId="org.argeo.cms.e4.toolbar.0">
+ <children xsi:type="menu:HandledToolItem" xmi:id="_nElwUMKMEeq1Ytjq4ALs6g" elementId="org.argeo.cms.e4.handledtoolitem.changepassword" label="Change password" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/actions/edit.png" command="_jEjCUMKMEeq1Ytjq4ALs6g"/>
+ <children xsi:type="menu:HandledToolItem" xmi:id="_WAD4UMKMEeqaPNgZ5fEKYw" elementId="org.argeo.cms.e4.handledtoolitem.logout" label="Log out" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/logout.png" command="_PsWd0FhLEeiknZQLx-vtnA"/>
+ </toolbar>
+ </children>
+ </children>
+ </children>
+ </children>
+ <handlers xmi:id="_Xp-P4CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.0" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.AddFolderNode" command="_RgE5cCqREeidr6NYQH6GbQ"/>
+ <handlers xmi:id="_jbnNwCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.1" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.DeleteNodes" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
+ <handlers xmi:id="_loxB0CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.2" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.Refresh" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
+ <handlers xmi:id="_omPfkCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.3" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.RenameNode" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
+ <handlers xmi:id="_dUg-cFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.9" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.handlers.AddRemoteRepository" command="_ZWpasFgQEeiknZQLx-vtnA"/>
+ <handlers xmi:id="_RQyFAFhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.logout" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.CloseWorkbench" command="_PsWd0FhLEeiknZQLx-vtnA"/>
+ <handlers xmi:id="_lN4GUMKMEeq1Ytjq4ALs6g" elementId="org.argeo.suite.e4.handler.changePassword" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.ChangePassword" command="_jEjCUMKMEeq1Ytjq4ALs6g"/>
+ <descriptors xmi:id="_XzfoMCqlEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.partdescriptor.nodeEditor" label="Node Editor" iconURI="platform:/plugin/org.argeo.cms.ui.theme/icons/node.gif" allowMultiple="true" category="dataExplorer" closeable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrNodeEditor"/>
+ <commands xmi:id="_RgE5cCqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.addFolderNode" commandName="Add folder node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
+ <commands xmi:id="_ChJ-4CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.deleteNodes" commandName="Delete nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
+ <commands xmi:id="_TOKHsCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.refreshNodes" commandName="Refresh nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
+ <commands xmi:id="_ZrcUMCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.renameNode" commandName="Rename node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
+ <commands xmi:id="_uL5i4DvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.add" commandName="Add"/>
+ <commands xmi:id="_xkcMADvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.delete" commandName="Delete"/>
+ <commands xmi:id="_AF1UsDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.openPerspective" commandName="Open Perspective">
+ <parameters xmi:id="_F3WAUDvrEeiF1foPJZSZkw" elementId="perspectiveId" name="Perspective Id" optional="false"/>
+ </commands>
+ <commands xmi:id="_ZWpasFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.addRemoteRepository" commandName="Add Remote Repository"/>
+ <commands xmi:id="_PsWd0FhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.logout" commandName="Log out"/>
+ <commands xmi:id="_jEjCUMKMEeq1Ytjq4ALs6g" elementId="org.argeo.cms.e4.command.changePassword" commandName="Change Password"/>
+ <addons xmi:id="_XqkCQaknEeObFrG_clJBYA" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
+ <addons xmi:id="_XqkCQqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
+ <addons xmi:id="_XqkCQ6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
+ <addons xmi:id="_XqkCRKknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
+ <addons xmi:id="_XqkCRaknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
+ <addons xmi:id="_XqkCRqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
+ <addons xmi:id="_XqkCR6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
+ <addons xmi:id="_8VnK8OdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.locale" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.LocaleAddon"/>
+ <addons xmi:id="_-xeJYOdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.auth" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.AuthAddon"/>
+ <categories xmi:id="_MDkwUCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.category.jcrBrowser" name="JCR Browser"/>
+</application:Application>
--- /dev/null
+package org.argeo.cms.e4;
+
+import java.util.List;
+
+import org.argeo.cms.swt.CmsException;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+/** Static utilities simplifying recurring Eclipse 4 patterns. */
+public class CmsE4Utils {
+ /** Open an editor based on its id. */
+ public static void openEditor(EPartService partService, String editorId, String key, String state) {
+ for (MPart part : partService.getParts()) {
+ String id = part.getPersistedState().get(key);
+ if (id != null && state.equals(id)) {
+ partService.showPart(part, PartState.ACTIVATE);
+ return;
+ }
+ }
+
+ // new part
+ MPart part = partService.createPart(editorId);
+ if (part == null)
+ throw new CmsException("No editor found with id " + editorId);
+ part.getPersistedState().put(key, state);
+ partService.showPart(part, PartState.ACTIVATE);
+ }
+
+ /** Dynamically creates an handled menu item from a command ID. */
+ public static MHandledMenuItem createHandledMenuItem(EModelService modelService, MApplication app,
+ String commandId) {
+ MCommand command = findCommand(modelService, app, commandId);
+ if (command == null)
+ return null;
+ MHandledMenuItem handledItem = modelService.createModelElement(MHandledMenuItem.class);
+ handledItem.setCommand(command);
+ return handledItem;
+
+ }
+
+ /**
+ * Finds a command by ID.
+ *
+ * @return the {@link MCommand} or <code>null</code> if not found.
+ */
+ public static MCommand findCommand(EModelService modelService, MApplication app, String commandId) {
+ List<MCommand> cmds = modelService.findElements(app, null, MCommand.class, null);
+ for (MCommand cmd : cmds) {
+ if (cmd.getElementId().equals(commandId)) {
+ return cmd;
+ }
+ }
+ return null;
+ }
+
+ /** Dynamically creates a direct menu item from a class. */
+ public static MDirectMenuItem createDirectMenuItem(EModelService modelService, Class<?> clss, String label) {
+ MDirectMenuItem dynamicItem = modelService.createModelElement(MDirectMenuItem.class);
+ dynamicItem.setLabel(label);
+ Bundle bundle = FrameworkUtil.getBundle(clss);
+ dynamicItem.setContributionURI("bundleclass://" + bundle.getSymbolicName() + "/" + clss.getName());
+ return dynamicItem;
+ }
+
+ /** Singleton. */
+ private CmsE4Utils() {
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4;
+
+import org.argeo.cms.swt.CmsException;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.IInjector;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/** An Eclipse 4 {@link ContextFunction} based on an OSGi filter. */
+public class OsgiFilterContextFunction extends ContextFunction {
+
+ private BundleContext bc = FrameworkUtil.getBundle(OsgiFilterContextFunction.class).getBundleContext();
+
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ ServiceReference<?>[] srs;
+ try {
+ srs = bc.getServiceReferences((String) null, contextKey);
+ } catch (InvalidSyntaxException e) {
+ throw new CmsException("Context key " + contextKey + " must be a valid osgi filter", e);
+ }
+ if (srs == null || srs.length == 0) {
+ return IInjector.NOT_A_VALUE;
+ } else {
+ // return the first one
+ return bc.getService(srs[0]);
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import javax.security.auth.Subject;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * Propagate authentication to an eclipse job. Typically to execute a privileged
+ * action outside the UI thread
+ */
+public abstract class PrivilegedJob extends Job {
+ private final Subject subject;
+
+ public PrivilegedJob(String jobName) {
+ this(jobName, AccessController.getContext());
+ }
+
+ public PrivilegedJob(String jobName,
+ AccessControlContext accessControlContext) {
+ super(jobName);
+ subject = Subject.getSubject(accessControlContext);
+
+ // Must be called *before* the job is scheduled,
+ // it is required for the progress window to appear
+ setUser(true);
+ }
+
+ @Override
+ protected IStatus run(final IProgressMonitor progressMonitor) {
+ PrivilegedAction<IStatus> privilegedAction = new PrivilegedAction<IStatus>() {
+ public IStatus run() {
+ return doRun(progressMonitor);
+ }
+ };
+ return Subject.doAs(subject, privilegedAction);
+ }
+
+ /**
+ * Implement here what should be executed with default context
+ * authentication
+ */
+ protected abstract IStatus doRun(IProgressMonitor progressMonitor);
+}
--- /dev/null
+package org.argeo.cms.e4.addons;
+
+import java.security.AccessController;
+import java.util.Iterator;
+
+import javax.annotation.PostConstruct;
+import javax.security.auth.Subject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsException;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+
+public class AuthAddon {
+ private final static CmsLog log = CmsLog.getLog(AuthAddon.class);
+
+ public final static String AUTH = "auth.";
+
+ @PostConstruct
+ void init(MApplication application) {
+ Iterator<MWindow> windows = application.getChildren().iterator();
+ boolean atLeastOneTopLevelWindowVisible = false;
+ windows: while (windows.hasNext()) {
+ MWindow window = windows.next();
+ // main window
+ boolean windowVisible = process(window);
+ if (!windowVisible) {
+// windows.remove();
+ continue windows;
+ }
+ atLeastOneTopLevelWindowVisible = true;
+ // trim bars
+ if (window instanceof MTrimmedWindow) {
+ Iterator<MTrimBar> trimBars = ((MTrimmedWindow) window).getTrimBars().iterator();
+ while (trimBars.hasNext()) {
+ MTrimBar trimBar = trimBars.next();
+ if (!process(trimBar)) {
+ trimBars.remove();
+ }
+ }
+ }
+ }
+
+ if (!atLeastOneTopLevelWindowVisible) {
+ log.warn("No top-level window is authorized for user " + CurrentUser.getUsername() + ", logging out..");
+ logout();
+ }
+ }
+
+ protected boolean process(MUIElement element) {
+ for (String tag : element.getTags()) {
+ if (tag.startsWith(AUTH)) {
+ String role = tag.substring(AUTH.length(), tag.length());
+ if (!CurrentUser.isInRole(role)) {
+ element.setVisible(false);
+ element.setToBeRendered(false);
+ return false;
+ }
+ }
+ }
+
+ // children
+ if (element instanceof MElementContainer) {
+ @SuppressWarnings("unchecked")
+ MElementContainer<? extends MUIElement> container = (MElementContainer<? extends MUIElement>) element;
+ Iterator<? extends MUIElement> children = container.getChildren().iterator();
+ while (children.hasNext()) {
+ MUIElement child = children.next();
+ boolean visible = process(child);
+ if (!visible)
+ children.remove();
+ }
+
+ for (Object child : container.getChildren()) {
+ if (child instanceof MUIElement) {
+ boolean visible = process((MUIElement) child);
+ if (!visible)
+ container.getChildren().remove(child);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ protected void logout() {
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ try {
+ CurrentUser.logoutCmsSession(subject);
+ } catch (Exception e) {
+ throw new CmsException("Cannot log out", e);
+ }
+ HttpServletRequest request = org.argeo.eclipse.ui.specific.UiContext.getHttpRequest();
+ if (request != null)
+ request.getSession().setMaxInactiveInterval(0);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.addons;
+
+import java.security.AccessController;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.annotation.PostConstruct;
+import javax.security.auth.Subject;
+
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.eclipse.e4.core.services.nls.ILocaleChangeService;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.ElementMatcher;
+import org.eclipse.swt.SWT;
+
+/** Integrate workbench with the locale provided at log in. */
+public class LocaleAddon {
+ private final static String STYLE_OVERRIDE = "styleOverride";
+
+ // Right to left languages
+ private final static String ARABIC = "ar";
+ private final static String HEBREW = "he";
+
+ @PostConstruct
+ public void init(ILocaleChangeService localeChangeService, EModelService modelService, MApplication application) {
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ Set<Locale> locales = subject.getPublicCredentials(Locale.class);
+ if (!locales.isEmpty()) {
+ Locale locale = locales.iterator().next();
+ localeChangeService.changeApplicationLocale(locale);
+ UiContext.setLocale(locale);
+
+ if (locale.getLanguage().equals(ARABIC) || locale.getLanguage().equals(HEBREW)) {
+ List<MWindow> windows = modelService.findElements(application, MWindow.class, EModelService.ANYWHERE,
+ new ElementMatcher(null, null, (String) null));
+ for (MWindow window : windows) {
+ String currentStyle = window.getPersistedState().get(STYLE_OVERRIDE);
+ int style = 0;
+ if (currentStyle != null) {
+ style = Integer.parseInt(currentStyle);
+ }
+ style = style | SWT.RIGHT_TO_LEFT;
+ window.getPersistedState().put(STYLE_OVERRIDE, Integer.toString(style));
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/** Eclipse 4 addons to integrate with Argeo CMS. */
+package org.argeo.cms.e4.addons;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.files;
+
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.spi.FileSystemProvider;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.eclipse.ui.fs.AdvancedFsBrowser;
+import org.argeo.eclipse.ui.fs.SimpleFsBrowser;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+
+/** Browse the node file system. */
+public class NodeFsBrowserView {
+ // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID +
+ // ".nodeFsBrowserView";
+
+ @Inject
+ FileSystemProvider nodeFileSystemProvider;
+
+ @PostConstruct
+ public void createPartControl(Composite parent) {
+ try {
+ //URI uri = new URI("node://root:demo@localhost:7070/");
+ URI uri = new URI("node:///");
+ FileSystem fileSystem = nodeFileSystemProvider.getFileSystem(uri);
+ if (fileSystem == null)
+ fileSystem = nodeFileSystemProvider.newFileSystem(uri, null);
+ Path nodePath = fileSystem.getPath("/");
+
+ Path localPath = Paths.get(System.getProperty("user.home"));
+
+ SimpleFsBrowser browser = new SimpleFsBrowser(parent, SWT.NO_FOCUS);
+ browser.setInput(nodePath, localPath);
+// AdvancedFsBrowser browser = new AdvancedFsBrowser();
+// browser.createUi(parent, localPath);
+ } catch (Exception e) {
+ throw new CmsException("Cannot open file system browser", e);
+ }
+ }
+
+ public void setFocus() {
+ }
+}
--- /dev/null
+/** Files browser perspective. */
+package org.argeo.cms.e4.files;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.handlers;
+
+import java.util.Locale;
+
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.services.nls.ILocaleChangeService;
+
+public class ChangeLanguage {
+ @Execute
+ public void execute(ILocaleChangeService localeChangeService) {
+ localeChangeService.changeApplicationLocale(Locale.FRENCH);
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.handlers;
+
+import static org.argeo.cms.CmsMsg.changePassword;
+import static org.argeo.cms.CmsMsg.currentPassword;
+import static org.argeo.cms.CmsMsg.newPassword;
+import static org.argeo.cms.CmsMsg.passwordChanged;
+import static org.argeo.cms.CmsMsg.repeatNewPassword;
+
+import java.util.Arrays;
+
+import javax.inject.Inject;
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.security.CryptoKeyring;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.swt.dialogs.CmsMessageDialog;
+import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
+import org.argeo.util.transaction.WorkTransaction;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/** Change the password of the logged-in user. */
+public class ChangePassword {
+ @Inject
+ private UserAdmin userAdmin;
+ @Inject
+ private WorkTransaction userTransaction;
+ @Inject
+ @Optional
+ private CryptoKeyring keyring = null;
+
+ @Execute
+ public void execute() {
+ ChangePasswordDialog dialog = new ChangePasswordDialog(Display.getCurrent().getActiveShell(), userAdmin);
+ if (dialog.open() == Dialog.OK) {
+ new CmsMessageDialog(Display.getCurrent().getActiveShell(), passwordChanged.lead(),
+ CmsMessageDialog.INFORMATION).open();
+ }
+ }
+
+ protected void changePassword(char[] oldPassword, char[] newPassword) {
+ String name = CurrentUser.getUsername();
+ LdapName dn;
+ try {
+ dn = new LdapName(name);
+ } catch (InvalidNameException e) {
+ throw new CmsException("Invalid user dn " + name, e);
+ }
+ User user = (User) userAdmin.getRole(dn.toString());
+ if (!user.hasCredential(null, oldPassword))
+ throw new CmsException("Invalid password");
+ if (Arrays.equals(newPassword, new char[0]))
+ throw new CmsException("New password empty");
+ try {
+ userTransaction.begin();
+ user.getCredentials().put(null, newPassword);
+ if (keyring != null) {
+ keyring.changePassword(oldPassword, newPassword);
+ // TODO change secret keys in the CMS session
+ }
+ userTransaction.commit();
+ } catch (Exception e) {
+ try {
+ userTransaction.rollback();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ if (e instanceof RuntimeException)
+ throw (RuntimeException) e;
+ else
+ throw new CmsException("Cannot change password", e);
+ }
+ }
+
+ class ChangePasswordDialog extends CmsMessageDialog {
+ private Text oldPassword, newPassword1, newPassword2;
+
+ public ChangePasswordDialog(Shell parentShell, UserAdmin securityService) {
+ super(parentShell, changePassword.lead(), CONFIRM);
+ }
+
+// protected Point getInitialSize() {
+// return new Point(400, 450);
+// }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite dialogarea = (Composite) super.createDialogArea(parent);
+ dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ Composite composite = new Composite(dialogarea, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ oldPassword = createLP(composite, currentPassword.lead());
+ newPassword1 = createLP(composite, newPassword.lead());
+ newPassword2 = createLP(composite, repeatNewPassword.lead());
+
+// parent.pack();
+ oldPassword.setFocus();
+ return composite;
+ }
+
+ @Override
+ protected void okPressed() {
+ try {
+ if (!newPassword1.getText().equals(newPassword2.getText()))
+ throw new CmsException("New passwords are different");
+ changePassword(oldPassword.getTextChars(), newPassword1.getTextChars());
+ closeShell(OK);
+ } catch (Exception e) {
+ ErrorFeedback.show("Cannot change password", e);
+ }
+ }
+
+ /** Creates label and password. */
+ protected Text createLP(Composite parent, String label) {
+ new Label(parent, SWT.NONE).setText(label);
+ Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD | SWT.BORDER);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ return text;
+ }
+
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.handlers;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+
+public class CloseAllParts {
+
+ @Execute
+ void execute(EPartService partService) {
+ for (MPart part : partService.getParts()) {
+ if (part.isCloseable()) {
+ if (part.isDirty()) {
+ if (partService.savePart(part, true)) {
+ partService.hidePart(part, true);
+ }
+ } else {
+ partService.hidePart(part, true);
+ }
+ }
+ }
+ }
+
+ @CanExecute
+ boolean canExecute(EPartService partService) {
+ boolean atLeastOnePart = false;
+ for (MPart part : partService.getParts()) {
+ if (part.isVisible() && part.isCloseable()) {
+ atLeastOnePart = true;
+ break;
+ }
+ }
+ return atLeastOnePart;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.handlers;
+
+import java.security.AccessController;
+
+import javax.security.auth.Subject;
+
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsException;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.workbench.IWorkbench;
+
+public class CloseWorkbench {
+ @Execute
+ public void execute(IWorkbench workbench) {
+ logout();
+ workbench.close();
+ }
+
+ protected void logout() {
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ try {
+ CurrentUser.logoutCmsSession(subject);
+ } catch (Exception e) {
+ throw new CmsException("Cannot log out", e);
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.handlers;
+
+import org.eclipse.e4.core.di.annotations.Execute;
+
+public class DoNothing {
+ @Execute
+ public void execute() {
+
+ }
+}
--- /dev/null
+
+package org.argeo.cms.e4.handlers;
+
+import java.util.Date;
+import java.util.List;
+
+import org.eclipse.e4.ui.di.AboutToHide;
+import org.eclipse.e4.ui.di.AboutToShow;
+import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+
+public class LanguageMenuContribution {
+ @AboutToShow
+ public void aboutToShow(List<MMenuElement> items, EModelService modelService) {
+ MDirectMenuItem dynamicItem = modelService.createModelElement(MDirectMenuItem.class);
+ dynamicItem.setLabel("Dynamic Menu Item (" + new Date() + ")");
+ //dynamicItem.setContributorURI("platform:/plugin/org.argeo.cms.e4");
+ //dynamicItem.setContributionURI("bundleclass://org.argeo.cms.e4/" + ChangeLanguage.class.getName());
+ dynamicItem.setEnabled(true);
+ dynamicItem.setContributionURI("bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.ChangeLanguage");
+ items.add(dynamicItem);
+ }
+
+ @AboutToHide
+ public void aboutToHide() {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.handlers;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+
+public class OpenPerspective {
+ @Inject
+ MApplication application;
+ @Inject
+ EPartService partService;
+ @Inject
+ EModelService modelService;
+
+ @Execute
+ public void execute(@Named("perspectiveId") String perspectiveId) {
+ List<MPerspective> perspectives = modelService.findElements(application, perspectiveId, MPerspective.class,
+ null);
+ if (perspectives.size() == 0)
+ return;
+ MPerspective perspective = perspectives.get(0);
+ partService.switchPerspective(perspective);
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.handlers;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+
+public class SaveAllParts {
+
+ @Execute
+ void execute(EPartService partService) {
+ partService.saveAll(false);
+ }
+
+ @CanExecute
+ boolean canExecute(EPartService partService) {
+ return partService.getDirtyParts().size() > 0;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.handlers;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+
+public class SavePart {
+ @Execute
+ void execute(EPartService partService, MPart part) {
+ partService.savePart(part, false);
+ }
+
+ @CanExecute
+ boolean canExecute(MPart part) {
+ return part.isDirty();
+ }
+}
\ No newline at end of file
--- /dev/null
+/** Generic Eclipse 4 handlers. */
+package org.argeo.cms.e4.handlers;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.jcr;
+
+import org.argeo.jcr.JcrMonitor;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Wraps an Eclipse {@link IProgressMonitor} so that it can be passed to
+ * framework agnostic Argeo routines.
+ */
+public class EclipseJcrMonitor implements JcrMonitor {
+ private final IProgressMonitor progressMonitor;
+
+ public EclipseJcrMonitor(IProgressMonitor progressMonitor) {
+ this.progressMonitor = progressMonitor;
+ }
+
+ public void beginTask(String name, int totalWork) {
+ progressMonitor.beginTask(name, totalWork);
+ }
+
+ public void done() {
+ progressMonitor.done();
+ }
+
+ public boolean isCanceled() {
+ return progressMonitor.isCanceled();
+ }
+
+ public void setCanceled(boolean value) {
+ progressMonitor.setCanceled(value);
+ }
+
+ public void setTaskName(String name) {
+ progressMonitor.setTaskName(name);
+ }
+
+ public void subTask(String name) {
+ progressMonitor.subTask(name);
+ }
+
+ public void worked(int work) {
+ progressMonitor.worked(work);
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.jcr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.jcr.PropertyLabelProvider;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.layout.TreeColumnLayout;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ * Generic editor property page. Lists all properties of current node as a
+ * complex tree. TODO: enable editing
+ */
+public class GenericPropertyPage {
+
+ // Main business Objects
+ private Node currentNode;
+
+ public GenericPropertyPage(Node currentNode) {
+ this.currentNode = currentNode;
+ }
+
+ protected void createFormContent(Composite parent) {
+ Composite innerBox = new Composite(parent, SWT.NONE);
+ // Composite innerBox = new Composite(body, SWT.NO_FOCUS);
+ FillLayout layout = new FillLayout();
+ layout.marginHeight = 5;
+ layout.marginWidth = 5;
+ innerBox.setLayout(layout);
+ createComplexTree(innerBox);
+ // TODO TreeColumnLayout triggers a scroll issue with the form:
+ // The inside body is always to big and a scroll bar is shown
+ // Composite tableCmp = new Composite(body, SWT.NO_FOCUS);
+ // createComplexTree(tableCmp);
+ }
+
+ private TreeViewer createComplexTree(Composite parent) {
+ int style = SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION;
+ Tree tree = new Tree(parent, style);
+ TreeColumnLayout tableColumnLayout = new TreeColumnLayout();
+
+ createColumn(tree, tableColumnLayout, "Property", SWT.LEFT, 200, 30);
+ createColumn(tree, tableColumnLayout, "Value(s)", SWT.LEFT, 300, 60);
+ createColumn(tree, tableColumnLayout, "Type", SWT.LEFT, 75, 10);
+ createColumn(tree, tableColumnLayout, "Attributes", SWT.LEFT, 75, 0);
+ // Do not apply the treeColumnLayout it does not work yet
+ // parent.setLayout(tableColumnLayout);
+
+ tree.setLinesVisible(true);
+ tree.setHeaderVisible(true);
+
+ TreeViewer treeViewer = new TreeViewer(tree);
+ treeViewer.setContentProvider(new TreeContentProvider());
+ treeViewer.setLabelProvider((IBaseLabelProvider) new PropertyLabelProvider());
+ treeViewer.setInput(currentNode);
+ treeViewer.expandAll();
+ return treeViewer;
+ }
+
+ private static TreeColumn createColumn(Tree parent, TreeColumnLayout tableColumnLayout, String name, int style,
+ int width, int weight) {
+ TreeColumn column = new TreeColumn(parent, style);
+ column.setText(name);
+ column.setWidth(width);
+ column.setMoveable(true);
+ column.setResizable(true);
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight, width, true));
+ return column;
+ }
+
+ private class TreeContentProvider implements ITreeContentProvider {
+ private static final long serialVersionUID = -6162736530019406214L;
+
+ public Object[] getElements(Object parent) {
+ Object[] props = null;
+ try {
+
+ if (parent instanceof Node) {
+ Node node = (Node) parent;
+ PropertyIterator pi;
+ pi = node.getProperties();
+ List<Property> propList = new ArrayList<Property>();
+ while (pi.hasNext()) {
+ propList.add(pi.nextProperty());
+ }
+ props = propList.toArray();
+ }
+ } catch (RepositoryException e) {
+ throw new EclipseUiException("Unexpected exception while listing node properties", e);
+ }
+ return props;
+ }
+
+ public Object getParent(Object child) {
+ return null;
+ }
+
+ public Object[] getChildren(Object parent) {
+ if (parent instanceof Property) {
+ Property prop = (Property) parent;
+ try {
+ if (prop.isMultiple())
+ return prop.getValues();
+ } catch (RepositoryException e) {
+ throw new EclipseUiException("Cannot get multi-prop values on " + prop, e);
+ }
+ }
+ return null;
+ }
+
+ public boolean hasChildren(Object parent) {
+ try {
+ return (parent instanceof Property && ((Property) parent).isMultiple());
+ } catch (RepositoryException e) {
+ throw new EclipseUiException("Cannot check if property is multiple for " + parent, e);
+ }
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public void dispose() {
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.jcr;
+
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.security.CryptoKeyring;
+import org.argeo.cms.security.Keyring;
+import org.argeo.cms.swt.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.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
+import org.argeo.eclipse.ui.jcr.util.NodeViewerComparer;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.services.EMenuService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Basic View to display a sash form to browse a JCR compliant multiple
+ * repository environment
+ */
+public class JcrBrowserView {
+ final static String ID = "org.argeo.cms.e4.jcrbrowser";
+ final static String NODE_VIEWER_POPUP_MENU_ID = "org.argeo.cms.e4.popupmenu.nodeViewer";
+
+ private boolean sortChildNodes = true;
+
+ /* DEPENDENCY INJECTION */
+ @Inject
+ @Optional
+ private Keyring keyring;
+ @Inject
+ private RepositoryFactory repositoryFactory;
+ @Inject
+ private Repository nodeRepository;
+
+ // Current user session on the home repository default workspace
+ private Session userSession;
+
+ private OsgiRepositoryRegister repositoryRegister = new OsgiRepositoryRegister();
+
+ // This page widgets
+ private TreeViewer nodesViewer;
+ private NodeContentProvider nodeContentProvider;
+ private TableViewer propertiesViewer;
+ private EventListener resultsObserver;
+
+ @PostConstruct
+ public void createPartControl(Composite parent, IEclipseContext context, EPartService partService,
+ ESelectionService selectionService, EMenuService menuService) {
+ repositoryRegister.init();
+
+ parent.setLayout(new FillLayout());
+ SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
+ // sashForm.setSashWidth(4);
+ // sashForm.setLayout(new FillLayout());
+
+ // Create the tree on top of the view
+ Composite top = new Composite(sashForm, SWT.NONE);
+ // GridLayout gl = new GridLayout(1, false);
+ top.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+ try {
+ this.userSession = this.nodeRepository.login(CmsConstants.HOME_WORKSPACE);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot open user session", e);
+ }
+
+ nodeContentProvider = new NodeContentProvider(userSession, keyring, repositoryRegister, repositoryFactory,
+ sortChildNodes);
+
+ // nodes viewer
+ nodesViewer = createNodeViewer(top, nodeContentProvider);
+
+ // context menu : it is completely defined in the plugin.xml file.
+ // MenuManager menuManager = new MenuManager();
+ // Menu menu = menuManager.createContextMenu(nodesViewer.getTree());
+
+ // nodesViewer.getTree().setMenu(menu);
+
+ nodesViewer.setInput("");
+
+ // Create the property viewer on the bottom
+ Composite bottom = new Composite(sashForm, SWT.NONE);
+ bottom.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ propertiesViewer = createPropertiesViewer(bottom);
+
+ sashForm.setWeights(getWeights());
+ nodesViewer.setComparer(new NodeViewerComparer());
+ nodesViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ selectionService.setSelection(selection.toList());
+ }
+ });
+ nodesViewer.addDoubleClickListener(new JcrE4DClickListener(nodesViewer, partService));
+ menuService.registerContextMenu(nodesViewer.getControl(), NODE_VIEWER_POPUP_MENU_ID);
+ // getSite().registerContextMenu(menuManager, nodesViewer);
+ // getSite().setSelectionProvider(nodesViewer);
+ }
+
+ @PreDestroy
+ public void dispose() {
+ JcrUtils.logoutQuietly(userSession);
+ repositoryRegister.destroy();
+ }
+
+ public void refresh(Object obj) {
+ // Enable full refresh from a command when no element of the tree is
+ // selected
+ if (obj == null) {
+ Object[] elements = nodeContentProvider.getElements(null);
+ for (Object el : elements) {
+ if (el instanceof TreeParent)
+ JcrBrowserUtils.forceRefreshIfNeeded((TreeParent) el);
+ getNodeViewer().refresh(el);
+ }
+ } else
+ getNodeViewer().refresh(obj);
+ }
+
+ /**
+ * To be overridden to adapt size of form and result frames.
+ */
+ protected int[] getWeights() {
+ return new int[] { 70, 30 };
+ }
+
+ protected TreeViewer createNodeViewer(Composite parent, final ITreeContentProvider nodeContentProvider) {
+
+ final TreeViewer tmpNodeViewer = new TreeViewer(parent, SWT.MULTI);
+
+ tmpNodeViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ tmpNodeViewer.setContentProvider(nodeContentProvider);
+ tmpNodeViewer.setLabelProvider((IBaseLabelProvider) new NodeLabelProvider());
+ tmpNodeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ if (!event.getSelection().isEmpty()) {
+ IStructuredSelection sel = (IStructuredSelection) event.getSelection();
+ Object firstItem = sel.getFirstElement();
+ if (firstItem instanceof SingleJcrNodeElem)
+ propertiesViewer.setInput(((SingleJcrNodeElem) firstItem).getNode());
+ } else {
+ propertiesViewer.setInput("");
+ }
+ }
+ });
+
+ resultsObserver = new TreeObserver(tmpNodeViewer.getTree().getDisplay());
+ if (keyring != null)
+ try {
+ ObservationManager observationManager = userSession.getWorkspace().getObservationManager();
+ observationManager.addEventListener(resultsObserver, Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED, "/",
+ true, null, null, false);
+ } catch (RepositoryException e) {
+ throw new EclipseUiException("Cannot register listeners", e);
+ }
+
+ // tmpNodeViewer.addDoubleClickListener(new JcrDClickListener(tmpNodeViewer));
+ return tmpNodeViewer;
+ }
+
+ protected TableViewer createPropertiesViewer(Composite parent) {
+ propertiesViewer = new TableViewer(parent, SWT.NONE);
+ propertiesViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ propertiesViewer.getTable().setHeaderVisible(true);
+ propertiesViewer.setContentProvider(new PropertiesContentProvider());
+ TableViewerColumn col = new TableViewerColumn(propertiesViewer, SWT.NONE);
+ col.getColumn().setText("Name");
+ col.getColumn().setWidth(200);
+ col.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -6684361063107478595L;
+
+ public String getText(Object element) {
+ try {
+ return ((Property) element).getName();
+ } catch (RepositoryException e) {
+ throw new EclipseUiException("Unexpected exception in label provider", e);
+ }
+ }
+ });
+ col = new TableViewerColumn(propertiesViewer, SWT.NONE);
+ col.getColumn().setText("Value");
+ col.getColumn().setWidth(400);
+ col.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -8201994187693336657L;
+
+ public String getText(Object element) {
+ try {
+ Property property = (Property) element;
+ if (property.getType() == PropertyType.BINARY)
+ return "<binary>";
+ else if (property.isMultiple()) {
+ StringBuffer buf = new StringBuffer("[");
+ Value[] values = property.getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (i != 0)
+ buf.append(", ");
+ buf.append(values[i].getString());
+ }
+ buf.append(']');
+ return buf.toString();
+ } else
+ return property.getValue().getString();
+ } catch (RepositoryException e) {
+ throw new EclipseUiException("Unexpected exception in label provider", e);
+ }
+ }
+ });
+ col = new TableViewerColumn(propertiesViewer, SWT.NONE);
+ col.getColumn().setText("Type");
+ col.getColumn().setWidth(200);
+ col.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -6009599998150286070L;
+
+ public String getText(Object element) {
+ return JcrBrowserUtils.getPropertyTypeAsString((Property) element);
+ }
+ });
+ propertiesViewer.setInput("");
+ return propertiesViewer;
+ }
+
+ protected TreeViewer getNodeViewer() {
+ return nodesViewer;
+ }
+
+ /**
+ * Resets the tree content provider
+ *
+ * @param sortChildNodes if true the content provider will use a comparer to
+ * sort nodes that might slow down the display
+ */
+ public void setSortChildNodes(boolean sortChildNodes) {
+ this.sortChildNodes = sortChildNodes;
+ ((NodeContentProvider) nodesViewer.getContentProvider()).setSortChildren(sortChildNodes);
+ nodesViewer.setInput("");
+ }
+
+ /** Notifies the current view that a node has been added */
+ public void nodeAdded(TreeParent parentNode) {
+ // insure that Ui objects have been correctly created:
+ JcrBrowserUtils.forceRefreshIfNeeded(parentNode);
+ getNodeViewer().refresh(parentNode);
+ getNodeViewer().expandToLevel(parentNode, 1);
+ }
+
+ /** Notifies the current view that a node has been removed */
+ public void nodeRemoved(TreeParent parentNode) {
+ IStructuredSelection newSel = new StructuredSelection(parentNode);
+ getNodeViewer().setSelection(newSel, true);
+ // Force refresh
+ IStructuredSelection tmpSel = (IStructuredSelection) getNodeViewer().getSelection();
+ getNodeViewer().refresh(tmpSel.getFirstElement());
+ }
+
+ class TreeObserver extends AsyncUiEventListener {
+
+ public TreeObserver(Display display) {
+ super(display);
+ }
+
+ @Override
+ protected Boolean willProcessInUiThread(List<Event> events) throws RepositoryException {
+ for (Event event : events) {
+ if (getLog().isTraceEnabled())
+ getLog().debug("Received event " + event);
+ String path = event.getPath();
+ int index = path.lastIndexOf('/');
+ String propertyName = path.substring(index + 1);
+ if (getLog().isTraceEnabled())
+ getLog().debug("Concerned property " + propertyName);
+ }
+ return false;
+ }
+
+ protected void onEventInUiThread(List<Event> events) throws RepositoryException {
+ if (getLog().isTraceEnabled())
+ getLog().trace("Refresh result list");
+ nodesViewer.refresh();
+ }
+
+ }
+
+ public boolean getSortChildNodes() {
+ return sortChildNodes;
+ }
+
+ public void setFocus() {
+ getNodeViewer().getTree().setFocus();
+ }
+
+ /* DEPENDENCY INJECTION */
+ // public void setRepositoryRegister(RepositoryRegister repositoryRegister) {
+ // this.repositoryRegister = repositoryRegister;
+ // }
+
+ public void setKeyring(CryptoKeyring keyring) {
+ this.keyring = keyring;
+ }
+
+ public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
+ this.repositoryFactory = repositoryFactory;
+ }
+
+ public void setNodeRepository(Repository nodeRepository) {
+ this.nodeRepository = nodeRepository;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.ui.jcr.JcrDClickListener;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
+import org.eclipse.jface.viewers.TreeViewer;
+
+public class JcrE4DClickListener extends JcrDClickListener {
+ EPartService partService;
+
+ public JcrE4DClickListener(TreeViewer nodeViewer, EPartService partService) {
+ super(nodeViewer);
+ this.partService = partService;
+ }
+
+ @Override
+ protected void openNode(Node node) {
+ MPart part = partService.createPart(JcrNodeEditor.DESCRIPTOR_ID);
+ try {
+ part.setLabel(node.getName());
+ part.getPersistedState().put("nodeWorkspace", node.getSession().getWorkspace().getName());
+ part.getPersistedState().put("nodePath", node.getPath());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot open " + node, e);
+ }
+
+ // the provided part is be shown
+ partService.showPart(part, PartState.ACTIVATE);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.jcr;
+
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+
+public class JcrNodeEditor {
+ final static String DESCRIPTOR_ID = "org.argeo.cms.e4.partdescriptor.nodeEditor";
+
+ @PostConstruct
+ public void createUi(Composite parent, MPart part, ESelectionService selectionService) {
+ parent.setLayout(new FillLayout());
+ List<?> selection = (List<?>) selectionService.getSelection();
+ Node node = ((SingleJcrNodeElem) selection.get(0)).getNode();
+ GenericPropertyPage propertyPage = new GenericPropertyPage(node);
+ propertyPage.createFormContent(parent);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.jcr;
+
+import javax.annotation.PostConstruct;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+public class SimplePart {
+
+ @PostConstruct
+ void init(Composite parent) {
+ parent.setLayout(new GridLayout());
+ Label label = new Label(parent, SWT.NONE);
+ label.setText("Hello e4 World");
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.jcr.handlers;
+
+import java.util.List;
+
+import javax.inject.Named;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.cms.e4.jcr.JcrBrowserView;
+import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
+import org.argeo.cms.ui.jcr.model.WorkspaceElem;
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
+import org.argeo.eclipse.ui.dialogs.SingleValue;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+
+/**
+ * Adds a node of type nt:folder, only on {@link SingleJcrNodeElem} and
+ * {@link WorkspaceElem} TreeObject types.
+ *
+ * This handler assumes that a selection provider is available and picks only
+ * first selected item. It is UI's job to enable the command only when the
+ * selection contains one and only one element. Thus no parameter is passed
+ * through the command.
+ */
+public class AddFolderNode {
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
+ List<?> selection = (List<?>) selectionService.getSelection();
+ JcrBrowserView view = (JcrBrowserView) part.getObject();
+
+ if (selection != null && selection.size() == 1) {
+ TreeParent treeParentNode = null;
+ Node jcrParentNode = null;
+ Object obj = selection.get(0);
+
+ if (obj instanceof SingleJcrNodeElem) {
+ treeParentNode = (TreeParent) obj;
+ jcrParentNode = ((SingleJcrNodeElem) treeParentNode).getNode();
+ } else if (obj instanceof WorkspaceElem) {
+ treeParentNode = (TreeParent) obj;
+ jcrParentNode = ((WorkspaceElem) treeParentNode).getRootNode();
+ } else
+ return;
+
+ String folderName = SingleValue.ask("Folder name", "Enter folder name");
+ if (folderName != null) {
+ try {
+ jcrParentNode.addNode(folderName, NodeType.NT_FOLDER);
+ jcrParentNode.getSession().save();
+ view.nodeAdded(treeParentNode);
+ } catch (RepositoryException e) {
+ ErrorFeedback.show("Cannot create folder " + folderName + " under " + treeParentNode, e);
+ }
+ }
+ } else {
+ // ErrorFeedback.show(WorkbenchUiPlugin
+ // .getMessage("errorUnvalidNtFolderNodeType"));
+ ErrorFeedback.show("Invalid NT folder node type");
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.jcr.handlers;
+
+import java.net.URI;
+import java.util.Hashtable;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.ArgeoNames;
+import org.argeo.cms.ArgeoTypes;
+import org.argeo.cms.e4.jcr.JcrBrowserView;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.security.Keyring;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+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.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;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Connect to a remote repository and, if successful publish it as an OSGi
+ * service.
+ */
+public class AddRemoteRepository {
+
+ @Inject
+ private RepositoryFactory repositoryFactory;
+ @Inject
+ private Repository nodeRepository;
+ @Inject
+ @Optional
+ private Keyring keyring;
+
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part) {
+ JcrBrowserView view = (JcrBrowserView) part.getObject();
+ RemoteRepositoryLoginDialog dlg = new RemoteRepositoryLoginDialog(Display.getDefault().getActiveShell());
+ if (dlg.open() == Dialog.OK) {
+ view.refresh(null);
+ }
+ }
+
+ // public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
+ // this.repositoryFactory = repositoryFactory;
+ // }
+ //
+ // public void setKeyring(Keyring keyring) {
+ // this.keyring = keyring;
+ // }
+ //
+ // public void setNodeRepository(Repository nodeRepository) {
+ // this.nodeRepository = nodeRepository;
+ // }
+
+ class RemoteRepositoryLoginDialog extends TitleAreaDialog {
+ private static final long serialVersionUID = 2234006887750103399L;
+ private Text name;
+ private Text uri;
+ private Text username;
+ private Text password;
+ private Button saveInKeyring;
+
+ public RemoteRepositoryLoginDialog(Shell parentShell) {
+ super(parentShell);
+ }
+
+ protected Point getInitialSize() {
+ return new Point(600, 400);
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite dialogarea = (Composite) super.createDialogArea(parent);
+ dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ Composite composite = new Composite(dialogarea, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ setMessage("Login to remote repository", IMessageProvider.NONE);
+ name = createLT(composite, "Name", "remoteRepository");
+ uri = createLT(composite, "URI", "http://localhost:7070/jcr/node");
+ username = createLT(composite, "User", "");
+ password = createLP(composite, "Password");
+
+ saveInKeyring = createLC(composite, "Remember password", false);
+ parent.pack();
+ return composite;
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ super.createButtonsForButtonBar(parent);
+ Button test = createButton(parent, 2, "Test", false);
+ test.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -1829962269440419560L;
+
+ public void widgetSelected(SelectionEvent arg0) {
+ testConnection();
+ }
+ });
+ }
+
+ void testConnection() {
+ Session session = null;
+ try {
+ URI checkedUri = new URI(uri.getText());
+ String checkedUriStr = checkedUri.toString();
+
+ Hashtable<String, String> params = new Hashtable<String, String>();
+ params.put(CmsConstants.LABELED_URI, checkedUriStr);
+ Repository repository = repositoryFactory.getRepository(params);
+ if (username.getText().trim().equals("")) {// anonymous
+ // FIXME make it more generic
+ session = repository.login(CmsConstants.SYS_WORKSPACE);
+ } else {
+ // FIXME use getTextChars() when upgrading to 3.7
+ // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=297412
+ char[] pwd = password.getText().toCharArray();
+ SimpleCredentials sc = new SimpleCredentials(username.getText(), pwd);
+ session = repository.login(sc, "main");
+ MessageDialog.openInformation(getParentShell(), "Success",
+ "Connection to '" + uri.getText() + "' successful");
+ }
+ } catch (Exception e) {
+ ErrorFeedback.show("Connection test failed for " + uri.getText(), e);
+ } finally {
+ JcrUtils.logoutQuietly(session);
+ }
+ }
+
+ @Override
+ protected void okPressed() {
+ Session nodeSession = null;
+ try {
+ nodeSession = nodeRepository.login();
+ Node home = CmsJcrUtils.getUserHome(nodeSession);
+
+ Node remote = home.hasNode(ArgeoNames.ARGEO_REMOTE) ? home.getNode(ArgeoNames.ARGEO_REMOTE)
+ : home.addNode(ArgeoNames.ARGEO_REMOTE);
+ if (remote.hasNode(name.getText()))
+ throw new EclipseUiException("There is already a remote repository named " + name.getText());
+ Node remoteRepository = remote.addNode(name.getText(), ArgeoTypes.ARGEO_REMOTE_REPOSITORY);
+ remoteRepository.setProperty(ArgeoNames.ARGEO_URI, uri.getText());
+ remoteRepository.setProperty(ArgeoNames.ARGEO_USER_ID, username.getText());
+ nodeSession.save();
+ if (saveInKeyring.getSelection()) {
+ String pwdPath = remoteRepository.getPath() + '/' + ArgeoNames.ARGEO_PASSWORD;
+ keyring.set(pwdPath, password.getText().toCharArray());
+ }
+ nodeSession.save();
+ MessageDialog.openInformation(getParentShell(), "Repository Added",
+ "Remote repository '" + username.getText() + "@" + uri.getText() + "' added");
+
+ super.okPressed();
+ } catch (Exception e) {
+ ErrorFeedback.show("Cannot add remote repository", e);
+ } finally {
+ JcrUtils.logoutQuietly(nodeSession);
+ }
+ }
+
+ /** Creates label and text. */
+ protected Text createLT(Composite parent, String label, String initial) {
+ new Label(parent, SWT.NONE).setText(label);
+ Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ text.setText(initial);
+ return text;
+ }
+
+ /** Creates label and check. */
+ protected Button createLC(Composite parent, String label, Boolean initial) {
+ new Label(parent, SWT.NONE).setText(label);
+ Button check = new Button(parent, SWT.CHECK);
+ check.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ check.setSelection(initial);
+ return check;
+ }
+
+ protected Text createLP(Composite parent, String label) {
+ new Label(parent, SWT.NONE).setText(label);
+ Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER | SWT.PASSWORD);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ return text;
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.jcr.handlers;
+
+import java.util.List;
+
+import javax.inject.Named;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.e4.jcr.JcrBrowserView;
+import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
+import org.argeo.cms.ui.jcr.model.WorkspaceElem;
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Delete the selected nodes: both in the JCR repository and in the UI view.
+ * Warning no check is done, except implementation dependent native checks,
+ * handle with care.
+ *
+ * This handler is still 'hard linked' to a GenericJcrBrowser view to enable
+ * correct tree refresh when a node is added. This must be corrected in future
+ * versions.
+ */
+public class DeleteNodes {
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
+ List<?> selection = (List<?>) selectionService.getSelection();
+ if (selection == null)
+ return;
+
+ JcrBrowserView view = (JcrBrowserView) part.getObject();
+
+ // confirmation
+ StringBuffer buf = new StringBuffer("");
+ for (Object o : selection) {
+ SingleJcrNodeElem sjn = (SingleJcrNodeElem) o;
+ buf.append(sjn.getName()).append(' ');
+ }
+ Boolean doRemove = MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "Confirm deletion",
+ "Do you want to delete " + buf + "?");
+
+ // operation
+ if (doRemove) {
+ SingleJcrNodeElem ancestor = null;
+ WorkspaceElem rootAncestor = null;
+ try {
+ for (Object obj : selection) {
+ if (obj instanceof SingleJcrNodeElem) {
+ // Cache objects
+ SingleJcrNodeElem sjn = (SingleJcrNodeElem) obj;
+ TreeParent tp = (TreeParent) sjn.getParent();
+ Node node = sjn.getNode();
+
+ // Jcr Remove
+ node.remove();
+ node.getSession().save();
+ // UI remove
+ tp.removeChild(sjn);
+
+ // Check if the parent is the root node
+ if (tp instanceof WorkspaceElem)
+ rootAncestor = (WorkspaceElem) tp;
+ else
+ ancestor = getOlder(ancestor, (SingleJcrNodeElem) tp);
+ }
+ }
+ if (rootAncestor != null)
+ view.nodeRemoved(rootAncestor);
+ else if (ancestor != null)
+ view.nodeRemoved(ancestor);
+ } catch (Exception e) {
+ ErrorFeedback.show("Cannot delete selected node ", e);
+ }
+ }
+ }
+
+ private SingleJcrNodeElem getOlder(SingleJcrNodeElem A, SingleJcrNodeElem B) {
+ try {
+ if (A == null)
+ return B == null ? null : B;
+ // Todo enhanced this method
+ else
+ return A.getNode().getDepth() <= B.getNode().getDepth() ? A : B;
+ } catch (RepositoryException re) {
+ throw new EclipseUiException("Cannot find ancestor", re);
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.jcr.handlers;
+
+import java.util.List;
+
+import javax.inject.Named;
+
+import org.argeo.cms.e4.jcr.JcrBrowserView;
+import org.argeo.cms.ui.jcr.JcrBrowserUtils;
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+
+/**
+ * Force the selected objects of the active view to be refreshed doing the
+ * following:
+ * <ol>
+ * <li>The model objects are recomputed</li>
+ * <li>the view is refreshed</li>
+ * </ol>
+ */
+public class Refresh {
+
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, EPartService partService,
+ ESelectionService selectionService) {
+
+ JcrBrowserView view = (JcrBrowserView) part.getObject();
+ List<?> selection = (List<?>) selectionService.getSelection();
+
+ if (selection != null && !selection.isEmpty()) {
+ for (Object obj : selection)
+ if (obj instanceof TreeParent) {
+ TreeParent tp = (TreeParent) obj;
+ JcrBrowserUtils.forceRefreshIfNeeded(tp);
+ view.refresh(obj);
+ }
+ } else if (view instanceof JcrBrowserView)
+ view.refresh(null); // force full refresh
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.jcr.handlers;
+
+import java.util.List;
+
+import javax.inject.Named;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.cms.e4.jcr.JcrBrowserView;
+import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.dialogs.SingleValue;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+
+/**
+ * Canonically call JCR Session#move(String, String) on the first element
+ * returned by HandlerUtil#getActiveWorkbenchWindow()
+ * (...getActivePage().getSelection()), if it is a {@link SingleJcrNodeElem}.
+ * The user must then fill a new name in and confirm
+ */
+public class RenameNode {
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, EPartService partService,
+ ESelectionService selectionService) {
+ List<?> selection = (List<?>) selectionService.getSelection();
+ if (selection == null || selection.size() != 1)
+ return;
+ JcrBrowserView view = (JcrBrowserView) part.getObject();
+
+ Object element = selection.get(0);
+ if (element instanceof SingleJcrNodeElem) {
+ SingleJcrNodeElem sjn = (SingleJcrNodeElem) element;
+ Node node = sjn.getNode();
+ Session session = null;
+ String newName = null;
+ String oldPath = null;
+ try {
+ newName = SingleValue.ask("New node name", "Please provide a new name for [" + node.getName() + "]");
+ // TODO sanity check and user feedback
+ newName = JcrUtils.replaceInvalidChars(newName);
+ oldPath = node.getPath();
+ session = node.getSession();
+ session.move(oldPath, JcrUtils.parentPath(oldPath) + "/" + newName);
+ session.save();
+
+ // Manually refresh the browser view. Must be enhanced
+ view.refresh(sjn);
+ } catch (RepositoryException e) {
+ throw new EclipseUiException("Unable to rename " + node + " to " + newName, e);
+ }
+ }
+ }
+}
--- /dev/null
+/** JCR browser handlers. */
+package org.argeo.cms.e4.jcr.handlers;
\ No newline at end of file
--- /dev/null
+/** JCR browser perspective. */
+package org.argeo.cms.e4.jcr;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.util.Collection;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+abstract class AbstractOsgiComposite extends Composite {
+ private static final long serialVersionUID = -4097415973477517137L;
+ protected final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
+ protected final CmsLog log = CmsLog.getLog(getClass());
+
+ public AbstractOsgiComposite(Composite parent, int style) {
+ super(parent, style);
+ parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ setLayout(CmsSwtUtils.noSpaceGridLayout());
+ setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ initUi(style);
+ }
+
+ protected abstract void initUi(int style);
+
+ protected <T> T getService(Class<? extends T> clazz) {
+ return bc.getService(bc.getServiceReference(clazz));
+ }
+
+ protected <T> Collection<ServiceReference<T>> getServiceReferences(Class<T> clazz, String filter) {
+ try {
+ return bc.getServiceReferences(clazz, filter);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Filter " + filter + " is invalid", e);
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import static org.eclipse.swt.SWT.RIGHT;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.LinkedHashMap;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.cms.swt.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.widgets.EditableImage;
+import org.argeo.cms.ui.widgets.Img;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ILazyContentProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+
+public class Browse implements CmsUiProvider {
+
+ // Some local constants to experiment. should be cleaned
+ private final static String BROWSE_PREFIX = "browse#";
+ private final static int THUMBNAIL_WIDTH = 400;
+ private final static int COLUMN_WIDTH = 160;
+ private DateFormat timeFormatter = new SimpleDateFormat("dd-MM-yyyy', 'HH:mm");
+
+ // keep a cache of the opened nodes
+ // Key is the path
+ private LinkedHashMap<String, FilterEntitiesVirtualTable> browserCols = new LinkedHashMap<String, Browse.FilterEntitiesVirtualTable>();
+ private Composite nodeDisplayParent;
+ private Composite colViewer;
+ private ScrolledComposite scrolledCmp;
+ private Text parentPathTxt;
+ private Text filterTxt;
+ private Node currEdited;
+
+ private String initialPath;
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ if (context == null)
+ // return null;
+ throw new CmsException("Context cannot be null");
+ GridLayout layout = CmsSwtUtils.noSpaceGridLayout();
+ layout.numColumns = 2;
+ parent.setLayout(layout);
+
+ // Left
+ Composite leftCmp = new Composite(parent, SWT.NO_FOCUS);
+ leftCmp.setLayoutData(CmsSwtUtils.fillAll());
+ createBrowserPart(leftCmp, context);
+
+ // Right
+ nodeDisplayParent = new Composite(parent, SWT.NO_FOCUS | SWT.BORDER);
+ GridData gd = new GridData(SWT.RIGHT, SWT.FILL, false, true);
+ gd.widthHint = THUMBNAIL_WIDTH;
+ nodeDisplayParent.setLayoutData(gd);
+ createNodeView(nodeDisplayParent, context);
+
+ // INIT
+ setEdited(context);
+ initialPath = context.getPath();
+
+ // Workaround we don't yet manage the delete to display parent of the
+ // initial context node
+
+ return null;
+ }
+
+ private void createBrowserPart(Composite parent, Node context) throws RepositoryException {
+ GridLayout layout = CmsSwtUtils.noSpaceGridLayout();
+ parent.setLayout(layout);
+ Composite filterCmp = new Composite(parent, SWT.NO_FOCUS);
+ filterCmp.setLayoutData(CmsSwtUtils.fillWidth());
+
+ // top filter
+ addFilterPanel(filterCmp);
+
+ // scrolled composite
+ scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER | SWT.NO_FOCUS);
+ scrolledCmp.setLayoutData(CmsSwtUtils.fillAll());
+ scrolledCmp.setExpandVertical(true);
+ scrolledCmp.setExpandHorizontal(true);
+ scrolledCmp.setShowFocusedControl(true);
+
+ colViewer = new Composite(scrolledCmp, SWT.NO_FOCUS);
+ scrolledCmp.setContent(colViewer);
+ scrolledCmp.addControlListener(new ControlAdapter() {
+ private static final long serialVersionUID = 6589392045145698201L;
+
+ @Override
+ public void controlResized(ControlEvent e) {
+ Rectangle r = scrolledCmp.getClientArea();
+ scrolledCmp.setMinSize(colViewer.computeSize(SWT.DEFAULT, r.height));
+ }
+ });
+ initExplorer(colViewer, context);
+ }
+
+ private Control initExplorer(Composite parent, Node context) throws RepositoryException {
+ parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ createBrowserColumn(parent, context);
+ return null;
+ }
+
+ private Control createBrowserColumn(Composite parent, Node context) throws RepositoryException {
+ // TODO style is not correctly managed.
+ FilterEntitiesVirtualTable table = new FilterEntitiesVirtualTable(parent, SWT.BORDER | SWT.NO_FOCUS, context);
+ // CmsUiUtils.style(table, ArgeoOrgStyle.browserColumn.style());
+ table.filterList("*");
+ table.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true));
+ browserCols.put(context.getPath(), table);
+ return null;
+ }
+
+ public void addFilterPanel(Composite parent) {
+
+ parent.setLayout(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(CmsSwtUtils.fillWidth());
+ filterTxt.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = 7709303319740056286L;
+
+ public void modifyText(ModifyEvent event) {
+ modifyFilter(false);
+ }
+ });
+
+ filterTxt.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -4523394262771183968L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
+ // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
+ FilterEntitiesVirtualTable currTable = null;
+ if (currEdited != null) {
+ FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited));
+ if (table != null && !table.isDisposed())
+ currTable = table;
+ }
+
+ try {
+ if (e.keyCode == SWT.ARROW_DOWN)
+ currTable.setFocus();
+ else if (e.keyCode == SWT.BS) {
+ if (filterTxt.getText().equals("")
+ && !(getPath(currEdited).equals("/") || getPath(currEdited).equals(initialPath))) {
+ setEdited(currEdited.getParent());
+ e.doit = false;
+ filterTxt.setFocus();
+ }
+ } else if (e.keyCode == SWT.TAB && !shiftPressed) {
+ if (currEdited.getNodes(filterTxt.getText() + "*").getSize() == 1) {
+ setEdited(currEdited.getNodes(filterTxt.getText() + "*").nextNode());
+ }
+ filterTxt.setFocus();
+ e.doit = false;
+ }
+ } catch (RepositoryException e1) {
+ throw new CmsException("Unexpected error in key management for " + currEdited + "with filter "
+ + filterTxt.getText(), e1);
+ }
+
+ }
+ });
+ }
+
+ private void setEdited(Node node) {
+ try {
+ currEdited = node;
+ CmsSwtUtils.clear(nodeDisplayParent);
+ createNodeView(nodeDisplayParent, currEdited);
+ nodeDisplayParent.layout();
+ refreshFilters(node);
+ refreshBrowser(node);
+ } catch (RepositoryException re) {
+ throw new CmsException("Unable to update browser for " + node, re);
+ }
+ }
+
+ private void refreshFilters(Node node) throws RepositoryException {
+ String currNodePath = node.getPath();
+ parentPathTxt.setText(currNodePath);
+ filterTxt.setText("");
+ filterTxt.getParent().layout();
+ }
+
+ private void refreshBrowser(Node node) throws RepositoryException {
+
+ // Retrieve
+ String currNodePath = node.getPath();
+ String currParPath = "";
+ if (!"/".equals(currNodePath))
+ currParPath = JcrUtils.parentPath(currNodePath);
+ if ("".equals(currParPath))
+ currParPath = "/";
+
+ Object[][] colMatrix = new Object[browserCols.size()][2];
+
+ int i = 0, j = -1, k = -1;
+ for (String path : browserCols.keySet()) {
+ colMatrix[i][0] = path;
+ colMatrix[i][1] = browserCols.get(path);
+ if (j >= 0 && k < 0 && !currNodePath.equals("/")) {
+ boolean leaveOpened = path.startsWith(currNodePath);
+
+ // workaround for same name siblings
+ // fix me weird side effect when we go left or click on anb
+ // already selected, unfocused node
+ if (leaveOpened && (path.lastIndexOf("/") == 0 && currNodePath.lastIndexOf("/") == 0
+ || JcrUtils.parentPath(path).equals(JcrUtils.parentPath(currNodePath))))
+ leaveOpened = JcrUtils.lastPathElement(path).equals(JcrUtils.lastPathElement(currNodePath));
+
+ if (!leaveOpened)
+ k = i;
+ }
+ if (currParPath.equals(path))
+ j = i;
+ i++;
+ }
+
+ if (j >= 0 && k >= 0)
+ // remove useless cols
+ for (int l = i - 1; l >= k; l--) {
+ browserCols.remove(colMatrix[l][0]);
+ ((FilterEntitiesVirtualTable) colMatrix[l][1]).dispose();
+ }
+
+ // Remove disposed columns
+ // TODO investigate and fix the mechanism that leave them there after
+ // disposal
+ if (browserCols.containsKey(currNodePath)) {
+ FilterEntitiesVirtualTable currCol = browserCols.get(currNodePath);
+ if (currCol.isDisposed())
+ browserCols.remove(currNodePath);
+ }
+
+ if (!browserCols.containsKey(currNodePath))
+ createBrowserColumn(colViewer, node);
+
+ colViewer.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false)));
+ // colViewer.pack();
+ colViewer.layout();
+ // also resize the scrolled composite
+ scrolledCmp.layout();
+ scrolledCmp.getShowFocusedControl();
+ // colViewer.getParent().layout();
+ // if (JcrUtils.parentPath(currNodePath).equals(currBrowserKey)) {
+ // } else {
+ // }
+ }
+
+ private void modifyFilter(boolean fromOutside) {
+ if (!fromOutside)
+ if (currEdited != null) {
+ String filter = filterTxt.getText() + "*";
+ FilterEntitiesVirtualTable table = browserCols.get(getPath(currEdited));
+ if (table != null && !table.isDisposed())
+ table.filterList(filter);
+ }
+
+ }
+
+ private String getPath(Node node) {
+ try {
+ return node.getPath();
+ } catch (RepositoryException e) {
+ throw new CmsException("Unable to get path for node " + node, e);
+ }
+ }
+
+ private Cms2DSize imageWidth = new Cms2DSize(250, 0);
+
+ /**
+ * Recreates the content of the box that displays information about the current
+ * selected node.
+ */
+ private Control createNodeView(Composite parent, Node context) throws RepositoryException {
+
+ parent.setLayout(new GridLayout(2, false));
+
+ if (isImg(context)) {
+ EditableImage image = new Img(parent, RIGHT, context, imageWidth);
+ image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 2, 1));
+ }
+
+ // Name and primary type
+ Label contextL = new Label(parent, SWT.NONE);
+ CmsSwtUtils.markup(contextL);
+ contextL.setText("<b>" + context.getName() + "</b>");
+ new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType().getName());
+
+ // Children
+ for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) {
+ Node child = nIt.nextNode();
+ new CmsLink(child.getName(), BROWSE_PREFIX + child.getPath()).createUi(parent, context);
+ new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType().getName());
+ }
+
+ // Properties
+ for (PropertyIterator pIt = context.getProperties(); pIt.hasNext();) {
+ Property property = pIt.nextProperty();
+ Label label = new Label(parent, SWT.NONE);
+ label.setText(property.getName());
+ label.setToolTipText(JcrUtils.getPropertyDefinitionAsString(property));
+ new Label(parent, SWT.NONE).setText(getPropAsString(property));
+ }
+
+ return null;
+ }
+
+ private boolean isImg(Node node) throws RepositoryException {
+ // TODO support images
+ return false;
+// return node.hasNode(JCR_CONTENT) && node.isNodeType(CmsTypes.CMS_IMAGE);
+ }
+
+ private String getPropAsString(Property property) throws RepositoryException {
+ String result = "";
+ if (property.isMultiple()) {
+ result = getMultiAsString(property, ", ");
+ } else {
+ Value value = property.getValue();
+ if (value.getType() == PropertyType.BINARY)
+ result = "<binary>";
+ else if (value.getType() == PropertyType.DATE)
+ result = timeFormatter.format(value.getDate().getTime());
+ else
+ result = value.getString();
+ }
+ return result;
+ }
+
+ private String getMultiAsString(Property property, String separator) throws RepositoryException {
+ if (separator == null)
+ separator = "; ";
+ Value[] values = property.getValues();
+ StringBuilder builder = new StringBuilder();
+ for (Value val : values) {
+ String currStr = val.getString();
+ if (!"".equals(currStr.trim()))
+ builder.append(currStr).append(separator);
+ }
+ if (builder.lastIndexOf(separator) >= 0)
+ return builder.substring(0, builder.length() - separator.length());
+ else
+ return builder.toString();
+ }
+
+ /** Almost canonical implementation of a table that display entities */
+ private class FilterEntitiesVirtualTable extends Composite {
+ private static final long serialVersionUID = 8798147431706283824L;
+
+ // Context
+ private Node context;
+
+ // UI Objects
+ private TableViewer entityViewer;
+
+ // enable management of multiple columns
+ Node getNode() {
+ return context;
+ }
+
+ @Override
+ public boolean setFocus() {
+ if (entityViewer.getTable().isDisposed())
+ return false;
+ if (entityViewer.getSelection().isEmpty()) {
+ Object first = entityViewer.getElementAt(0);
+ if (first != null) {
+ entityViewer.setSelection(new StructuredSelection(first), true);
+ }
+ }
+ return entityViewer.getTable().setFocus();
+ }
+
+ void filterList(String filter) {
+ try {
+ NodeIterator nit = context.getNodes(filter);
+ refreshFilteredList(nit);
+ } catch (RepositoryException e) {
+ throw new CmsException("Unable to filter " + getNode() + " children with filter " + filter, e);
+ }
+
+ }
+
+ public FilterEntitiesVirtualTable(Composite parent, int style, Node context) {
+ super(parent, SWT.NO_FOCUS);
+ this.context = context;
+ populate();
+ }
+
+ protected void populate() {
+ Composite parent = this;
+ GridLayout layout = CmsSwtUtils.noSpaceGridLayout();
+
+ this.setLayout(layout);
+ createTableViewer(parent);
+ }
+
+ private void createTableViewer(final Composite parent) {
+ // the list
+ // We must limit the size of the table otherwise the full list is
+ // loaded
+ // before the layout happens
+ Composite listCmp = new Composite(parent, SWT.NO_FOCUS);
+ GridData gd = new GridData(SWT.LEFT, SWT.FILL, false, true);
+ gd.widthHint = COLUMN_WIDTH;
+ listCmp.setLayoutData(gd);
+ listCmp.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+ entityViewer = new TableViewer(listCmp, SWT.VIRTUAL | SWT.SINGLE);
+ Table table = entityViewer.getTable();
+
+ table.setLayoutData(CmsSwtUtils.fillAll());
+ table.setLinesVisible(true);
+ table.setHeaderVisible(false);
+ CmsSwtUtils.markup(table);
+
+ CmsSwtUtils.style(table, MaintenanceStyles.BROWSER_COLUMN);
+
+ // first column
+ TableViewerColumn column = new TableViewerColumn(entityViewer, SWT.NONE);
+ TableColumn tcol = column.getColumn();
+ tcol.setWidth(COLUMN_WIDTH);
+ tcol.setResizable(true);
+ column.setLabelProvider(new SimpleNameLP());
+
+ entityViewer.setContentProvider(new MyLazyCP(entityViewer));
+ entityViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection();
+ if (selection.isEmpty())
+ return;
+ else
+ setEdited((Node) selection.getFirstElement());
+
+ }
+ });
+
+ table.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -330694313896036230L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+
+ IStructuredSelection selection = (IStructuredSelection) entityViewer.getSelection();
+ Node selected = null;
+ if (!selection.isEmpty())
+ selected = ((Node) selection.getFirstElement());
+ try {
+ if (e.keyCode == SWT.ARROW_RIGHT) {
+ if (selected != null) {
+ setEdited(selected);
+ browserCols.get(selected.getPath()).setFocus();
+ }
+ } else if (e.keyCode == SWT.ARROW_LEFT) {
+ try {
+ selected = getNode().getParent();
+ String newPath = selected.getPath(); // getNode().getParent()
+ setEdited(selected);
+ if (browserCols.containsKey(newPath))
+ browserCols.get(newPath).setFocus();
+ } catch (ItemNotFoundException ie) {
+ // root silent
+ }
+ }
+ } catch (RepositoryException ie) {
+ throw new CmsException("Error while managing arrow " + "events in the browser for " + selected,
+ ie);
+ }
+ }
+ });
+ }
+
+ private class MyLazyCP implements ILazyContentProvider {
+ private static final long serialVersionUID = 1L;
+ private TableViewer viewer;
+ private Object[] elements;
+
+ public MyLazyCP(TableViewer viewer) {
+ this.viewer = viewer;
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // IMPORTANT: don't forget this: an exception will be thrown if
+ // a selected object is not part of the results anymore.
+ viewer.setSelection(null);
+ this.elements = (Object[]) newInput;
+ }
+
+ public void updateElement(int index) {
+ viewer.replace(elements[index], index);
+ }
+ }
+
+ protected void refreshFilteredList(NodeIterator children) {
+ Object[] rows = JcrUtils.nodeIteratorToList(children).toArray();
+ entityViewer.setInput(rows);
+ entityViewer.setItemCount(rows.length);
+ entityViewer.refresh();
+ }
+
+ public class SimpleNameLP extends ColumnLabelProvider {
+ private static final long serialVersionUID = 2465059387875338553L;
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof Node) {
+ Node curr = ((Node) element);
+ try {
+ return curr.getName();
+ } catch (RepositoryException e) {
+ throw new CmsException("Unable to get name for" + curr);
+ }
+ }
+ return super.getText(element);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.useradmin.UserAdmin;
+
+class ConnectivityDeploymentUi extends AbstractOsgiComposite {
+ private static final long serialVersionUID = 590221539553514693L;
+
+ public ConnectivityDeploymentUi(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void initUi(int style) {
+ StringBuffer text = new StringBuffer();
+ text.append("<span style='font-variant: small-caps;'>Provided Servers</span><br/>");
+
+ ServiceReference<HttpService> userAdminRef = bc.getServiceReference(HttpService.class);
+ if (userAdminRef != null) {
+ // FIXME use constants
+ Object httpPort = userAdminRef.getProperty("http.port");
+ Object httpsPort = userAdminRef.getProperty("https.port");
+ if (httpPort != null)
+ text.append("<b>http</b> ").append(httpPort).append("<br/>");
+ if (httpsPort != null)
+ text.append("<b>https</b> ").append(httpsPort).append("<br/>");
+
+ }
+
+ text.append("<br/>");
+ text.append("<span style='font-variant: small-caps;'>Referenced Servers</span><br/>");
+
+ Label label = new Label(this, SWT.NONE);
+ label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ CmsSwtUtils.markup(label);
+ label.setText(text.toString());
+ }
+
+ protected boolean isDeployed() {
+ return bc.getServiceReference(UserAdmin.class) != null;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+
+import org.apache.jackrabbit.core.RepositoryContext;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.ServiceReference;
+
+class DataDeploymentUi extends AbstractOsgiComposite {
+ private static final long serialVersionUID = 590221539553514693L;
+
+ public DataDeploymentUi(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void initUi(int style) {
+ if (isDeployed()) {
+ initCurrentUi(this);
+ } else {
+ initNewUi(this);
+ }
+ }
+
+ private void initNewUi(Composite parent) {
+// try {
+// ConfigurationAdmin confAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class));
+// Configuration[] confs = confAdmin.listConfigurations(
+// "(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + NodeConstants.NODE_REPOS_FACTORY_PID + ")");
+// if (confs == null || confs.length == 0) {
+// Group buttonGroup = new Group(parent, SWT.NONE);
+// buttonGroup.setText("Repository Type");
+// buttonGroup.setLayout(new GridLayout(2, true));
+// buttonGroup.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+//
+// SelectionListener selectionListener = new SelectionAdapter() {
+// private static final long serialVersionUID = 6247064348421088092L;
+//
+// public void widgetSelected(SelectionEvent event) {
+// Button radio = (Button) event.widget;
+// if (!radio.getSelection())
+// return;
+// log.debug(event);
+// JackrabbitType nodeType = (JackrabbitType) radio.getData();
+// if (log.isDebugEnabled())
+// log.debug(" selected = " + nodeType.name());
+// };
+// };
+//
+// for (JackrabbitType nodeType : JackrabbitType.values()) {
+// Button radio = new Button(buttonGroup, SWT.RADIO);
+// radio.setText(nodeType.name());
+// radio.setData(nodeType);
+// if (nodeType.equals(JackrabbitType.localfs))
+// radio.setSelection(true);
+// radio.addSelectionListener(selectionListener);
+// }
+//
+// } else if (confs.length == 1) {
+//
+// } else {
+// throw new CmsException("Multiple repos not yet supported");
+// }
+// } catch (Exception e) {
+// throw new CmsException("Cannot initialize UI", e);
+// }
+
+ }
+
+ private void initCurrentUi(Composite parent) {
+ parent.setLayout(new GridLayout());
+ Collection<ServiceReference<RepositoryContext>> contexts = getServiceReferences(RepositoryContext.class,
+ "(" + CmsConstants.CN + "=*)");
+ StringBuffer text = new StringBuffer();
+ text.append("<span style='font-variant: small-caps;'>Jackrabbit Repositories</span><br/>");
+ for (ServiceReference<RepositoryContext> sr : contexts) {
+ RepositoryContext repositoryContext = bc.getService(sr);
+ String alias = sr.getProperty(CmsConstants.CN).toString();
+ String rootNodeId = repositoryContext.getRootNodeId().toString();
+ RepositoryConfig repositoryConfig = repositoryContext.getRepositoryConfig();
+ Path repoHomePath = new File(repositoryConfig.getHomeDir()).toPath().toAbsolutePath();
+ // TODO check data store
+
+ text.append("<b>" + alias + "</b><br/>");
+ text.append("rootNodeId: " + rootNodeId + "<br/>");
+ try {
+ FileStore fileStore = Files.getFileStore(repoHomePath);
+ text.append("partition: " + fileStore.toString() + "<br/>");
+ text.append(
+ percentUsed(fileStore) + " used (" + humanReadable(fileStore.getUsableSpace()) + " free)<br/>");
+ } catch (IOException e) {
+ log.error("Cannot check fileStore for " + repoHomePath, e);
+ }
+ }
+ Label label = new Label(parent, SWT.NONE);
+ label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ CmsSwtUtils.markup(label);
+ label.setText("<span style=''>" + text.toString() + "</span>");
+ }
+
+ private String humanReadable(long bytes) {
+ long mb = bytes / (1024 * 1024);
+ return mb >= 2048 ? Long.toString(mb / 1024) + " GB" : Long.toString(mb) + " MB";
+ }
+
+ private String percentUsed(FileStore fs) throws IOException {
+ long used = fs.getTotalSpace() - fs.getUnallocatedSpace();
+ long percent = used * 100 / fs.getTotalSpace();
+ if (log.isTraceEnabled()) {
+ // output identical to `df -B 1`)
+ log.trace(fs.getTotalSpace() + "," + used + "," + fs.getUsableSpace());
+ }
+ String span;
+ if (percent < 80)
+ span = "<span style='color:green;font-weight:bold'>";
+ else if (percent < 95)
+ span = "<span style='color:orange;font-weight:bold'>";
+ else
+ span = "<span style='color:red;font-weight:bold'>";
+ return span + percent + "%</span>";
+ }
+
+ protected boolean isDeployed() {
+ return bc.getServiceReference(RepositoryContext.class) != null;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsContext;
+import org.argeo.api.cms.CmsDeployment;
+import org.argeo.api.cms.CmsState;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+
+class DeploymentEntryPoint {
+ private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
+
+ protected void createContents(Composite parent) {
+ // FIXME manage authentication if needed
+ // if (!CurrentUser.roles().contains(AuthConstants.ROLE_ADMIN))
+ // return;
+
+ // parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ if (isDesktop()) {
+ parent.setLayout(new GridLayout(2, true));
+ } else {
+ // TODO add scrolling
+ parent.setLayout(new GridLayout(1, true));
+ }
+
+ initHighLevelSummary(parent);
+
+ Group securityGroup = createHighLevelGroup(parent, "Security");
+ securityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ new SecurityDeploymentUi(securityGroup, SWT.NONE);
+
+ Group dataGroup = createHighLevelGroup(parent, "Data");
+ dataGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ new DataDeploymentUi(dataGroup, SWT.NONE);
+
+ Group logGroup = createHighLevelGroup(parent, "Notifications");
+ logGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
+ new LogDeploymentUi(logGroup, SWT.NONE);
+
+ Group connectivityGroup = createHighLevelGroup(parent, "Connectivity");
+ new ConnectivityDeploymentUi(connectivityGroup, SWT.NONE);
+ connectivityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
+
+ }
+
+ private void initHighLevelSummary(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
+ if (isDesktop())
+ gridData.horizontalSpan = 3;
+ composite.setLayoutData(gridData);
+ composite.setLayout(new FillLayout());
+
+ ServiceReference<CmsState> nodeStateRef = bc.getServiceReference(CmsState.class);
+ if (nodeStateRef == null)
+ throw new IllegalStateException("No CMS state available");
+ CmsState nodeState = bc.getService(nodeStateRef);
+ ServiceReference<CmsContext> nodeDeploymentRef = bc.getServiceReference(CmsContext.class);
+ Label label = new Label(composite, SWT.WRAP);
+ CmsSwtUtils.markup(label);
+ if (nodeDeploymentRef == null) {
+ label.setText("Not yet deployed on <br>" + nodeState.getHostname() + "</br>, please configure below.");
+ } else {
+ Object stateUuid = nodeStateRef.getProperty(CmsConstants.CN);
+ CmsContext nodeDeployment = bc.getService(nodeDeploymentRef);
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTimeInMillis(nodeDeployment.getAvailableSince());
+ calendar.setTimeZone(TimeZone.getDefault());
+ label.setText("[" + "<b>" + nodeState.getHostname() + "</b>]# " + "Deployment state " + stateUuid
+ + ", available since <b>" + calendar.getTime() + "</b>");
+ }
+ }
+
+ private static Group createHighLevelGroup(Composite parent, String text) {
+ Group group = new Group(parent, SWT.NONE);
+ group.setText(text);
+ CmsSwtUtils.markup(group);
+ return group;
+ }
+
+ private boolean isDesktop() {
+ return true;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Enumeration;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogListener;
+import org.osgi.service.log.LogReaderService;
+
+class LogDeploymentUi extends AbstractOsgiComposite implements LogListener {
+ private static final long serialVersionUID = 590221539553514693L;
+
+ private DateFormat dateFormat = new SimpleDateFormat("MMdd HH:mm");
+
+ private Display display;
+ private Text logDisplay;
+
+ public LogDeploymentUi(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void initUi(int style) {
+ LogReaderService logReader = getService(LogReaderService.class);
+ // FIXME use server push
+ // logReader.addLogListener(this);
+ this.display = getDisplay();
+ this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ logDisplay = new Text(this, SWT.WRAP | SWT.MULTI | SWT.READ_ONLY);
+ logDisplay.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ CmsSwtUtils.markup(logDisplay);
+ Enumeration<LogEntry> logEntries = (Enumeration<LogEntry>) logReader.getLog();
+ while (logEntries.hasMoreElements())
+ logDisplay.append(printEntry(logEntries.nextElement()));
+ }
+
+ private String printEntry(LogEntry entry) {
+ StringBuilder sb = new StringBuilder();
+ GregorianCalendar calendar = new GregorianCalendar(TimeZone.getDefault());
+ calendar.setTimeInMillis(entry.getTime());
+ sb.append(dateFormat.format(calendar.getTime())).append(' ');
+ sb.append(entry.getMessage());
+ sb.append('\n');
+ return sb.toString();
+ }
+
+ @Override
+ public void logged(LogEntry entry) {
+ if (display.isDisposed())
+ return;
+ display.asyncExec(() -> {
+ if (logDisplay.isDisposed())
+ return;
+ logDisplay.append(printEntry(entry));
+ });
+ display.wake();
+ }
+
+ // @Override
+ // public void dispose() {
+ // super.dispose();
+ // getService(LogReaderService.class).removeLogListener(this);
+ // }
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+/** Specific styles used by the various maintenance pages . */
+public interface MaintenanceStyles {
+ // General
+ public final static String PREFIX = "maintenance_";
+
+ // Browser
+ public final static String BROWSER_COLUMN = "browser_column";
+ }
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+public class NonAdminPage implements CmsUiProvider{
+
+ @Override
+ public Control createUi(Composite parent, Node context)
+ throws RepositoryException {
+ Composite body = new Composite(parent, SWT.NO_FOCUS);
+ body.setLayoutData(CmsSwtUtils.fillAll());
+ body.setLayout(new GridLayout());
+ Label label = new Label(body, SWT.NONE);
+ label.setText("You should be an admin to perform maintenance operations. "
+ + "Are you sure you are logged in?");
+ label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+ return null;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.maintenance;
+
+import java.net.URI;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdmin;
+
+class SecurityDeploymentUi extends AbstractOsgiComposite {
+ private static final long serialVersionUID = 590221539553514693L;
+
+ public SecurityDeploymentUi(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void initUi(int style) {
+ if (isDeployed()) {
+ initCurrentUi(this);
+ } else {
+ initNewUi(this);
+ }
+ }
+
+ private void initNewUi(Composite parent) {
+ new Label(parent, SWT.NONE).setText("Security is not configured");
+ }
+
+ private void initCurrentUi(Composite parent) {
+ ServiceReference<UserAdmin> userAdminRef = bc.getServiceReference(UserAdmin.class);
+ UserAdmin userAdmin = bc.getService(userAdminRef);
+ StringBuffer text = new StringBuffer();
+ text.append("<span style='font-variant: small-caps;'>Domains</span><br/>");
+ domains: for (String key : userAdminRef.getPropertyKeys()) {
+ if (!key.startsWith("/"))
+ continue domains;
+ URI uri;
+ try {
+ uri = new URI(key);
+ } catch (Exception e) {
+ // ignore non URI keys
+ continue domains;
+ }
+
+ String rootDn = uri.getPath().substring(1, uri.getPath().length());
+ // FIXME make reading query options more robust, using utils
+ boolean readOnly = uri.getQuery().equals("readOnly=true");
+ if (readOnly)
+ text.append("<span style='font-weight:bold;font-style: italic'>");
+ else
+ text.append("<span style='font-weight:bold'>");
+
+ text.append(rootDn);
+ text.append("</span><br/>");
+ try {
+ Role[] roles = userAdmin.getRoles("(dn=*," + rootDn + ")");
+ long userCount = 0;
+ long groupCount = 0;
+ for (Role role : roles) {
+ if (role.getType() == Role.USER)
+ userCount++;
+ else
+ groupCount++;
+ }
+ text.append(" " + userCount + " users, " + groupCount +" groups.<br/>");
+ } catch (InvalidSyntaxException e) {
+ log.error("Invalid syntax", e);
+ }
+ }
+ Label label = new Label(parent, SWT.NONE);
+ label.setData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ CmsSwtUtils.markup(label);
+ label.setText(text.toString());
+ }
+
+ protected boolean isDeployed() {
+ return bc.getServiceReference(UserAdmin.class) != null;
+ }
+}
--- /dev/null
+/** Maintenance perspective. */
+package org.argeo.cms.e4.maintenance;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.monitoring;
+
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+/** A tree element representing a {@link Bundle} */
+class BundleNode extends TreeParent {
+ private final Bundle bundle;
+
+ public BundleNode(Bundle bundle) {
+ this(bundle, false);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public BundleNode(Bundle bundle, boolean hasChildren) {
+ super(bundle.getSymbolicName());
+ this.bundle = bundle;
+
+ if (hasChildren) {
+ // REFERENCES
+ ServiceReference[] usedServices = bundle.getServicesInUse();
+ if (usedServices != null) {
+ for (ServiceReference sr : usedServices) {
+ if (sr != null)
+ addChild(new ServiceReferenceNode(sr, false));
+ }
+ }
+
+ // SERVICES
+ ServiceReference[] registeredServices = bundle
+ .getRegisteredServices();
+ if (registeredServices != null) {
+ for (ServiceReference sr : registeredServices) {
+ if (sr != null)
+ addChild(new ServiceReferenceNode(sr, true));
+ }
+ }
+ }
+
+ }
+
+ Bundle getBundle() {
+ return bundle;
+ }
+}
--- /dev/null
+//package org.argeo.eclipse.ui.workbench.osgi;
+//public class BundlesView {}
+
+package org.argeo.cms.e4.monitoring;
+
+import javax.annotation.PostConstruct;
+
+import org.argeo.eclipse.ui.ColumnViewerComparator;
+import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * Overview of the bundles as a table. Equivalent to Equinox 'ss' console
+ * command.
+ */
+public class BundlesView {
+ private final static BundleContext bc = FrameworkUtil.getBundle(BundlesView.class).getBundleContext();
+ private TableViewer viewer;
+
+ @PostConstruct
+ public void createPartControl(Composite parent) {
+ viewer = new TableViewer(parent);
+ viewer.setContentProvider(new BundleContentProvider());
+ viewer.getTable().setHeaderVisible(true);
+
+ EclipseUiSpecificUtils.enableToolTipSupport(viewer);
+
+ // ID
+ TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(30);
+ column.getColumn().setText("ID");
+ column.getColumn().setAlignment(SWT.RIGHT);
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -3122136344359358605L;
+
+ public String getText(Object element) {
+ return Long.toString(((Bundle) element).getBundleId());
+ }
+ });
+ new ColumnViewerComparator(column);
+
+ // State
+ column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(18);
+ column.getColumn().setText("State");
+ column.setLabelProvider(new StateLabelProvider());
+ new ColumnViewerComparator(column);
+
+ // Symbolic name
+ column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(250);
+ column.getColumn().setText("Symbolic Name");
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -4280840684440451080L;
+
+ public String getText(Object element) {
+ return ((Bundle) element).getSymbolicName();
+ }
+ });
+ new ColumnViewerComparator(column);
+
+ // Version
+ column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(250);
+ column.getColumn().setText("Version");
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = 6871926308708629989L;
+
+ public String getText(Object element) {
+ Bundle bundle = (org.osgi.framework.Bundle) element;
+ return bundle.getVersion().toString();
+ }
+ });
+ new ColumnViewerComparator(column);
+
+ viewer.setInput(bc);
+
+ }
+
+ @Focus
+ public void setFocus() {
+ if (viewer != null)
+ viewer.getControl().setFocus();
+ }
+
+ /** Content provider managing the array of bundles */
+ private static class BundleContentProvider implements IStructuredContentProvider {
+ private static final long serialVersionUID = -8533792785725875977L;
+
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof BundleContext) {
+ BundleContext bc = (BundleContext) inputElement;
+ return bc.getBundles();
+ }
+ return null;
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ }
+}
--- /dev/null
+//package org.argeo.eclipse.ui.workbench.osgi;
+//public class BundlesView {}
+
+package org.argeo.cms.e4.monitoring;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.argeo.api.cms.CmsSession;
+import org.argeo.cms.auth.RoleNameUtils;
+import org.argeo.eclipse.ui.ColumnViewerComparator;
+import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
+import org.argeo.util.LangUtils;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Overview of the active CMS sessions.
+ */
+public class CmsSessionsView {
+ private final static BundleContext bc = FrameworkUtil.getBundle(CmsSessionsView.class).getBundleContext();
+
+ private TableViewer viewer;
+
+ @PostConstruct
+ public void createPartControl(Composite parent) {
+ viewer = new TableViewer(parent);
+ viewer.setContentProvider(new CmsSessionContentProvider());
+ viewer.getTable().setHeaderVisible(true);
+
+ EclipseUiSpecificUtils.enableToolTipSupport(viewer);
+
+ int longColWidth = 150;
+ int smallColWidth = 100;
+
+ // Display name
+ TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(longColWidth);
+ column.getColumn().setText("User");
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -5234573509093747505L;
+
+ public String getText(Object element) {
+ return ((CmsSession) element).getDisplayName();
+ }
+
+ public String getToolTipText(Object element) {
+ return ((CmsSession) element).getUserDn().toString();
+ }
+ });
+ new ColumnViewerComparator(column);
+
+ // Creation time
+ column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(smallColWidth);
+ column.getColumn().setText("Since");
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -5234573509093747505L;
+
+ public String getText(Object element) {
+ return LangUtils.since(((CmsSession) element).getCreationTime());
+ }
+
+ public String getToolTipText(Object element) {
+ return ((CmsSession) element).getCreationTime().toString();
+ }
+ });
+ new ColumnViewerComparator(column);
+
+ // Username
+ column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(smallColWidth);
+ column.getColumn().setText("Username");
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -5234573509093747505L;
+
+ public String getText(Object element) {
+ String userDn = ((CmsSession) element).getUserDn();
+ return RoleNameUtils.getLastRdnValue(userDn);
+ }
+
+ public String getToolTipText(Object element) {
+ return ((CmsSession) element).getUserDn().toString();
+ }
+ });
+ new ColumnViewerComparator(column);
+
+ // UUID
+ column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(smallColWidth);
+ column.getColumn().setText("UUID");
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -5234573509093747505L;
+
+ public String getText(Object element) {
+ return ((CmsSession) element).getUuid().toString();
+ }
+
+ public String getToolTipText(Object element) {
+ return getText(element);
+ }
+ });
+ new ColumnViewerComparator(column);
+
+ // Local ID
+ column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setWidth(smallColWidth);
+ column.getColumn().setText("Local ID");
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -5234573509093747505L;
+
+ public String getText(Object element) {
+ return ((CmsSession) element).getLocalId();
+ }
+
+ public String getToolTipText(Object element) {
+ return getText(element);
+ }
+ });
+ new ColumnViewerComparator(column);
+
+ viewer.setInput(bc);
+
+ }
+
+ @Focus
+ public void setFocus() {
+ if (viewer != null)
+ viewer.getControl().setFocus();
+ }
+
+ /** Content provider managing the array of bundles */
+ private static class CmsSessionContentProvider implements IStructuredContentProvider {
+ private static final long serialVersionUID = -8533792785725875977L;
+
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof BundleContext) {
+ BundleContext bc = (BundleContext) inputElement;
+ Collection<ServiceReference<CmsSession>> srs;
+ try {
+ srs = bc.getServiceReferences(CmsSession.class, null);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Cannot retrieve CMS sessions", e);
+ }
+ List<CmsSession> res = new ArrayList<>();
+ for (ServiceReference<CmsSession> sr : srs) {
+ res.add(bc.getService(sr));
+ }
+ return res.toArray();
+ }
+ return null;
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.monitoring;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+/** The OSGi runtime from a module perspective. */
+public class ModulesView {
+ private final static BundleContext bc = FrameworkUtil.getBundle(ModulesView.class).getBundleContext();
+ private TreeViewer viewer;
+
+ @PostConstruct
+ public void createPartControl(Composite parent) {
+ viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ viewer.setContentProvider(new ModulesContentProvider());
+ viewer.setLabelProvider(new ModulesLabelProvider());
+ viewer.setInput(bc);
+ }
+
+ @Focus
+ public void setFocus() {
+ viewer.getTree().setFocus();
+ }
+
+ private class ModulesContentProvider implements ITreeContentProvider {
+ private static final long serialVersionUID = 3819934804640641721L;
+
+ public Object[] getElements(Object inputElement) {
+ return getChildren(inputElement);
+ }
+
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof BundleContext) {
+ BundleContext bundleContext = (BundleContext) parentElement;
+ Bundle[] bundles = bundleContext.getBundles();
+
+ List<BundleNode> modules = new ArrayList<BundleNode>();
+ for (Bundle bundle : bundles) {
+ if (bundle.getState() == Bundle.ACTIVE)
+ modules.add(new BundleNode(bundle, true));
+ }
+ return modules.toArray();
+ } else if (parentElement instanceof TreeParent) {
+ return ((TreeParent) parentElement).getChildren();
+ } else {
+ return null;
+ }
+ }
+
+ public Object getParent(Object element) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean hasChildren(Object element) {
+ if (element instanceof TreeParent) {
+ return ((TreeParent) element).hasChildren();
+ }
+ return false;
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ }
+
+ private class ModulesLabelProvider extends StateLabelProvider {
+ private static final long serialVersionUID = 5290046145534824722L;
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof BundleNode)
+ return element.toString() + " [" + ((BundleNode) element).getBundle().getBundleId() + "]";
+ return element.toString();
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.monitoring;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.argeo.cms.swt.CmsException;
+import org.argeo.util.LangUtils;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class OsgiConfigurationsView {
+ private final static BundleContext bc = FrameworkUtil.getBundle(OsgiConfigurationsView.class).getBundleContext();
+
+ @PostConstruct
+ public void createPartControl(Composite parent) {
+ ConfigurationAdmin configurationAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class));
+
+ TreeViewer viewer = new TreeViewer(parent);
+ // viewer.getTree().setHeaderVisible(true);
+
+ TreeViewerColumn tvc = new TreeViewerColumn(viewer, SWT.NONE);
+ tvc.getColumn().setWidth(400);
+ tvc.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = 835407996597566763L;
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof Configuration) {
+ return ((Configuration) element).getPid();
+ } else if (element instanceof Prop) {
+ return ((Prop) element).key;
+ }
+ return super.getText(element);
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ if (element instanceof Configuration)
+ return OsgiExplorerImages.CONFIGURATION;
+ return null;
+ }
+
+ });
+
+ tvc = new TreeViewerColumn(viewer, SWT.NONE);
+ tvc.getColumn().setWidth(400);
+ tvc.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = 6999659261190014687L;
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof Configuration) {
+ // return ((Configuration) element).getFactoryPid();
+ return null;
+ } else if (element instanceof Prop) {
+ return ((Prop) element).value.toString();
+ }
+ return super.getText(element);
+ }
+ });
+
+ viewer.setContentProvider(new ConfigurationsContentProvider());
+ viewer.setInput(configurationAdmin);
+ }
+
+ static class ConfigurationsContentProvider implements ITreeContentProvider {
+ private static final long serialVersionUID = -4892768279440981042L;
+ private ConfigurationComparator configurationComparator = new ConfigurationComparator();
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ ConfigurationAdmin configurationAdmin = (ConfigurationAdmin) inputElement;
+ try {
+ Configuration[] configurations = configurationAdmin.listConfigurations(null);
+ Arrays.sort(configurations, configurationComparator);
+ return configurations;
+ } catch (IOException | InvalidSyntaxException e) {
+ throw new CmsException("Cannot list configurations", e);
+ }
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof Configuration) {
+ List<Prop> res = new ArrayList<>();
+ Configuration configuration = (Configuration) parentElement;
+ Dictionary<String, Object> props = configuration.getProperties();
+ keys: for (String key : LangUtils.keys(props)) {
+ if (Constants.SERVICE_PID.equals(key))
+ continue keys;
+ if (ConfigurationAdmin.SERVICE_FACTORYPID.equals(key))
+ continue keys;
+ res.add(new Prop(configuration, key, props.get(key)));
+ }
+ return res.toArray(new Prop[res.size()]);
+ }
+ return null;
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ if (element instanceof Prop)
+ return ((Prop) element).configuration;
+ return null;
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ if (element instanceof Configuration)
+ return true;
+ return false;
+ }
+
+ }
+
+ static class Prop {
+ final Configuration configuration;
+ final String key;
+ final Object value;
+
+ public Prop(Configuration configuration, String key, Object value) {
+ this.configuration = configuration;
+ this.key = key;
+ this.value = value;
+ }
+
+ }
+
+ static class ConfigurationComparator implements Comparator<Configuration> {
+
+ @Override
+ public int compare(Configuration o1, Configuration o2) {
+ return o1.getPid().compareTo(o2.getPid());
+ }
+
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.monitoring;
+
+import org.argeo.cms.ui.theme.CmsImages;
+import org.eclipse.swt.graphics.Image;
+
+/** Shared icons. */
+public class OsgiExplorerImages extends CmsImages {
+ public final static Image INSTALLED = createIcon("installed.gif");
+ public final static Image RESOLVED = createIcon("resolved.gif");
+ public final static Image STARTING = createIcon("starting.gif");
+ public final static Image ACTIVE = createIcon("active.gif");
+ public final static Image SERVICE_PUBLISHED = createIcon("service_published.gif");
+ public final static Image SERVICE_REFERENCED = createIcon("service_referenced.gif");
+ public final static Image CONFIGURATION = createIcon("node.gif");
+}
--- /dev/null
+package org.argeo.cms.e4.monitoring;
+
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+/** A tree element representing a {@link ServiceReference} */
+@SuppressWarnings({ "rawtypes" })
+class ServiceReferenceNode extends TreeParent {
+ private final ServiceReference serviceReference;
+ private final boolean published;
+
+ public ServiceReferenceNode(ServiceReference serviceReference,
+ boolean published) {
+ super(serviceReference.toString());
+ this.serviceReference = serviceReference;
+ this.published = published;
+
+ if (isPublished()) {
+ Bundle[] usedBundles = serviceReference.getUsingBundles();
+ if (usedBundles != null) {
+ for (Bundle b : usedBundles) {
+ if (b != null)
+ addChild(new BundleNode(b));
+ }
+ }
+ } else {
+ Bundle provider = serviceReference.getBundle();
+ addChild(new BundleNode(provider));
+ }
+
+ for (String key : serviceReference.getPropertyKeys()) {
+ addChild(new TreeParent(key + "="
+ + serviceReference.getProperty(key)));
+ }
+
+ }
+
+ public ServiceReference getServiceReference() {
+ return serviceReference;
+ }
+
+ public boolean isPublished() {
+ return published;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.monitoring;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+/** Label provider showing the sate of bundles */
+class StateLabelProvider extends ColumnLabelProvider {
+ private static final long serialVersionUID = -7885583135316000733L;
+
+ @Override
+ public Image getImage(Object element) {
+ int state;
+ if (element instanceof Bundle)
+ state = ((Bundle) element).getState();
+ else if (element instanceof BundleNode)
+ state = ((BundleNode) element).getBundle().getState();
+ else if (element instanceof ServiceReferenceNode)
+ if (((ServiceReferenceNode) element).isPublished())
+ return OsgiExplorerImages.SERVICE_PUBLISHED;
+ else
+ return OsgiExplorerImages.SERVICE_REFERENCED;
+ else
+ return null;
+
+ switch (state) {
+ case Bundle.UNINSTALLED:
+ return OsgiExplorerImages.INSTALLED;
+ case Bundle.INSTALLED:
+ return OsgiExplorerImages.INSTALLED;
+ case Bundle.RESOLVED:
+ return OsgiExplorerImages.RESOLVED;
+ case Bundle.STARTING:
+ return OsgiExplorerImages.STARTING;
+ case Bundle.STOPPING:
+ return OsgiExplorerImages.STARTING;
+ case Bundle.ACTIVE:
+ return OsgiExplorerImages.ACTIVE;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public String getText(Object element) {
+ return null;
+ }
+
+ @Override
+ public String getToolTipText(Object element) {
+ Bundle bundle = (Bundle) element;
+ Integer state = bundle.getState();
+ switch (state) {
+ case Bundle.UNINSTALLED:
+ return "UNINSTALLED";
+ case Bundle.INSTALLED:
+ return "INSTALLED";
+ case Bundle.RESOLVED:
+ return "RESOLVED";
+ case Bundle.STARTING:
+ String activationPolicy = bundle.getHeaders()
+ .get(Constants.BUNDLE_ACTIVATIONPOLICY).toString();
+
+ // .get("Bundle-ActivationPolicy").toString();
+ // FIXME constant triggers the compilation failure
+ if (activationPolicy != null
+ && activationPolicy.equals(Constants.ACTIVATION_LAZY))
+ // && activationPolicy.equals("lazy"))
+ // FIXME constant triggers the compilation failure
+ // && activationPolicy.equals(Constants.ACTIVATION_LAZY))
+ return "<<LAZY>>";
+ return "STARTING";
+ case Bundle.STOPPING:
+ return "STOPPING";
+ case Bundle.ACTIVE:
+ return "ACTIVE";
+ default:
+ return null;
+ }
+ }
+}
--- /dev/null
+/** Monitoring perspective. */
+package org.argeo.cms.e4.monitoring;
\ No newline at end of file
--- /dev/null
+/** Eclipse 4 user interfaces. */
+package org.argeo.cms.e4;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.parts;
+
+import java.time.ZonedDateTime;
+
+import javax.annotation.PostConstruct;
+
+import org.argeo.api.cms.CmsSession;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/** A canonical view of the logged in user. */
+public class EgoDashboard {
+// private BundleContext bc = FrameworkUtil.getBundle(EgoDashboard.class).getBundleContext();
+
+ @PostConstruct
+ public void createPartControl(Composite p) {
+ p.setLayout(new GridLayout());
+ String username = CurrentUser.getUsername();
+
+ CmsSwtUtils.lbl(p, "<strong>" + CurrentUser.getDisplayName() + "</strong>");
+ CmsSwtUtils.txt(p, username);
+ CmsSwtUtils.lbl(p, "Roles:");
+ roles: for (String role : CurrentUser.roles()) {
+ if (username.equals(role))
+ continue roles;
+ CmsSwtUtils.txt(p, role);
+ }
+
+// Subject subject = Subject.getSubject(AccessController.getContext());
+// if (subject != null) {
+ CmsSession cmsSession = CurrentUser.getCmsSession();
+ ZonedDateTime loggedIndSince = cmsSession.getCreationTime();
+ CmsSwtUtils.lbl(p, "Session:");
+ CmsSwtUtils.txt(p, cmsSession.getUuid().toString());
+ CmsSwtUtils.lbl(p, "Logged in since:");
+ CmsSwtUtils.txt(p, loggedIndSince.toString());
+// }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
+import org.argeo.cms.ui.eclipse.forms.IManagedForm;
+import org.argeo.cms.ui.eclipse.forms.ManagedForm;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.util.naming.LdapAttrs;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.e4.ui.di.Persist;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+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.Label;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/** Editor for a user, might be a user or a group. */
+public abstract class AbstractRoleEditor {
+
+ // public final static String USER_EDITOR_ID = WorkbenchUiPlugin.PLUGIN_ID +
+ // ".userEditor";
+ // public final static String GROUP_EDITOR_ID = WorkbenchUiPlugin.PLUGIN_ID +
+ // ".groupEditor";
+
+ /* DEPENDENCY INJECTION */
+ @Inject
+ protected UserAdminWrapper userAdminWrapper;
+
+ @Inject
+ private MPart mPart;
+
+ // @Inject
+ // Composite parent;
+
+ private UserAdmin userAdmin;
+
+ // Context
+ private User user;
+ private String username;
+
+ private NameChangeListener listener;
+
+ private ManagedForm managedForm;
+
+ // public void init(IEditorSite site, IEditorInput input) throws
+ // PartInitException {
+ @PostConstruct
+ public void init(Composite parent) {
+ this.userAdmin = userAdminWrapper.getUserAdmin();
+ username = mPart.getPersistedState().get(LdapAttrs.uid.name());
+ user = (User) userAdmin.getRole(username);
+
+ listener = new NameChangeListener(Display.getCurrent());
+ userAdminWrapper.addListener(listener);
+ updateEditorTitle(null);
+
+ managedForm = new ManagedForm(parent) {
+
+ @Override
+ public void staleStateChanged() {
+ refresh();
+ }
+ };
+ ScrolledComposite scrolled = managedForm.getForm();
+ Composite body = new Composite(scrolled, SWT.NONE);
+ scrolled.setContent(body);
+ createUi(body);
+ managedForm.refresh();
+ }
+
+ abstract void createUi(Composite parent);
+
+ /**
+ * returns the list of all authorizations for the given user or of the current
+ * displayed user if parameter is null
+ */
+ protected List<User> getFlatGroups(User aUser) {
+ Authorization currAuth;
+ if (aUser == null)
+ currAuth = userAdmin.getAuthorization(this.user);
+ else
+ currAuth = userAdmin.getAuthorization(aUser);
+
+ String[] roles = currAuth.getRoles();
+
+ List<User> groups = new ArrayList<User>();
+ for (String roleStr : roles) {
+ User currRole = (User) userAdmin.getRole(roleStr);
+ if (currRole != null && !groups.contains(currRole))
+ groups.add(currRole);
+ }
+ return groups;
+ }
+
+ protected IManagedForm getManagedForm() {
+ return managedForm;
+ }
+
+ /** Exposes the user (or group) that is displayed by the current editor */
+ protected User getDisplayedUser() {
+ return user;
+ }
+
+ private void setDisplayedUser(User user) {
+ this.user = user;
+ }
+
+ void updateEditorTitle(String title) {
+ if (title == null) {
+ String commonName = UserAdminUtils.getProperty(user, LdapAttrs.cn.name());
+ title = "".equals(commonName) ? user.getName() : commonName;
+ }
+ setPartName(title);
+ }
+
+ protected void setPartName(String name) {
+ mPart.setLabel(name);
+ }
+
+ // protected void addPages() {
+ // try {
+ // if (user.getType() == Role.GROUP)
+ // addPage(new GroupMainPage(this, userAdminWrapper, repository, nodeInstance));
+ // else
+ // addPage(new UserMainPage(this, userAdminWrapper));
+ // } catch (Exception e) {
+ // throw new CmsException("Cannot add pages", e);
+ // }
+ // }
+
+ @Persist
+ public void doSave(IProgressMonitor monitor) {
+ userAdminWrapper.beginTransactionIfNeeded();
+ commitPages(true);
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ // firePropertyChange(PROP_DIRTY);
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_REMOVED, user));
+ }
+
+ protected void commitPages(boolean b) {
+ managedForm.commit(b);
+ }
+
+ @PreDestroy
+ public void dispose() {
+ userAdminWrapper.removeListener(listener);
+ managedForm.dispose();
+ }
+
+ // CONTROLERS FOR THIS EDITOR AND ITS PAGES
+
+ class NameChangeListener extends UiUserAdminListener {
+ public NameChangeListener(Display display) {
+ super(display);
+ }
+
+ @Override
+ public void roleChangedToUiThread(UserAdminEvent event) {
+ Role changedRole = event.getRole();
+ if (changedRole == null || changedRole.equals(user)) {
+ updateEditorTitle(null);
+ User reloadedUser = (User) userAdminWrapper.getUserAdmin().getRole(user.getName());
+ setDisplayedUser(reloadedUser);
+ }
+ }
+ }
+
+ class MainInfoListener extends UiUserAdminListener {
+ private final AbstractFormPart part;
+
+ public MainInfoListener(Display display, AbstractFormPart part) {
+ super(display);
+ this.part = part;
+ }
+
+ @Override
+ public void roleChangedToUiThread(UserAdminEvent event) {
+ // Rollback
+ if (event.getRole() == null)
+ part.markStale();
+ }
+ }
+
+ class GroupChangeListener extends UiUserAdminListener {
+ private final AbstractFormPart part;
+
+ public GroupChangeListener(Display display, AbstractFormPart part) {
+ super(display);
+ this.part = part;
+ }
+
+ @Override
+ public void roleChangedToUiThread(UserAdminEvent event) {
+ // always mark as stale
+ part.markStale();
+ }
+ }
+
+ /** Registers a listener that will notify this part */
+ class FormPartML implements ModifyListener {
+ private static final long serialVersionUID = 6299808129505381333L;
+ private AbstractFormPart formPart;
+
+ public FormPartML(AbstractFormPart generalPart) {
+ this.formPart = generalPart;
+ }
+
+ public void modifyText(ModifyEvent e) {
+ // Discard event when the control does not have the focus, typically
+ // to avoid all editors being marked as dirty during a Rollback
+ if (((Control) e.widget).isFocusControl())
+ formPart.markDirty();
+ }
+ }
+
+ /* DEPENDENCY INJECTION */
+ public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
+ this.userAdminWrapper = userAdminWrapper;
+ }
+
+ /** Creates label and multiline text. */
+ Text createLMT(Composite parent, String label, String value) {
+ Label lbl = new Label(parent, SWT.NONE);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+ Text text = new Text(parent, SWT.NONE);
+ text.setText(value);
+ text.setLayoutData(new GridData(SWT.LEAD, SWT.FILL, true, true));
+ return text;
+ }
+
+ /** Creates label and password. */
+ Text createLP(Composite parent, String label, String value) {
+ Label lbl = new Label(parent, SWT.NONE);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+ Text text = new Text(parent, SWT.PASSWORD | SWT.BORDER);
+ text.setText(value);
+ text.setLayoutData(new GridData(SWT.LEAD, SWT.FILL, true, false));
+ return text;
+ }
+
+ /** Creates label and text. */
+ Text createLT(Composite parent, String label, String value) {
+ Label lbl = new Label(parent, SWT.NONE);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+ lbl.setFont(EclipseUiUtils.getBoldFont(parent));
+ Text text = new Text(parent, SWT.BORDER);
+ text.setText(value);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
+ return text;
+ }
+
+ Text createReadOnlyLT(Composite parent, String label, String value) {
+ Label lbl = new Label(parent, SWT.NONE);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+ lbl.setFont(EclipseUiUtils.getBoldFont(parent));
+ Text text = new Text(parent, SWT.NONE);
+ text.setText(value);
+ text.setLayoutData(new GridData(SWT.LEAD, SWT.FILL, true, false));
+ text.setEditable(false);
+ // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
+ return text;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+/** Centralize the declaration of Workbench specific CSS Styles */
+interface CmsWorkbenchStyles {
+
+ // Specific People layouting
+ String WORKBENCH_FORM_TEXT = "workbench_form_text";
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import static org.argeo.api.cms.CmsContext.WORKGROUP;
+import static org.argeo.cms.auth.UserAdminUtils.setProperty;
+import static org.argeo.util.naming.LdapAttrs.businessCategory;
+import static org.argeo.util.naming.LdapAttrs.description;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsContext;
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.e4.users.providers.CommonNameLP;
+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.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.parts.LdifUsersTable;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.transaction.WorkTransaction;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.ViewerDropAdapter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.dnd.TransferData;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+//import org.eclipse.ui.forms.AbstractFormPart;
+//import org.eclipse.ui.forms.IManagedForm;
+//import org.eclipse.ui.forms.SectionPart;
+//import org.eclipse.ui.forms.editor.FormEditor;
+//import org.eclipse.ui.forms.editor.FormPage;
+//import org.eclipse.ui.forms.widgets.FormToolkit;
+//import org.eclipse.ui.forms.widgets.ScrolledForm;
+//import org.eclipse.ui.forms.widgets.Section;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/** Display/edit main properties of a given group */
+public class GroupEditor extends AbstractRoleEditor {
+ // final static String ID = "GroupEditor.mainPage";
+
+ @Inject
+ private EPartService partService;
+
+ // private final UserEditor editor;
+ @Inject
+ private Repository repository;
+ @Inject
+ private CmsContext nodeInstance;
+ // private final UserAdminWrapper userAdminWrapper;
+ private Session groupsSession;
+
+ // public GroupMainPage(FormEditor editor, UserAdminWrapper userAdminWrapper,
+ // Repository repository,
+ // NodeInstance nodeInstance) {
+ // super(editor, ID, "Main");
+ // try {
+ // session = repository.login();
+ // } catch (RepositoryException e) {
+ // throw new CmsException("Cannot retrieve session of in MainGroupPage
+ // constructor", e);
+ // }
+ // this.editor = (UserEditor) editor;
+ // this.userAdminWrapper = userAdminWrapper;
+ // this.nodeInstance = nodeInstance;
+ // }
+
+ // protected void createFormContent(final IManagedForm mf) {
+ // ScrolledForm form = mf.getForm();
+ // Composite body = form.getBody();
+ // GridLayout mainLayout = new GridLayout();
+ // body.setLayout(mainLayout);
+ // Group group = (Group) editor.getDisplayedUser();
+ // appendOverviewPart(body, group);
+ // appendMembersPart(body, group);
+ // }
+
+ @Override
+ protected void createUi(Composite parent) {
+ try {
+ groupsSession = repository.login(CmsConstants.SRV_WORKSPACE);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot retrieve session", e);
+ }
+ // ScrolledForm form = mf.getForm();
+ // Composite body = form.getBody();
+ // Composite body = new Composite(parent, SWT.NONE);
+ Composite body = parent;
+ GridLayout mainLayout = new GridLayout();
+ body.setLayout(mainLayout);
+ Group group = (Group) getDisplayedUser();
+ appendOverviewPart(body, group);
+ appendMembersPart(body, group);
+ }
+
+ @PreDestroy
+ public void dispose() {
+ JcrUtils.logoutQuietly(groupsSession);
+ super.dispose();
+ }
+
+ /** Creates the general section */
+ protected void appendOverviewPart(final Composite parent, final Group group) {
+ Composite body = new Composite(parent, SWT.NONE);
+ // GridLayout layout = new GridLayout(5, false);
+ GridLayout layout = new GridLayout(2, false);
+ body.setLayout(layout);
+ body.setLayoutData(CmsSwtUtils.fillWidth());
+
+ String cn = UserAdminUtils.getProperty(group, LdapAttrs.cn.name());
+ createReadOnlyLT(body, "Name", cn);
+ createReadOnlyLT(body, "DN", group.getName());
+ createReadOnlyLT(body, "Domain", UserAdminUtils.getDomainName(group));
+
+ // Description
+ Label descLbl = new Label(body, SWT.LEAD);
+ descLbl.setFont(EclipseUiUtils.getBoldFont(body));
+ descLbl.setText("Description");
+ descLbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false, 2, 1));
+ final Text descTxt = new Text(body, SWT.LEAD | SWT.MULTI | SWT.WRAP | SWT.BORDER);
+ GridData gd = EclipseUiUtils.fillWidth();
+ gd.heightHint = 50;
+ gd.horizontalSpan = 2;
+ descTxt.setLayoutData(gd);
+
+ // Mark as workgroup
+ Link markAsWorkgroupLk = new Link(body, SWT.NONE);
+ markAsWorkgroupLk.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
+
+ // create form part (controller)
+ final AbstractFormPart part = new AbstractFormPart() {
+
+ private MainInfoListener listener;
+
+ @Override
+ public void initialize(IManagedForm form) {
+ super.initialize(form);
+ listener = new MainInfoListener(parent.getDisplay(), this);
+ userAdminWrapper.addListener(listener);
+ }
+
+ @Override
+ public void dispose() {
+ userAdminWrapper.removeListener(listener);
+ super.dispose();
+ }
+
+ public void commit(boolean onSave) {
+ // group.getProperties().put(LdapAttrs.description.name(), descTxt.getText());
+ setProperty(group, description, descTxt.getText());
+ super.commit(onSave);
+ }
+
+ @Override
+ public void refresh() {
+ // dnTxt.setText(group.getName());
+ // cnTxt.setText(UserAdminUtils.getProperty(group, LdapAttrs.cn.name()));
+ descTxt.setText(UserAdminUtils.getProperty(group, LdapAttrs.description.name()));
+ Node workgroupHome = CmsJcrUtils.getGroupHome(groupsSession, cn);
+ if (workgroupHome == null)
+ markAsWorkgroupLk.setText("<a>Mark as workgroup</a>");
+ else
+ markAsWorkgroupLk.setText("Configured as workgroup");
+ parent.layout(true, true);
+ super.refresh();
+ }
+ };
+
+ markAsWorkgroupLk.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -6439340898096365078L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+
+ boolean confirmed = MessageDialog.openConfirm(parent.getShell(), "Mark as workgroup",
+ "Are you sure you want to mark " + cn + " as being a workgroup? ");
+ if (confirmed) {
+ Node workgroupHome = CmsJcrUtils.getGroupHome(groupsSession, cn);
+ if (workgroupHome != null)
+ return; // already marked as workgroup, do nothing
+ else {
+ // improve transaction management
+ userAdminWrapper.beginTransactionIfNeeded();
+ nodeInstance.createWorkgroup(group.getName());
+ setProperty(group, businessCategory, WORKGROUP);
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
+ part.refresh();
+ }
+ }
+ }
+ });
+
+ ModifyListener defaultListener = new FormPartML(part);
+ descTxt.addModifyListener(defaultListener);
+ getManagedForm().addPart(part);
+ }
+
+ /** Filtered table with members. Has drag and drop ability */
+ protected void appendMembersPart(Composite parent, Group group) {
+ // Section section = tk.createSection(parent, Section.TITLE_BAR);
+ // section.setText("Members");
+ // section.setLayoutData(EclipseUiUtils.fillAll());
+
+ Composite body = new Composite(parent, SWT.BORDER);
+ body.setLayout(new GridLayout());
+ // section.setClient(body);
+ body.setLayoutData(EclipseUiUtils.fillAll());
+
+ // Define the displayed columns
+ List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+ columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
+ columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
+ columnDefs.add(new ColumnDefinition(new MailLP(), "Mail", 150));
+ // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name",
+ // 240));
+
+ // Create and configure the table
+ LdifUsersTable userViewerCmp = new MyUserTableViewer(body, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL,
+ userAdminWrapper.getUserAdmin());
+
+ userViewerCmp.setColumnDefinitions(columnDefs);
+ userViewerCmp.populate(true, false);
+ userViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
+
+ // Controllers
+ TableViewer userViewer = userViewerCmp.getTableViewer();
+ userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
+ int operations = DND.DROP_COPY | DND.DROP_MOVE;
+ Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
+ userViewer.addDropSupport(operations, tt,
+ new GroupDropListener(userAdminWrapper, userViewerCmp, (Group) getDisplayedUser()));
+
+ AbstractFormPart part = new GroupMembersPart(userViewerCmp);
+ getManagedForm().addPart(part);
+
+ // remove button
+ // addRemoveAbility(toolBarManager, userViewerCmp.getTableViewer(), group);
+ Action action = new RemoveMembershipAction(userViewer, group, "Remove selected items from this group",
+ SecurityAdminImages.ICON_REMOVE_DESC);
+
+ ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
+ ToolBar toolBar = toolBarManager.createControl(body);
+ toolBar.setLayoutData(CmsSwtUtils.fillWidth());
+
+ toolBarManager.add(action);
+ toolBarManager.update(true);
+
+ }
+
+ // private LdifUsersTable createMemberPart(Composite parent, Group group) {
+ //
+ // // Define the displayed columns
+ // List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+ // columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
+ // columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
+ // columnDefs.add(new ColumnDefinition(new MailLP(), "Mail", 150));
+ // // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished
+ // Name",
+ // // 240));
+ //
+ // // Create and configure the table
+ // LdifUsersTable userViewerCmp = new MyUserTableViewer(parent, SWT.MULTI |
+ // SWT.H_SCROLL | SWT.V_SCROLL,
+ // userAdminWrapper.getUserAdmin());
+ //
+ // userViewerCmp.setColumnDefinitions(columnDefs);
+ // userViewerCmp.populate(true, false);
+ // userViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
+ //
+ // // Controllers
+ // TableViewer userViewer = userViewerCmp.getTableViewer();
+ // userViewer.addDoubleClickListener(new
+ // UserTableDefaultDClickListener(partService));
+ // int operations = DND.DROP_COPY | DND.DROP_MOVE;
+ // Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
+ // userViewer.addDropSupport(operations, tt,
+ // new GroupDropListener(userAdminWrapper, userViewerCmp, (Group)
+ // getDisplayedUser()));
+ //
+ // // userViewerCmp.refresh();
+ // return userViewerCmp;
+ // }
+
+ // Local viewers
+ private class MyUserTableViewer extends LdifUsersTable {
+ private static final long serialVersionUID = 8467999509931900367L;
+
+ private final UserFilter userFilter;
+
+ public MyUserTableViewer(Composite parent, int style, UserAdmin userAdmin) {
+ super(parent, style, true);
+ userFilter = new UserFilter();
+
+ }
+
+ @Override
+ protected List<User> listFilteredElements(String filter) {
+ // reload user and set it in the editor
+ Group group = (Group) getDisplayedUser();
+ Role[] roles = group.getMembers();
+ List<User> users = new ArrayList<User>();
+ userFilter.setSearchText(filter);
+ // userFilter.setShowSystemRole(true);
+ for (Role role : roles)
+ // if (role.getType() == Role.GROUP)
+ if (userFilter.select(null, null, role))
+ users.add((User) role);
+ return users;
+ }
+ }
+
+ // private void addRemoveAbility(ToolBarManager toolBarManager, TableViewer
+ // userViewer, Group group) {
+ // // Section section = sectionPart.getSection();
+ // // ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
+ // // ToolBar toolbar = toolBarManager.createControl(parent);
+ // // ToolBar toolbar = toolBarManager.getControl();
+ // // final Cursor handCursor = new Cursor(toolbar.getDisplay(),
+ // SWT.CURSOR_HAND);
+ // // toolbar.setCursor(handCursor);
+ // // toolbar.addDisposeListener(new DisposeListener() {
+ // // private static final long serialVersionUID = 3882131405820522925L;
+ // //
+ // // public void widgetDisposed(DisposeEvent e) {
+ // // if ((handCursor != null) && (handCursor.isDisposed() == false)) {
+ // // handCursor.dispose();
+ // // }
+ // // }
+ // // });
+ //
+ // Action action = new RemoveMembershipAction(userViewer, group, "Remove
+ // selected items from this group",
+ // SecurityAdminImages.ICON_REMOVE_DESC);
+ // toolBarManager.add(action);
+ // toolBarManager.update(true);
+ // // section.setTextClient(toolbar);
+ // }
+
+ private class RemoveMembershipAction extends Action {
+ private static final long serialVersionUID = -1337713097184522588L;
+
+ private final TableViewer userViewer;
+ private final Group group;
+
+ RemoveMembershipAction(TableViewer userViewer, Group group, String name, ImageDescriptor img) {
+ super(name, img);
+ this.userViewer = userViewer;
+ this.group = group;
+ }
+
+ @Override
+ public void run() {
+ ISelection selection = userViewer.getSelection();
+ if (selection.isEmpty())
+ return;
+
+ @SuppressWarnings("unchecked")
+ Iterator<User> it = ((IStructuredSelection) selection).iterator();
+ List<User> users = new ArrayList<User>();
+ while (it.hasNext()) {
+ User currUser = it.next();
+ users.add(currUser);
+ }
+
+ userAdminWrapper.beginTransactionIfNeeded();
+ for (User user : users) {
+ group.removeMember(user);
+ }
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
+ }
+ }
+
+ // LOCAL CONTROLLERS
+ private class GroupMembersPart extends AbstractFormPart {
+ private final LdifUsersTable userViewer;
+ // private final Group group;
+
+ private GroupChangeListener listener;
+
+ public GroupMembersPart(LdifUsersTable userViewer) {
+ // super(section);
+ this.userViewer = userViewer;
+ // this.group = group;
+ }
+
+ @Override
+ public void initialize(IManagedForm form) {
+ super.initialize(form);
+ listener = new GroupChangeListener(userViewer.getDisplay(), GroupMembersPart.this);
+ userAdminWrapper.addListener(listener);
+ }
+
+ @Override
+ public void dispose() {
+ userAdminWrapper.removeListener(listener);
+ super.dispose();
+ }
+
+ @Override
+ public void refresh() {
+ userViewer.refresh();
+ super.refresh();
+ }
+ }
+
+ /**
+ * Defines this table as being a potential target to add group membership
+ * (roles) to this group
+ */
+ private class GroupDropListener extends ViewerDropAdapter {
+ private static final long serialVersionUID = 2893468717831451621L;
+
+ private final UserAdminWrapper userAdminWrapper;
+ // private final LdifUsersTable myUserViewerCmp;
+ private final Group myGroup;
+
+ public GroupDropListener(UserAdminWrapper userAdminWrapper, LdifUsersTable userTableViewerCmp, Group group) {
+ super(userTableViewerCmp.getTableViewer());
+ this.userAdminWrapper = userAdminWrapper;
+ this.myGroup = group;
+ // this.myUserViewerCmp = userTableViewerCmp;
+ }
+
+ @Override
+ public boolean validateDrop(Object target, int operation, TransferData transferType) {
+ // Target is always OK in a list only view
+ // TODO check if not a string
+ boolean validDrop = true;
+ return validDrop;
+ }
+
+ @Override
+ public void drop(DropTargetEvent event) {
+ // TODO Is there an opportunity to perform the check before?
+ String newUserName = (String) event.data;
+ UserAdmin myUserAdmin = userAdminWrapper.getUserAdmin();
+ Role role = myUserAdmin.getRole(newUserName);
+ if (role.getType() == Role.GROUP) {
+ Group newGroup = (Group) role;
+ Shell shell = getViewer().getControl().getShell();
+ // Sanity checks
+ if (myGroup == newGroup) { // Equality
+ MessageDialog.openError(shell, "Forbidden addition ", "A group cannot be a member of itself.");
+ return;
+ }
+
+ // Cycle
+ String myName = myGroup.getName();
+ List<User> myMemberships = getFlatGroups(myGroup);
+ if (myMemberships.contains(newGroup)) {
+ MessageDialog.openError(shell, "Forbidden addition: cycle",
+ "Cannot add " + newUserName + " to group " + myName + ". This would create a cycle");
+ return;
+ }
+
+ // Already member
+ List<User> newGroupMemberships = getFlatGroups(newGroup);
+ if (newGroupMemberships.contains(myGroup)) {
+ MessageDialog.openError(shell, "Forbidden addition",
+ "Cannot add " + newUserName + " to group " + myName + ", this membership already exists");
+ return;
+ }
+ userAdminWrapper.beginTransactionIfNeeded();
+ myGroup.addMember(newGroup);
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, myGroup));
+ } else if (role.getType() == Role.USER) {
+ // TODO check if the group is already member of this group
+ WorkTransaction transaction = userAdminWrapper.beginTransactionIfNeeded();
+ User user = (User) role;
+ myGroup.addMember(user);
+ if (UserAdminWrapper.COMMIT_ON_SAVE)
+ try {
+ transaction.commit();
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Cannot commit transaction " + "after user group membership update", e);
+ }
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, myGroup));
+ }
+ super.drop(event);
+ }
+
+ @Override
+ public boolean performDrop(Object data) {
+ // myUserViewerCmp.refresh();
+ return true;
+ }
+ }
+
+ // LOCAL HELPERS
+ // private Composite addSection(FormToolkit tk, Composite parent) {
+ // Section section = tk.createSection(parent, SWT.NO_FOCUS);
+ // section.setLayoutData(EclipseUiUtils.fillWidth());
+ // Composite body = tk.createComposite(section, SWT.WRAP);
+ // body.setLayoutData(EclipseUiUtils.fillAll());
+ // section.setClient(body);
+ // return body;
+ // }
+
+ /** Creates label and text. */
+ // private Text createLT(Composite parent, String label, String value) {
+ // FormToolkit toolkit = getManagedForm().getToolkit();
+ // Label lbl = toolkit.createLabel(parent, label);
+ // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+ // lbl.setFont(EclipseUiUtils.getBoldFont(parent));
+ // Text text = toolkit.createText(parent, value, SWT.BORDER);
+ // text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
+ // return text;
+ // }
+ //
+ // Text createReadOnlyLT(Composite parent, String label, String value) {
+ // FormToolkit toolkit = getManagedForm().getToolkit();
+ // Label lbl = toolkit.createLabel(parent, label);
+ // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+ // lbl.setFont(EclipseUiUtils.getBoldFont(parent));
+ // Text text = toolkit.createText(parent, value, SWT.NONE);
+ // text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ // text.setEditable(false);
+ // CmsUiUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
+ // return text;
+ // }
+
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.auth.CurrentUser;
+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.UserDragListener;
+import org.argeo.cms.swt.CmsException;
+//import org.argeo.cms.ui.workbench.WorkbenchUiPlugin;
+//import org.argeo.cms.ui.workbench.internal.useradmin.UiUserAdminListener;
+//import org.argeo.cms.ui.workbench.internal.useradmin.UserAdminWrapper;
+//import org.argeo.cms.ui.workbench.internal.useradmin.providers.CommonNameLP;
+//import org.argeo.cms.ui.workbench.internal.useradmin.providers.DomainNameLP;
+//import org.argeo.cms.ui.workbench.internal.useradmin.providers.RoleIconLP;
+//import org.argeo.cms.ui.workbench.internal.useradmin.providers.UserDragListener;
+//import org.argeo.cms.ui.workbench.internal.useradmin.providers.UserTableDefaultDClickListener;
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.parts.LdifUsersTable;
+import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.naming.LdapObjs;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+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.dnd.DND;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+//import org.eclipse.ui.part.ViewPart;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminListener;
+
+/** List all groups with filter */
+public class GroupsView {
+ private final static CmsLog log = CmsLog.getLog(GroupsView.class);
+ // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".groupsView";
+
+ @Inject
+ private EPartService partService;
+ @Inject
+ private UserAdminWrapper userAdminWrapper;
+
+ // UI Objects
+ private LdifUsersTable groupTableViewerCmp;
+ private TableViewer userViewer;
+ private List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+
+ private UserAdminListener listener;
+
+ @PostConstruct
+ public void createPartControl(Composite parent, ESelectionService selectionService) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ // boolean isAdmin = CurrentUser.isInRole(NodeConstants.ROLE_ADMIN);
+
+ // Define the displayed columns
+ columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 19));
+ columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
+ columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 100));
+ // Only show technical DN to admin
+ // if (isAdmin)
+ // columnDefs.add(new ColumnDefinition(new UserNameLP(),
+ // "Distinguished Name", 300));
+
+ // Create and configure the table
+ groupTableViewerCmp = new MyUserTableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+
+ groupTableViewerCmp.setColumnDefinitions(columnDefs);
+ // if (isAdmin)
+ // groupTableViewerCmp.populateWithStaticFilters(false, false);
+ // else
+ groupTableViewerCmp.populate(true, false);
+
+ groupTableViewerCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ // Links
+ userViewer = groupTableViewerCmp.getTableViewer();
+ userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
+ // getViewSite().setSelectionProvider(userViewer);
+ userViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ selectionService.setSelection(selection.toList());
+ }
+ });
+
+ // Really?
+ groupTableViewerCmp.refresh();
+
+ // Drag and drop
+ int operations = DND.DROP_COPY | DND.DROP_MOVE;
+ Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
+ userViewer.addDragSupport(operations, tt, new UserDragListener(userViewer));
+
+ // // Register a useradmin listener
+ // listener = new UserAdminListener() {
+ // @Override
+ // public void roleChanged(UserAdminEvent event) {
+ // if (userViewer != null && !userViewer.getTable().isDisposed())
+ // refresh();
+ // }
+ // };
+ // userAdminWrapper.addListener(listener);
+ // }
+
+ // Register a useradmin listener
+ listener = new MyUiUAListener(parent.getDisplay());
+ userAdminWrapper.addListener(listener);
+ }
+
+ private class MyUiUAListener extends UiUserAdminListener {
+ public MyUiUAListener(Display display) {
+ super(display);
+ }
+
+ @Override
+ public void roleChangedToUiThread(UserAdminEvent event) {
+ if (userViewer != null && !userViewer.getTable().isDisposed())
+ refresh();
+ }
+ }
+
+ private class MyUserTableViewer extends LdifUsersTable {
+ private static final long serialVersionUID = 8467999509931900367L;
+
+ private boolean showSystemRoles = true;
+
+ private final String[] knownProps = { LdapAttrs.uid.name(), LdapAttrs.cn.name(), LdapAttrs.DN };
+
+ public MyUserTableViewer(Composite parent, int style) {
+ super(parent, style);
+ showSystemRoles = CurrentUser.isInRole(CmsConstants.ROLE_ADMIN);
+ }
+
+ protected void populateStaticFilters(Composite staticFilterCmp) {
+ staticFilterCmp.setLayout(new GridLayout());
+ final Button showSystemRoleBtn = new Button(staticFilterCmp, SWT.CHECK);
+ showSystemRoleBtn.setText("Show system roles");
+ showSystemRoles = CurrentUser.isInRole(CmsConstants.ROLE_ADMIN);
+ showSystemRoleBtn.setSelection(showSystemRoles);
+
+ showSystemRoleBtn.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -7033424592697691676L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ showSystemRoles = showSystemRoleBtn.getSelection();
+ refresh();
+ }
+
+ });
+ }
+
+ @Override
+ protected List<User> listFilteredElements(String filter) {
+ Role[] roles;
+ try {
+ StringBuilder builder = new StringBuilder();
+ StringBuilder tmpBuilder = new StringBuilder();
+ if (EclipseUiUtils.notEmpty(filter))
+ for (String prop : knownProps) {
+ tmpBuilder.append("(");
+ tmpBuilder.append(prop);
+ tmpBuilder.append("=*");
+ tmpBuilder.append(filter);
+ tmpBuilder.append("*)");
+ }
+ if (tmpBuilder.length() > 1) {
+ builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
+ .append(LdapObjs.groupOfNames.name()).append(")");
+ // hide tokens
+ builder.append("(!(").append(LdapAttrs.DN).append("=*").append(CmsConstants.TOKENS_BASEDN)
+ .append("))");
+
+ if (!showSystemRoles)
+ builder.append("(!(").append(LdapAttrs.DN).append("=*").append(CmsConstants.ROLES_BASEDN)
+ .append("))");
+ builder.append("(|");
+ builder.append(tmpBuilder.toString());
+ builder.append("))");
+ } else {
+ if (!showSystemRoles)
+ builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
+ .append(LdapObjs.groupOfNames.name()).append(")(!(").append(LdapAttrs.DN).append("=*")
+ .append(CmsConstants.ROLES_BASEDN).append("))(!(").append(LdapAttrs.DN).append("=*")
+ .append(CmsConstants.TOKENS_BASEDN).append(")))");
+ else
+ builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
+ .append(LdapObjs.groupOfNames.name()).append(")(!(").append(LdapAttrs.DN).append("=*")
+ .append(CmsConstants.TOKENS_BASEDN).append(")))");
+
+ }
+ roles = userAdminWrapper.getUserAdmin().getRoles(builder.toString());
+ } catch (InvalidSyntaxException e) {
+ throw new CmsException("Unable to get roles with filter: " + filter, e);
+ }
+ List<User> users = new ArrayList<User>();
+ for (Role role : roles)
+ if (!users.contains(role))
+ users.add((User) role);
+ else
+ log.warn("Duplicated role: " + role);
+
+ return users;
+ }
+ }
+
+ public void refresh() {
+ groupTableViewerCmp.refresh();
+ }
+
+ @PreDestroy
+ public void dispose() {
+ userAdminWrapper.removeListener(listener);
+ }
+
+ @Focus
+ public void setFocus() {
+ groupTableViewerCmp.setFocus();
+ }
+
+ /* DEPENDENCY INJECTION */
+ public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
+ this.userAdminWrapper = userAdminWrapper;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import org.argeo.cms.ui.theme.CmsImages;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+
+/** Shared icons that must be declared programmatically . */
+public class SecurityAdminImages extends CmsImages {
+ private final static String PREFIX = "icons/";
+
+ public final static ImageDescriptor ICON_REMOVE_DESC = createDesc(PREFIX + "delete.png");
+ public final static ImageDescriptor ICON_USER_DESC = createDesc(PREFIX + "person.png");
+
+ public final static Image ICON_USER = ICON_USER_DESC.createImage();
+ public final static Image ICON_GROUP = createImg(PREFIX + "group.png");
+ public final static Image ICON_WORKGROUP = createImg(PREFIX + "workgroup.png");
+ public final static Image ICON_ROLE = createImg(PREFIX + "role.gif");
+
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import org.argeo.util.transaction.WorkTransaction;
+
+/** First effort to centralize back end methods used by the user admin UI */
+public class UiAdminUtils {
+ /*
+ * INTERNAL METHODS: Below methods are meant to stay here and are not part
+ * of a potential generic backend to manage the useradmin
+ */
+ /** Easily notify the ActiveWindow that the transaction had a state change */
+ public final static void notifyTransactionStateChange(
+ WorkTransaction userTransaction) {
+// try {
+// IWorkbenchWindow aww = PlatformUI.getWorkbench()
+// .getActiveWorkbenchWindow();
+// ISourceProviderService sourceProviderService = (ISourceProviderService) aww
+// .getService(ISourceProviderService.class);
+// UserTransactionProvider esp = (UserTransactionProvider) sourceProviderService
+// .getSourceProvider(UserTransactionProvider.TRANSACTION_STATE);
+// esp.fireTransactionStateChange();
+// } catch (Exception e) {
+// throw new CmsException("Unable to begin transaction", e);
+// }
+ }
+
+ /**
+ * Email addresses must match this regexp pattern ({@value #EMAIL_PATTERN}.
+ * Thanks to <a href=
+ * "http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/"
+ * >this tip</a>.
+ */
+ public final static String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import org.eclipse.swt.widgets.Display;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminListener;
+
+/** Convenience class to insure the call to refresh is done in the UI thread */
+public abstract class UiUserAdminListener implements UserAdminListener {
+
+ private final Display display;
+
+ public UiUserAdminListener(Display display) {
+ this.display = display;
+ }
+
+ @Override
+ public void roleChanged(final UserAdminEvent event) {
+ display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ roleChangedToUiThread(event);
+ }
+ });
+ }
+
+ public abstract void roleChangedToUiThread(UserAdminEvent event);
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.osgi.useradmin.UserDirectory;
+import org.argeo.util.directory.DirectoryConf;
+import org.argeo.util.transaction.WorkTransaction;
+import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminListener;
+
+/** Centralise interaction with the UserAdmin in this bundle */
+public class UserAdminWrapper {
+
+ private UserAdmin userAdmin;
+ // private ServiceReference<UserAdmin> userAdminServiceReference;
+// private Set<String> uris;
+ private Map<UserDirectory, Hashtable<String, String>> userDirectories = Collections
+ .synchronizedMap(new LinkedHashMap<>());
+ private WorkTransaction userTransaction;
+
+ // First effort to simplify UX while managing users and groups
+ public final static boolean COMMIT_ON_SAVE = true;
+
+ // Registered listeners
+ List<UserAdminListener> listeners = new ArrayList<UserAdminListener>();
+
+ /**
+ * Starts a transaction if necessary. Should always been called together with
+ * {@link UserAdminWrapper#commitOrNotifyTransactionStateChange()} once the
+ * security model changes have been performed.
+ */
+ public WorkTransaction beginTransactionIfNeeded() {
+ try {
+ // UserTransaction userTransaction = getUserTransaction();
+ if (userTransaction.isNoTransactionStatus()) {
+ userTransaction.begin();
+ // UiAdminUtils.notifyTransactionStateChange(userTransaction);
+ }
+ return userTransaction;
+ } catch (Exception e) {
+ throw new CmsException("Unable to begin transaction", e);
+ }
+ }
+
+ /**
+ * Depending on the current application configuration, it will either commit the
+ * current transaction or throw a notification that the transaction state has
+ * changed (In the later case, it must be called from the UI thread).
+ */
+ public void commitOrNotifyTransactionStateChange() {
+ try {
+ // UserTransaction userTransaction = getUserTransaction();
+ if (userTransaction.isNoTransactionStatus())
+ return;
+
+ if (UserAdminWrapper.COMMIT_ON_SAVE)
+ userTransaction.commit();
+ else
+ UiAdminUtils.notifyTransactionStateChange(userTransaction);
+ } catch (Exception e) {
+ throw new CmsException("Unable to clean transaction", e);
+ }
+ }
+
+ // TODO implement safer mechanism
+ public void addListener(UserAdminListener userAdminListener) {
+ if (!listeners.contains(userAdminListener))
+ listeners.add(userAdminListener);
+ }
+
+ public void removeListener(UserAdminListener userAdminListener) {
+ if (listeners.contains(userAdminListener))
+ listeners.remove(userAdminListener);
+ }
+
+ public void notifyListeners(UserAdminEvent event) {
+ for (UserAdminListener listener : listeners)
+ listener.roleChanged(event);
+ }
+
+ public Map<String, String> getKnownBaseDns(boolean onlyWritable) {
+ Map<String, String> dns = new HashMap<String, String>();
+ for (UserDirectory userDirectory : userDirectories.keySet()) {
+ Boolean readOnly = userDirectory.isReadOnly();
+ String baseDn = userDirectory.getContext();
+
+ if (onlyWritable && readOnly)
+ continue;
+ if (baseDn.equalsIgnoreCase(CmsConstants.ROLES_BASEDN))
+ continue;
+ if (baseDn.equalsIgnoreCase(CmsConstants.TOKENS_BASEDN))
+ continue;
+ dns.put(baseDn, DirectoryConf.propertiesAsUri(userDirectories.get(userDirectory)).toString());
+
+ }
+// for (String uri : uris) {
+// if (!uri.startsWith("/"))
+// continue;
+// Dictionary<String, ?> props = UserAdminConf.uriAsProperties(uri);
+// String readOnly = UserAdminConf.readOnly.getValue(props);
+// String baseDn = UserAdminConf.baseDn.getValue(props);
+//
+// if (onlyWritable && "true".equals(readOnly))
+// continue;
+// if (baseDn.equalsIgnoreCase(NodeConstants.ROLES_BASEDN))
+// continue;
+// if (baseDn.equalsIgnoreCase(NodeConstants.TOKENS_BASEDN))
+// continue;
+// dns.put(baseDn, uri);
+// }
+ return dns;
+ }
+
+ public UserAdmin getUserAdmin() {
+ return userAdmin;
+ }
+
+ public WorkTransaction getUserTransaction() {
+ return userTransaction;
+ }
+
+ /* DEPENDENCY INJECTION */
+ public void setUserAdmin(UserAdmin userAdmin, Map<String, String> properties) {
+ this.userAdmin = userAdmin;
+// this.uris = Collections.unmodifiableSortedSet(new TreeSet<>(properties.keySet()));
+ }
+
+ public void setUserTransaction(WorkTransaction userTransaction) {
+ this.userTransaction = userTransaction;
+ }
+
+ public void addUserDirectory(UserDirectory userDirectory, Map<String, String> properties) {
+ userDirectories.put(userDirectory, new Hashtable<>(properties));
+ }
+
+ public void removeUserDirectory(UserDirectory userDirectory, Map<String, String> properties) {
+ userDirectories.remove(userDirectory);
+ }
+
+ // public void setUserAdminServiceReference(
+ // ServiceReference<UserAdmin> userAdminServiceReference) {
+ // this.userAdminServiceReference = userAdminServiceReference;
+ // }
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.e4.users.providers.CommonNameLP;
+import org.argeo.cms.e4.users.providers.DomainNameLP;
+import org.argeo.cms.e4.users.providers.MailLP;
+import org.argeo.cms.e4.users.providers.UserNameLP;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.parts.LdifUsersTable;
+import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.naming.LdapObjs;
+import org.argeo.util.transaction.WorkTransaction;
+import org.eclipse.jface.dialogs.IPageChangeProvider;
+import org.eclipse.jface.dialogs.IPageChangedListener;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.PageChangedEvent;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/** Wizard to update users */
+public class UserBatchUpdateWizard extends Wizard {
+
+ private final static CmsLog log = CmsLog.getLog(UserBatchUpdateWizard.class);
+ private UserAdminWrapper userAdminWrapper;
+
+ // pages
+ private ChooseCommandWizardPage chooseCommandPage;
+ private ChooseUsersWizardPage userListPage;
+ private ValidateAndLaunchWizardPage validatePage;
+
+ // Various implemented commands keys
+ private final static String CMD_UPDATE_PASSWORD = "resetPassword";
+ private final static String CMD_UPDATE_EMAIL = "resetEmail";
+ private final static String CMD_GROUP_MEMBERSHIP = "groupMembership";
+
+ private final Map<String, String> commands = new HashMap<String, String>() {
+ private static final long serialVersionUID = 1L;
+ {
+ put("Reset password(s)", CMD_UPDATE_PASSWORD);
+ put("Reset email(s)", CMD_UPDATE_EMAIL);
+ // TODO implement role / group management
+ // put("Add/Remove from group", CMD_GROUP_MEMBERSHIP);
+ }
+ };
+
+ public UserBatchUpdateWizard(UserAdminWrapper userAdminWrapper) {
+ this.userAdminWrapper = userAdminWrapper;
+ }
+
+ @Override
+ public void addPages() {
+ chooseCommandPage = new ChooseCommandWizardPage();
+ addPage(chooseCommandPage);
+ userListPage = new ChooseUsersWizardPage();
+ addPage(userListPage);
+ validatePage = new ValidateAndLaunchWizardPage();
+ addPage(validatePage);
+ }
+
+ @Override
+ public boolean performFinish() {
+ if (!canFinish())
+ return false;
+ WorkTransaction ut = userAdminWrapper.getUserTransaction();
+ if (!ut.isNoTransactionStatus() && !MessageDialog.openConfirm(getShell(), "Existing Transaction",
+ "A user transaction is already existing, " + "are you sure you want to proceed ?"))
+ return false;
+
+ // We cannot use jobs, user modifications are still meant to be done in
+ // the UIThread
+ // UpdateJob job = null;
+ // if (job != null)
+ // job.schedule();
+
+ if (CMD_UPDATE_PASSWORD.equals(chooseCommandPage.getCommand())) {
+ char[] newValue = chooseCommandPage.getPwdValue();
+ if (newValue == null)
+ throw new CmsException("Password cannot be null or an empty string");
+ ResetPassword job = new ResetPassword(userAdminWrapper, userListPage.getSelectedUsers(), newValue);
+ job.doUpdate();
+ } else if (CMD_UPDATE_EMAIL.equals(chooseCommandPage.getCommand())) {
+ String newValue = chooseCommandPage.getEmailValue();
+ if (newValue == null)
+ throw new CmsException("Password cannot be null or an empty string");
+ ResetEmail job = new ResetEmail(userAdminWrapper, userListPage.getSelectedUsers(), newValue);
+ job.doUpdate();
+ }
+ return true;
+ }
+
+ public boolean canFinish() {
+ if (this.getContainer().getCurrentPage() == validatePage)
+ return true;
+ return false;
+ }
+
+ private class ResetPassword {
+ private char[] newPwd;
+ private UserAdminWrapper userAdminWrapper;
+ private List<User> usersToUpdate;
+
+ public ResetPassword(UserAdminWrapper userAdminWrapper, List<User> usersToUpdate, char[] newPwd) {
+ this.newPwd = newPwd;
+ this.usersToUpdate = usersToUpdate;
+ this.userAdminWrapper = userAdminWrapper;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void doUpdate() {
+ userAdminWrapper.beginTransactionIfNeeded();
+ try {
+ for (User user : usersToUpdate) {
+ // the char array is emptied after being used.
+ user.getCredentials().put(null, newPwd.clone());
+ }
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ } catch (Exception e) {
+ throw new CmsException("Cannot perform batch update on users", e);
+ } finally {
+ WorkTransaction ut = userAdminWrapper.getUserTransaction();
+ if (!ut.isNoTransactionStatus())
+ ut.rollback();
+ }
+ }
+ }
+
+ private class ResetEmail {
+ private String newEmail;
+ private UserAdminWrapper userAdminWrapper;
+ private List<User> usersToUpdate;
+
+ public ResetEmail(UserAdminWrapper userAdminWrapper, List<User> usersToUpdate, String newEmail) {
+ this.newEmail = newEmail;
+ this.usersToUpdate = usersToUpdate;
+ this.userAdminWrapper = userAdminWrapper;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void doUpdate() {
+ userAdminWrapper.beginTransactionIfNeeded();
+ try {
+ for (User user : usersToUpdate) {
+ // the char array is emptied after being used.
+ user.getProperties().put(LdapAttrs.mail.name(), newEmail);
+ }
+
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ if (!usersToUpdate.isEmpty())
+ userAdminWrapper.notifyListeners(
+ new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, usersToUpdate.get(0)));
+ } catch (Exception e) {
+ throw new CmsException("Cannot perform batch update on users", e);
+ } finally {
+ WorkTransaction ut = userAdminWrapper.getUserTransaction();
+ if (!ut.isNoTransactionStatus())
+ ut.rollback();
+ }
+ }
+ }
+
+ // @SuppressWarnings("unused")
+ // private class AddToGroup extends UpdateJob {
+ // private String groupID;
+ // private Session session;
+ //
+ // public AddToGroup(Session session, List<Node> nodesToUpdate,
+ // String groupID) {
+ // super(session, nodesToUpdate);
+ // this.session = session;
+ // this.groupID = groupID;
+ // }
+ //
+ // protected void doUpdate(Node node) {
+ // log.info("Add/Remove to group actions are not yet implemented");
+ // // TODO implement this
+ // // try {
+ // // throw new CmsException("Not yet implemented");
+ // // } catch (RepositoryException re) {
+ // // throw new CmsException(
+ // // "Unable to update boolean value for node " + node, re);
+ // // }
+ // }
+ // }
+
+ // /**
+ // * Base privileged job that will be run asynchronously to perform the
+ // batch
+ // * update
+ // */
+ // private abstract class UpdateJob extends PrivilegedJob {
+ //
+ // private final UserAdminWrapper userAdminWrapper;
+ // private final List<User> usersToUpdate;
+ //
+ // protected abstract void doUpdate(User user);
+ //
+ // public UpdateJob(UserAdminWrapper userAdminWrapper,
+ // List<User> usersToUpdate) {
+ // super("Perform update");
+ // this.usersToUpdate = usersToUpdate;
+ // this.userAdminWrapper = userAdminWrapper;
+ // }
+ //
+ // @Override
+ // protected IStatus doRun(IProgressMonitor progressMonitor) {
+ // try {
+ // JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor);
+ // int total = usersToUpdate.size();
+ // monitor.beginTask("Performing change", total);
+ // userAdminWrapper.beginTransactionIfNeeded();
+ // for (User user : usersToUpdate) {
+ // doUpdate(user);
+ // monitor.worked(1);
+ // }
+ // userAdminWrapper.getUserTransaction().commit();
+ // } catch (Exception e) {
+ // throw new CmsException(
+ // "Cannot perform batch update on users", e);
+ // } finally {
+ // UserTransaction ut = userAdminWrapper.getUserTransaction();
+ // try {
+ // if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION)
+ // ut.rollback();
+ // } catch (IllegalStateException | SecurityException
+ // | SystemException e) {
+ // log.error("Unable to rollback session in 'finally', "
+ // + "the system might be in a dirty state");
+ // e.printStackTrace();
+ // }
+ // }
+ // return Status.OK_STATUS;
+ // }
+ // }
+
+ // PAGES
+ /**
+ * Displays a combo box that enables user to choose which action to perform
+ */
+ private class ChooseCommandWizardPage extends WizardPage {
+ private static final long serialVersionUID = -8069434295293996633L;
+ private Combo chooseCommandCmb;
+ private Button trueChk;
+ private Text valueTxt;
+ private Text pwdTxt;
+ private Text pwd2Txt;
+
+ public ChooseCommandWizardPage() {
+ super("Choose a command to run.");
+ setTitle("Choose a command to run.");
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ GridLayout gl = new GridLayout();
+ Composite container = new Composite(parent, SWT.NO_FOCUS);
+ container.setLayout(gl);
+
+ chooseCommandCmb = new Combo(container, SWT.READ_ONLY);
+ chooseCommandCmb.setLayoutData(EclipseUiUtils.fillWidth());
+ String[] values = commands.keySet().toArray(new String[0]);
+ chooseCommandCmb.setItems(values);
+
+ final Composite bottomPart = new Composite(container, SWT.NO_FOCUS);
+ bottomPart.setLayoutData(EclipseUiUtils.fillAll());
+ bottomPart.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ chooseCommandCmb.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (getCommand().equals(CMD_UPDATE_PASSWORD))
+ populatePasswordCmp(bottomPart);
+ else if (getCommand().equals(CMD_UPDATE_EMAIL))
+ populateEmailCmp(bottomPart);
+ else if (getCommand().equals(CMD_GROUP_MEMBERSHIP))
+ populateGroupCmp(bottomPart);
+ else
+ populateBooleanFlagCmp(bottomPart);
+ checkPageComplete();
+ bottomPart.layout(true, true);
+ }
+ });
+ setControl(container);
+ }
+
+ private void populateBooleanFlagCmp(Composite parent) {
+ EclipseUiUtils.clear(parent);
+ trueChk = new Button(parent, SWT.CHECK);
+ trueChk.setText("Do it. (It will to the contrary if unchecked)");
+ trueChk.setSelection(true);
+ trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+ }
+
+ private void populatePasswordCmp(Composite parent) {
+ EclipseUiUtils.clear(parent);
+ Composite body = new Composite(parent, SWT.NO_FOCUS);
+
+ ModifyListener ml = new ModifyListener() {
+ private static final long serialVersionUID = -1558726363536729634L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ checkPageComplete();
+ }
+ };
+
+ body.setLayout(new GridLayout(2, false));
+ body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ pwdTxt = EclipseUiUtils.createGridLP(body, "New password", ml);
+ pwd2Txt = EclipseUiUtils.createGridLP(body, "Repeat password", ml);
+ }
+
+ private void populateEmailCmp(Composite parent) {
+ EclipseUiUtils.clear(parent);
+ Composite body = new Composite(parent, SWT.NO_FOCUS);
+
+ ModifyListener ml = new ModifyListener() {
+ private static final long serialVersionUID = 2147704227294268317L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ checkPageComplete();
+ }
+ };
+
+ body.setLayout(new GridLayout(2, false));
+ body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ valueTxt = EclipseUiUtils.createGridLT(body, "New e-mail", ml);
+ }
+
+ private void checkPageComplete() {
+ String errorMsg = null;
+ if (chooseCommandCmb.getSelectionIndex() < 0)
+ errorMsg = "Please select an action";
+ else if (CMD_UPDATE_EMAIL.equals(getCommand())) {
+ if (!valueTxt.getText().matches(UiAdminUtils.EMAIL_PATTERN))
+ errorMsg = "Not a valid e-mail address";
+ } else if (CMD_UPDATE_PASSWORD.equals(getCommand())) {
+ if (EclipseUiUtils.isEmpty(pwdTxt.getText()) || pwdTxt.getText().length() < 4)
+ errorMsg = "Please enter a password that is at least 4 character long";
+ else if (!pwdTxt.getText().equals(pwd2Txt.getText()))
+ errorMsg = "Passwords are different";
+ }
+ if (EclipseUiUtils.notEmpty(errorMsg)) {
+ setMessage(errorMsg, WizardPage.ERROR);
+ setPageComplete(false);
+ } else {
+ setMessage("Page complete, you can proceed to user choice", WizardPage.INFORMATION);
+ setPageComplete(true);
+ }
+
+ getContainer().updateButtons();
+ }
+
+ private void populateGroupCmp(Composite parent) {
+ EclipseUiUtils.clear(parent);
+ trueChk = new Button(parent, SWT.CHECK);
+ trueChk.setText("Add to group. (It will remove user(s) from the " + "corresponding group if unchecked)");
+ trueChk.setSelection(true);
+ trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+ }
+
+ protected String getCommand() {
+ return commands.get(chooseCommandCmb.getItem(chooseCommandCmb.getSelectionIndex()));
+ }
+
+ protected String getCommandLbl() {
+ return chooseCommandCmb.getItem(chooseCommandCmb.getSelectionIndex());
+ }
+
+ @SuppressWarnings("unused")
+ protected boolean getBoleanValue() {
+ // FIXME this is not consistent and will lead to errors.
+ if ("argeo:enabled".equals(getCommand()))
+ return trueChk.getSelection();
+ else
+ return !trueChk.getSelection();
+ }
+
+ @SuppressWarnings("unused")
+ protected String getStringValue() {
+ String value = null;
+ if (valueTxt != null) {
+ value = valueTxt.getText();
+ if ("".equals(value.trim()))
+ value = null;
+ }
+ return value;
+ }
+
+ protected char[] getPwdValue() {
+ // We do not directly reset the password text fields: There is no
+ // need to over secure this process: setting a pwd to multi users
+ // at the same time is anyhow a bad practice and should be used only
+ // in test environment or for temporary access
+ if (pwdTxt == null || pwdTxt.isDisposed())
+ return null;
+ else
+ return pwdTxt.getText().toCharArray();
+ }
+
+ protected String getEmailValue() {
+ // We do not directly reset the password text fields: There is no
+ // need to over secure this process: setting a pwd to multi users
+ // at the same time is anyhow a bad practice and should be used only
+ // in test environment or for temporary access
+ if (valueTxt == null || valueTxt.isDisposed())
+ return null;
+ else
+ return valueTxt.getText();
+ }
+ }
+
+ /**
+ * Displays a list of users with a check box to be able to choose some of them
+ */
+ private class ChooseUsersWizardPage extends WizardPage implements IPageChangedListener {
+ private static final long serialVersionUID = 7651807402211214274L;
+ private ChooseUserTableViewer userTableCmp;
+
+ public ChooseUsersWizardPage() {
+ super("Choose Users");
+ setTitle("Select users who will be impacted");
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ Composite pageCmp = new Composite(parent, SWT.NONE);
+ pageCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ // Define the displayed columns
+ List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+ columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
+ columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
+ columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
+
+ // Only show technical DN to admin
+ if (CurrentUser.isInRole(CmsConstants.ROLE_ADMIN))
+ columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
+
+ userTableCmp = new ChooseUserTableViewer(pageCmp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ userTableCmp.setLayoutData(EclipseUiUtils.fillAll());
+ userTableCmp.setColumnDefinitions(columnDefs);
+ userTableCmp.populate(true, true);
+ userTableCmp.refresh();
+
+ setControl(pageCmp);
+
+ // Add listener to update message when shown
+ final IWizardContainer wContainer = this.getContainer();
+ if (wContainer instanceof IPageChangeProvider) {
+ ((IPageChangeProvider) wContainer).addPageChangedListener(this);
+ }
+
+ }
+
+ @Override
+ public void pageChanged(PageChangedEvent event) {
+ if (event.getSelectedPage() == this) {
+ String msg = "Chosen batch action: " + chooseCommandPage.getCommandLbl();
+ ((WizardPage) event.getSelectedPage()).setMessage(msg);
+ }
+ }
+
+ protected List<User> getSelectedUsers() {
+ return userTableCmp.getSelectedUsers();
+ }
+
+ private class ChooseUserTableViewer extends LdifUsersTable {
+ private static final long serialVersionUID = 5080437561015853124L;
+ private final String[] knownProps = { LdapAttrs.uid.name(), LdapAttrs.DN, LdapAttrs.cn.name(),
+ LdapAttrs.givenName.name(), LdapAttrs.sn.name(), LdapAttrs.mail.name() };
+
+ public ChooseUserTableViewer(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected List<User> listFilteredElements(String filter) {
+ Role[] roles;
+
+ try {
+ StringBuilder builder = new StringBuilder();
+
+ StringBuilder tmpBuilder = new StringBuilder();
+ if (EclipseUiUtils.notEmpty(filter))
+ for (String prop : knownProps) {
+ tmpBuilder.append("(");
+ tmpBuilder.append(prop);
+ tmpBuilder.append("=*");
+ tmpBuilder.append(filter);
+ tmpBuilder.append("*)");
+ }
+ if (tmpBuilder.length() > 1) {
+ builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
+ .append(LdapObjs.inetOrgPerson.name()).append(")(|");
+ builder.append(tmpBuilder.toString());
+ builder.append("))");
+ } else
+ builder.append("(").append(LdapAttrs.objectClass.name()).append("=")
+ .append(LdapObjs.inetOrgPerson.name()).append(")");
+ roles = userAdminWrapper.getUserAdmin().getRoles(builder.toString());
+ } catch (InvalidSyntaxException e) {
+ throw new CmsException("Unable to get roles with filter: " + filter, e);
+ }
+ List<User> users = new ArrayList<User>();
+ for (Role role : roles)
+ // Prevent current logged in user to perform batch on
+ // himself
+ if (!UserAdminUtils.isCurrentUser((User) role))
+ users.add((User) role);
+ return users;
+ }
+ }
+ }
+
+ /** Summary of input data before launching the process */
+ private class ValidateAndLaunchWizardPage extends WizardPage implements IPageChangedListener {
+ private static final long serialVersionUID = 7098918351451743853L;
+ private ChosenUsersTableViewer userTableCmp;
+
+ public ValidateAndLaunchWizardPage() {
+ super("Validate and launch");
+ setTitle("Validate and launch");
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ Composite pageCmp = new Composite(parent, SWT.NO_FOCUS);
+ pageCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+ columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
+ columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
+ columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
+ // Only show technical DN to admin
+ if (CurrentUser.isInRole(CmsConstants.ROLE_ADMIN))
+ columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
+ userTableCmp = new ChosenUsersTableViewer(pageCmp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ userTableCmp.setLayoutData(EclipseUiUtils.fillAll());
+ userTableCmp.setColumnDefinitions(columnDefs);
+ userTableCmp.populate(false, false);
+ userTableCmp.refresh();
+ setControl(pageCmp);
+ // Add listener to update message when shown
+ final IWizardContainer wContainer = this.getContainer();
+ if (wContainer instanceof IPageChangeProvider) {
+ ((IPageChangeProvider) wContainer).addPageChangedListener(this);
+ }
+ }
+
+ @Override
+ public void pageChanged(PageChangedEvent event) {
+ if (event.getSelectedPage() == this) {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ Object[] values = ((ArrayList) userListPage.getSelectedUsers())
+ .toArray(new Object[userListPage.getSelectedUsers().size()]);
+ userTableCmp.getTableViewer().setInput(values);
+ String msg = "Following batch action: [" + chooseCommandPage.getCommandLbl()
+ + "] will be perfomed on the users listed below.\n";
+ // + "Are you sure you want to proceed?";
+ setMessage(msg);
+ }
+ }
+
+ private class ChosenUsersTableViewer extends LdifUsersTable {
+ private static final long serialVersionUID = 7814764735794270541L;
+
+ public ChosenUsersTableViewer(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected List<User> listFilteredElements(String filter) {
+ return userListPage.getSelectedUsers();
+ }
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import static org.argeo.cms.auth.UserAdminUtils.getProperty;
+import static org.argeo.util.naming.LdapAttrs.cn;
+import static org.argeo.util.naming.LdapAttrs.givenName;
+import static org.argeo.util.naming.LdapAttrs.mail;
+import static org.argeo.util.naming.LdapAttrs.sn;
+import static org.argeo.util.naming.LdapAttrs.uid;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.UserAdminUtils;
+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.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.parts.LdifUsersTable;
+import org.argeo.util.naming.LdapAttrs;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerDropAdapter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.dnd.TransferData;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/** Display/edit the properties of a given user */
+public class UserEditor extends AbstractRoleEditor {
+ // final static String ID = "UserEditor.mainPage";
+
+ @Inject
+ private EPartService partService;
+
+ // private final UserEditor editor;
+ // private UserAdminWrapper userAdminWrapper;
+
+ // Local configuration
+ // private final int PRE_TITLE_INDENT = 10;
+
+ // public UserMainPage(FormEditor editor, UserAdminWrapper userAdminWrapper) {
+ // super(editor, ID, "Main");
+ // this.editor = (UserEditor) editor;
+ // this.userAdminWrapper = userAdminWrapper;
+ // }
+
+ // protected void createFormContent(final IManagedForm mf) {
+ // ScrolledForm form = mf.getForm();
+ // Composite body = form.getBody();
+ // GridLayout mainLayout = new GridLayout();
+ // // mainLayout.marginRight = 10;
+ // body.setLayout(mainLayout);
+ // User user = editor.getDisplayedUser();
+ // appendOverviewPart(body, user);
+ // // Remove to ability to force the password for his own user. The user
+ // // must then use the change pwd feature
+ // appendMemberOfPart(body, user);
+ // }
+
+ @Override
+ protected void createUi(Composite body) {
+ // Composite body = new Composite(parent, SWT.BORDER);
+ GridLayout mainLayout = new GridLayout();
+ // mainLayout.marginRight = 10;
+ body.setLayout(mainLayout);
+ // body.getParent().setLayout(new GridLayout());
+ // body.setLayoutData(CmsUiUtils.fillAll());
+ User user = getDisplayedUser();
+ appendOverviewPart(body, user);
+ // Remove to ability to force the password for his own user. The user
+ // must then use the change pwd feature
+ appendMemberOfPart(body, user);
+ }
+
+ /** Creates the general section */
+ private void appendOverviewPart(final Composite parent, final User user) {
+ // FormToolkit tk = getManagedForm().getToolkit();
+
+ // Section section = tk.createSection(parent, SWT.NO_FOCUS);
+ // GridData gd = EclipseUiUtils.fillWidth();
+ // // gd.verticalAlignment = PRE_TITLE_INDENT;
+ // section.setLayoutData(gd);
+ Composite body = new Composite(parent, SWT.NONE);
+ body.setLayoutData(EclipseUiUtils.fillWidth());
+ // section.setClient(body);
+ // body.setLayout(new GridLayout(6, false));
+ body.setLayout(new GridLayout(2, false));
+
+ Text commonName = createReadOnlyLT(body, "Name", getProperty(user, cn));
+ Text distinguishedName = createReadOnlyLT(body, "Login", getProperty(user, uid));
+ Text firstName = createLT(body, "First name", getProperty(user, givenName));
+ Text lastName = createLT(body, "Last name", getProperty(user, sn));
+ Text email = createLT(body, "Email", getProperty(user, mail));
+
+ Link resetPwdLk = new Link(body, SWT.NONE);
+ if (!UserAdminUtils.isCurrentUser(user)) {
+ resetPwdLk.setText("<a>Reset password</a>");
+ }
+ resetPwdLk.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+
+ // create form part (controller)
+ AbstractFormPart part = new AbstractFormPart() {
+ private MainInfoListener listener;
+
+ @Override
+ public void initialize(IManagedForm form) {
+ super.initialize(form);
+ listener = new MainInfoListener(parent.getDisplay(), this);
+ userAdminWrapper.addListener(listener);
+ }
+
+ @Override
+ public void dispose() {
+ userAdminWrapper.removeListener(listener);
+ super.dispose();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void commit(boolean onSave) {
+ // TODO Sanity checks (mail validity...)
+ user.getProperties().put(LdapAttrs.givenName.name(), firstName.getText());
+ user.getProperties().put(LdapAttrs.sn.name(), lastName.getText());
+ user.getProperties().put(LdapAttrs.cn.name(), commonName.getText());
+ user.getProperties().put(LdapAttrs.mail.name(), email.getText());
+ super.commit(onSave);
+ }
+
+ @Override
+ public void refresh() {
+ distinguishedName.setText(UserAdminUtils.getProperty(user, LdapAttrs.uid.name()));
+ commonName.setText(UserAdminUtils.getProperty(user, LdapAttrs.cn.name()));
+ firstName.setText(UserAdminUtils.getProperty(user, LdapAttrs.givenName.name()));
+ lastName.setText(UserAdminUtils.getProperty(user, LdapAttrs.sn.name()));
+ email.setText(UserAdminUtils.getProperty(user, LdapAttrs.mail.name()));
+ refreshFormTitle(user);
+ super.refresh();
+ }
+ };
+
+ // Improve this: automatically generate CN when first or last name
+ // changes
+ ModifyListener cnML = new ModifyListener() {
+ private static final long serialVersionUID = 4298649222869835486L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ String first = firstName.getText();
+ String last = lastName.getText();
+ String cn = first.trim() + " " + last.trim() + " ";
+ cn = cn.trim();
+ commonName.setText(cn);
+ // getManagedForm().getForm().setText(cn);
+ updateEditorTitle(cn);
+ }
+ };
+ firstName.addModifyListener(cnML);
+ lastName.addModifyListener(cnML);
+
+ ModifyListener defaultListener = new FormPartML(part);
+ firstName.addModifyListener(defaultListener);
+ lastName.addModifyListener(defaultListener);
+ email.addModifyListener(defaultListener);
+
+ if (!UserAdminUtils.isCurrentUser(user))
+ resetPwdLk.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = 5881800534589073787L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ new ChangePasswordDialog(user, "Reset password").open();
+ }
+ });
+
+ getManagedForm().addPart(part);
+ }
+
+ private class ChangePasswordDialog extends TrayDialog {
+ private static final long serialVersionUID = 2843538207460082349L;
+
+ private User user;
+ private Text password1;
+ private Text password2;
+ private String title;
+ // private FormToolkit tk;
+
+ public ChangePasswordDialog(User user, String title) {
+ super(Display.getDefault().getActiveShell());
+ // this.tk = tk;
+ this.user = user;
+ this.title = title;
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite dialogarea = (Composite) super.createDialogArea(parent);
+ dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ Composite body = new Composite(dialogarea, SWT.NO_FOCUS);
+ body.setLayoutData(EclipseUiUtils.fillAll());
+ GridLayout layout = new GridLayout(2, false);
+ body.setLayout(layout);
+
+ password1 = createLP(body, "New password", "");
+ password2 = createLP(body, "Repeat password", "");
+ parent.pack();
+ return body;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void okPressed() {
+ String msg = null;
+
+ if (password1.getText().equals(""))
+ msg = "Password cannot be empty";
+ else if (password1.getText().equals(password2.getText())) {
+ char[] newPassword = password1.getText().toCharArray();
+ // userAdminWrapper.beginTransactionIfNeeded();
+ userAdminWrapper.beginTransactionIfNeeded();
+ user.getCredentials().put(null, newPassword);
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ super.okPressed();
+ } else {
+ msg = "Passwords are not equals";
+ }
+
+ if (EclipseUiUtils.notEmpty(msg))
+ MessageDialog.openError(getParentShell(), "Cannot reset pasword", msg);
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText(title);
+ }
+ }
+
+ private LdifUsersTable appendMemberOfPart(final Composite parent, User user) {
+ // Section section = addSection(tk, parent, "Roles");
+ // Composite body = (Composite) section.getClient();
+ // Composite body= parent;
+ Composite body = new Composite(parent, SWT.BORDER);
+ body.setLayout(new GridLayout());
+ body.setLayoutData(CmsSwtUtils.fillAll());
+
+ // boolean isAdmin = CurrentUser.isInRole(NodeConstants.ROLE_ADMIN);
+
+ // Displayed columns
+ List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+ columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
+ columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
+ columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 100));
+ // Only show technical DN to administrators
+ // if (isAdmin)
+ // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name",
+ // 300));
+
+ // Create and configure the table
+ final LdifUsersTable userViewerCmp = new MyUserTableViewer(body, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL, user);
+
+ userViewerCmp.setColumnDefinitions(columnDefs);
+ // if (isAdmin)
+ // userViewerCmp.populateWithStaticFilters(false, false);
+ // else
+ userViewerCmp.populate(true, false);
+ GridData gd = EclipseUiUtils.fillAll();
+ gd.heightHint = 500;
+ userViewerCmp.setLayoutData(gd);
+
+ // Controllers
+ TableViewer userViewer = userViewerCmp.getTableViewer();
+ userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
+ int operations = DND.DROP_COPY | DND.DROP_MOVE;
+ Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
+ GroupDropListener dropL = new GroupDropListener(userAdminWrapper, userViewer, user);
+ userViewer.addDropSupport(operations, tt, dropL);
+
+ AbstractFormPart part = new AbstractFormPart() {
+
+ private GroupChangeListener listener;
+
+ @Override
+ public void initialize(IManagedForm form) {
+ super.initialize(form);
+ listener = new GroupChangeListener(parent.getDisplay(), this);
+ userAdminWrapper.addListener(listener);
+ }
+
+ public void commit(boolean onSave) {
+ super.commit(onSave);
+ }
+
+ @Override
+ public void dispose() {
+ userAdminWrapper.removeListener(listener);
+ super.dispose();
+ }
+
+ @Override
+ public void refresh() {
+ userViewerCmp.refresh();
+ super.refresh();
+ }
+ };
+ getManagedForm().addPart(part);
+ // addRemoveAbitily(body, userViewer, user);
+ // userViewerCmp.refresh();
+ String tooltip = "Remove " + UserAdminUtils.getUserLocalId(user.getName()) + " from the below selected groups";
+ Action action = new RemoveMembershipAction(userViewer, user, tooltip, SecurityAdminImages.ICON_REMOVE_DESC);
+ ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
+ ToolBar toolBar = toolBarManager.createControl(body);
+ toolBar.setLayoutData(CmsSwtUtils.fillWidth());
+ toolBarManager.add(action);
+ toolBarManager.update(true);
+ return userViewerCmp;
+ }
+
+ private class MyUserTableViewer extends LdifUsersTable {
+ private static final long serialVersionUID = 2653790051461237329L;
+
+ private Button showSystemRoleBtn;
+
+ private final User user;
+ private final UserFilter userFilter;
+
+ public MyUserTableViewer(Composite parent, int style, User user) {
+ super(parent, style, true);
+ this.user = user;
+ userFilter = new UserFilter();
+ }
+
+ protected void populateStaticFilters(Composite staticFilterCmp) {
+ staticFilterCmp.setLayout(new GridLayout());
+ showSystemRoleBtn = new Button(staticFilterCmp, SWT.CHECK);
+ showSystemRoleBtn.setText("Show system roles");
+ boolean showSysRole = CurrentUser.isInRole(CmsConstants.ROLE_ADMIN);
+ showSystemRoleBtn.setSelection(showSysRole);
+ userFilter.setShowSystemRole(showSysRole);
+ showSystemRoleBtn.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -7033424592697691676L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ userFilter.setShowSystemRole(showSystemRoleBtn.getSelection());
+ refresh();
+ }
+ });
+ }
+
+ @Override
+ protected List<User> listFilteredElements(String filter) {
+ List<User> users = (List<User>) getFlatGroups(null);
+ List<User> filteredUsers = new ArrayList<User>();
+ if (users.contains(user))
+ users.remove(user);
+ userFilter.setSearchText(filter);
+ for (User user : users)
+ if (userFilter.select(null, null, user))
+ filteredUsers.add(user);
+ return filteredUsers;
+ }
+ }
+
+ // private void addRemoveAbility(Composite parent, TableViewer userViewer, User
+ // user) {
+ // // Section section = sectionPart.getSection();
+ // ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
+ // ToolBar toolbar = toolBarManager.createControl(parent);
+ // final Cursor handCursor = new Cursor(Display.getCurrent(), SWT.CURSOR_HAND);
+ // toolbar.setCursor(handCursor);
+ // toolbar.addDisposeListener(new DisposeListener() {
+ // private static final long serialVersionUID = 3882131405820522925L;
+ //
+ // public void widgetDisposed(DisposeEvent e) {
+ // if ((handCursor != null) && (handCursor.isDisposed() == false)) {
+ // handCursor.dispose();
+ // }
+ // }
+ // });
+ //
+ // String tooltip = "Remove " + UserAdminUtils.getUserLocalId(user.getName()) +
+ // " from the below selected groups";
+ // Action action = new RemoveMembershipAction(userViewer, user, tooltip,
+ // SecurityAdminImages.ICON_REMOVE_DESC);
+ // toolBarManager.add(action);
+ // toolBarManager.update(true);
+ // // section.setTextClient(toolbar);
+ // }
+
+ private class RemoveMembershipAction extends Action {
+ private static final long serialVersionUID = -1337713097184522588L;
+
+ private final TableViewer userViewer;
+ private final User user;
+
+ RemoveMembershipAction(TableViewer userViewer, User user, String name, ImageDescriptor img) {
+ super(name, img);
+ this.userViewer = userViewer;
+ this.user = user;
+ }
+
+ @Override
+ public void run() {
+ ISelection selection = userViewer.getSelection();
+ if (selection.isEmpty())
+ return;
+
+ @SuppressWarnings("unchecked")
+ Iterator<Group> it = ((IStructuredSelection) selection).iterator();
+ List<Group> groups = new ArrayList<Group>();
+ while (it.hasNext()) {
+ Group currGroup = it.next();
+ groups.add(currGroup);
+ }
+
+ userAdminWrapper.beginTransactionIfNeeded();
+ for (Group group : groups) {
+ group.removeMember(user);
+ }
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ for (Group group : groups) {
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
+ }
+ }
+ }
+
+ /**
+ * Defines the table as being a potential target to add group memberships
+ * (roles) to this user
+ */
+ private class GroupDropListener extends ViewerDropAdapter {
+ private static final long serialVersionUID = 2893468717831451621L;
+
+ private final UserAdminWrapper myUserAdminWrapper;
+ private final User myUser;
+
+ public GroupDropListener(UserAdminWrapper userAdminWrapper, Viewer userViewer, User user) {
+ super(userViewer);
+ this.myUserAdminWrapper = userAdminWrapper;
+ this.myUser = user;
+ }
+
+ @Override
+ public boolean validateDrop(Object target, int operation, TransferData transferType) {
+ // Target is always OK in a list only view
+ // TODO check if not a string
+ boolean validDrop = true;
+ return validDrop;
+ }
+
+ @Override
+ public void drop(DropTargetEvent event) {
+ String name = (String) event.data;
+ UserAdmin myUserAdmin = myUserAdminWrapper.getUserAdmin();
+ Role role = myUserAdmin.getRole(name);
+ // TODO this check should be done before.
+ if (role.getType() == Role.GROUP) {
+ // TODO check if the user is already member of this group
+
+ myUserAdminWrapper.beginTransactionIfNeeded();
+ Group group = (Group) role;
+ group.addMember(myUser);
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ myUserAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
+ }
+ super.drop(event);
+ }
+
+ @Override
+ public boolean performDrop(Object data) {
+ // userTableViewerCmp.refresh();
+ return true;
+ }
+ }
+
+ // LOCAL HELPERS
+ private void refreshFormTitle(User group) {
+ // getManagedForm().getForm().setText(UserAdminUtils.getProperty(group,
+ // LdapAttrs.cn.name()));
+ }
+
+ /** Appends a section with a title */
+ // private Section addSection(FormToolkit tk, Composite parent, String title) {
+ // Section section = tk.createSection(parent, Section.TITLE_BAR);
+ // GridData gd = EclipseUiUtils.fillWidth();
+ // gd.verticalAlignment = PRE_TITLE_INDENT;
+ // section.setLayoutData(gd);
+ // section.setText(title);
+ // // section.getMenu().setVisible(true);
+ //
+ // Composite body = tk.createComposite(section, SWT.WRAP);
+ // body.setLayoutData(EclipseUiUtils.fillAll());
+ // section.setClient(body);
+ //
+ // return section;
+ // }
+
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import org.argeo.cms.e4.CmsE4Utils;
+import org.argeo.util.naming.LdapAttrs;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Default double click listener for the various user tables, will open the
+ * clicked item in the editor
+ */
+public class UserTableDefaultDClickListener implements IDoubleClickListener {
+ private final EPartService partService;
+
+ public UserTableDefaultDClickListener(EPartService partService) {
+ this.partService = partService;
+ }
+
+ public void doubleClick(DoubleClickEvent evt) {
+ if (evt.getSelection().isEmpty())
+ return;
+ Object obj = ((IStructuredSelection) evt.getSelection()).getFirstElement();
+ User user = (User) obj;
+
+ String editorId = getEditorId(user);
+ CmsE4Utils.openEditor(partService, editorId, LdapAttrs.uid.name(), user.getName());
+ }
+
+ protected String getEditorId(User user) {
+ if (user instanceof Group)
+ return "org.argeo.cms.e4.partdescriptor.groupEditor";
+ else
+ return "org.argeo.cms.e4.partdescriptor.userEditor";
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.e4.users.providers.CommonNameLP;
+import org.argeo.cms.e4.users.providers.DomainNameLP;
+import org.argeo.cms.e4.users.providers.MailLP;
+import org.argeo.cms.e4.users.providers.UserDragListener;
+import org.argeo.cms.e4.users.providers.UserNameLP;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.parts.LdifUsersTable;
+import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.naming.LdapObjs;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+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.dnd.DND;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminListener;
+
+/** List all users with filter - based on Ldif userAdmin */
+public class UsersView {
+ // private final static Log log = LogFactory.getLog(UsersView.class);
+
+ // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".usersView";
+
+ @Inject
+ private UserAdminWrapper userAdminWrapper;
+ @Inject
+ private EPartService partService;
+
+ // UI Objects
+ private LdifUsersTable userTableViewerCmp;
+ private TableViewer userViewer;
+ private List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+
+ private UserAdminListener listener;
+
+ @PostConstruct
+ public void createPartControl(Composite parent, ESelectionService selectionService) {
+
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ // Define the displayed columns
+ columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
+ columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
+ columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
+ // Only show technical DN to admin
+ if (CurrentUser.isInRole(CmsConstants.ROLE_ADMIN))
+ columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
+
+ // Create and configure the table
+ userTableViewerCmp = new MyUserTableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ userTableViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
+ userTableViewerCmp.setColumnDefinitions(columnDefs);
+ userTableViewerCmp.populate(true, false);
+
+ // Links
+ userViewer = userTableViewerCmp.getTableViewer();
+ userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
+ userViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ selectionService.setSelection(selection.toList());
+ }
+ });
+ // getViewSite().setSelectionProvider(userViewer);
+
+ // Really?
+ userTableViewerCmp.refresh();
+
+ // Drag and drop
+ int operations = DND.DROP_COPY | DND.DROP_MOVE;
+ Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
+ userViewer.addDragSupport(operations, tt, new UserDragListener(userViewer));
+
+ // Register a useradmin listener
+ listener = new MyUiUAListener(parent.getDisplay());
+ userAdminWrapper.addListener(listener);
+ }
+
+ private class MyUiUAListener extends UiUserAdminListener {
+ public MyUiUAListener(Display display) {
+ super(display);
+ }
+
+ @Override
+ public void roleChangedToUiThread(UserAdminEvent event) {
+ if (userViewer != null && !userViewer.getTable().isDisposed())
+ refresh();
+ }
+ }
+
+ private class MyUserTableViewer extends LdifUsersTable {
+ private static final long serialVersionUID = 8467999509931900367L;
+
+ private final String[] knownProps = { LdapAttrs.DN, LdapAttrs.uid.name(), LdapAttrs.cn.name(),
+ LdapAttrs.givenName.name(), LdapAttrs.sn.name(), LdapAttrs.mail.name() };
+
+ public MyUserTableViewer(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected List<User> listFilteredElements(String filter) {
+ Role[] roles;
+
+ try {
+ StringBuilder builder = new StringBuilder();
+
+ StringBuilder tmpBuilder = new StringBuilder();
+ if (EclipseUiUtils.notEmpty(filter))
+ for (String prop : knownProps) {
+ tmpBuilder.append("(");
+ tmpBuilder.append(prop);
+ tmpBuilder.append("=*");
+ tmpBuilder.append(filter);
+ tmpBuilder.append("*)");
+ }
+ if (tmpBuilder.length() > 1) {
+ builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
+ .append(LdapObjs.inetOrgPerson.name()).append(")(|");
+ builder.append(tmpBuilder.toString());
+ builder.append("))");
+ } else
+ builder.append("(").append(LdapAttrs.objectClass.name()).append("=")
+ .append(LdapObjs.inetOrgPerson.name()).append(")");
+ roles = userAdminWrapper.getUserAdmin().getRoles(builder.toString());
+ } catch (InvalidSyntaxException e) {
+ throw new CmsException("Unable to get roles with filter: " + filter, e);
+ }
+ List<User> users = new ArrayList<User>();
+ for (Role role : roles)
+ // if (role.getType() == Role.USER && role.getType() !=
+ // Role.GROUP)
+ users.add((User) role);
+ return users;
+ }
+ }
+
+ public void refresh() {
+ userTableViewerCmp.refresh();
+ }
+
+ // Override generic view methods
+ @PreDestroy
+ public void dispose() {
+ userAdminWrapper.removeListener(listener);
+ }
+
+ @Focus
+ public void setFocus() {
+ userTableViewerCmp.setFocus();
+ }
+
+ /* DEPENDENCY INJECTION */
+ public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
+ this.userAdminWrapper = userAdminWrapper;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users.handlers;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.e4.users.GroupsView;
+import org.argeo.cms.e4.users.UserAdminWrapper;
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/** Delete the selected groups */
+public class DeleteGroups {
+ // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID +
+ // ".deleteGroups";
+
+ /* DEPENDENCY INJECTION */
+ @Inject
+ private UserAdminWrapper userAdminWrapper;
+
+ @Inject
+ ESelectionService selectionService;
+
+ @SuppressWarnings("unchecked")
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
+ // ISelection selection = null;// HandlerUtil.getCurrentSelection(event);
+ // if (selection.isEmpty())
+ // return null;
+ //
+ // List<Group> groups = new ArrayList<Group>();
+ // Iterator<Group> it = ((IStructuredSelection) selection).iterator();
+
+ List<Group> selection = (List<Group>) selectionService.getSelection();
+ if (selection == null)
+ return;
+
+ StringBuilder builder = new StringBuilder();
+ for (Group group : selection) {
+ Group currGroup = group;
+ String groupName = UserAdminUtils.getUserLocalId(currGroup.getName());
+ // TODO add checks
+ builder.append(groupName).append("; ");
+ // groups.add(currGroup);
+ }
+
+ if (!MessageDialog.openQuestion(Display.getCurrent().getActiveShell(), "Delete Groups", "Are you sure that you "
+ + "want to delete these groups?\n" + builder.substring(0, builder.length() - 2)))
+ return;
+
+ userAdminWrapper.beginTransactionIfNeeded();
+ UserAdmin userAdmin = userAdminWrapper.getUserAdmin();
+ // IWorkbenchPage iwp =
+ // HandlerUtil.getActiveWorkbenchWindow(event).getActivePage();
+ for (Group group : selection) {
+ String groupName = group.getName();
+ // TODO find a way to close the editor cleanly if opened. Cannot be
+ // done through the UserAdminListeners, it causes a
+ // java.util.ConcurrentModificationException because disposing the
+ // editor unregisters and disposes the listener
+ // IEditorPart part = iwp.findEditor(new UserEditorInput(groupName));
+ // if (part != null)
+ // iwp.closeEditor(part, false);
+ userAdmin.removeRole(groupName);
+ }
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+
+ // Update the view
+ for (Group group : selection) {
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_REMOVED, group));
+ }
+
+ // return null;
+ }
+
+ @CanExecute
+ public boolean canExecute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
+ return part.getObject() instanceof GroupsView && selectionService.getSelection() != null;
+ }
+
+ /* DEPENDENCY INJECTION */
+ // public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
+ // this.userAdminWrapper = userAdminWrapper;
+ // }
+}
--- /dev/null
+package org.argeo.cms.e4.users.handlers;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.e4.users.UserAdminWrapper;
+import org.argeo.cms.e4.users.UsersView;
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/** Delete the selected users */
+public class DeleteUsers {
+ // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".deleteUsers";
+
+ /* DEPENDENCY INJECTION */
+ @Inject
+ private UserAdminWrapper userAdminWrapper;
+
+ @SuppressWarnings("unchecked")
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
+ // ISelection selection = null;// HandlerUtil.getCurrentSelection(event);
+ // if (selection.isEmpty())
+ // return null;
+ List<User> selection = (List<User>) selectionService.getSelection();
+ if (selection == null)
+ return;
+
+// Iterator<User> it = ((IStructuredSelection) selection).iterator();
+// List<User> users = new ArrayList<User>();
+ StringBuilder builder = new StringBuilder();
+
+ for(User user:selection) {
+ User currUser = user;
+// User currUser = it.next();
+ String userName = UserAdminUtils.getUserLocalId(currUser.getName());
+ if (UserAdminUtils.isCurrentUser(currUser)) {
+ MessageDialog.openError(Display.getCurrent().getActiveShell(), "Deletion forbidden",
+ "You cannot delete your own user this way.");
+ return;
+ }
+ builder.append(userName).append("; ");
+// users.add(currUser);
+ }
+
+ if (!MessageDialog.openQuestion(Display.getCurrent().getActiveShell(), "Delete Users",
+ "Are you sure that you want to delete these users?\n" + builder.substring(0, builder.length() - 2)))
+ return;
+
+ userAdminWrapper.beginTransactionIfNeeded();
+ UserAdmin userAdmin = userAdminWrapper.getUserAdmin();
+ // IWorkbenchPage iwp =
+ // HandlerUtil.getActiveWorkbenchWindow(event).getActivePage();
+
+ for (User user : selection) {
+ String userName = user.getName();
+ // TODO find a way to close the editor cleanly if opened. Cannot be
+ // done through the UserAdminListeners, it causes a
+ // java.util.ConcurrentModificationException because disposing the
+ // editor unregisters and disposes the listener
+ // IEditorPart part = iwp.findEditor(new UserEditorInput(userName));
+ // if (part != null)
+ // iwp.closeEditor(part, false);
+ userAdmin.removeRole(userName);
+ }
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+
+ for (User user : selection) {
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_REMOVED, user));
+ }
+ }
+
+ @CanExecute
+ public boolean canExecute(@Named(IServiceConstants.ACTIVE_PART) MPart part, ESelectionService selectionService) {
+ return part.getObject() instanceof UsersView && selectionService.getSelection() != null;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users.handlers;
+
+import java.util.Dictionary;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.argeo.cms.e4.users.UserAdminWrapper;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
+import org.argeo.util.directory.DirectoryConf;
+import org.argeo.util.naming.LdapAttrs;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/** Create a new group */
+public class NewGroup {
+ // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".newGroup";
+
+ /* DEPENDENCY INJECTION */
+ @Inject
+ private UserAdminWrapper userAdminWrapper;
+
+ @Execute
+ public Object execute() {
+ NewGroupWizard newGroupWizard = new NewGroupWizard();
+ newGroupWizard.setWindowTitle("Group creation");
+ WizardDialog dialog = new WizardDialog(Display.getCurrent().getActiveShell(), newGroupWizard);
+ dialog.open();
+ return null;
+ }
+
+ private class NewGroupWizard extends Wizard {
+
+ // Pages
+ private MainGroupInfoWizardPage mainGroupInfo;
+
+ // UI fields
+ private Text dNameTxt, commonNameTxt, descriptionTxt;
+ private Combo baseDnCmb;
+
+ public NewGroupWizard() {
+ }
+
+ @Override
+ public void addPages() {
+ mainGroupInfo = new MainGroupInfoWizardPage();
+ addPage(mainGroupInfo);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public boolean performFinish() {
+ if (!canFinish())
+ return false;
+ String commonName = commonNameTxt.getText();
+ try {
+ userAdminWrapper.beginTransactionIfNeeded();
+ String dn = getDn(commonName);
+ Group group = (Group) userAdminWrapper.getUserAdmin().createRole(dn, Role.GROUP);
+ Dictionary props = group.getProperties();
+ String descStr = descriptionTxt.getText();
+ if (EclipseUiUtils.notEmpty(descStr))
+ props.put(LdapAttrs.description.name(), descStr);
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CREATED, group));
+ return true;
+ } catch (Exception e) {
+ ErrorFeedback.show("Cannot create new group " + commonName, e);
+ return false;
+ }
+ }
+
+ private class MainGroupInfoWizardPage extends WizardPage implements FocusListener {
+ private static final long serialVersionUID = -3150193365151601807L;
+
+ public MainGroupInfoWizardPage() {
+ super("Main");
+ setTitle("General information");
+ setMessage("Please choose a domain, provide a common name " + "and a free description");
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ Composite bodyCmp = new Composite(parent, SWT.NONE);
+ setControl(bodyCmp);
+ bodyCmp.setLayout(new GridLayout(2, false));
+
+ dNameTxt = EclipseUiUtils.createGridLT(bodyCmp, "Distinguished name");
+ dNameTxt.setEnabled(false);
+
+ baseDnCmb = createGridLC(bodyCmp, "Base DN");
+ // Initialise before adding the listener to avoid NPE
+ initialiseDnCmb(baseDnCmb);
+ baseDnCmb.addFocusListener(this);
+
+ commonNameTxt = EclipseUiUtils.createGridLT(bodyCmp, "Common name");
+ commonNameTxt.addFocusListener(this);
+
+ Label descLbl = new Label(bodyCmp, SWT.LEAD);
+ descLbl.setText("Description");
+ descLbl.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ descriptionTxt = new Text(bodyCmp, SWT.LEAD | SWT.MULTI | SWT.WRAP | SWT.BORDER);
+ descriptionTxt.setLayoutData(EclipseUiUtils.fillAll());
+ descriptionTxt.addFocusListener(this);
+
+ // Initialize buttons
+ setPageComplete(false);
+ getContainer().updateButtons();
+ }
+
+ @Override
+ public void focusLost(FocusEvent event) {
+ String name = commonNameTxt.getText();
+ if (EclipseUiUtils.isEmpty(name))
+ dNameTxt.setText("");
+ else
+ dNameTxt.setText(getDn(name));
+
+ String message = checkComplete();
+ if (message != null) {
+ setMessage(message, WizardPage.ERROR);
+ setPageComplete(false);
+ } else {
+ setMessage("Complete", WizardPage.INFORMATION);
+ setPageComplete(true);
+ }
+ getContainer().updateButtons();
+ }
+
+ @Override
+ public void focusGained(FocusEvent event) {
+ }
+
+ /** @return the error message or null if complete */
+ protected String checkComplete() {
+ String name = commonNameTxt.getText();
+
+ if (name.trim().equals(""))
+ return "Common name must not be empty";
+ Role role = userAdminWrapper.getUserAdmin().getRole(getDn(name));
+ if (role != null)
+ return "Group " + name + " already exists";
+ return null;
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (visible)
+ if (baseDnCmb.getSelectionIndex() == -1)
+ baseDnCmb.setFocus();
+ else
+ commonNameTxt.setFocus();
+ }
+ }
+
+ private Map<String, String> getDns() {
+ return userAdminWrapper.getKnownBaseDns(true);
+ }
+
+ private String getDn(String cn) {
+ Map<String, String> dns = getDns();
+ String bdn = baseDnCmb.getText();
+ if (EclipseUiUtils.notEmpty(bdn)) {
+ Dictionary<String, ?> props = DirectoryConf.uriAsProperties(dns.get(bdn));
+ String dn = LdapAttrs.cn.name() + "=" + cn + "," + DirectoryConf.groupBase.getValue(props) + "," + bdn;
+ return dn;
+ }
+ return null;
+ }
+
+ private void initialiseDnCmb(Combo combo) {
+ Map<String, String> dns = userAdminWrapper.getKnownBaseDns(true);
+ if (dns.isEmpty())
+ throw new CmsException("No writable base dn found. Cannot create group");
+ combo.setItems(dns.keySet().toArray(new String[0]));
+ if (dns.size() == 1)
+ combo.select(0);
+ }
+ }
+
+ private Combo createGridLC(Composite parent, String label) {
+ Label lbl = new Label(parent, SWT.LEAD);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ Combo combo = new Combo(parent, SWT.LEAD | SWT.BORDER | SWT.READ_ONLY);
+ combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ return combo;
+ }
+
+ /* DEPENDENCY INJECTION */
+ public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
+ this.userAdminWrapper = userAdminWrapper;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users.handlers;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.e4.users.UiAdminUtils;
+import org.argeo.cms.e4.users.UserAdminWrapper;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
+import org.argeo.util.directory.DirectoryConf;
+import org.argeo.util.naming.LdapAttrs;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/** Open a wizard that enables creation of a new user. */
+public class NewUser {
+ // private final static Log log = LogFactory.getLog(NewUser.class);
+ // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".newUser";
+
+ /* DEPENDENCY INJECTION */
+ @Inject
+ private UserAdminWrapper userAdminWrapper;
+
+ @Execute
+ public Object execute() {
+ NewUserWizard newUserWizard = new NewUserWizard();
+ newUserWizard.setWindowTitle("User creation");
+ WizardDialog dialog = new WizardDialog(Display.getCurrent().getActiveShell(), newUserWizard);
+ dialog.open();
+ return null;
+ }
+
+ private class NewUserWizard extends Wizard {
+
+ // pages
+ private MainUserInfoWizardPage mainUserInfo;
+
+ // End user fields
+ private Text dNameTxt, usernameTxt, firstNameTxt, lastNameTxt, primaryMailTxt, pwd1Txt, pwd2Txt;
+ private Combo baseDnCmb;
+
+ public NewUserWizard() {
+
+ }
+
+ @Override
+ public void addPages() {
+ mainUserInfo = new MainUserInfoWizardPage();
+ addPage(mainUserInfo);
+ String message = "Default wizard that also eases user creation tests:\n "
+ + "Mail and last name are automatically "
+ + "generated form the uid. Password are defauted to 'demo'.";
+ mainUserInfo.setMessage(message, WizardPage.WARNING);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public boolean performFinish() {
+ if (!canFinish())
+ return false;
+ String username = mainUserInfo.getUsername();
+ userAdminWrapper.beginTransactionIfNeeded();
+ try {
+ User user = (User) userAdminWrapper.getUserAdmin().createRole(getDn(username), Role.USER);
+
+ Dictionary props = user.getProperties();
+
+ String lastNameStr = lastNameTxt.getText();
+ if (EclipseUiUtils.notEmpty(lastNameStr))
+ props.put(LdapAttrs.sn.name(), lastNameStr);
+
+ String firstNameStr = firstNameTxt.getText();
+ if (EclipseUiUtils.notEmpty(firstNameStr))
+ props.put(LdapAttrs.givenName.name(), firstNameStr);
+
+ String cn = UserAdminUtils.buildDefaultCn(firstNameStr, lastNameStr);
+ if (EclipseUiUtils.notEmpty(cn))
+ props.put(LdapAttrs.cn.name(), cn);
+
+ String mailStr = primaryMailTxt.getText();
+ if (EclipseUiUtils.notEmpty(mailStr))
+ props.put(LdapAttrs.mail.name(), mailStr);
+
+ char[] password = mainUserInfo.getPassword();
+ user.getCredentials().put(null, password);
+ userAdminWrapper.commitOrNotifyTransactionStateChange();
+ userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CREATED, user));
+ return true;
+ } catch (Exception e) {
+ ErrorFeedback.show("Cannot create new user " + username, e);
+ return false;
+ }
+ }
+
+ private class MainUserInfoWizardPage extends WizardPage implements ModifyListener {
+ private static final long serialVersionUID = -3150193365151601807L;
+
+ public MainUserInfoWizardPage() {
+ super("Main");
+ setTitle("Required Information");
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ dNameTxt = EclipseUiUtils.createGridLT(composite, "Distinguished name", this);
+ dNameTxt.setEnabled(false);
+
+ baseDnCmb = createGridLC(composite, "Base DN");
+ initialiseDnCmb(baseDnCmb);
+ baseDnCmb.addModifyListener(this);
+ baseDnCmb.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = -1435351236582736843L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ String name = usernameTxt.getText();
+ dNameTxt.setText(getDn(name));
+ }
+ });
+
+ usernameTxt = EclipseUiUtils.createGridLT(composite, "Local ID", this);
+ usernameTxt.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = -1435351236582736843L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ String name = usernameTxt.getText();
+ if (name.trim().equals("")) {
+ dNameTxt.setText("");
+ lastNameTxt.setText("");
+ primaryMailTxt.setText("");
+ pwd1Txt.setText("");
+ pwd2Txt.setText("");
+ } else {
+ dNameTxt.setText(getDn(name));
+ lastNameTxt.setText(name.toUpperCase());
+ primaryMailTxt.setText(getMail(name));
+ pwd1Txt.setText("demo");
+ pwd2Txt.setText("demo");
+ }
+ }
+ });
+
+ primaryMailTxt = EclipseUiUtils.createGridLT(composite, "Email", this);
+ firstNameTxt = EclipseUiUtils.createGridLT(composite, "First name", this);
+ lastNameTxt = EclipseUiUtils.createGridLT(composite, "Last name", this);
+ pwd1Txt = EclipseUiUtils.createGridLP(composite, "Password", this);
+ pwd2Txt = EclipseUiUtils.createGridLP(composite, "Repeat password", this);
+ setControl(composite);
+
+ // Initialize buttons
+ setPageComplete(false);
+ getContainer().updateButtons();
+ }
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ String message = checkComplete();
+ if (message != null) {
+ setMessage(message, WizardPage.ERROR);
+ setPageComplete(false);
+ } else {
+ setMessage("Complete", WizardPage.INFORMATION);
+ setPageComplete(true);
+ }
+ getContainer().updateButtons();
+ }
+
+ /** @return error message or null if complete */
+ protected String checkComplete() {
+ String name = usernameTxt.getText();
+
+ if (name.trim().equals(""))
+ return "User name must not be empty";
+ Role role = userAdminWrapper.getUserAdmin().getRole(getDn(name));
+ if (role != null)
+ return "User " + name + " already exists";
+ if (!primaryMailTxt.getText().matches(UiAdminUtils.EMAIL_PATTERN))
+ return "Not a valid email address";
+ if (lastNameTxt.getText().trim().equals(""))
+ return "Specify a last name";
+ if (pwd1Txt.getText().trim().equals(""))
+ return "Specify a password";
+ if (pwd2Txt.getText().trim().equals(""))
+ return "Repeat the password";
+ if (!pwd2Txt.getText().equals(pwd1Txt.getText()))
+ return "Passwords are different";
+ return null;
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (visible)
+ if (baseDnCmb.getSelectionIndex() == -1)
+ baseDnCmb.setFocus();
+ else
+ usernameTxt.setFocus();
+ }
+
+ public String getUsername() {
+ return usernameTxt.getText();
+ }
+
+ public char[] getPassword() {
+ return pwd1Txt.getTextChars();
+ }
+
+ }
+
+ private Map<String, String> getDns() {
+ return userAdminWrapper.getKnownBaseDns(true);
+ }
+
+ private String getDn(String uid) {
+ Map<String, String> dns = getDns();
+ String bdn = baseDnCmb.getText();
+ if (EclipseUiUtils.notEmpty(bdn)) {
+ Dictionary<String, ?> props = DirectoryConf.uriAsProperties(dns.get(bdn));
+ String dn = LdapAttrs.uid.name() + "=" + uid + "," + DirectoryConf.userBase.getValue(props) + "," + bdn;
+ return dn;
+ }
+ return null;
+ }
+
+ private void initialiseDnCmb(Combo combo) {
+ Map<String, String> dns = userAdminWrapper.getKnownBaseDns(true);
+ if (dns.isEmpty())
+ throw new CmsException("No writable base dn found. Cannot create user");
+ combo.setItems(dns.keySet().toArray(new String[0]));
+ if (dns.size() == 1)
+ combo.select(0);
+ }
+
+ private String getMail(String username) {
+ if (baseDnCmb.getSelectionIndex() == -1)
+ return null;
+ String baseDn = baseDnCmb.getText();
+ try {
+ LdapName name = new LdapName(baseDn);
+ List<Rdn> rdns = name.getRdns();
+ return username + "@" + (String) rdns.get(1).getValue() + '.' + (String) rdns.get(0).getValue();
+ } catch (InvalidNameException e) {
+ throw new CmsException("Unable to generate mail for " + username + " with base dn " + baseDn, e);
+ }
+ }
+ }
+
+ private Combo createGridLC(Composite parent, String label) {
+ Label lbl = new Label(parent, SWT.LEAD);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ Combo combo = new Combo(parent, SWT.LEAD | SWT.BORDER | SWT.READ_ONLY);
+ combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ return combo;
+ }
+
+ /* DEPENDENCY INJECTION */
+ public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
+ this.userAdminWrapper = userAdminWrapper;
+ }
+}
--- /dev/null
+/** Users management handlers. */
+package org.argeo.cms.e4.users.handlers;
\ No newline at end of file
--- /dev/null
+/** Users management perspective. */
+package org.argeo.cms.e4.users;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.e4.users.providers;
+
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.util.naming.LdapAttrs;
+import org.osgi.service.useradmin.User;
+
+/** Simply declare a label provider that returns the common name of a user */
+public class CommonNameLP extends UserAdminAbstractLP {
+ private static final long serialVersionUID = 5256703081044911941L;
+
+ @Override
+ public String getText(User user) {
+ return UserAdminUtils.getProperty(user, LdapAttrs.cn.name());
+ }
+
+ @Override
+ public String getToolTipText(Object element) {
+ return UserAdminUtils.getProperty((User) element, LdapAttrs.DN);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.users.providers;
+
+import org.argeo.cms.auth.UserAdminUtils;
+import org.osgi.service.useradmin.User;
+
+/** The human friendly domain name for the corresponding user. */
+public class DomainNameLP extends UserAdminAbstractLP {
+ private static final long serialVersionUID = 5256703081044911941L;
+
+ @Override
+ public String getText(User user) {
+ return UserAdminUtils.getDomainName(user);
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users.providers;
+
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.util.naming.LdapAttrs;
+import org.osgi.service.useradmin.User;
+
+/** Simply declare a label provider that returns the Primary Mail of a user */
+public class MailLP extends UserAdminAbstractLP {
+ private static final long serialVersionUID = 8329764452141982707L;
+
+ @Override
+ public String getText(User user) {
+ return UserAdminUtils.getProperty(user, LdapAttrs.mail.name());
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users.providers;
+
+import org.argeo.api.cms.CmsContext;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.e4.users.SecurityAdminImages;
+import org.argeo.util.naming.LdapAttrs;
+import org.eclipse.swt.graphics.Image;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+
+/** Provide a bundle specific image depending on the current user type */
+public class RoleIconLP extends UserAdminAbstractLP {
+ private static final long serialVersionUID = 6550449442061090388L;
+
+ @Override
+ public String getText(User user) {
+ return "";
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ User user = (User) element;
+ String dn = user.getName();
+ if (dn.endsWith(CmsConstants.ROLES_BASEDN))
+ return SecurityAdminImages.ICON_ROLE;
+ else if (user.getType() == Role.GROUP) {
+ String businessCategory = UserAdminUtils.getProperty(user, LdapAttrs.businessCategory);
+ if (businessCategory != null && businessCategory.equals(CmsContext.WORKGROUP))
+ return SecurityAdminImages.ICON_WORKGROUP;
+ return SecurityAdminImages.ICON_GROUP;
+ } else
+ return SecurityAdminImages.ICON_USER;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users.providers;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.swt.CmsException;
+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.widgets.Display;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Utility class that add font modifications to a column label provider
+ * depending on the given user properties
+ */
+public abstract class UserAdminAbstractLP extends ColumnLabelProvider {
+ private static final long serialVersionUID = 137336765024922368L;
+
+ // private Font italic;
+ private Font bold;
+
+ @Override
+ public Font getFont(Object element) {
+ // Self as bold
+ try {
+ LdapName selfUserName = UserAdminUtils.getCurrentUserLdapName();
+ String userName = ((User) element).getName();
+ LdapName userLdapName = new LdapName(userName);
+ if (userLdapName.equals(selfUserName)) {
+ if (bold == null)
+ bold = JFaceResources.getFontRegistry()
+ .defaultFontDescriptor().setStyle(SWT.BOLD)
+ .createFont(Display.getCurrent());
+ return bold;
+ }
+ } catch (InvalidNameException e) {
+ throw new CmsException("cannot parse dn for " + element, e);
+ }
+
+ // Disabled as Italic
+ // Node userProfile = (Node) elem;
+ // if (!userProfile.getProperty(ARGEO_ENABLED).getBoolean())
+ // return italic;
+
+ return null;
+ // return super.getFont(element);
+ }
+
+ @Override
+ public String getText(Object element) {
+ User user = (User) element;
+ return getText(user);
+ }
+
+ public void setDisplay(Display display) {
+ // italic = JFaceResources.getFontRegistry().defaultFontDescriptor()
+ // .setStyle(SWT.ITALIC).createFont(display);
+ bold = JFaceResources.getFontRegistry().defaultFontDescriptor()
+ .setStyle(SWT.BOLD).createFont(Display.getCurrent());
+ }
+
+ public abstract String getText(User user);
+}
--- /dev/null
+package org.argeo.cms.e4.users.providers;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.dnd.DragSourceEvent;
+import org.eclipse.swt.dnd.DragSourceListener;
+import org.osgi.service.useradmin.User;
+
+/** Default drag listener to modify group and users via the UI */
+public class UserDragListener implements DragSourceListener {
+ private static final long serialVersionUID = -2074337775033781454L;
+ private final Viewer viewer;
+
+ public UserDragListener(Viewer viewer) {
+ this.viewer = viewer;
+ }
+
+ public void dragStart(DragSourceEvent event) {
+ // TODO implement finer checks
+ IStructuredSelection selection = (IStructuredSelection) viewer
+ .getSelection();
+ if (selection.isEmpty() || selection.size() > 1)
+ event.doit = false;
+ else
+ event.doit = true;
+ }
+
+ public void dragSetData(DragSourceEvent event) {
+ // TODO Support multiple selection
+ Object obj = ((IStructuredSelection) viewer.getSelection())
+ .getFirstElement();
+ if (obj != null) {
+ User user = (User) obj;
+ event.data = user.getName();
+ }
+ }
+
+ public void dragFinished(DragSourceEvent event) {
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users.providers;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.util.naming.LdapAttrs;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Filter user list using JFace mechanism on the client (yet on the server) side
+ * rather than having the UserAdmin to process the search
+ */
+public class UserFilter extends ViewerFilter {
+ private static final long serialVersionUID = 5082509381672880568L;
+
+ private String searchString;
+ private boolean showSystemRole = true;
+
+ private final String[] knownProps = { LdapAttrs.DN, LdapAttrs.cn.name(), LdapAttrs.givenName.name(),
+ LdapAttrs.sn.name(), LdapAttrs.uid.name(), LdapAttrs.description.name(), LdapAttrs.mail.name() };
+
+ public void setSearchText(String s) {
+ // ensure that the value can be used for matching
+ if (notEmpty(s))
+ searchString = ".*" + s.toLowerCase() + ".*";
+ else
+ searchString = ".*";
+ }
+
+ public void setShowSystemRole(boolean showSystemRole) {
+ this.showSystemRole = showSystemRole;
+ }
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ User user = (User) element;
+ if (!showSystemRole && user.getName().matches(".*(" + CmsConstants.ROLES_BASEDN + ")"))
+ // UserAdminUtils.getProperty(user, LdifName.dn.name())
+ // .toLowerCase().endsWith(AuthConstants.ROLES_BASEDN))
+ return false;
+
+ if (searchString == null || searchString.length() == 0)
+ return true;
+
+ if (user.getName().matches(searchString))
+ return true;
+
+ for (String key : knownProps) {
+ String currVal = UserAdminUtils.getProperty(user, key);
+ if (notEmpty(currVal) && currVal.toLowerCase().matches(searchString))
+ return true;
+ }
+ return false;
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.users.providers;
+
+import org.osgi.service.useradmin.User;
+
+/** Simply declare a label provider that returns the username of a user */
+public class UserNameLP extends UserAdminAbstractLP {
+ private static final long serialVersionUID = 6550449442061090388L;
+
+ @Override
+ public String getText(User user) {
+ return user.getName();
+ }
+}
--- /dev/null
+/** Users management content providers. */
+package org.argeo.cms.e4.users.providers;
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src" />
+ <classpathentry kind="con"
+ path="org.eclipse.pde.core.requiredPlugins" />
+ <classpathentry kind="con"
+ path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11" />
+ <classpathentry kind="output" path="bin" />
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.swt</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="CMS User App">
+ <implementation class="org.argeo.cms.swt.app.CmsUserApp"/>
+ <property name="argeo.cms.app.contextName" type="String" value="cms/user"/>
+ <service>
+ <provide interface="org.argeo.api.cms.CmsApp"/>
+ </service>
+ <reference bind="setCmsContext" cardinality="1..1" interface="org.argeo.api.cms.CmsContext" name="CmsContext" policy="static"/>
+ <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.ContentRepository" name="ContentRepository" policy="static"/>
+</scr:component>
--- /dev/null
+Import-Package: org.eclipse.swt,\
+org.eclipse.jface.window,\
+org.eclipse.core.commands.common,\
+javax.servlet.*;version="[3,5)",\
+*
+
+Bundle-ActivationPolicy: lazy
+
+Service-Component: \
+OSGI-INF/cmsUserApp.xml
+
\ No newline at end of file
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/cmsUserApp.xml
+source.. = src/
--- /dev/null
+package org.argeo.cms.jface.dialog;
+
+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.cms.swt.dialogs.LightweightDialog;
+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 {
+ // FIXME it creates a dependency to Eclipse Core Runtime
+ // 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);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt;
+
+/** @deprecated Use standard Java {@link RuntimeException} instead. */
+@Deprecated
+public class CmsException extends RuntimeException {
+ private static final long serialVersionUID = -5341764743356771313L;
+
+ public CmsException(String message) {
+ super(message);
+ }
+
+ public CmsException(String message, Throwable e) {
+ super(message, e);
+ }
+
+}
--- /dev/null
+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";
+}
--- /dev/null
+package org.argeo.cms.swt;
+
+import org.argeo.api.cms.ux.CmsIcon;
+import org.argeo.api.cms.ux.CmsTheme;
+import org.eclipse.swt.graphics.Image;
+
+/** SWT specific {@link CmsTheme}. */
+public interface CmsSwtTheme extends CmsTheme {
+// /** The image registered at this path, or <code>null</code> 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 <code>null</code> if not found.
+ *
+ * @param name An icon file name without path and extension.
+ * @param preferredSize the preferred size, if <code>null</code>,
+ * {@link #getDefaultIconSize()} will be tried.
+ */
+ Image getIcon(String name, Integer preferredSize);
+
+ Image getSmallIcon(CmsIcon icon);
+
+ Image getBigIcon(CmsIcon icon);
+}
--- /dev/null
+package org.argeo.cms.swt;
+
+import org.argeo.api.cms.ux.CmsUi;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/** A basic {@link CmsUi}, based on an SWT {@link Composite}. */
+public class CmsSwtUi extends Composite implements CmsUi {
+
+ private static final long serialVersionUID = -107939076610406448L;
+
+ public CmsSwtUi(Composite parent, int style) {
+ super(parent, style);
+ setLayout(new GridLayout());
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.swt;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.argeo.api.cms.ux.CmsIcon;
+import org.argeo.api.cms.ux.CmsStyle;
+import org.argeo.api.cms.ux.CmsTheme;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.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.Layout;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+
+/** SWT utilities. */
+public class CmsSwtUtils {
+ /*
+ * THEME AND VIEW
+ */
+
+ public static CmsSwtTheme getCmsTheme(Composite parent) {
+ CmsSwtTheme theme = (CmsSwtTheme) parent.getData(CmsTheme.class.getName());
+ if (theme == null) {
+ // find parent shell
+ Shell topShell = parent.getShell();
+ while (topShell.getParent() != null)
+ topShell = (Shell) topShell.getParent();
+ theme = (CmsSwtTheme) 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);
+ }
+
+ /*
+ * EVENTS
+ */
+
+ /** Sends an event via {@link CmsView#sendEvent(String, Map)}. */
+ public static void sendEventOnSelect(Control control, String topic, Map<String, Object> 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<String, Object> properties = new HashMap<>();
+ properties.put(key, value);
+ sendEventOnSelect(control, topic, properties);
+ }
+
+ /*
+ * ICONS
+ */
+ /** Get a small icon from this theme. */
+ public static Image getSmallIcon(CmsTheme theme, CmsIcon icon) {
+ return ((CmsSwtTheme) theme).getSmallIcon(icon);
+ }
+
+ /** Get a big icon from this theme. */
+ public static Image getBigIcon(CmsTheme theme, CmsIcon icon) {
+ return ((CmsSwtTheme) theme).getBigIcon(icon);
+ }
+
+ /*
+ * LAYOUT INDEPENDENT
+ */
+ /** Takes the most space possible, depending on parent layout. */
+ public static void fill(Control control) {
+ Layout parentLayout = control.getParent().getLayout();
+ if (parentLayout == null)
+ throw new IllegalStateException("Parent layout is not set");
+ if (parentLayout instanceof GridLayout) {
+ control.setLayoutData(fillAll());
+ } else if (parentLayout instanceof FormLayout) {
+ control.setLayoutData(coverAll());
+ } else {
+ throw new IllegalArgumentException("Unsupported parent layout " + parentLayout.getClass().getName());
+ }
+ }
+
+ /*
+ * GRID LAYOUT
+ */
+ /** A {@link GridLayout} without any spacing and one column. */
+ public static GridLayout noSpaceGridLayout() {
+ return noSpaceGridLayout(new GridLayout());
+ }
+
+ /**
+ * A {@link GridLayout} without any spacing and multiple columns of unequal
+ * width.
+ */
+ 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 extends Widget> 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 extends Widget> T style(T widget, CmsStyle style) {
+ return style(widget, style.style());
+ }
+
+ /** Enable markups on widget */
+ public static <T extends Widget> T markup(T widget) {
+ EclipseUiSpecificUtils.setMarkupData(widget);
+ return widget;
+ }
+
+ /** Disable markup validation. */
+ public static <T extends Widget> 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 <code>toString()</code> method.
+ * This argument should not be null, but if it is null and
+ * assertions are disabled "<null>" is displayed instead; if
+ * assertions are enabled the call will fail.
+ *
+ * @see markup
+ */
+ public static <T extends Widget> T text(T widget, Object txt) {
+ assert txt != null;
+ String str = txt != null ? txt.toString() : "<null>";
+ 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();
+ }
+
+ /** Clean reserved URL characters for use in HTTP links. */
+ public static String cleanPathForUrl(String path) {
+ StringTokenizer st = new StringTokenizer(path, "/");
+ StringBuilder sb = new StringBuilder();
+ while (st.hasMoreElements()) {
+ sb.append('/');
+ String encoded = URLEncoder.encode(st.nextToken(), StandardCharsets.UTF_8);
+ encoded = encoded.replace("+", "%20");
+ sb.append(encoded);
+
+ }
+ return sb.toString();
+ }
+
+ /** Singleton. */
+ private CmsSwtUtils() {
+ }
+
+}
--- /dev/null
+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
+ }
+}
--- /dev/null
+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
+ }
+}
--- /dev/null
+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
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt;
+
+import org.argeo.api.cms.ux.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;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt;
+
+import org.argeo.cms.ux.widgets.EditablePart;
+import org.eclipse.swt.widgets.Control;
+
+/** Manages whether an editable or non editable control is shown. */
+public interface SwtEditablePart extends EditablePart {
+ public Control getControl();
+}
--- /dev/null
+package org.argeo.cms.swt.acr;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.spi.ProvidedContent;
+import org.eclipse.swt.widgets.Composite;
+
+/** A composite which can (optionally) manage a content. */
+public class ContentComposite extends Composite {
+ private static final long serialVersionUID = -1447009015451153367L;
+
+ public ContentComposite(Composite parent, int style, Content item) {
+ super(parent, style);
+ setData(item);
+ }
+
+ public Content getContent() {
+ return (Content) getData();
+ }
+
+ @Deprecated
+ public Content getNode() {
+ return getContent();
+ }
+
+ protected ProvidedContent getProvidedContent() {
+ return (ProvidedContent) getContent();
+ }
+
+ public String getSessionLocalId() {
+ return getProvidedContent().getSessionLocalId();
+ }
+
+ protected void itemUpdated() {
+ layout();
+ }
+
+ public void setContent(Content content) {
+ setData(content);
+ itemUpdated();
+ }
+}
--- /dev/null
+package org.argeo.cms.swt.acr;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.argeo.api.acr.Content;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ux.widgets.EditablePart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** A structured UI related to a JCR context. */
+public class SwtSection extends ContentComposite {
+ private static final long serialVersionUID = -5933796173755739207L;
+
+ private final SwtSection parentSection;
+ private Composite sectionHeader;
+ private final Integer relativeDepth;
+
+ public SwtSection(Composite parent, int style, Content node) {
+ this(parent, findSection(parent), style, node);
+ }
+
+ public SwtSection(SwtSection section, int style, Content node) {
+ this(section, section, style, node);
+ }
+
+ protected SwtSection(Composite parent, SwtSection parentSection, int style, Content node) {
+ super(parent, style, node);
+ this.parentSection = parentSection;
+ if (parentSection != null) {
+ relativeDepth = getProvidedContent().getDepth() - parentSection.getProvidedContent().getDepth();
+ } else {
+ relativeDepth = 0;
+ }
+ setLayout(CmsSwtUtils.noSpaceGridLayout());
+ }
+
+ public Map<String, SwtSection> getSubSections() {
+ LinkedHashMap<String, SwtSection> result = new LinkedHashMap<String, SwtSection>();
+ for (Control child : getChildren()) {
+ if (child instanceof Composite) {
+ collectDirectSubSections((Composite) child, result);
+ }
+ }
+ return Collections.unmodifiableMap(result);
+ }
+
+ private void collectDirectSubSections(Composite composite, LinkedHashMap<String, SwtSection> subSections) {
+ if (composite == sectionHeader || composite instanceof EditablePart)
+ return;
+ if (composite instanceof SwtSection) {
+ SwtSection section = (SwtSection) composite;
+ subSections.put(section.getProvidedContent().getSessionLocalId(), section);
+ return;
+ }
+
+ for (Control child : composite.getChildren())
+ if (child instanceof Composite)
+ collectDirectSubSections((Composite) child, subSections);
+ }
+
+ public Composite createHeader() {
+ return createHeader(this);
+ }
+
+ public Composite createHeader(Composite parent) {
+ if (sectionHeader != null)
+ sectionHeader.dispose();
+
+ sectionHeader = new Composite(parent, SWT.NONE);
+ sectionHeader.setLayoutData(CmsSwtUtils.fillWidth());
+ sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ // sectionHeader.moveAbove(null);
+ // layout();
+ return sectionHeader;
+ }
+
+ public Composite getHeader() {
+ if (sectionHeader != null && sectionHeader.isDisposed())
+ sectionHeader = null;
+ return sectionHeader;
+ }
+
+ // SECTION PARTS
+ public SwtSectionPart getSectionPart(String partId) {
+ for (Control child : getChildren()) {
+ if (child instanceof SwtSectionPart) {
+ SwtSectionPart sectionPart = (SwtSectionPart) child;
+ if (sectionPart.getPartId().equals(partId))
+ return sectionPart;
+ }
+ }
+ return null;
+ }
+
+ public SwtSectionPart nextSectionPart(SwtSectionPart sectionPart) {
+ Control[] children = getChildren();
+ for (int i = 0; i < children.length; i++) {
+ if (sectionPart == children[i]) {
+ for (int j = i + 1; j < children.length; j++) {
+ if (children[i + 1] instanceof SwtSectionPart) {
+ return (SwtSectionPart) children[i + 1];
+ }
+ }
+
+// if (i + 1 < children.length) {
+// Composite next = (Composite) children[i + 1];
+// return (SectionPart) next;
+// } else {
+// // next section
+// }
+ }
+ }
+ return null;
+ }
+
+ public SwtSectionPart previousSectionPart(SwtSectionPart sectionPart) {
+ Control[] children = getChildren();
+ for (int i = 0; i < children.length; i++) {
+ if (sectionPart == children[i])
+ if (i != 0) {
+ Composite previous = (Composite) children[i - 1];
+ return (SwtSectionPart) previous;
+ } else {
+ // previous section
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ if (parentSection == null)
+ return "Main section " + getContent();
+ return "Section " + getContent();
+ }
+
+ public SwtSection getParentSection() {
+ return parentSection;
+ }
+
+ public Integer getRelativeDepth() {
+ return relativeDepth;
+ }
+
+ /** Recursively finds the related section in the parents (can be itself) */
+ public static SwtSection findSection(Control control) {
+ if (control == null)
+ return null;
+ if (control instanceof SwtSection)
+ return (SwtSection) control;
+ else
+ return findSection(control.getParent());
+ }
+}
--- /dev/null
+package org.argeo.cms.swt.acr;
+
+import org.argeo.cms.ux.acr.ContentPart;
+import org.argeo.cms.ux.widgets.EditablePart;
+
+/** An editable part dynamically related to a Section */
+public interface SwtSectionPart extends EditablePart, ContentPart {
+ public String getPartId();
+
+ public SwtSection getSection();
+}
--- /dev/null
+package org.argeo.cms.swt.acr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.spi.ProvidedContent;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.Selected;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.graphics.Image;
+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.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** Manages {@link SwtSection} in a tab-like structure. */
+public class SwtTabbedArea extends Composite {
+ private static final long serialVersionUID = 8659669229482033444L;
+
+ private Composite headers;
+ private Composite body;
+
+ private List<SwtSection> sections = new ArrayList<>();
+
+ private ProvidedContent previousNode;
+ private SwtUiProvider previousUiProvider;
+ private SwtUiProvider currentUiProvider;
+
+ private String tabStyle;
+ private String tabSelectedStyle;
+ private String bodyStyle;
+ private Image closeIcon;
+
+ private StackLayout stackLayout;
+
+ private boolean singleTab = false;
+
+ public SwtTabbedArea(Composite parent, int style) {
+ super(parent, SWT.NONE);
+ CmsSwtUtils.style(parent, bodyStyle);
+
+ setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+ // TODO manage tabs at bottom or sides
+ headers = new Composite(this, SWT.NONE);
+ headers.setLayoutData(CmsSwtUtils.fillWidth());
+ body = new Composite(this, SWT.NONE);
+ body.setLayoutData(CmsSwtUtils.fillAll());
+ // body.setLayout(new FormLayout());
+ stackLayout = new StackLayout();
+ body.setLayout(stackLayout);
+ emptyState();
+ }
+
+ protected void refreshTabHeaders() {
+ int tabCount = sections.size() > 0 ? sections.size() : 1;
+ for (Control tab : headers.getChildren())
+ tab.dispose();
+
+ headers.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(tabCount, true)));
+
+ if (sections.size() == 0) {
+ Composite emptyHeader = new Composite(headers, SWT.NONE);
+ emptyHeader.setLayoutData(CmsSwtUtils.fillAll());
+ emptyHeader.setLayout(new GridLayout());
+ Label lbl = new Label(emptyHeader, SWT.NONE);
+ lbl.setText("");
+ lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
+
+ }
+
+ SwtSection currentSection = getCurrentSection();
+ for (SwtSection section : sections) {
+ boolean selected = section == currentSection;
+ Composite sectionHeader = section.createHeader(headers);
+ CmsSwtUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle);
+ int headerColumns = singleTab ? 1 : 2;
+ sectionHeader.setLayout(new GridLayout(headerColumns, false));
+ sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout(headerColumns));
+ Button title = new Button(sectionHeader, SWT.FLAT);
+ CmsSwtUtils.style(title, selected ? tabSelectedStyle : tabStyle);
+ title.setLayoutData(CmsSwtUtils.fillWidth());
+ title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode())));
+ Content node = section.getContent();
+
+ // FIXME find a standard way to display titles
+ String titleStr = node.getName().getLocalPart();
+
+ // TODO internationalize
+ title.setText(titleStr);
+ if (!singleTab) {
+ ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
+ ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT);
+ if (closeIcon != null)
+ closeItem.setImage(closeIcon);
+ else
+ closeItem.setText("X");
+ CmsSwtUtils.style(closeItem, selected ? tabSelectedStyle : tabStyle);
+ closeItem.addSelectionListener((Selected) (e) -> closeTab(section));
+ }
+ }
+
+ }
+
+ public void view(SwtUiProvider uiProvider, Content context) {
+ if (body.isDisposed())
+ return;
+ int index = tabIndex(context);
+ if (index >= 0) {
+ showTab(index);
+ previousNode = (ProvidedContent) context;
+ previousUiProvider = uiProvider;
+ return;
+ }
+ SwtSection section = (SwtSection) body.getChildren()[0];
+ previousNode = (ProvidedContent) section.getNode();
+ if (previousNode == null) {// empty state
+ previousNode = (ProvidedContent) context;
+ previousUiProvider = uiProvider;
+ } else {
+ previousUiProvider = currentUiProvider;
+ }
+ currentUiProvider = uiProvider;
+ section.setContent(context);
+ // section.setLayoutData(CmsUiUtils.coverAll());
+ build(section, uiProvider, context);
+ if (sections.size() == 0)
+ sections.add(section);
+ refreshTabHeaders();
+ index = tabIndex(context);
+ showTab(index);
+ layout(true, true);
+ }
+
+ public void open(SwtUiProvider uiProvider, Content context) {
+ if (singleTab)
+ throw new UnsupportedOperationException("Open is not supported in single tab mode.");
+
+ if (previousNode != null
+ && previousNode.getSessionLocalId().equals(((ProvidedContent) context).getSessionLocalId())) {
+ // does nothing
+ return;
+ }
+ if (sections.size() == 0)
+ CmsSwtUtils.clear(body);
+ SwtSection currentSection = getCurrentSection();
+ int currentIndex = sections.indexOf(currentSection);
+ SwtSection previousSection = new SwtSection(body, SWT.NONE, context);
+ build(previousSection, previousUiProvider, previousNode);
+ // previousSection.setLayoutData(CmsUiUtils.coverAll());
+ int newIndex = currentIndex + 1;
+ sections.add(currentIndex, previousSection);
+// sections.add(newIndex, previousSection);
+ showTab(newIndex);
+ refreshTabHeaders();
+ layout(true, true);
+ }
+
+ public void showTab(int index) {
+ SwtSection sectionToShow = sections.get(index);
+ // sectionToShow.moveAbove(null);
+ stackLayout.topControl = sectionToShow;
+ refreshTabHeaders();
+ layout(true, true);
+ }
+
+ protected void build(SwtSection section, SwtUiProvider uiProvider, Content context) {
+ for (Control child : section.getChildren())
+ child.dispose();
+ CmsSwtUtils.style(section, bodyStyle);
+ section.setContent(context);
+ uiProvider.createUiPart(section, context);
+
+ }
+
+ private int tabIndex(Content context) {
+ for (int i = 0; i < sections.size(); i++) {
+ SwtSection section = sections.get(i);
+ if (section.getSessionLocalId().equals(((ProvidedContent) context).getSessionLocalId()))
+ return i;
+ }
+ return -1;
+ }
+
+ public void closeTab(SwtSection section) {
+ int currentIndex = sections.indexOf(section);
+ int nextIndex = currentIndex == 0 ? 0 : currentIndex - 1;
+ sections.remove(section);
+ section.dispose();
+ if (sections.size() == 0) {
+ emptyState();
+ refreshTabHeaders();
+ layout(true, true);
+ return;
+ }
+ refreshTabHeaders();
+ showTab(nextIndex);
+ }
+
+ public void closeAllTabs() {
+ for (SwtSection section : sections) {
+ section.dispose();
+ }
+ sections.clear();
+ emptyState();
+ refreshTabHeaders();
+ layout(true, true);
+ }
+
+ protected void emptyState() {
+ new SwtSection(body, SWT.NONE, null);
+ refreshTabHeaders();
+ }
+
+ public Composite getCurrent() {
+ return getCurrentSection();
+ }
+
+ protected SwtSection getCurrentSection() {
+ return (SwtSection) stackLayout.topControl;
+ }
+
+ public Content getCurrentContext() {
+ SwtSection section = getCurrentSection();
+ if (section != null) {
+ return section.getNode();
+ } else {
+ return null;
+ }
+ }
+
+ public void setTabStyle(String tabStyle) {
+ this.tabStyle = tabStyle;
+ }
+
+ public void setTabSelectedStyle(String tabSelectedStyle) {
+ this.tabSelectedStyle = tabSelectedStyle;
+ }
+
+ public void setBodyStyle(String bodyStyle) {
+ this.bodyStyle = bodyStyle;
+ }
+
+ public void setCloseIcon(Image closeIcon) {
+ this.closeIcon = closeIcon;
+ }
+
+ public void setSingleTab(boolean singleTab) {
+ this.singleTab = singleTab;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.acr;
+
+import org.argeo.api.acr.Content;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+@FunctionalInterface
+public interface SwtUiProvider {
+ Control createUiPart(Composite parent, Content context);
+}
--- /dev/null
+package org.argeo.cms.swt.app;
+
+import static org.argeo.api.acr.NamespaceUtils.toPrefixedName;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.widgets.SwtHierarchicalPart;
+import org.argeo.cms.swt.widgets.SwtTabularPart;
+import org.argeo.cms.ux.acr.ContentHierarchicalPart;
+import org.argeo.cms.ux.widgets.Column;
+import org.argeo.cms.ux.widgets.DefaultTabularPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.widgets.Composite;
+
+public class AcrContentTreeView extends Composite {
+ private static final long serialVersionUID = -3707881216246077323L;
+
+ private Content rootContent;
+
+// private Content selected;
+
+ public AcrContentTreeView(Composite parent, int style, Content content) {
+ super(parent, style);
+ this.rootContent = content;
+ // this.selected = rootContent;
+ setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+ SashForm split = new SashForm(this, SWT.HORIZONTAL);
+ split.setLayoutData(CmsSwtUtils.fillAll());
+
+ ContentHierarchicalPart contentPart = new ContentHierarchicalPart();
+ contentPart.setInput(rootContent);
+
+ SwtHierarchicalPart<Content> hPart = new SwtHierarchicalPart<>(split, getStyle(), contentPart);
+
+ Composite area = new Composite(split, SWT.BORDER);
+ area.setLayout(CmsSwtUtils.noSpaceGridLayout(2));
+ split.setWeights(new int[] { 30, 70 });
+
+ // attributes
+ DefaultTabularPart<Content, QName> attributesPart = new DefaultTabularPart<>() {
+
+ @Override
+ protected List<QName> asList(Content input) {
+ return new ArrayList<>(input.keySet());
+ }
+ };
+
+ attributesPart.addColumn(new Column<QName>() {
+
+ @Override
+ public String getText(QName model) {
+ try {
+ return NamespaceUtils.toPrefixedName(model);
+ } catch (IllegalStateException e) {
+ return model.toString();
+ }
+ }
+ });
+ attributesPart.addColumn(new Column<QName>() {
+
+ @Override
+ public String getText(QName model) {
+ return attributesPart.getInput().get(model).toString();
+ }
+
+ @Override
+ public int getWidth() {
+ return 400;
+ }
+
+ });
+ // attributesPart.setInput(selected);
+
+ SwtTabularPart<Content, QName> attributeTable = new SwtTabularPart<>(area, style, attributesPart);
+ attributeTable.setLayoutData(CmsSwtUtils.fillAll());
+
+ // types
+ DefaultTabularPart<Content, QName> typesPart = new DefaultTabularPart<>() {
+
+ @Override
+ protected List<QName> asList(Content input) {
+ return input.getContentClasses();
+ }
+ };
+ typesPart.addColumn(new Column<QName>() {
+
+ @Override
+ public String getText(QName model) {
+ return toPrefixedName(model);
+ }
+
+ });
+
+ // typesPart.setInput(selected);
+
+ SwtTabularPart<Content, QName> typesTable = new SwtTabularPart<>(area, style, typesPart);
+ typesTable.setLayoutData(CmsSwtUtils.fillAll());
+
+ // controller
+ contentPart.setInput(rootContent);
+ contentPart.onSelected((o) -> {
+ Content c = (Content) o;
+// selected = c;
+ attributesPart.setInput(c);
+ typesPart.setInput(c);
+ });
+
+ attributesPart.refresh();
+ typesPart.refresh();
+ }
+
+// protected void refreshTable() {
+// for (TableItem item : table.getItems()) {
+// item.dispose();
+// }
+// for (QName key : selected.keySet()) {
+// TableItem item = new TableItem(table, 0);
+// item.setText(0, key.toString());
+// Object value = selected.get(key);
+// item.setText(1, value.toString());
+// }
+// table.getColumn(0).pack();
+// table.getColumn(1).pack();
+// }
+
+// public static void main(String[] args) {
+// Path basePath;
+// if (args.length > 0) {
+// basePath = Paths.get(args[0]);
+// } else {
+// basePath = Paths.get(System.getProperty("user.home"));
+// }
+//
+// final Display display = new Display();
+// final Shell shell = new Shell(display);
+// shell.setText(basePath.toString());
+// shell.setLayout(new FillLayout());
+//
+// FsContentProvider contentSession = new FsContentProvider("/", basePath);
+//// GcrContentTreeView treeView = new GcrContentTreeView(shell, 0, contentSession.get("/"));
+//
+// shell.setSize(shell.computeSize(800, 600));
+// shell.open();
+// while (!shell.isDisposed()) {
+// if (!display.readAndDispatch())
+// display.sleep();
+// }
+// display.dispose();
+// }
+}
--- /dev/null
+package org.argeo.cms.swt.app;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentRepository;
+import org.argeo.api.cms.CmsContext;
+import org.argeo.api.cms.ux.CmsUi;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.cms.AbstractCmsApp;
+import org.argeo.cms.swt.CmsSwtUi;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.auth.CmsLogin;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+
+public class CmsUserApp extends AbstractCmsApp {
+ private ContentRepository contentRepository;
+
+ @Override
+ public Set<String> getUiNames() {
+ Set<String> uiNames = new HashSet<>();
+ uiNames.add("login");
+ uiNames.add("data");
+ return uiNames;
+ }
+
+ @Override
+ public CmsUi initUi(Object uiParent) {
+ Composite parent = (Composite) uiParent;
+ String uiName = parent.getData(UI_NAME_PROPERTY) != null ? parent.getData(UI_NAME_PROPERTY).toString() : null;
+ CmsSwtUi cmsUi = new CmsSwtUi(parent, SWT.NONE);
+ if ("login".equals(uiName)) {
+ CmsView cmsView = CmsSwtUtils.getCmsView(cmsUi);
+ CmsLogin cmsLogin = new CmsLogin(cmsView, getCmsContext());
+ cmsLogin.createUi(cmsUi);
+
+ } else if ("data".equals(uiName)) {
+ Content rootContent = contentRepository.get().get("/");
+ AcrContentTreeView view = new AcrContentTreeView(cmsUi, 0, rootContent);
+ view.setLayoutData(CmsSwtUtils.fillAll());
+
+ }
+ return cmsUi;
+ }
+
+ @Override
+ public void refreshUi(CmsUi cmsUi, String state) {
+ }
+
+ @Override
+ public void setState(CmsUi cmsUi, String state) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setContentRepository(ContentRepository contentRepository) {
+ this.contentRepository = contentRepository;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+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 org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.CmsContext;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.cms.CmsMsg;
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.auth.RemoteAuthCallback;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.cms.servlet.ServletHttpResponse;
+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 CmsLog log = CmsLog.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;
+
+ private CmsContext cmsContext;
+
+ public CmsLogin(CmsView cmsView, CmsContext cmsContext) {
+ this.cmsView = cmsView;
+ this.cmsContext = cmsContext;
+ if (this.cmsContext != null) {
+ defaultLocale = this.cmsContext.getDefaultLocale();
+ List<Locale> locales = this.cmsContext.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<Locale> 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(CmsAuth.LOGIN_CONTEXT_USER, this);
+ else
+ loginContext = new LoginContext(CmsAuth.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 RemoteAuthCallback) {
+ ((RemoteAuthCallback) callback).setRequest(new ServletHttpRequest(UiContext.getHttpRequest()));
+ ((RemoteAuthCallback) callback).setResponse(new ServletHttpResponse(UiContext.getHttpResponse()));
+ } else if (callback instanceof LanguageCallback) {
+ Locale toUse = null;
+ if (localeChoice != null)
+ toUse = localeChoice.getSelectedLocale();
+ else if (defaultLocale != null)
+ toUse = defaultLocale;
+
+ if (toUse != null) {
+ ((LanguageCallback) callback).setLocale(toUse);
+ UiContext.setLocale(toUse);
+ }
+
+ }
+ }
+ }
+
+ public void setSubject(Subject subject) {
+ this.subject = subject;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.auth;
+
+import org.argeo.api.cms.CmsContext;
+import org.argeo.api.cms.ux.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, CmsContext cmsContext) {
+ super(cmsView, cmsContext);
+ 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);
+ }
+}
--- /dev/null
+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:<br>
+ * <ul>
+ * <li>{@link PasswordCallback}</li>
+ * <li>{@link NameCallback}</li>
+ * <li>{@link TextOutputCallback}</li>
+ * </ul>
+ * Supported Argeo {@link Callback}s are:<br>
+ * <ul>
+ * <li>{@link LocaleChoice}</li>
+ * </ul>
+ */
+public class CompositeCallbackHandler extends Composite implements CallbackHandler {
+ private static final long serialVersionUID = -928223893722723777L;
+
+ private boolean wasUsedAlready = false;
+ private boolean isSubmitted = false;
+ private boolean isCanceled = false;
+
+ public CompositeCallbackHandler(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ public synchronized void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ // reset
+ if (wasUsedAlready && !isSubmitted() && !isCanceled()) {
+ cancel();
+ for (Control control : getChildren())
+ control.dispose();
+ isSubmitted = false;
+ isCanceled = false;
+ }
+
+ for (Callback callback : callbacks)
+ checkCallbackSupported(callback);
+ // create controls synchronously in the UI thread
+ getDisplay().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ createCallbackHandlers(callbacks);
+ }
+ });
+
+ if (!wasUsedAlready)
+ wasUsedAlready = true;
+
+ // while (!isSubmitted() && !isCanceled()) {
+ // try {
+ // wait(1000l);
+ // } catch (InterruptedException e) {
+ // // silent
+ // }
+ // }
+
+ // cleanCallbacksAfterCancel(callbacks);
+ }
+
+ public void checkCallbackSupported(Callback callback) throws UnsupportedCallbackException {
+ if (callback instanceof TextOutputCallback || callback instanceof NameCallback
+ || callback instanceof PasswordCallback || callback instanceof LocaleChoice) {
+ return;
+ } else {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+
+ /**
+ * Set writable callbacks to null if the handle is canceled (check is done
+ * by the method)
+ */
+ public void cleanCallbacksAfterCancel(Callback[] callbacks) {
+ if (isCanceled()) {
+ for (Callback callback : callbacks) {
+ if (callback instanceof NameCallback) {
+ ((NameCallback) callback).setName(null);
+ } else if (callback instanceof PasswordCallback) {
+ PasswordCallback pCallback = (PasswordCallback) callback;
+ char[] arr = pCallback.getPassword();
+ if (arr != null) {
+ Arrays.fill(arr, '*');
+ pCallback.setPassword(null);
+ }
+ }
+ }
+ }
+ }
+
+ public void createCallbackHandlers(Callback[] callbacks) {
+ Composite composite = this;
+ for (int i = 0; i < callbacks.length; i++) {
+ Callback callback = callbacks[i];
+ if (callback instanceof TextOutputCallback) {
+ createLabelTextoutputHandler(composite, (TextOutputCallback) callback);
+ } else if (callback instanceof NameCallback) {
+ createNameHandler(composite, (NameCallback) callback);
+ } else if (callback instanceof PasswordCallback) {
+ createPasswordHandler(composite, (PasswordCallback) callback);
+ } else if (callback instanceof LocaleChoice) {
+ createLocaleHandler(composite, (LocaleChoice) callback);
+ }
+ }
+ }
+
+ protected Text createNameHandler(Composite composite, final NameCallback callback) {
+ Label label = new Label(composite, SWT.NONE);
+ label.setText(callback.getPrompt());
+ final Text text = new Text(composite, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
+ if (callback.getDefaultName() != null) {
+ // set default value, if provided
+ text.setText(callback.getDefaultName());
+ callback.setName(callback.getDefaultName());
+ }
+ text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ text.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = 7300032545287292973L;
+
+ public void modifyText(ModifyEvent event) {
+ callback.setName(text.getText());
+ }
+ });
+ text.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = 1820530045857665111L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ submit();
+ }
+ });
+
+ text.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -8698107785092095713L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ }
+ });
+ return text;
+ }
+
+ protected Text createPasswordHandler(Composite composite, final PasswordCallback callback) {
+ Label label = new Label(composite, SWT.NONE);
+ label.setText(callback.getPrompt());
+ final Text passwordText = new Text(composite, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD | SWT.BORDER);
+ passwordText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ passwordText.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = -7099363995047686732L;
+
+ public void modifyText(ModifyEvent event) {
+ callback.setPassword(passwordText.getTextChars());
+ }
+ });
+ passwordText.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = 1820530045857665111L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ submit();
+ }
+ });
+ return passwordText;
+ }
+
+ protected Combo createLocaleHandler(Composite composite, final LocaleChoice callback) {
+ String[] labels = callback.getSupportedLocalesLabels();
+ if (labels.length == 0)
+ return null;
+ Label label = new Label(composite, SWT.NONE);
+ label.setText("Language");
+
+ final Combo combo = new Combo(composite, SWT.READ_ONLY);
+ combo.setItems(labels);
+ combo.select(callback.getDefaultIndex());
+ combo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ combo.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = 38678989091946277L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ callback.setSelectedIndex(combo.getSelectionIndex());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ return combo;
+ }
+
+ protected Label createLabelTextoutputHandler(Composite composite, final TextOutputCallback callback) {
+ Label label = new Label(composite, SWT.NONE);
+ label.setText(callback.getMessage());
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.horizontalSpan = 2;
+ label.setLayoutData(data);
+ return label;
+ // TODO: find a way to pass this information
+ // int messageType = callback.getMessageType();
+ // int dialogMessageType = IMessageProvider.NONE;
+ // switch (messageType) {
+ // case TextOutputCallback.INFORMATION:
+ // dialogMessageType = IMessageProvider.INFORMATION;
+ // break;
+ // case TextOutputCallback.WARNING:
+ // dialogMessageType = IMessageProvider.WARNING;
+ // break;
+ // case TextOutputCallback.ERROR:
+ // dialogMessageType = IMessageProvider.ERROR;
+ // break;
+ // }
+ // setMessage(callback.getMessage(), dialogMessageType);
+ }
+
+ synchronized boolean isSubmitted() {
+ return isSubmitted;
+ }
+
+ synchronized boolean isCanceled() {
+ return isCanceled;
+ }
+
+ protected synchronized void submit() {
+ isSubmitted = true;
+ notifyAll();
+ }
+
+ protected synchronized void cancel() {
+ isCanceled = true;
+ notifyAll();
+ }
+}
--- /dev/null
+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();
+ }
+
+}
--- /dev/null
+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.swt.CmsException;
+
+/** Choose in a list of locales. TODO: replace with {@link LanguageCallback} */
+@Deprecated
+public class LocaleChoice {
+ private final List<Locale> locales;
+
+ private Integer selectedIndex = null;
+ private final Integer defaultIndex;
+
+ public LocaleChoice(List<Locale> locales, Locale defaultLocale) {
+ Integer defaultIndex = null;
+ this.locales = Collections.unmodifiableList(locales);
+ for (int i = 0; i < locales.size(); i++)
+ if (locales.get(i).equals(defaultLocale))
+ defaultIndex = i;
+
+ // based on language only
+ if (defaultIndex == null)
+ for (int i = 0; i < locales.size(); i++)
+ if (locales.get(i).getLanguage().equals(defaultLocale.getLanguage()))
+ defaultIndex = i;
+
+ if (defaultIndex == null)
+ throw new CmsException("Default locale " + defaultLocale + " is not in available locales " + locales);
+ this.defaultIndex = defaultIndex;
+
+ this.selectedIndex = defaultIndex;
+ }
+
+// /**
+// * Convenience constructor based on a comma separated list of iso codes (en,
+// * en_US, fr_CA, etc.). Default selection is default locale.
+// */
+// public LocaleChoice(String locales, Locale defaultLocale) {
+// this(LocaleUtils.asLocaleList(locales), defaultLocale);
+// }
+
+ public String[] getSupportedLocalesLabels() {
+ String[] labels = new String[locales.size()];
+ for (int i = 0; i < locales.size(); i++) {
+ Locale locale = locales.get(i);
+ if (locale.getCountry().equals(""))
+ labels[i] = locale.getDisplayLanguage(locale) + " [" + locale.getLanguage() + "]";
+ else
+ labels[i] = locale.getDisplayLanguage(locale) + " (" + locale.getDisplayCountry(locale) + ") ["
+ + locale.getLanguage() + "_" + locale.getCountry() + "]";
+
+ }
+ return labels;
+ }
+
+ public Locale getSelectedLocale() {
+ if (selectedIndex == null)
+ return null;
+ return locales.get(selectedIndex);
+ }
+
+ public void setSelectedIndex(Integer selectedIndex) {
+ this.selectedIndex = selectedIndex;
+ }
+
+ public Integer getSelectedIndex() {
+ return selectedIndex;
+ }
+
+ public Integer getDefaultIndex() {
+ return defaultIndex;
+ }
+
+ public List<Locale> getLocales() {
+ return locales;
+ }
+
+ public Locale getDefaultLocale() {
+ return locales.get(getDefaultIndex());
+ }
+}
--- /dev/null
+/** Argeo CMS authentication widgets, based on SWT. */
+package org.argeo.cms.swt.auth;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.swt.dialogs;
+
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.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 CmsLog log = CmsLog.getLog(ChangePasswordDialog.class);
+
+ private CmsUserManager cmsUserManager;
+ private CmsView cmsView;
+
+ private PrivilegedAction<Integer> 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;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.dialogs;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.argeo.api.cms.CmsLog;
+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 CmsLog log = CmsLog.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;
+ }
+
+}
--- /dev/null
+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);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.dialogs;
+
+import org.argeo.api.cms.CmsLog;
+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 CmsLog log = CmsLog.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
--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+/** SWT/JFace dialogs. */
+package org.argeo.cms.swt.dialogs;
\ No newline at end of file
--- /dev/null
+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.api.cms.ux.CmsIcon;
+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<String, ImageData> imageCache = new HashMap<>();
+
+ private Map<String, Map<Integer, String>> iconPaths = new HashMap<>();
+
+ protected 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 <code>null</code> if not found.
+ *
+ * @param name An icon file name without path and extension.
+ * @param preferredSize the preferred size, if <code>null</code>,
+ * {@link #getSmallIconSize()} will be tried.
+ */
+ public Image getIcon(String name, Integer preferredSize) {
+ if (preferredSize == null)
+ preferredSize = getSmallIconSize();
+ Map<Integer, String> 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;
+ String ext = "";
+ if (lastSlash >= 0)
+ fileName = p.substring(lastSlash + 1);
+ int lastDot = fileName.lastIndexOf('.');
+ if (lastDot >= 0) {
+ ext = fileName.substring(lastDot + 1);
+ fileName = fileName.substring(0, lastDot);
+ }
+
+ if ("svg".equals(ext))
+ continue paths;
+
+ 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 Image getSmallIcon(CmsIcon icon) {
+ return getIcon(icon.name(), getSmallIconSize());
+ }
+
+ @Override
+ public Image getBigIcon(CmsIcon icon) {
+ return getIcon(icon.name(), getBigIconSize());
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.osgi;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.ImageTranscoder;
+import org.apache.batik.transcoder.image.PNGTranscoder;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.BundleContext;
+
+/** Theme which can dynamically create icons from SVG data. */
+public class BundleSvgTheme extends BundleCmsSwtTheme {
+ private final static Logger logger = System.getLogger(BundleSvgTheme.class.getName());
+
+ private Map<String, Map<Integer, Image>> imageCache = Collections.synchronizedMap(new HashMap<>());
+
+ private Map<Integer, ImageTranscoder> transcoders = Collections.synchronizedMap(new HashMap<>());
+
+ @Override
+ public Image getIcon(String name, Integer preferredSize) {
+ String path = "icons/types/svg/" + name + ".svg";
+ return createImageFromSvg(path, preferredSize);
+ }
+
+ protected Image createImageFromSvg(String path, Integer preferredSize) {
+ Image image = null;
+ if (imageCache.containsKey(path)) {
+ image = imageCache.get(path).get(preferredSize);
+ }
+ if (image != null)
+ return image;
+ ImageData imageData = loadFromSvg(path, preferredSize);
+ image = new Image(Display.getDefault(), imageData);
+ if (!imageCache.containsKey(path))
+ imageCache.put(path, Collections.synchronizedMap(new HashMap<>()));
+ imageCache.get(path).put(preferredSize, image);
+ return image;
+ }
+
+ protected ImageData loadFromSvg(String path, int size) {
+ ImageTranscoder transcoder = null;
+ synchronized (this) {
+ transcoder = transcoders.get(size);
+ if (transcoder == null) {
+ transcoder = new PNGTranscoder();
+ transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) size);
+ transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) size);
+ transcoders.put(size, transcoder);
+ }
+ }
+ ImageData imageData;
+ try (InputStream in = getResourceAsStream(path); ByteArrayOutputStream out = new ByteArrayOutputStream();) {
+ if (in == null)
+ throw new IllegalArgumentException(path + " not found");
+ TranscoderInput input = new TranscoderInput(in);
+ TranscoderOutput output = new TranscoderOutput(out);
+ transcoder.transcode(input, output);
+ try (InputStream imageIn = new ByteArrayInputStream(out.toByteArray())) {
+ imageData = new ImageData(imageIn);
+ }
+ logger.log(Level.DEBUG, () -> "Generated " + size + "x" + size + " PNG icon from " + path);
+ } catch (IOException | TranscoderException e) {
+ throw new RuntimeException("Cannot transcode SVG " + path, e);
+ }
+
+ return imageData;
+ }
+
+ @Override
+ public void init(BundleContext bundleContext, Map<String, String> properties) {
+ super.init(bundleContext, properties);
+
+ // preload all icons
+// paths: for (String p : getImagesPaths()) {
+// if (!p.endsWith(".svg"))
+// continue paths;
+// createImageFromSvg(p, getDefaultIconSize());
+// }
+ }
+
+ @Override
+ public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+ Display display = Display.getDefault();
+ if (display != null)
+ for (String path : imageCache.keySet()) {
+ for (Image image : imageCache.get(path).values()) {
+ display.syncExec(() -> image.dispose());
+ }
+ }
+ super.destroy(bundleContext, properties);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.useradmin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.api.cms.CmsConstants;
+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.util.naming.LdapAttrs;
+import org.argeo.util.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<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+
+ /**
+ * 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<ColumnDefinition> 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<User> 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 + "=*"
+ + CmsConstants.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<User> users = new ArrayList<User>();
+ 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());
+ }
+}
--- /dev/null
+package org.argeo.cms.swt.useradmin;
+
+import org.argeo.api.cms.CmsConstants;
+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(CmsConstants.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 "";
+ }
+}
--- /dev/null
+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");
+}
--- /dev/null
+/** SWT/JFace users management components. */
+package org.argeo.cms.swt.useradmin;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.swt.widgets;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ux.widgets.DataPart;
+import org.argeo.cms.ux.widgets.DataView;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Composite;
+
+public abstract class AbstractSwtPart<INPUT, TYPE> extends Composite implements DataView<INPUT, TYPE> {
+ private static final long serialVersionUID = -1999179054267812170L;
+
+ protected DataPart<INPUT, TYPE> dataPart;
+
+ protected final SelectionListener selectionListener;
+
+ public AbstractSwtPart(Composite parent, int style, DataPart<INPUT, TYPE> dataPart) {
+ super(parent, style);
+ setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+ this.dataPart = dataPart;
+
+ selectionListener = new SelectionListener() {
+
+ private static final long serialVersionUID = 4334785560035009330L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (dataPart.getOnSelected() != null)
+ dataPart.getOnSelected().accept((TYPE) e.item.getData());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ if (dataPart.getOnAction() != null)
+ dataPart.getOnAction().accept((TYPE) e.item.getData());
+ }
+ };
+
+ dataPart.addView(this);
+ addDisposeListener((e) -> dataPart.removeView(this));
+ }
+
+ public abstract void refresh();
+}
--- /dev/null
+package org.argeo.cms.swt.widgets;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Manages a lightweight shell which is related to a {@link Control}, typically
+ * in order to reproduce a dropdown semantic, but with more flexibility.
+ */
+public class ContextOverlay extends ScrolledPage {
+ private static final long serialVersionUID = 6702077429573324009L;
+
+// private Shell shell;
+ private Control control;
+
+ private int maxHeight = 400;
+
+ public ContextOverlay(Control control, int style) {
+ super(createShell(control, style), SWT.NONE);
+ Shell shell = getShell();
+ setLayoutData(CmsSwtUtils.fillAll());
+ // TODO make autohide configurable?
+ //shell.addShellListener(new AutoHideShellListener());
+ this.control = control;
+ control.addDisposeListener((e) -> {
+ dispose();
+ shell.dispose();
+ });
+ }
+
+ private static Composite createShell(Control control, int style) {
+ if (control == null)
+ throw new IllegalArgumentException("Control cannot be null");
+ if (control.isDisposed())
+ throw new IllegalArgumentException("Control is disposed");
+ Shell shell = new Shell(control.getShell(), SWT.NO_TRIM);
+ shell.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ Composite placeholder = new Composite(shell, SWT.BORDER);
+ placeholder.setLayoutData(CmsSwtUtils.fillAll());
+ placeholder.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ return placeholder;
+ }
+
+ public void show() {
+ Point relativeControlLocation = control.getLocation();
+ Point controlLocation = control.toDisplay(relativeControlLocation.x, relativeControlLocation.y);
+
+ int controlWidth = control.getBounds().width;
+
+ Shell shell = getShell();
+
+ layout(true, true);
+ shell.pack();
+ shell.layout(true, true);
+ int targetShellWidth = shell.getSize().x < controlWidth ? controlWidth : shell.getSize().x;
+ if (shell.getSize().y > maxHeight) {
+ shell.setSize(targetShellWidth, maxHeight);
+ } else {
+ shell.setSize(targetShellWidth, shell.getSize().y);
+ }
+
+ int shellHeight = shell.getSize().y;
+ int controlHeight = control.getBounds().height;
+ Point shellLocation = new Point(controlLocation.x, controlLocation.y + controlHeight);
+ int displayHeight = shell.getDisplay().getBounds().height;
+ if (shellLocation.y + shellHeight > displayHeight) {// bottom of page
+ shellLocation = new Point(controlLocation.x, controlLocation.y - shellHeight);
+ }
+ shell.setLocation(shellLocation);
+
+ if (getChildren().length != 0)
+ shell.open();
+ if (!control.isDisposed())
+ control.setFocus();
+ }
+
+ public void hide() {
+ getShell().setVisible(false);
+ onHide();
+ }
+
+ public boolean isShellVisible() {
+ if (isDisposed())
+ return false;
+ return getShell().isVisible();
+ }
+
+ /** to be overridden */
+ protected void onHide() {
+ // does nothing by default.
+ }
+
+ private class AutoHideShellListener extends ShellAdapter {
+ private static final long serialVersionUID = 7743287433907938099L;
+
+ @Override
+ public void shellDeactivated(ShellEvent e) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e1) {
+ // silent
+ }
+ if (!control.isDisposed() && !control.isFocusControl())
+ hide();
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.swt.widgets;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Editable text part displaying styled text. */
+public class EditableText extends StyledControl {
+ private static final long serialVersionUID = -6372283442330912755L;
+
+ private boolean editable = true;
+ private boolean multiLine = true;
+
+ private Color highlightColor;
+ private Composite highlight;
+
+ private boolean useTextAsLabel = false;
+
+ public EditableText(Composite parent, int style) {
+ super(parent, style);
+ editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
+ multiLine = !(SWT.SINGLE == (style & SWT.SINGLE));
+ highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
+ useTextAsLabel = SWT.FLAT == (style & SWT.FLAT);
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ if (isEditing() && getEditable()) {
+ return createText(box, style, true);
+ } else {
+ if (useTextAsLabel) {
+ return createTextLabel(box, style);
+ } else {
+ return createLabel(box, style);
+ }
+ }
+ }
+
+ protected Label createLabel(Composite box, String style) {
+ Label lbl = new Label(box, getStyle() | SWT.WRAP);
+ lbl.setLayoutData(CmsSwtUtils.fillWidth());
+ if (style != null)
+ CmsSwtUtils.style(lbl, style);
+ CmsSwtUtils.markup(lbl);
+ if (mouseListener != null)
+ lbl.addMouseListener(mouseListener);
+ return lbl;
+ }
+
+ protected Text createTextLabel(Composite box, String style) {
+ Text lbl = new Text(box, getStyle() | (multiLine ? SWT.MULTI : SWT.SINGLE));
+ lbl.setEditable(false);
+ lbl.setLayoutData(CmsSwtUtils.fillWidth());
+ if (style != null)
+ CmsSwtUtils.style(lbl, style);
+ CmsSwtUtils.markup(lbl);
+ if (mouseListener != null)
+ lbl.addMouseListener(mouseListener);
+ return lbl;
+ }
+
+ protected Text createText(Composite box, String style, boolean editable) {
+ highlight = new Composite(box, SWT.NONE);
+ highlight.setBackground(highlightColor);
+ GridData highlightGd = new GridData(SWT.FILL, SWT.FILL, false, false);
+ highlightGd.widthHint = 5;
+ highlightGd.heightHint = 3;
+ highlight.setLayoutData(highlightGd);
+
+ final Text text = new Text(box, getStyle() | (multiLine ? SWT.MULTI : SWT.SINGLE) | SWT.WRAP);
+ text.setEditable(editable);
+ GridData textLayoutData = CmsSwtUtils.fillWidth();
+ // textLayoutData.heightHint = preferredHeight;
+ text.setLayoutData(textLayoutData);
+ if (style != null)
+ CmsSwtUtils.style(text, style);
+ text.setFocus();
+ return text;
+ }
+
+ @Override
+ protected void clear(boolean deep) {
+ if (highlight != null)
+ highlight.dispose();
+ super.clear(deep);
+ }
+
+ public void setText(String text) {
+ Control child = getControl();
+ if (child instanceof Label)
+ ((Label) child).setText(text);
+ else if (child instanceof Text)
+ ((Text) child).setText(text);
+ }
+
+ public Text getAsText() {
+ return (Text) getControl();
+ }
+
+ public Label getAsLabel() {
+ return (Label) getControl();
+ }
+
+ public String getText() {
+ Control child = getControl();
+
+ if (child instanceof Label)
+ return ((Label) child).getText();
+ else if (child instanceof Text)
+ return ((Text) child).getText();
+ else
+ throw new IllegalStateException("Unsupported control " + child.getClass());
+ }
+
+ /** @deprecated Use {@link #isEditable()} instead. */
+ @Deprecated
+ public boolean getEditable() {
+ return isEditable();
+ }
+
+ public boolean isEditable() {
+ return editable;
+ }
+
+ public void setUseTextAsLabel(boolean useTextAsLabel) {
+ this.useTextAsLabel = useTextAsLabel;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * A composite that can be scrolled vertically. It wraps a
+ * {@link ScrolledComposite} (and is being wrapped by it), simplifying its
+ * configuration.
+ */
+public class ScrolledPage extends Composite {
+ private static final long serialVersionUID = 1593536965663574437L;
+
+ private ScrolledComposite scrolledComposite;
+
+ public ScrolledPage(Composite parent, int style) {
+ this(parent, style, false);
+ }
+
+ public ScrolledPage(Composite parent, int style, boolean alwaysShowScroll) {
+ super(createScrolledComposite(parent, alwaysShowScroll), style);
+ scrolledComposite = (ScrolledComposite) getParent();
+ scrolledComposite.setContent(this);
+
+ scrolledComposite.setExpandVertical(true);
+ scrolledComposite.setExpandHorizontal(true);
+ scrolledComposite.addControlListener(new ScrollControlListener());
+ }
+
+ private static ScrolledComposite createScrolledComposite(Composite parent, boolean alwaysShowScroll) {
+ ScrolledComposite scrolledComposite = new ScrolledComposite(parent, SWT.V_SCROLL);
+ scrolledComposite.setAlwaysShowScrollBars(alwaysShowScroll);
+ return scrolledComposite;
+ }
+
+ @Override
+ public void layout(boolean changed, boolean all) {
+ updateScroll();
+ super.layout(changed, all);
+ }
+
+ public void showControl(Control control) {
+ scrolledComposite.showControl(control);
+ }
+
+ protected void updateScroll() {
+ Rectangle r = scrolledComposite.getClientArea();
+ Point preferredSize = computeSize(r.width, SWT.DEFAULT);
+ scrolledComposite.setMinHeight(preferredSize.y);
+ }
+
+ // public ScrolledComposite getScrolledComposite() {
+ // return this.scrolledComposite;
+ // }
+
+ /** Set it on the wrapping scrolled composite */
+ @Override
+ public void setLayoutData(Object layoutData) {
+ scrolledComposite.setLayoutData(layoutData);
+ }
+
+ private class ScrollControlListener extends org.eclipse.swt.events.ControlAdapter {
+ private static final long serialVersionUID = -3586986238567483316L;
+
+ public void controlResized(ControlEvent e) {
+ updateScroll();
+ }
+ }
+}
--- /dev/null
+package org.argeo.cms.swt.widgets;
+
+import org.argeo.api.cms.ux.CmsStyle;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Editable text part displaying styled text. */
+public abstract class StyledControl extends Composite implements SwtEditablePart {
+ private static final long serialVersionUID = -6372283442330912755L;
+ private Control control;
+
+ private Composite container;
+ private Composite box;
+
+ protected MouseListener mouseListener;
+ protected FocusListener focusListener;
+
+ private Boolean editing = Boolean.FALSE;
+
+ private Composite ancestorToLayout;
+
+ public StyledControl(Composite parent, int swtStyle) {
+ super(parent, swtStyle);
+ setLayout(CmsSwtUtils.noSpaceGridLayout());
+ }
+
+ protected abstract Control createControl(Composite box, String style);
+
+ protected Composite createBox() {
+ Composite box = new Composite(container, SWT.INHERIT_DEFAULT);
+ setContainerLayoutData(box);
+ box.setLayout(CmsSwtUtils.noSpaceGridLayout(3));
+ return box;
+ }
+
+ protected Composite createContainer() {
+ Composite container = new Composite(this, SWT.INHERIT_DEFAULT);
+ setContainerLayoutData(container);
+ container.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ return container;
+ }
+
+ @Override
+ public Control getControl() {
+ return control;
+ }
+
+ protected synchronized Boolean isEditing() {
+ return editing;
+ }
+
+ @Override
+ public synchronized void startEditing() {
+ assert !isEditing();
+ editing = true;
+ // int height = control.getSize().y;
+ String style = (String) EclipseUiSpecificUtils.getStyleData(control);
+ clear(false);
+ refreshControl(style);
+
+ // add the focus listener to the newly created edition control
+ if (focusListener != null)
+ control.addFocusListener(focusListener);
+ }
+
+ @Override
+ public synchronized void stopEditing() {
+ assert isEditing();
+ editing = false;
+ String style = (String) EclipseUiSpecificUtils.getStyleData(control);
+ clear(false);
+ refreshControl(style);
+ }
+
+ protected void refreshControl(String style) {
+ control = createControl(box, style);
+ setControlLayoutData(control);
+ if (ancestorToLayout != null)
+ ancestorToLayout.layout(true, true);
+ else
+ getParent().layout(true, true);
+ }
+
+ public void setStyle(CmsStyle style) {
+ setStyle(style.style());
+ }
+
+ public void setStyle(String style) {
+ Object currentStyle = null;
+ if (control != null)
+ currentStyle = EclipseUiSpecificUtils.getStyleData(control);
+ if (currentStyle != null && currentStyle.equals(style))
+ return;
+
+ clear(true);
+ refreshControl(style);
+
+ if (style != null) {
+ CmsSwtUtils.style(box, style + "_box");
+ CmsSwtUtils.style(container, style + "_container");
+ }
+ }
+
+ /** To be overridden */
+ protected void setControlLayoutData(Control control) {
+ control.setLayoutData(CmsSwtUtils.fillWidth());
+ }
+
+ /** To be overridden */
+ protected void setContainerLayoutData(Composite composite) {
+ composite.setLayoutData(CmsSwtUtils.fillWidth());
+ }
+
+ protected void clear(boolean deep) {
+ if (deep) {
+ for (Control control : getChildren())
+ control.dispose();
+ container = createContainer();
+ box = createBox();
+ } else {
+ control.dispose();
+ }
+ }
+
+ public void setMouseListener(MouseListener mouseListener) {
+ if (this.mouseListener != null && control != null)
+ control.removeMouseListener(this.mouseListener);
+ this.mouseListener = mouseListener;
+ if (control != null && this.mouseListener != null)
+ control.addMouseListener(mouseListener);
+ }
+
+ public void setFocusListener(FocusListener focusListener) {
+ if (this.focusListener != null && control != null)
+ control.removeFocusListener(this.focusListener);
+ this.focusListener = focusListener;
+ if (control != null && this.focusListener != null)
+ control.addFocusListener(focusListener);
+ }
+
+ public void setAncestorToLayout(Composite ancestorToLayout) {
+ this.ancestorToLayout = ancestorToLayout;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.widgets;
+
+import java.util.List;
+
+import org.argeo.api.cms.ux.CmsIcon;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ux.widgets.HierarchicalPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+/** {@link HierarchicalPart} implementation based on a {@link Tree}. */
+public class SwtHierarchicalPart<T> extends AbstractSwtPart<T, T> {
+ private static final long serialVersionUID = -6247710601465713047L;
+
+ private final Tree tree;
+
+ private HierarchicalPart<T> hierarchicalPart;
+
+ public SwtHierarchicalPart(Composite parent, int style, HierarchicalPart<T> hierarchicalPart) {
+ super(parent, style, hierarchicalPart);
+ tree = new Tree(this, SWT.BORDER);
+ tree.setLayoutData(CmsSwtUtils.fillAll());
+ this.hierarchicalPart = hierarchicalPart;
+
+ tree.addSelectionListener(selectionListener);
+ }
+
+ @Override
+ public void refresh() {
+ // TODO optimise
+ // tree.clearAll(true);
+
+ for (TreeItem rootItem : tree.getItems()) {
+ rootItem.dispose();
+ }
+
+ List<T> rootItems = hierarchicalPart.getChildren(hierarchicalPart.getInput());
+ for (T child : rootItems) {
+ TreeItem childItem = addTreeItem(null, child);
+// List<T> grandChildren = hierarchicalPart.getChildren(child);
+// for (T grandChild : grandChildren) {
+// addTreeItem(childItem, grandChild);
+// }
+ }
+// tree.addListener(SWT.SetData, event -> {
+// TreeItem item = (TreeItem) event.item;
+// TreeItem parentItem = item.getParentItem();
+// if (parentItem == null) {
+// refreshRootItem(item);
+// } else {
+// refreshItem(parentItem, item);
+// }
+// });
+// tree.setItemCount(getRootItemCount());
+
+ tree.addListener(SWT.Expand, event -> {
+ final TreeItem root = (TreeItem) event.item;
+ TreeItem[] items = root.getItems();
+ for (TreeItem item : items) {
+ if (item.getData() != null) {
+// List<T> grandChildren = hierarchicalPart.getChildren((T) item.getData());
+// for (T grandChild : grandChildren) {
+// addTreeItem(item, grandChild);
+// }
+ return;
+ }
+ item.dispose();
+ }
+
+ List<T> children = hierarchicalPart.getChildren((T) root.getData());
+ for (T child : children) {
+ TreeItem childItem = addTreeItem(root, child);
+// List<T> grandChildren = hierarchicalPart.getChildren(child);
+// for (T grandChild : grandChildren) {
+// addTreeItem(childItem, grandChild);
+// }
+ }
+ });
+
+ CmsSwtUtils.fill(tree);
+
+ }
+
+ protected TreeItem addTreeItem(TreeItem parent, T data) {
+ TreeItem item = parent == null ? new TreeItem(tree, SWT.NONE) : new TreeItem(parent, SWT.NONE);
+ item.setData(data);
+ String txt = hierarchicalPart.getText(data);
+ if (txt != null)
+ item.setText(hierarchicalPart.getText(data));
+ CmsIcon icon = hierarchicalPart.getIcon(data);
+ // TODO optimize
+ List<T> grandChildren = hierarchicalPart.getChildren(data);
+ if (grandChildren.size() != 0)
+ new TreeItem(item, SWT.NONE);
+ return item;
+//if(icon!=null)
+// item.setImage(null);
+ }
+
+ protected Tree getTree() {
+ return tree;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.swt.widgets;
+
+import org.argeo.api.cms.ux.CmsIcon;
+import org.argeo.cms.swt.CmsSwtTheme;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ux.widgets.Column;
+import org.argeo.cms.ux.widgets.TabularPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+
+/** {@link TabularPart} implementation based on a {@link Table}. */
+public class SwtTabularPart<INPUT, T> extends AbstractSwtPart<INPUT, T> {
+ private static final long serialVersionUID = -1114155772446357750L;
+ private final Table table;
+ private TabularPart<INPUT, T> tabularPart;
+
+ private CmsSwtTheme theme;
+
+ public SwtTabularPart(Composite parent, int style, TabularPart<INPUT, T> tabularPart) {
+ super(parent, style, tabularPart);
+ theme = CmsSwtUtils.getCmsTheme(parent);
+
+ table = new Table(this, SWT.VIRTUAL | SWT.BORDER);
+ table.setLinesVisible(true);
+ table.setLayoutData(CmsSwtUtils.fillAll());
+
+ this.tabularPart = tabularPart;
+ }
+
+ @Override
+ public void refresh() {
+ // TODO optimise
+ table.clearAll();
+ table.addListener(SWT.SetData, event -> {
+ TableItem item = (TableItem) event.item;
+ refreshItem(item);
+ });
+ table.setItemCount(tabularPart.getItemCount());
+ for (int i = 0; i < tabularPart.getColumnCount(); i++) {
+ TableColumn swtColumn = new TableColumn(table, SWT.NONE);
+ swtColumn.setWidth(tabularPart.getColumn(i).getWidth());
+ }
+ CmsSwtUtils.fill(table);
+
+ table.addSelectionListener(selectionListener);
+
+ }
+
+ protected Object getDataFromEvent(SelectionEvent e) {
+ Object data = e.item.getData();
+ if (data == null)
+ data = tabularPart.getData(getTable().indexOf((TableItem) e.item));
+ return data;
+ }
+
+ protected void refreshItem(TableItem item) {
+ int row = getTable().indexOf(item);
+ for (int i = 0; i < tabularPart.getColumnCount(); i++) {
+ Column<T> column = tabularPart.getColumn(i);
+ T data = tabularPart.getData(row);
+ item.setData(data);
+ String text = data != null ? column.getText(data) : "";
+ if (text != null)
+ item.setText(i, text);
+ CmsIcon icon = column.getIcon(data);
+ if (icon != null) {
+ Image image = theme.getSmallIcon(icon);
+ item.setImage(i, image);
+ }
+ }
+ }
+
+ protected Table getTable() {
+ return table;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.theme;
+
+import java.net.URL;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+public class CmsImages {
+ private static BundleContext themeBc = FrameworkUtil.getBundle(CmsImages.class).getBundleContext();
+
+ final public static String ICONS_BASE = "icons/";
+ final public static String TYPES_BASE = ICONS_BASE + "types/";
+ final public static String ACTIONS_BASE = ICONS_BASE + "actions/";
+
+ public static Image createIcon(String name) {
+ return createImg(CmsImages.ICONS_BASE + name);
+ }
+
+ public static Image createAction(String name) {
+ return createImg(CmsImages.ACTIONS_BASE + name);
+ }
+
+ public static Image createType(String name) {
+ return createImg(CmsImages.TYPES_BASE + name);
+ }
+
+ public static Image createImg(String name) {
+ return CmsImages.createDesc(name).createImage(Display.getDefault());
+ }
+
+ public static ImageDescriptor createDesc(String name) {
+ return createDesc(themeBc, name);
+ }
+
+ public static ImageDescriptor createDesc(BundleContext bc, String name) {
+ URL url = bc.getBundle().getResource(name);
+ if (url == null)
+ return ImageDescriptor.getMissingImageDescriptor();
+ return ImageDescriptor.createFromURL(url);
+ }
+
+ public static Image createImg(BundleContext bc, String name) {
+ return createDesc(bc, name).createImage(Display.getDefault());
+ }
+
+}
--- /dev/null
+/** Argeo CMS core theme images. */
+package org.argeo.cms.ui.theme;
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui;
+
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Tree content provider dealing with tree objects and providing reasonable
+ * defaults.
+ */
+public abstract class AbstractTreeContentProvider implements
+ ITreeContentProvider {
+ private static final long serialVersionUID = 8246126401957763868L;
+
+ /** Does nothing */
+ public void dispose() {
+ }
+
+ /** Does nothing */
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public Object[] getChildren(Object element) {
+ if (element instanceof TreeParent) {
+ return ((TreeParent) element).getChildren();
+ }
+ return new Object[0];
+ }
+
+ public Object getParent(Object element) {
+ if (element instanceof TreeParent) {
+ return ((TreeParent) element).getParent();
+ }
+ return null;
+ }
+
+ public boolean hasChildren(Object element) {
+ if (element instanceof TreeParent) {
+ return ((TreeParent) element).hasChildren();
+ }
+ return false;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+/**
+ * Wraps the definition of a column to be used in the various JFace viewers
+ * (typically tree and table). It enables definition of generic viewers which
+ * column can be then defined externally. Also used to generate export.
+ */
+public class ColumnDefinition {
+ private ColumnLabelProvider labelProvider;
+ private String label;
+ private int weight = 0;
+ private int minWidth = 120;
+
+ public ColumnDefinition(ColumnLabelProvider labelProvider, String label) {
+ this.labelProvider = labelProvider;
+ this.label = label;
+ }
+
+ public ColumnDefinition(ColumnLabelProvider labelProvider, String label,
+ int weight) {
+ this.labelProvider = labelProvider;
+ this.label = label;
+ this.weight = weight;
+ this.minWidth = weight;
+ }
+
+ public ColumnDefinition(ColumnLabelProvider labelProvider, String label,
+ int weight, int minimumWidth) {
+ this.labelProvider = labelProvider;
+ this.label = label;
+ this.weight = weight;
+ this.minWidth = minimumWidth;
+ }
+
+ public ColumnLabelProvider getLabelProvider() {
+ return labelProvider;
+ }
+
+ public void setLabelProvider(ColumnLabelProvider labelProvider) {
+ this.labelProvider = labelProvider;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public void setWeight(int weight) {
+ this.weight = weight;
+ }
+
+ public int getMinWidth() {
+ return minWidth;
+ }
+
+ public void setMinWidth(int minWidth) {
+ this.minWidth = minWidth;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui;
+
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+
+/** Generic column viewer sorter */
+public class ColumnViewerComparator extends ViewerComparator {
+ private static final long serialVersionUID = -2266218906355859909L;
+
+ public static final int ASC = 1;
+
+ public static final int NONE = 0;
+
+ public static final int DESC = -1;
+
+ private int direction = 0;
+
+ private TableViewerColumn column;
+
+ private ColumnViewer viewer;
+
+ public ColumnViewerComparator(TableViewerColumn column) {
+ super(null);
+ this.column = column;
+ this.viewer = column.getViewer();
+ this.column.getColumn().addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = 7586796298965472189L;
+
+ public void widgetSelected(SelectionEvent e) {
+ if (ColumnViewerComparator.this.viewer.getComparator() != null) {
+ if (ColumnViewerComparator.this.viewer.getComparator() == ColumnViewerComparator.this) {
+ int tdirection = ColumnViewerComparator.this.direction;
+
+ if (tdirection == ASC) {
+ setSortDirection(DESC);
+ } else if (tdirection == DESC) {
+ setSortDirection(NONE);
+ }
+ } else {
+ setSortDirection(ASC);
+ }
+ } else {
+ setSortDirection(ASC);
+ }
+ }
+ });
+ }
+
+ private void setSortDirection(int direction) {
+ if (direction == NONE) {
+ column.getColumn().getParent().setSortColumn(null);
+ column.getColumn().getParent().setSortDirection(SWT.NONE);
+ viewer.setComparator(null);
+ } else {
+ column.getColumn().getParent().setSortColumn(column.getColumn());
+ this.direction = direction;
+
+ if (direction == ASC) {
+ column.getColumn().getParent().setSortDirection(SWT.DOWN);
+ } else {
+ column.getColumn().getParent().setSortDirection(SWT.UP);
+ }
+
+ if (viewer.getComparator() == this) {
+ viewer.refresh();
+ } else {
+ viewer.setComparator(this);
+ }
+
+ }
+ }
+
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ return direction * super.compare(viewer, e1, e2);
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui;
+
+/** CMS specific exceptions. */
+public class EclipseUiException extends RuntimeException {
+ private static final long serialVersionUID = -5341764743356771313L;
+
+ public EclipseUiException(String message) {
+ super(message);
+ }
+
+ public EclipseUiException(String message, Throwable e) {
+ super(message, e);
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.graphics.Font;
+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.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Utilities to simplify UI development. */
+public class EclipseUiUtils {
+
+ /** Dispose all children of a Composite */
+ public static void clear(Composite composite) {
+ for (Control child : composite.getChildren())
+ child.dispose();
+ }
+
+ /**
+ * Enables efficient call to the layout method of a composite, refreshing only
+ * some of the children controls.
+ */
+ public static void layout(Composite parent, Control... toUpdateControls) {
+ parent.layout(toUpdateControls);
+ }
+
+ //
+ // FONTS
+ //
+ /** Shortcut to retrieve default italic font from display */
+ public static Font getItalicFont(Composite parent) {
+ return JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.ITALIC)
+ .createFont(parent.getDisplay());
+ }
+
+ /** Shortcut to retrieve default bold font from display */
+ public static Font getBoldFont(Composite parent) {
+ return JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.BOLD)
+ .createFont(parent.getDisplay());
+ }
+
+ /** Shortcut to retrieve default bold italic font from display */
+ public static Font getBoldItalicFont(Composite parent) {
+ return JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.BOLD | SWT.ITALIC)
+ .createFont(parent.getDisplay());
+ }
+
+ //
+ // Simplify grid layouts management
+ //
+ public static GridLayout noSpaceGridLayout() {
+ return noSpaceGridLayout(new GridLayout());
+ }
+
+ public static GridLayout noSpaceGridLayout(int columns) {
+ return noSpaceGridLayout(new GridLayout(columns, false));
+ }
+
+ public static GridLayout noSpaceGridLayout(GridLayout layout) {
+ layout.horizontalSpacing = 0;
+ layout.verticalSpacing = 0;
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ return layout;
+ }
+
+ public static GridData fillWidth() {
+ return grabWidth(SWT.FILL, SWT.FILL);
+ }
+
+ public static GridData fillWidth(int colSpan) {
+ GridData gd = grabWidth(SWT.FILL, SWT.FILL);
+ gd.horizontalSpan = colSpan;
+ return gd;
+ }
+
+ public static GridData fillAll() {
+ return new GridData(SWT.FILL, SWT.FILL, true, true);
+ }
+
+ public static GridData fillAll(int colSpan, int rowSpan) {
+ return new GridData(SWT.FILL, SWT.FILL, true, true, colSpan, rowSpan);
+ }
+
+ public static GridData grabWidth(int horizontalAlignment, int verticalAlignment) {
+ return new GridData(horizontalAlignment, horizontalAlignment, true, false);
+ }
+
+ //
+ // Simplify Form layout management
+ //
+
+ /**
+ * Creates a basic form data that is attached to the 4 corners of the parent
+ * composite
+ */
+ public static FormData fillFormData() {
+ FormData formData = new FormData();
+ formData.top = new FormAttachment(0, 0);
+ formData.left = new FormAttachment(0, 0);
+ formData.right = new FormAttachment(100, 0);
+ formData.bottom = new FormAttachment(100, 0);
+ return formData;
+ }
+
+ /**
+ * Create a label and a text field for a grid layout, the text field grabbing
+ * excess horizontal
+ *
+ * @param parent
+ * the parent composite
+ * @param label
+ * the label to display
+ * @param modifyListener
+ * a {@link ModifyListener} to listen on events on the text, can be
+ * null
+ * @return the created text
+ *
+ */
+ // FIXME why was this deprecated.
+ // * @ deprecated use { @ link #createGridLT(Composite, String)} instead
+ // @ Deprecated
+ public static Text createGridLT(Composite parent, String label, ModifyListener modifyListener) {
+ Label lbl = new Label(parent, SWT.LEAD);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ Text txt = new Text(parent, SWT.LEAD | SWT.BORDER);
+ txt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ if (modifyListener != null)
+ txt.addModifyListener(modifyListener);
+ return txt;
+ }
+
+ /**
+ * Create a label and a text field for a grid layout, the text field grabbing
+ * excess horizontal
+ */
+ public static Text createGridLT(Composite parent, String label) {
+ return createGridLT(parent, label, null);
+ }
+
+ /**
+ * Creates one label and a text field not editable with background colour of the
+ * parent (like a label but with selectable text)
+ */
+ public static Text createGridLL(Composite parent, String label, String text) {
+ Text txt = createGridLT(parent, label);
+ txt.setText(text);
+ txt.setEditable(false);
+ txt.setBackground(parent.getBackground());
+ return txt;
+ }
+
+ /**
+ * Create a label and a text field with password display for a grid layout, the
+ * text field grabbing excess horizontal
+ */
+ public static Text createGridLP(Composite parent, String label) {
+ return createGridLP(parent, label, null);
+ }
+
+ /**
+ * Create a label and a text field with password display for a grid layout, the
+ * text field grabbing excess horizontal. The given modify listener will be
+ * added to the newly created text field if not null.
+ */
+ public static Text createGridLP(Composite parent, String label, ModifyListener modifyListener) {
+ Label lbl = new Label(parent, SWT.LEAD);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ Text txt = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.PASSWORD);
+ txt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ if (modifyListener != null)
+ txt.addModifyListener(modifyListener);
+ return txt;
+ }
+
+ // MISCELLANEOUS
+
+ /** Simply checks if a string is not null nor empty */
+ public static boolean notEmpty(String stringToTest) {
+ return !(stringToTest == null || "".equals(stringToTest.trim()));
+ }
+
+ /** Simply checks if a string is null or empty */
+ public static boolean isEmpty(String stringToTest) {
+ return stringToTest == null || "".equals(stringToTest.trim());
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui;
+
+import java.io.InputStream;
+
+/**
+ * Used for file download : subclasses must implement model specific methods to
+ * get a byte array representing a file given is ID.
+ */
+@Deprecated
+public interface FileProvider {
+
+ public byte[] getByteArrayFileFromId(String fileId);
+
+ public InputStream getInputStreamFromFileId(String fileId);
+
+}
--- /dev/null
+package org.argeo.eclipse.ui;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+
+public abstract class GenericTableComparator extends ViewerComparator {
+ private static final long serialVersionUID = -1175894935075325810L;
+ protected int propertyIndex;
+ public static final int ASCENDING = 0, DESCENDING = 1;
+ protected int direction = DESCENDING;
+
+ /**
+ * Creates an instance of a sorter for TableViewer.
+ *
+ * @param defaultColumnIndex
+ * the default sorter column
+ */
+
+ public GenericTableComparator(int defaultColumnIndex, int direction) {
+ propertyIndex = defaultColumnIndex;
+ this.direction = direction;
+ }
+
+ public void setColumn(int column) {
+ if (column == this.propertyIndex) {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ } else {
+ // New column; do a descending sort
+ this.propertyIndex = column;
+ direction = DESCENDING;
+ }
+ }
+
+ /**
+ * Must be Overriden in each view.
+ */
+ public abstract int compare(Viewer viewer, Object e1, Object e2);
+}
--- /dev/null
+package org.argeo.eclipse.ui;
+
+import java.util.List;
+
+/**
+ * Views and editors can implement this interface so that one of the list that
+ * is displayed in the part (For instance in a Table or a Tree Viewer) can be
+ * rebuilt externally. Typically to generate csv or calc extract.
+ */
+public interface IListProvider {
+ /**
+ * Returns an array of current and relevant elements
+ */
+ public Object[] getElements(String extractId);
+
+ /**
+ * Returns the column definition for passed ID
+ */
+ public List<ColumnDefinition> getColumnDefinition(String extractId);
+}
--- /dev/null
+package org.argeo.eclipse.ui.dialogs;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.argeo.api.cms.CmsLog;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+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;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Generic error dialog to be used in try/catch blocks.
+ *
+ * @deprecated Use CMS dialogs instead.
+ */
+@Deprecated
+public class ErrorFeedback extends TitleAreaDialog {
+ private static final long serialVersionUID = -8918084784628179044L;
+
+ private final static CmsLog log = CmsLog.getLog(ErrorFeedback.class);
+
+ private final String message;
+ private final Throwable exception;
+
+ public static void 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;
+
+ new ErrorFeedback(newShell(), message, e).open();
+ }
+
+ public static void show(String message) {
+ new ErrorFeedback(newShell(), message, null).open();
+ }
+
+ private static Shell newShell() {
+ return new Shell(getDisplay(), SWT.NO_TRIM);
+ }
+
+ /** 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 ErrorFeedback(Shell parentShell, String message, Throwable e) {
+ super(parentShell);
+ setShellStyle(SWT.NO_TRIM);
+ this.message = message;
+ this.exception = e;
+ log.error(message, e);
+ }
+
+ protected Point getInitialSize() {
+ if (exception != null)
+ return new Point(800, 600);
+ else
+ return new Point(400, 300);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite dialogarea = (Composite) super.createDialogArea(parent);
+ dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ Composite composite = new Composite(dialogarea, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ setMessage(message != null ? message + (exception != null ? ": " + exception.getMessage() : "")
+ : exception != null ? exception.getMessage() : "Unkown Error", IMessageProvider.ERROR);
+
+ if (exception != null) {
+ Text stack = new Text(composite, 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));
+ StringWriter sw = new StringWriter();
+ exception.printStackTrace(new PrintWriter(sw));
+ stack.setText(sw.toString());
+ }
+
+ parent.pack();
+ return composite;
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText("Error");
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui.dialogs;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.swt.SWT;
+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.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Generic lightweight dialog, not based on JFace.
+ *
+ * @deprecated Use CMS dialogs instead.
+ */
+@Deprecated
+public class FeedbackDialog extends LightweightDialog {
+ private final static CmsLog log = CmsLog.getLog(FeedbackDialog.class);
+
+ private String message;
+ private Throwable exception;
+
+// private Shell parentShell;
+ private Shell shell;
+
+ public static void 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;
+
+ new FeedbackDialog(getDisplay().getActiveShell(), message, e).open();
+ }
+
+ public static void show(String message) {
+ new FeedbackDialog(getDisplay().getActiveShell(), message, null).open();
+ }
+
+ /** 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 FeedbackDialog(Shell parentShell, String message, Throwable e) {
+ super(parentShell);
+ this.message = message;
+ this.exception = e;
+ log.error(message, e);
+ }
+
+ public int open() {
+ if (shell != null)
+ throw new EclipseUiException("There is already a shell");
+ shell = new Shell(getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+ shell.setLayout(new GridLayout());
+ // shell.setText("Error");
+ shell.setSize(getInitialSize());
+ createDialogArea(shell);
+ // shell.pack();
+ // shell.layout();
+
+ Rectangle shellBounds = Display.getCurrent().getBounds();// RAP
+ Point dialogSize = shell.getSize();
+ int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2;
+ int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2;
+ shell.setLocation(x, y);
+
+ shell.addShellListener(new ShellAdapter() {
+ private static final long serialVersionUID = -2701270481953688763L;
+
+ @Override
+ public void shellDeactivated(ShellEvent e) {
+ closeShell();
+ }
+ });
+
+ shell.open();
+ return OK;
+ }
+
+ protected void closeShell() {
+ shell.close();
+ shell.dispose();
+ shell = null;
+ }
+
+ protected Point getInitialSize() {
+ // if (exception != null)
+ // return new Point(800, 600);
+ // else
+ return new Point(400, 300);
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite dialogarea = new Composite(parent, SWT.NONE);
+ dialogarea.setLayout(new GridLayout());
+ // Composite dialogarea = (Composite) super.createDialogArea(parent);
+ dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Label messageLbl = new Label(dialogarea, SWT.NONE);
+ if (message != null)
+ messageLbl.setText(message);
+ else if (exception != null)
+ messageLbl.setText(exception.getLocalizedMessage());
+
+ 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(composite, 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));
+ StringWriter sw = new StringWriter();
+ exception.printStackTrace(new PrintWriter(sw));
+ stack.setText(sw.toString());
+ }
+
+ // parent.pack();
+ return composite;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui.dialogs;
+
+import org.argeo.api.cms.CmsLog;
+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. */
+@Deprecated
+public class LightweightDialog {
+ private final static CmsLog log = CmsLog.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
--- /dev/null
+package org.argeo.eclipse.ui.dialogs;
+
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+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.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Dialog to retrieve a single value.
+ *
+ * @deprecated Use CMS dialogs instead.
+ */
+@Deprecated
+public class SingleValue extends TitleAreaDialog {
+ private static final long serialVersionUID = 2843538207460082349L;
+
+ private Text valueT;
+ private String value;
+ private final String title, message, label;
+ private final Boolean multiline;
+
+ public static String ask(String label, String message) {
+ SingleValue svd = new SingleValue(label, message);
+ if (svd.open() == Window.OK)
+ return svd.getString();
+ else
+ return null;
+ }
+
+ public static Long askLong(String label, String message) {
+ SingleValue svd = new SingleValue(label, message);
+ if (svd.open() == Window.OK)
+ return svd.getLong();
+ else
+ return null;
+ }
+
+ public static Double askDouble(String label, String message) {
+ SingleValue svd = new SingleValue(label, message);
+ if (svd.open() == Window.OK)
+ return svd.getDouble();
+ else
+ return null;
+ }
+
+ public SingleValue(String label, String message) {
+ this(Display.getDefault().getActiveShell(), label, message, label, false);
+ }
+
+ public SingleValue(Shell parentShell, String title, String message, String label, Boolean multiline) {
+ super(parentShell);
+ this.title = title;
+ this.message = message;
+ this.label = label;
+ this.multiline = multiline;
+ }
+
+ protected Point getInitialSize() {
+ if (multiline)
+ return new Point(450, 350);
+
+ else
+ return new Point(400, 270);
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite dialogarea = (Composite) super.createDialogArea(parent);
+ dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ Composite composite = new Composite(dialogarea, SWT.NONE);
+ composite.setLayoutData(EclipseUiUtils.fillAll());
+ GridLayout layout = new GridLayout(2, false);
+ layout.marginWidth = layout.marginHeight = 20;
+ composite.setLayout(layout);
+
+ valueT = createLT(composite, label);
+
+ setMessage(message, IMessageProvider.NONE);
+
+ parent.pack();
+ valueT.setFocus();
+ return composite;
+ }
+
+ @Override
+ protected void okPressed() {
+ value = valueT.getText();
+ super.okPressed();
+ }
+
+ /** Creates label and text. */
+ protected Text createLT(Composite parent, String label) {
+ new Label(parent, SWT.NONE).setText(label);
+ Text text;
+ if (multiline) {
+ text = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.MULTI);
+ text.setLayoutData(EclipseUiUtils.fillAll());
+ } else {
+ text = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.SINGLE);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
+ }
+ return text;
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText(title);
+ }
+
+ public String getString() {
+ return value;
+ }
+
+ public Long getLong() {
+ return Long.valueOf(getString());
+ }
+
+ public Double getDouble() {
+ return Double.valueOf(getString());
+ }
+}
--- /dev/null
+/** Generic SWT/JFace dialogs. */
+package org.argeo.eclipse.ui.dialogs;
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.LinkedHashMap;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+
+/** Simple UI provider that populates a composite parent given a NIO path */
+public class AdvancedFsBrowser {
+ private final static CmsLog log = CmsLog.getLog(AdvancedFsBrowser.class);
+
+ // Some local constants to experiment. should be cleaned
+ // private final static int THUMBNAIL_WIDTH = 400;
+ // private Point imageWidth = new Point(250, 0);
+ private final static int COLUMN_WIDTH = 160;
+
+ private Path initialPath;
+ private Path currEdited;
+ // Filter
+ private Composite displayBoxCmp;
+ private Text parentPathTxt;
+ private Text filterTxt;
+ // Browser columns
+ private ScrolledComposite scrolledCmp;
+ // Keep a cache of the opened directories
+ private LinkedHashMap<Path, FilterEntitiesVirtualTable> browserCols = new LinkedHashMap<>();
+ private Composite scrolledCmpBody;
+
+ public Control createUi(Composite parent, Path basePath) {
+ if (basePath == null)
+ throw new IllegalArgumentException("Context cannot be null");
+ parent.setLayout(new GridLayout());
+
+ // top filter
+ Composite filterCmp = new Composite(parent, SWT.NO_FOCUS);
+ filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
+ addFilterPanel(filterCmp);
+
+ // Bottom part a sash with browser on the left
+ SashForm form = new SashForm(parent, SWT.HORIZONTAL);
+ // form.setLayout(new FillLayout());
+ form.setLayoutData(EclipseUiUtils.fillAll());
+ Composite leftCmp = new Composite(form, SWT.NO_FOCUS);
+ displayBoxCmp = new Composite(form, SWT.NONE);
+ form.setWeights(new int[] { 3, 1 });
+
+ createBrowserPart(leftCmp, basePath);
+ // leftCmp.addControlListener(new ControlAdapter() {
+ // @Override
+ // public void controlResized(ControlEvent e) {
+ // Rectangle r = leftCmp.getClientArea();
+ // log.warn("Browser resized: " + r.toString());
+ // scrolledCmp.setMinSize(browserCols.size() * (COLUMN_WIDTH + 2),
+ // SWT.DEFAULT);
+ // // scrolledCmp.setMinSize(scrolledCmpBody.computeSize(SWT.DEFAULT,
+ // // r.height));
+ // }
+ // });
+
+ populateCurrEditedDisplay(displayBoxCmp, basePath);
+
+ // INIT
+ setEdited(basePath);
+ initialPath = basePath;
+ // form.layout(true, true);
+ return parent;
+ }
+
+ private void createBrowserPart(Composite parent, Path context) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ // scrolled composite
+ scrolledCmp = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.BORDER | SWT.NO_FOCUS);
+ scrolledCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ scrolledCmp.setExpandVertical(true);
+ scrolledCmp.setExpandHorizontal(true);
+ scrolledCmp.setShowFocusedControl(true);
+
+ scrolledCmpBody = new Composite(scrolledCmp, SWT.NO_FOCUS);
+ scrolledCmp.setContent(scrolledCmpBody);
+ scrolledCmpBody.addControlListener(new ControlAdapter() {
+ private static final long serialVersionUID = 183238447102854553L;
+
+ @Override
+ public void controlResized(ControlEvent e) {
+ Rectangle r = scrolledCmp.getClientArea();
+ scrolledCmp.setMinSize(scrolledCmpBody.computeSize(SWT.DEFAULT, r.height));
+ }
+ });
+ initExplorer(scrolledCmpBody, context);
+ scrolledCmpBody.layout(true, true);
+ scrolledCmp.layout();
+
+ }
+
+ private Control initExplorer(Composite parent, Path context) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ return createBrowserColumn(parent, context);
+ }
+
+ private Control createBrowserColumn(Composite parent, Path context) {
+ // TODO style is not correctly managed.
+ FilterEntitiesVirtualTable table = new FilterEntitiesVirtualTable(parent, SWT.BORDER | SWT.NO_FOCUS, context);
+ // CmsUtils.style(table, ArgeoOrgStyle.browserColumn.style());
+ table.filterList("*");
+ table.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true));
+ browserCols.put(context, table);
+ parent.layout(true, true);
+ return table;
+ }
+
+ public void addFilterPanel(Composite parent) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false)));
+
+ 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(EclipseUiUtils.fillWidth());
+ filterTxt.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = 1L;
+
+ public void modifyText(ModifyEvent event) {
+ modifyFilter(false);
+ }
+ });
+ filterTxt.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = 2533535233583035527L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
+ // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
+ FilterEntitiesVirtualTable currTable = null;
+ if (currEdited != null) {
+ FilterEntitiesVirtualTable table = browserCols.get(currEdited);
+ if (table != null && !table.isDisposed())
+ currTable = table;
+ }
+
+ if (e.keyCode == SWT.ARROW_DOWN)
+ currTable.setFocus();
+ else if (e.keyCode == SWT.BS) {
+ if (filterTxt.getText().equals("")
+ && !(currEdited.getNameCount() == 1 || currEdited.equals(initialPath))) {
+ Path oldEdited = currEdited;
+ Path parentPath = currEdited.getParent();
+ setEdited(parentPath);
+ if (browserCols.containsKey(parentPath))
+ browserCols.get(parentPath).setSelected(oldEdited);
+ filterTxt.setFocus();
+ e.doit = false;
+ }
+ } else if (e.keyCode == SWT.TAB && !shiftPressed) {
+ Path uniqueChild = getOnlyChild(currEdited, filterTxt.getText());
+ if (uniqueChild != null) {
+ // Highlight the unique chosen child
+ currTable.setSelected(uniqueChild);
+ setEdited(uniqueChild);
+ }
+ filterTxt.setFocus();
+ e.doit = false;
+ }
+ }
+ });
+ }
+
+ private Path getOnlyChild(Path parent, String filter) {
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(currEdited, filter + "*")) {
+ Path uniqueChild = null;
+ boolean moreThanOne = false;
+ loop: for (Path entry : stream) {
+ if (uniqueChild == null) {
+ uniqueChild = entry;
+ } else {
+ moreThanOne = true;
+ break loop;
+ }
+ }
+ if (!moreThanOne)
+ return uniqueChild;
+ return null;
+ } catch (IOException ioe) {
+ throw new FsUiException(
+ "Unable to determine unique child existence and get it under " + parent + " with filter " + filter,
+ ioe);
+ }
+ }
+
+ private void setEdited(Path path) {
+ currEdited = path;
+ EclipseUiUtils.clear(displayBoxCmp);
+ populateCurrEditedDisplay(displayBoxCmp, currEdited);
+ refreshFilters(path);
+ refreshBrowser(path);
+ }
+
+ private void refreshFilters(Path path) {
+ parentPathTxt.setText(path.toUri().toString());
+ filterTxt.setText("");
+ filterTxt.getParent().layout();
+ }
+
+ private void refreshBrowser(Path currPath) {
+ Path currParPath = currPath.getParent();
+ Object[][] colMatrix = new Object[browserCols.size()][2];
+
+ int i = 0, currPathIndex = -1, lastLeftOpenedIndex = -1;
+ for (Path path : browserCols.keySet()) {
+ colMatrix[i][0] = path;
+ colMatrix[i][1] = browserCols.get(path);
+ if (currPathIndex >= 0 && lastLeftOpenedIndex < 0 && currParPath != null) {
+ boolean leaveOpened = path.startsWith(currPath);
+ if (!leaveOpened)
+ lastLeftOpenedIndex = i;
+ }
+ if (currParPath.equals(path))
+ currPathIndex = i;
+ i++;
+ }
+
+ if (currPathIndex >= 0 && lastLeftOpenedIndex >= 0) {
+ // dispose and remove useless cols
+ for (int l = i - 1; l >= lastLeftOpenedIndex; l--) {
+ ((FilterEntitiesVirtualTable) colMatrix[l][1]).dispose();
+ browserCols.remove(colMatrix[l][0]);
+ }
+ }
+
+ if (browserCols.containsKey(currPath)) {
+ FilterEntitiesVirtualTable currCol = browserCols.get(currPath);
+ if (currCol.isDisposed()) {
+ // Does it still happen ?
+ log.warn(currPath + " browser column was disposed and still listed");
+ browserCols.remove(currPath);
+ }
+ }
+
+ if (!browserCols.containsKey(currPath) && Files.isDirectory(currPath))
+ createBrowserColumn(scrolledCmpBody, currPath);
+
+ scrolledCmpBody.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(browserCols.size(), false)));
+ scrolledCmpBody.layout(true, true);
+ // also resize the scrolled composite
+ scrolledCmp.layout();
+ }
+
+ private void modifyFilter(boolean fromOutside) {
+ if (!fromOutside)
+ if (currEdited != null) {
+ String filter = filterTxt.getText() + "*";
+ FilterEntitiesVirtualTable table = browserCols.get(currEdited);
+ if (table != null && !table.isDisposed())
+ table.filterList(filter);
+ }
+ }
+
+ /**
+ * Recreates the content of the box that displays information about the current
+ * selected node.
+ */
+ private void populateCurrEditedDisplay(Composite parent, Path context) {
+ parent.setLayout(new GridLayout());
+
+ // if (isImg(context)) {
+ // EditableImage image = new Img(parent, RIGHT, context, imageWidth);
+ // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false,
+ // 2, 1));
+ // }
+
+ try {
+ Label contextL = new Label(parent, SWT.NONE);
+ contextL.setText(context.getFileName().toString());
+ contextL.setFont(EclipseUiUtils.getBoldFont(parent));
+ addProperty(parent, "Last modified", Files.getLastModifiedTime(context).toString());
+ addProperty(parent, "Owner", Files.getOwner(context).getName());
+ if (Files.isDirectory(context)) {
+ addProperty(parent, "Type", "Folder");
+ } else {
+ String mimeType = Files.probeContentType(context);
+ if (EclipseUiUtils.isEmpty(mimeType))
+ mimeType = "<i>Unknown</i>";
+ addProperty(parent, "Type", mimeType);
+ addProperty(parent, "Size", FsUiUtils.humanReadableByteCount(Files.size(context), false));
+ }
+ parent.layout(true, true);
+ } catch (IOException e) {
+ throw new FsUiException("Cannot display details for " + context, e);
+ }
+ }
+
+ private void addProperty(Composite parent, String propName, String value) {
+ Label contextL = new Label(parent, SWT.NONE);
+ contextL.setText(propName + ": " + value);
+ }
+
+ /**
+ * Almost canonical implementation of a table that displays the content of a
+ * directory
+ */
+ private class FilterEntitiesVirtualTable extends Composite {
+ private static final long serialVersionUID = 2223410043691844875L;
+
+ // Context
+ private Path context;
+ private Path currSelected = null;
+
+ // UI Objects
+ private FsTableViewer viewer;
+
+ @Override
+ public boolean setFocus() {
+ if (viewer.getTable().isDisposed())
+ return false;
+ if (currSelected != null)
+ viewer.setSelection(new StructuredSelection(currSelected), true);
+ else if (viewer.getSelection().isEmpty()) {
+ Object first = viewer.getElementAt(0);
+ if (first != null)
+ viewer.setSelection(new StructuredSelection(first), true);
+ }
+ return viewer.getTable().setFocus();
+ }
+
+ /**
+ * Enable highlighting the correct element in the table when externally browsing
+ * (typically via the command-line-like Text field)
+ */
+ void setSelected(Path selected) {
+ // to prevent change selection event to be thrown
+ currSelected = selected;
+ viewer.setSelection(new StructuredSelection(currSelected), true);
+ }
+
+ void filterList(String filter) {
+ viewer.setInput(context, filter);
+ }
+
+ public FilterEntitiesVirtualTable(Composite parent, int style, Path context) {
+ super(parent, SWT.NO_FOCUS);
+ this.context = context;
+ createTableViewer(this);
+ }
+
+ private void createTableViewer(final Composite parent) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ // We must limit the size of the table otherwise the full list is
+ // loaded before the layout happens
+ // Composite listCmp = new Composite(parent, SWT.NO_FOCUS);
+ // GridData gd = new GridData(SWT.LEFT, SWT.FILL, false, true);
+ // gd.widthHint = COLUMN_WIDTH;
+ // listCmp.setLayoutData(gd);
+ // listCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ // viewer = new TableViewer(listCmp, SWT.VIRTUAL | SWT.MULTI |
+ // SWT.V_SCROLL);
+ // Table table = viewer.getTable();
+ // table.setLayoutData(EclipseUiUtils.fillAll());
+
+ viewer = new FsTableViewer(parent, SWT.MULTI);
+ Table table = viewer.configureDefaultSingleColumnTable(COLUMN_WIDTH);
+
+ viewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
+ if (selection.isEmpty())
+ return;
+ Object obj = selection.getFirstElement();
+ Path newSelected;
+ if (obj instanceof Path)
+ newSelected = (Path) obj;
+ else if (obj instanceof ParentDir)
+ newSelected = ((ParentDir) obj).getPath();
+ else
+ return;
+ if (newSelected.equals(currSelected))
+ return;
+ currSelected = newSelected;
+ setEdited(newSelected);
+
+ }
+ });
+
+ table.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -8083424284436715709L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
+ Path selected = null;
+ if (!selection.isEmpty())
+ selected = ((Path) selection.getFirstElement());
+ if (e.keyCode == SWT.ARROW_RIGHT) {
+ if (!Files.isDirectory(selected))
+ return;
+ if (selected != null) {
+ setEdited(selected);
+ browserCols.get(selected).setFocus();
+ }
+ } else if (e.keyCode == SWT.ARROW_LEFT) {
+ if (context.equals(initialPath))
+ return;
+ Path parent = context.getParent();
+ if (parent == null)
+ return;
+
+ setEdited(parent);
+ browserCols.get(parent).setFocus();
+ }
+ }
+ });
+ }
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/** Basic label provider with icon for NIO file viewers */
+public class FileIconNameLabelProvider extends ColumnLabelProvider {
+ private static final long serialVersionUID = 8187902187946523148L;
+
+ private Image folderIcon;
+ private Image fileIcon;
+
+ public FileIconNameLabelProvider() {
+ // if (!PlatformUI.isWorkbenchRunning()) {
+ folderIcon = ImageDescriptor.createFromFile(getClass(), "folder.png").createImage();
+ fileIcon = ImageDescriptor.createFromFile(getClass(), "file.png").createImage();
+ // }
+ }
+
+ @Override
+ public void dispose() {
+ if (folderIcon != null)
+ folderIcon.dispose();
+ if (fileIcon != null)
+ fileIcon.dispose();
+ super.dispose();
+ }
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof Path) {
+ Path curr = ((Path) element);
+ Path name = curr.getFileName();
+ if (name == null)
+ return "[No name]";
+ else
+ return name.toString();
+ } else if (element instanceof ParentDir) {
+ return "..";
+ }
+ return null;
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ if (element instanceof Path) {
+ Path curr = ((Path) element);
+ if (Files.isDirectory(curr))
+ // if (folderIcon != null)
+ return folderIcon;
+ // else
+ // return
+ // PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
+ // else if (fileIcon != null)
+ return fileIcon;
+ // else
+ // return
+ // PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE);
+ } else if (element instanceof ParentDir) {
+ return folderIcon;
+ }
+ return null;
+ }
+
+ @Override
+ public String getToolTipText(Object element) {
+ if (element instanceof Path) {
+ Path curr = ((Path) element);
+ Path name = curr.getFileName();
+ if (name == null)
+ return "[No name]";
+ else
+ return name.toAbsolutePath().toString();
+ } else if (element instanceof ParentDir) {
+ return ((ParentDir) element).getPath().toAbsolutePath().toString();
+ }
+ return null;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.nio.file.Path;
+import java.util.List;
+
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.ILazyContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * Canonical implementation of a JFace table viewer to display the content of a
+ * file folder
+ */
+public class FsTableViewer extends TableViewer {
+ private static final long serialVersionUID = -5632407542678477234L;
+
+ private boolean showHiddenItems = false;
+ private boolean folderFirst = true;
+ private boolean reverseOrder = false;
+ private String orderProperty = FsUiConstants.PROPERTY_NAME;
+
+ private Path initialPath = null;
+
+ public FsTableViewer(Composite parent, int style) {
+ super(parent, style | SWT.VIRTUAL);
+ }
+
+ public Table configureDefaultSingleColumnTable(int tableWidthHint) {
+
+ return configureDefaultSingleColumnTable(tableWidthHint, new FileIconNameLabelProvider());
+ }
+
+ public Table configureDefaultSingleColumnTable(int tableWidthHint, CellLabelProvider labelProvider) {
+ Table table = this.getTable();
+ table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ table.setLinesVisible(false);
+ table.setHeaderVisible(false);
+ // CmsUtils.markup(table);
+ // CmsUtils.style(table, MaintenanceStyles.BROWSER_COLUMN);
+
+ TableViewerColumn column = new TableViewerColumn(this, SWT.NONE);
+ TableColumn tcol = column.getColumn();
+ tcol.setWidth(tableWidthHint);
+ column.setLabelProvider(labelProvider);
+ this.setContentProvider(new MyLazyCP());
+ return table;
+ }
+
+ public Table configureDefaultTable(List<ColumnDefinition> columns) {
+ this.setContentProvider(new MyLazyCP());
+ Table table = this.getTable();
+ table.setLinesVisible(true);
+ table.setHeaderVisible(true);
+ // CmsUtils.markup(table);
+ // CmsUtils.style(table, MaintenanceStyles.BROWSER_COLUMN);
+ for (ColumnDefinition colDef : columns) {
+ TableViewerColumn column = new TableViewerColumn(this, SWT.NONE);
+ column.setLabelProvider(colDef.getLabelProvider());
+ TableColumn tcol = column.getColumn();
+ tcol.setResizable(true);
+ tcol.setText(colDef.getLabel());
+ tcol.setWidth(colDef.getMinWidth());
+ }
+ return table;
+ }
+
+ public void setInput(Path dir, String filter) {
+ Path[] rows = FsUiUtils.getChildren(dir, filter, showHiddenItems, folderFirst, orderProperty, reverseOrder);
+ if (rows == null) {
+ this.setInput(null);
+ this.setItemCount(0);
+ return;
+ }
+ boolean isRoot;
+ try {
+ isRoot = dir.getRoot().equals(dir);
+ } catch (Exception e) {
+ // FIXME Workaround for JCR root node access
+ isRoot = dir.toString().equals("/");
+ }
+ final Object[] res;
+ if (isRoot)
+ res = rows;
+ else if (initialPath != null && initialPath.equals(dir))
+ res = rows;
+ else {
+ res = new Object[rows.length + 1];
+ res[0] = new ParentDir(dir.getParent());
+ for (int i = 1; i < res.length; i++) {
+ res[i] = rows[i - 1];
+ }
+ }
+ this.setInput(res);
+ int length = res.length;
+ this.setItemCount(length);
+ this.refresh();
+ }
+
+ /** Directly displays bookmarks **/
+ public void setPathsInput(Path... paths) {
+ this.setInput((Object[]) paths);
+ this.setItemCount(paths.length);
+ this.refresh();
+ }
+
+ /**
+ * A path which is to be considered as root (and thus provide no link to a
+ * parent directory)
+ */
+ public void setInitialPath(Path initialPath) {
+ this.initialPath = initialPath;
+ }
+
+ private class MyLazyCP implements ILazyContentProvider {
+ private static final long serialVersionUID = 9096550041395433128L;
+ private Object[] elements;
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // IMPORTANT: don't forget this: an exception will be thrown if
+ // a selected object is not part of the results anymore.
+ viewer.setSelection(null);
+ this.elements = (Object[]) newInput;
+ }
+
+ public void updateElement(int index) {
+ if (index < elements.length)
+ FsTableViewer.this.replace(elements[index], index);
+ }
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ * Canonical implementation of a JFace TreeViewer to display the content of a
+ * repository
+ */
+public class FsTreeViewer extends TreeViewer {
+ private static final long serialVersionUID = -5632407542678477234L;
+
+ private boolean showHiddenItems = false;
+ private boolean showDirectoryFirst = true;
+ private String orderingProperty = FsUiConstants.PROPERTY_NAME;
+
+ public FsTreeViewer(Composite parent, int style) {
+ super(parent, style | SWT.VIRTUAL);
+ }
+
+ public Tree configureDefaultSingleColumnTable(int tableWidthHint) {
+ Tree tree = this.getTree();
+ tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ tree.setLinesVisible(true);
+ tree.setHeaderVisible(false);
+// CmsUtils.markup(tree);
+
+ TreeViewerColumn column = new TreeViewerColumn(this, SWT.NONE);
+ TreeColumn tcol = column.getColumn();
+ tcol.setWidth(tableWidthHint);
+ column.setLabelProvider(new FileIconNameLabelProvider());
+
+ this.setContentProvider(new MyCP());
+ return tree;
+ }
+
+ public Tree configureDefaultTable(List<ColumnDefinition> columns) {
+ this.setContentProvider(new MyCP());
+ Tree tree = this.getTree();
+ tree.setLinesVisible(true);
+ tree.setHeaderVisible(true);
+// CmsUtils.markup(tree);
+// CmsUtils.style(tree, MaintenanceStyles.BROWSER_COLUMN);
+ for (ColumnDefinition colDef : columns) {
+ TreeViewerColumn column = new TreeViewerColumn(this, SWT.NONE);
+ column.setLabelProvider(colDef.getLabelProvider());
+ TreeColumn tcol = column.getColumn();
+ tcol.setResizable(true);
+ tcol.setText(colDef.getLabel());
+ tcol.setWidth(colDef.getMinWidth());
+ }
+ return tree;
+ }
+
+ public void setInput(Path dir, String filter) {
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
+ // TODO make this lazy
+ List<Path> paths = new ArrayList<>();
+ for (Path entry : stream) {
+ paths.add(entry);
+ }
+ Object[] rows = paths.toArray(new Object[0]);
+ this.setInput(rows);
+ // this.setItemCount(rows.length);
+ this.refresh();
+ } catch (IOException | DirectoryIteratorException e) {
+ throw new FsUiException("Unable to filter " + dir + " children with filter " + filter, e);
+ }
+ }
+
+ /** Directly displays bookmarks **/
+ public void setPathsInput(Path... paths) {
+ this.setInput((Object[]) paths);
+ // this.setItemCount(paths.length);
+ this.refresh();
+ }
+
+ private class MyCP implements ITreeContentProvider {
+ private static final long serialVersionUID = 9096550041395433128L;
+ private Object[] elements;
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // IMPORTANT: don't forget this: an exception will be thrown if
+ // a selected object is not part of the results anymore.
+ viewer.setSelection(null);
+ this.elements = (Object[]) newInput;
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return elements;
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ Path path = (Path) parentElement;
+ if (!Files.isDirectory(path))
+ return null;
+ else
+ return FsUiUtils.getChildren(path, "*", showHiddenItems, showDirectoryFirst, orderingProperty, false);
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ Path path = (Path) element;
+ return path.getParent();
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ Path path = (Path) element;
+ try {
+ if (!Files.isDirectory(path))
+ return false;
+ else
+ try (DirectoryStream<Path> children = Files.newDirectoryStream(path, "*")) {
+ return children.iterator().hasNext();
+ }
+ } catch (IOException e) {
+ throw new FsUiException("Unable to check child existence on " + path, e);
+ }
+ }
+
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+/** Centralize constants used by the Nio FS UI parts */
+public interface FsUiConstants {
+
+ // TODO use standard properties
+ String PROPERTY_NAME = "name";
+ String PROPERTY_SIZE = "size";
+ String PROPERTY_LAST_MODIFIED = "last-modified";
+ String PROPERTY_TYPE = "type";
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+/** Files specific exception */
+public class FsUiException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public FsUiException(String message) {
+ super(message);
+ }
+
+ public FsUiException(String message, Throwable e) {
+ super(message, e);
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** Centralise additional utilitary methods to manage Java7 NIO files */
+public class FsUiUtils {
+
+ /**
+ * thanks to
+ * http://programming.guide/java/formatting-byte-size-to-human-readable-format.html
+ */
+ public static String humanReadableByteCount(long bytes, boolean si) {
+ int unit = si ? 1000 : 1024;
+ if (bytes < unit)
+ return bytes + " B";
+ int exp = (int) (Math.log(bytes) / Math.log(unit));
+ String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
+ return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
+ }
+
+ public static Path[] getChildren(Path parent, String filter, boolean showHiddenItems, boolean folderFirst,
+ String orderProperty, boolean reverseOrder) {
+ if (!Files.isDirectory(parent))
+ return null;
+ List<Pair> pairs = new ArrayList<>();
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(parent, filter)) {
+ loop: for (Path entry : stream) {
+ if (!showHiddenItems)
+ if (Files.isHidden(entry))
+ continue loop;
+ switch (orderProperty) {
+ case FsUiConstants.PROPERTY_SIZE:
+ if (folderFirst)
+ pairs.add(new LPair(entry, Files.size(entry), Files.isDirectory(entry)));
+ else
+ pairs.add(new LPair(entry, Files.size(entry)));
+ break;
+ case FsUiConstants.PROPERTY_LAST_MODIFIED:
+ if (folderFirst)
+ pairs.add(new LPair(entry, Files.getLastModifiedTime(entry).toMillis(),
+ Files.isDirectory(entry)));
+ else
+ pairs.add(new LPair(entry, Files.getLastModifiedTime(entry).toMillis()));
+ break;
+ case FsUiConstants.PROPERTY_NAME:
+ if (folderFirst)
+ pairs.add(new SPair(entry, entry.getFileName().toString(), Files.isDirectory(entry)));
+ else
+ pairs.add(new SPair(entry, entry.getFileName().toString()));
+ break;
+ default:
+ throw new FsUiException("Unable to prepare sort for property " + orderProperty);
+ }
+ }
+ Pair[] rows = pairs.toArray(new Pair[0]);
+ Arrays.sort(rows);
+ Path[] results = new Path[rows.length];
+ if (reverseOrder) {
+ int j = rows.length - 1;
+ for (int i = 0; i < rows.length; i++)
+ results[i] = rows[j - i].p;
+ } else
+ for (int i = 0; i < rows.length; i++)
+ results[i] = rows[i].p;
+ return results;
+ } catch (IOException | DirectoryIteratorException e) {
+ throw new FsUiException("Unable to filter " + parent + " children with filter " + filter, e);
+ }
+ }
+
+ static abstract class Pair implements Comparable<Object> {
+ Path p;
+ Boolean i;
+ };
+
+ static class LPair extends Pair {
+ long v;
+
+ public LPair(Path path, long propValue) {
+ p = path;
+ v = propValue;
+ }
+
+ public LPair(Path path, long propValue, boolean isDir) {
+ p = path;
+ v = propValue;
+ i = isDir;
+ }
+
+ public int compareTo(Object o) {
+ if (i != null) {
+ Boolean j = ((LPair) o).i;
+ if (i.booleanValue() != j.booleanValue())
+ return i.booleanValue() ? -1 : 1;
+ }
+ long u = ((LPair) o).v;
+ return v < u ? -1 : v == u ? 0 : 1;
+ }
+ };
+
+ static class SPair extends Pair {
+ String v;
+
+ public SPair(Path path, String propValue) {
+ p = path;
+ v = propValue;
+ }
+
+ public SPair(Path path, String propValue, boolean isDir) {
+ p = path;
+ v = propValue;
+ i = isDir;
+ }
+
+ public int compareTo(Object o) {
+ if (i != null) {
+ Boolean j = ((SPair) o).i;
+ if (i.booleanValue() != j.booleanValue())
+ return i.booleanValue() ? -1 : 1;
+ }
+ String u = ((SPair) o).v;
+ return v.compareTo(u);
+ }
+ };
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+/** Expect a {@link Path} as input element */
+public class NioFileLabelProvider extends ColumnLabelProvider {
+ private final static FileTime EPOCH = FileTime.fromMillis(0);
+ private static final long serialVersionUID = 2160026425187796930L;
+ private final String propName;
+ private DateFormat dateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm");
+
+ // TODO use new formatting
+ // DateTimeFormatter formatter =
+ // DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
+ // .withLocale( Locale.UK )
+ // .withZone( ZoneId.systemDefault() );
+ public NioFileLabelProvider(String propName) {
+ this.propName = propName;
+ }
+
+ @Override
+ public String getText(Object element) {
+ try {
+ Path path;
+ if (element instanceof ParentDir) {
+// switch (propName) {
+// case FsUiConstants.PROPERTY_SIZE:
+// return "-";
+// case FsUiConstants.PROPERTY_LAST_MODIFIED:
+// return "-";
+// // return Files.getLastModifiedTime(((ParentDir) element).getPath()).toString();
+// case FsUiConstants.PROPERTY_TYPE:
+// return "Folder";
+// }
+ path = ((ParentDir) element).getPath();
+ } else
+ path = (Path) element;
+ switch (propName) {
+ case FsUiConstants.PROPERTY_SIZE:
+ if (Files.isDirectory(path))
+ return "-";
+ else
+ return FsUiUtils.humanReadableByteCount(Files.size(path), false);
+ case FsUiConstants.PROPERTY_LAST_MODIFIED:
+ if (Files.isDirectory(path))
+ return "-";
+ FileTime time = Files.getLastModifiedTime(path);
+ if (time.equals(EPOCH))
+ return "-";
+ else
+ return dateFormat.format(new Date(time.toMillis()));
+ case FsUiConstants.PROPERTY_TYPE:
+ if (Files.isDirectory(path))
+ return "Folder";
+ else {
+ String mimeType = Files.probeContentType(path);
+ if (EclipseUiUtils.isEmpty(mimeType))
+ return "Unknown";
+ else
+ return mimeType;
+ }
+ default:
+ throw new IllegalArgumentException("Unsupported property " + propName);
+ }
+ } catch (IOException ioe) {
+ throw new FsUiException("Cannot get property " + propName + " on " + element);
+ }
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.nio.file.Path;
+
+/** A parent directory (..) reference. */
+public class ParentDir {
+ Path path;
+
+ public ParentDir(Path path) {
+ super();
+ this.path = path;
+ }
+
+ public Path getPath() {
+ return path;
+ }
+
+ @Override
+ public int hashCode() {
+ return path.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Parent dir " + path;
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+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.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+
+/**
+ * Experimental UI upon Java 7 nio files api: SashForm layout with bookmarks on
+ * the left hand side and a simple table on the right hand side.
+ */
+public class SimpleFsBrowser extends Composite {
+ private final static CmsLog log = CmsLog.getLog(SimpleFsBrowser.class);
+ private static final long serialVersionUID = -40347919096946585L;
+
+ private Path currSelected;
+ private FsTableViewer bookmarksViewer;
+ private FsTableViewer directoryDisplayViewer;
+
+ public SimpleFsBrowser(Composite parent, int style) {
+ super(parent, style);
+ createContent(this);
+ // parent.layout(true, true);
+ }
+
+ public Viewer getViewer() {
+ return directoryDisplayViewer;
+ }
+
+ private void createContent(Composite parent) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ SashForm form = new SashForm(parent, SWT.HORIZONTAL);
+ Composite leftCmp = new Composite(form, SWT.NONE);
+ populateBookmarks(leftCmp);
+
+ Composite rightCmp = new Composite(form, SWT.BORDER);
+ populateDisplay(rightCmp);
+ form.setLayoutData(EclipseUiUtils.fillAll());
+ form.setWeights(new int[] { 1, 3 });
+ }
+
+ public void setInput(Path... paths) {
+ bookmarksViewer.setPathsInput(paths);
+ bookmarksViewer.getTable().getParent().layout(true, true);
+ }
+
+ private void populateBookmarks(final Composite parent) {
+ // GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
+ // layout.verticalSpacing = 5;
+ parent.setLayout(new GridLayout());
+
+ ISelectionChangedListener selList = new MySelectionChangedListener();
+
+ appendTitle(parent, "My bookmarks");
+ bookmarksViewer = new FsTableViewer(parent, SWT.MULTI | SWT.NO_SCROLL);
+ Table table = bookmarksViewer.configureDefaultSingleColumnTable(500);
+ GridData gd = EclipseUiUtils.fillWidth();
+ gd.horizontalIndent = 10;
+ table.setLayoutData(gd);
+ bookmarksViewer.addSelectionChangedListener(selList);
+
+ appendTitle(parent, "Jcr + File");
+
+ FsTableViewer jcrFilesViewers = new FsTableViewer(parent, SWT.MULTI | SWT.NO_SCROLL);
+ table = jcrFilesViewers.configureDefaultSingleColumnTable(500);
+ gd = EclipseUiUtils.fillWidth();
+ gd.horizontalIndent = 10;
+ table.setLayoutData(gd);
+ jcrFilesViewers.addSelectionChangedListener(selList);
+
+ // FileSystemProvider fsProvider = new JackrabbitMemoryFsProvider();
+ // try {
+ // Path testPath = fsProvider.getPath(new URI("jcr+memory:/"));
+ // jcrFilesViewers.setPathsInput(testPath);
+ // } catch (URISyntaxException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+ }
+
+ private Label appendTitle(Composite parent, String value) {
+ Label titleLbl = new Label(parent, SWT.NONE);
+ titleLbl.setText(value);
+ titleLbl.setFont(EclipseUiUtils.getBoldFont(parent));
+ GridData gd = EclipseUiUtils.fillWidth();
+ gd.horizontalIndent = 5;
+ gd.verticalIndent = 5;
+ titleLbl.setLayoutData(gd);
+ return titleLbl;
+ }
+
+ private class MySelectionChangedListener implements ISelectionChangedListener {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) bookmarksViewer.getSelection();
+ if (selection.isEmpty())
+ return;
+ else {
+ Path newSelected = (Path) selection.getFirstElement();
+ if (newSelected.equals(currSelected))
+ return;
+ currSelected = newSelected;
+ directoryDisplayViewer.setInput(currSelected, "*");
+ }
+ }
+ }
+
+ private void populateDisplay(final Composite parent) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
+ List<ColumnDefinition> colDefs = new ArrayList<>();
+ colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), "Name", 200));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 250));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
+ "Last modified", 200));
+ Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
+ table.setLayoutData(EclipseUiUtils.fillAll());
+
+ table.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -8083424284436715709L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ log.debug("Key event received: " + e.keyCode);
+ IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+ Path selected = null;
+ if (!selection.isEmpty())
+ selected = ((Path) selection.getFirstElement());
+ if (e.keyCode == SWT.CR) {
+ if (!Files.isDirectory(selected))
+ return;
+ if (selected != null) {
+ currSelected = selected;
+ directoryDisplayViewer.setInput(currSelected, "*");
+ }
+ } else if (e.keyCode == SWT.BS) {
+ currSelected = currSelected.getParent();
+ directoryDisplayViewer.setInput(currSelected, "*");
+ directoryDisplayViewer.getTable().setFocus();
+ }
+ }
+ });
+
+// directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
+// @Override
+// public void doubleClick(DoubleClickEvent event) {
+// IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+// Path selected = null;
+// if (!selection.isEmpty()) {
+// Object obj = selection.getFirstElement();
+// if (obj instanceof Path)
+// selected = (Path) obj;
+// else if (obj instanceof ParentDir)
+// selected = ((ParentDir) obj).getPath();
+// }
+// if (selected != null) {
+// if (!Files.isDirectory(selected))
+// return;
+// currSelected = selected;
+// directoryDisplayViewer.setInput(currSelected, "*");
+// }
+// }
+// });
+
+ directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+ Path selected = null;
+ if (!selection.isEmpty()) {
+ Object obj = selection.getFirstElement();
+ if (obj instanceof Path)
+ selected = (Path) obj;
+ else if (obj instanceof ParentDir)
+ selected = ((ParentDir) obj).getPath();
+ }
+ if (selected != null) {
+ if (!Files.isDirectory(selected))
+ return;
+ currSelected = selected;
+ directoryDisplayViewer.setInput(currSelected, "*");
+ }
+ }
+ });
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui.fs;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Tree;
+
+/** A simple Java 7 nio files browser with a tree */
+public class SimpleFsTreeBrowser extends Composite {
+ private final static CmsLog log = CmsLog.getLog(SimpleFsTreeBrowser.class);
+ private static final long serialVersionUID = -40347919096946585L;
+
+ private Path currSelected;
+ private FsTreeViewer treeViewer;
+ private FsTableViewer directoryDisplayViewer;
+
+ public SimpleFsTreeBrowser(Composite parent, int style) {
+ super(parent, style);
+ createContent(this);
+ // parent.layout(true, true);
+ }
+
+ private void createContent(Composite parent) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ SashForm form = new SashForm(parent, SWT.HORIZONTAL);
+ Composite child1 = new Composite(form, SWT.NONE);
+ populateTree(child1);
+ Composite child2 = new Composite(form, SWT.BORDER);
+ populateDisplay(child2);
+ form.setLayoutData(EclipseUiUtils.fillAll());
+ form.setWeights(new int[] { 1, 3 });
+ }
+
+ public void setInput(Path... paths) {
+ treeViewer.setPathsInput(paths);
+ treeViewer.getControl().getParent().layout(true, true);
+ }
+
+ private void populateTree(final Composite parent) {
+ // GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
+ // layout.verticalSpacing = 5;
+ parent.setLayout(new GridLayout());
+
+ ISelectionChangedListener selList = new MySelectionChangedListener();
+
+ treeViewer = new FsTreeViewer(parent, SWT.MULTI);
+ Tree tree = treeViewer.configureDefaultSingleColumnTable(500);
+ GridData gd = EclipseUiUtils.fillAll();
+ // gd.horizontalIndent = 10;
+ tree.setLayoutData(gd);
+ treeViewer.addSelectionChangedListener(selList);
+ }
+
+ private class MySelectionChangedListener implements ISelectionChangedListener {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();
+ if (selection.isEmpty())
+ return;
+ else {
+ Path newSelected = (Path) selection.getFirstElement();
+ if (newSelected.equals(currSelected))
+ return;
+ currSelected = newSelected;
+ if (Files.isDirectory(currSelected))
+ directoryDisplayViewer.setInput(currSelected, "*");
+ }
+ }
+ }
+
+ private void populateDisplay(final Composite parent) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
+ List<ColumnDefinition> colDefs = new ArrayList<>();
+ colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), "Name", 200, 200));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100, 100));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 300, 300));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
+ "Last modified", 100, 100));
+ Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
+ table.setLayoutData(EclipseUiUtils.fillAll());
+
+ table.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = -8083424284436715709L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ log.debug("Key event received: " + e.keyCode);
+ IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+ Path selected = null;
+ if (!selection.isEmpty())
+ selected = ((Path) selection.getFirstElement());
+ if (e.keyCode == SWT.CR) {
+ if (!Files.isDirectory(selected))
+ return;
+ if (selected != null) {
+ currSelected = selected;
+ directoryDisplayViewer.setInput(currSelected, "*");
+ }
+ } else if (e.keyCode == SWT.BS) {
+ currSelected = currSelected.getParent();
+ directoryDisplayViewer.setInput(currSelected, "*");
+ directoryDisplayViewer.getTable().setFocus();
+ }
+ }
+ });
+ }
+}
--- /dev/null
+/** Generic SWT/JFace file system utilities. */
+package org.argeo.eclipse.ui.fs;
\ No newline at end of file
--- /dev/null
+/** Generic SWT/JFace utilities. */
+package org.argeo.eclipse.ui;
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui.parts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.util.ViewerUtils;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Generic composite that display a filter and a table viewer to display users
+ * (can also be groups)
+ *
+ * Warning: this class does not extends <code>TableViewer</code>. Use the
+ * getTableViewer method to access it.
+ *
+ */
+public abstract class LdifUsersTable extends Composite {
+ private static final long serialVersionUID = -7385959046279360420L;
+
+ // Context
+ // private UserAdmin userAdmin;
+
+ // Configuration
+ private List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
+ private boolean hasFilter;
+ private boolean preventTableLayout = false;
+ private boolean hasSelectionColumn;
+ private int tableStyle;
+
+ // Local UI Objects
+ private TableViewer usersViewer;
+ private Text filterTxt;
+
+ /* EXPOSED METHODS */
+
+ /**
+ * @param parent
+ * @param style
+ */
+ public LdifUsersTable(Composite parent, int style) {
+ super(parent, SWT.NO_FOCUS);
+ this.tableStyle = style;
+ }
+
+ // TODO workaround the bug of the table layout in the Form
+ public LdifUsersTable(Composite parent, int style, boolean preventTableLayout) {
+ super(parent, SWT.NO_FOCUS);
+ this.tableStyle = style;
+ this.preventTableLayout = preventTableLayout;
+ }
+
+ /** This must be called before the call to populate method */
+ public void setColumnDefinitions(List<ColumnDefinition> columnDefinitions) {
+ this.columnDefs = columnDefinitions;
+ }
+
+ /**
+ *
+ * @param addFilter
+ * choose to add a field to filter results or not
+ * @param addSelection
+ * choose to add a column to select some of the displayed results or
+ * not
+ */
+ public void populate(boolean addFilter, boolean addSelection) {
+ // initialization
+ Composite parent = this;
+ hasFilter = addFilter;
+ hasSelectionColumn = addSelection;
+
+ // Main Layout
+ GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
+ layout.verticalSpacing = 5;
+ this.setLayout(layout);
+ if (hasFilter)
+ createFilterPart(parent);
+
+ Composite tableComp = new Composite(parent, SWT.NO_FOCUS);
+ tableComp.setLayoutData(EclipseUiUtils.fillAll());
+ usersViewer = createTableViewer(tableComp);
+ usersViewer.setContentProvider(new UsersContentProvider());
+ }
+
+ /**
+ *
+ * @param showMore
+ * display static filters on creation
+ * @param addSelection
+ * choose to add a column to select some of the displayed results or
+ * not
+ */
+ public void populateWithStaticFilters(boolean showMore, boolean addSelection) {
+ // initialization
+ Composite parent = this;
+ hasFilter = true;
+ hasSelectionColumn = addSelection;
+
+ // Main Layout
+ GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
+ layout.verticalSpacing = 5;
+ this.setLayout(layout);
+ createStaticFilterPart(parent, showMore);
+
+ Composite tableComp = new Composite(parent, SWT.NO_FOCUS);
+ tableComp.setLayoutData(EclipseUiUtils.fillAll());
+ usersViewer = createTableViewer(tableComp);
+ usersViewer.setContentProvider(new UsersContentProvider());
+ }
+
+ /** Enable access to the selected users or groups */
+ public List<User> getSelectedUsers() {
+ if (hasSelectionColumn) {
+ Object[] elements = ((CheckboxTableViewer) usersViewer).getCheckedElements();
+
+ List<User> result = new ArrayList<User>();
+ for (Object obj : elements) {
+ result.add((User) obj);
+ }
+ return result;
+ } else
+ throw new EclipseUiException(
+ "Unvalid request: no selection column " + "has been created for the current table");
+ }
+
+ /** Returns the User table viewer, typically to add doubleclick listener */
+ public TableViewer getTableViewer() {
+ return usersViewer;
+ }
+
+ /**
+ * Force the refresh of the underlying table using the current filter string if
+ * relevant
+ */
+ public void refresh() {
+ String filter = hasFilter ? filterTxt.getText().trim() : null;
+ if ("".equals(filter))
+ filter = null;
+ refreshFilteredList(filter);
+ }
+
+ /** Effective repository request: caller must implement this method */
+ abstract protected List<User> listFilteredElements(String filter);
+
+ // protected List<User> listFilteredElements(String filter) {
+ // List<User> users = new ArrayList<User>();
+ // try {
+ // Role[] roles = userAdmin.getRoles(filter);
+ // // Display all users and groups
+ // for (Role role : roles)
+ // users.add((User) role);
+ // } catch (InvalidSyntaxException e) {
+ // throw new EclipseUiException("Unable to get roles with filter: "
+ // + filter, e);
+ // }
+ // return users;
+ // }
+
+ /* GENERIC COMPOSITE METHODS */
+ @Override
+ public boolean setFocus() {
+ if (hasFilter)
+ return filterTxt.setFocus();
+ else
+ return usersViewer.getTable().setFocus();
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ }
+
+ /* LOCAL CLASSES AND METHODS */
+ // Will be usefull to rather use a virtual table viewer
+ private void refreshFilteredList(String filter) {
+ List<User> users = listFilteredElements(filter);
+ usersViewer.setInput(users.toArray());
+ }
+
+ private class UsersContentProvider implements IStructuredContentProvider {
+ private static final long serialVersionUID = 1L;
+
+ public Object[] getElements(Object inputElement) {
+ return (Object[]) inputElement;
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ }
+
+ /* MANAGE FILTER */
+ private void createFilterPart(Composite parent) {
+ // Text Area for the filter
+ filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
+ filterTxt.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ filterTxt.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = 1L;
+
+ public void modifyText(ModifyEvent event) {
+ refreshFilteredList(filterTxt.getText());
+ }
+ });
+ }
+
+ private void createStaticFilterPart(Composite parent, boolean showMore) {
+ Composite filterComp = new Composite(parent, SWT.NO_FOCUS);
+ filterComp.setLayout(new GridLayout(2, false));
+ filterComp.setLayoutData(EclipseUiUtils.fillWidth());
+ // generic search
+ filterTxt = new Text(filterComp, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
+ filterTxt.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ // filterTxt.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL |
+ // GridData.HORIZONTAL_ALIGN_FILL));
+ filterTxt.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = 1L;
+
+ public void modifyText(ModifyEvent event) {
+ refreshFilteredList(filterTxt.getText());
+ }
+ });
+
+ // add static filter abilities
+ Link moreLk = new Link(filterComp, SWT.NONE);
+ Composite staticFilterCmp = new Composite(filterComp, SWT.NO_FOCUS);
+ staticFilterCmp.setLayoutData(EclipseUiUtils.fillWidth(2));
+ populateStaticFilters(staticFilterCmp);
+
+ MoreLinkListener listener = new MoreLinkListener(moreLk, staticFilterCmp, showMore);
+ // initialise the layout
+ listener.refresh();
+ moreLk.addSelectionListener(listener);
+ }
+
+ /** Overwrite to add static filters */
+ protected void populateStaticFilters(Composite staticFilterCmp) {
+ }
+
+ // private void addMoreSL(final Link more) {
+ // more.addSelectionListener( }
+
+ private class MoreLinkListener extends SelectionAdapter {
+ private static final long serialVersionUID = -524987616510893463L;
+ private boolean isShown;
+ private final Composite staticFilterCmp;
+ private final Link moreLk;
+
+ public MoreLinkListener(Link moreLk, Composite staticFilterCmp, boolean isShown) {
+ this.moreLk = moreLk;
+ this.staticFilterCmp = staticFilterCmp;
+ this.isShown = isShown;
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ isShown = !isShown;
+ refresh();
+ }
+
+ public void refresh() {
+ GridData gd = (GridData) staticFilterCmp.getLayoutData();
+ if (isShown) {
+ moreLk.setText("<a> Less... </a>");
+ gd.heightHint = SWT.DEFAULT;
+ } else {
+ moreLk.setText("<a> More... </a>");
+ gd.heightHint = 0;
+ }
+ forceLayout();
+ }
+ }
+
+ private void forceLayout() {
+ LdifUsersTable.this.getParent().layout(true, true);
+ }
+
+ private TableViewer createTableViewer(final Composite parent) {
+
+ int style = tableStyle | SWT.H_SCROLL | SWT.V_SCROLL;
+ if (hasSelectionColumn)
+ style = style | SWT.CHECK;
+ Table table = new Table(parent, style);
+ TableColumnLayout layout = new TableColumnLayout();
+
+ // TODO the table layout does not works with the scrolled form
+
+ if (preventTableLayout) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ table.setLayoutData(EclipseUiUtils.fillAll());
+ } else
+ parent.setLayout(layout);
+
+ TableViewer viewer;
+ if (hasSelectionColumn)
+ viewer = new CheckboxTableViewer(table);
+ else
+ viewer = new TableViewer(table);
+ table.setLinesVisible(true);
+ table.setHeaderVisible(true);
+
+ TableViewerColumn column;
+ // int offset = 0;
+ if (hasSelectionColumn) {
+ // offset = 1;
+ column = ViewerUtils.createTableViewerColumn(viewer, "", SWT.NONE, 25);
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public String getText(Object element) {
+ return null;
+ }
+ });
+ layout.setColumnData(column.getColumn(), new ColumnWeightData(25, 25, false));
+
+ SelectionAdapter selectionAdapter = new SelectionAdapter() {
+ private static final long serialVersionUID = 1L;
+
+ boolean allSelected = false;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ allSelected = !allSelected;
+ ((CheckboxTableViewer) usersViewer).setAllChecked(allSelected);
+ }
+ };
+ column.getColumn().addSelectionListener(selectionAdapter);
+ }
+
+ // NodeViewerComparator comparator = new NodeViewerComparator();
+ // TODO enable the sort by click on the header
+ // int i = offset;
+ for (ColumnDefinition colDef : columnDefs)
+ createTableColumn(viewer, layout, colDef);
+
+ // column = ViewerUtils.createTableViewerColumn(viewer,
+ // colDef.getHeaderLabel(), SWT.NONE, colDef.getColumnSize());
+ // column.setLabelProvider(new CLProvider(colDef.getPropertyName()));
+ // column.getColumn().addSelectionListener(
+ // JcrUiUtils.getNodeSelectionAdapter(i,
+ // colDef.getPropertyType(), colDef.getPropertyName(),
+ // comparator, viewer));
+ // i++;
+ // }
+
+ // IMPORTANT: initialize comparator before setting it
+ // JcrColumnDefinition firstCol = colDefs.get(0);
+ // comparator.setColumn(firstCol.getPropertyType(),
+ // firstCol.getPropertyName());
+ // viewer.setComparator(comparator);
+
+ return viewer;
+ }
+
+ /** Default creation of a column for a user table */
+ private TableViewerColumn createTableColumn(TableViewer tableViewer, TableColumnLayout layout,
+ ColumnDefinition columnDef) {
+
+ boolean resizable = true;
+ TableViewerColumn tvc = new TableViewerColumn(tableViewer, SWT.NONE);
+ TableColumn column = tvc.getColumn();
+
+ column.setText(columnDef.getLabel());
+ column.setWidth(columnDef.getMinWidth());
+ column.setResizable(resizable);
+
+ ColumnLabelProvider lp = columnDef.getLabelProvider();
+ // add a reference to the display to enable font management
+ // if (lp instanceof UserAdminAbstractLP)
+ // ((UserAdminAbstractLP) lp).setDisplay(tableViewer.getTable()
+ // .getDisplay());
+ tvc.setLabelProvider(lp);
+
+ layout.setColumnData(column, new ColumnWeightData(columnDef.getWeight(), columnDef.getMinWidth(), resizable));
+
+ return tvc;
+ }
+}
--- /dev/null
+/** Generic SWT/JFace composites. */
+package org.argeo.eclipse.ui.parts;
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui.util;
+
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ * Centralise useful methods to manage JFace Table, Tree and TreeColumn viewers.
+ */
+public class ViewerUtils {
+
+ /**
+ * Creates a basic column for the given table. For the time being, we do not
+ * support movable columns.
+ */
+ public static TableColumn createColumn(Table parent, String name, int style, int width) {
+ TableColumn result = new TableColumn(parent, style);
+ result.setText(name);
+ result.setWidth(width);
+ result.setResizable(true);
+ return result;
+ }
+
+ /**
+ * Creates a TableViewerColumn for the given viewer. For the time being, we do
+ * not support movable columns.
+ */
+ public static TableViewerColumn createTableViewerColumn(TableViewer parent, String name, int style, int width) {
+ TableViewerColumn tvc = new TableViewerColumn(parent, style);
+ TableColumn column = tvc.getColumn();
+ column.setText(name);
+ column.setWidth(width);
+ column.setResizable(true);
+ return tvc;
+ }
+
+ // public static TableViewerColumn createTableViewerColumn(TableViewer parent,
+ // Localized name, int style, int width) {
+ // return createTableViewerColumn(parent, name.lead(), style, width);
+ // }
+
+ /**
+ * Creates a TreeViewerColumn for the given viewer. For the time being, we do
+ * not support movable columns.
+ */
+ public static TreeViewerColumn createTreeViewerColumn(TreeViewer parent, String name, int style, int width) {
+ TreeViewerColumn tvc = new TreeViewerColumn(parent, style);
+ TreeColumn column = tvc.getColumn();
+ column.setText(name);
+ column.setWidth(width);
+ column.setResizable(true);
+ return tvc;
+ }
+}
--- /dev/null
+/** Generic SWT/JFace JCR helpers. */
+package org.argeo.eclipse.ui.util;
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.e4.rap</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" configuration-policy="optional" name="CMS Admin RAP">
+ <implementation class="org.argeo.cms.e4.rap.CmsE4AdminApp"/>
+ <service>
+ <provide interface="org.eclipse.rap.rwt.application.ApplicationConfiguration"/>
+ <property name="contextName" type="String" value="cms"/>
+ </service>
+</scr:component>
--- /dev/null
+Bundle-ActivationPolicy: lazy
+Service-Component: OSGI-INF/cms-admin-rap.xml
+
+Import-Package: org.eclipse.swt,\
+org.eclipse.swt.graphics,\
+org.eclipse.e4.ui.workbench,\
+org.eclipse.rap.rwt.client,\
+org.eclipse.nebula.widgets.richtext;resolution:=optional,\
+*
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/
--- /dev/null
+package org.argeo.cms.e4.rap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.osgi.framework.BundleContext;
+
+/** Base class for CMS RAP applications. */
+public abstract class AbstractRapE4App implements ApplicationConfiguration {
+ private String e4Xmi;
+ private String path;
+ private String lifeCycleUri = "bundleclass://org.argeo.cms.e4.rap/org.argeo.cms.e4.rap.CmsLoginLifecycle";
+
+ private Map<String, String> baseProperties = new HashMap<String, String>();
+
+ private BundleContext bundleContext;
+ public final static String CONTEXT_NAME_PROPERTY = "contextName";
+ private String contextName;
+
+ /**
+ * To be overridden in order to add multiple entry points, directly or using
+ * {@link #addE4EntryPoint(Application, String, String, Map)}.
+ */
+ protected void addEntryPoints(Application application) {
+ }
+
+ public void configure(Application application) {
+ application.setExceptionHandler(new ExceptionHandler() {
+
+ @Override
+ public void handleException(Throwable throwable) {
+ CmsFeedback.show("Unexpected RWT exception", throwable);
+ }
+ });
+
+ if (e4Xmi != null) {// backward compatibility
+ addE4EntryPoint(application, path, e4Xmi, getBaseProperties());
+ } else {
+ addEntryPoints(application);
+ }
+ }
+
+ protected Map<String, String> getBaseProperties() {
+ return baseProperties;
+ }
+
+// protected void addEntryPoint(Application application, E4ApplicationConfig config, Map<String, String> properties) {
+// CmsE4EntryPointFactory entryPointFactory = new CmsE4EntryPointFactory(config);
+// application.addEntryPoint(path, entryPointFactory, properties);
+// application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+// }
+
+ protected void addE4EntryPoint(Application application, String path, String e4Xmi, Map<String, String> properties) {
+ E4ApplicationConfig config = createE4ApplicationConfig(e4Xmi);
+ CmsE4EntryPointFactory entryPointFactory = new CmsE4EntryPointFactory(config);
+ application.addEntryPoint(path, entryPointFactory, properties);
+ application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+ }
+
+ /**
+ * To be overridden for further configuration.
+ *
+ * @see E4ApplicationConfig
+ */
+ protected E4ApplicationConfig createE4ApplicationConfig(String e4Xmi) {
+ return new E4ApplicationConfig(e4Xmi, lifeCycleUri, null, null, false, true, true);
+ }
+
+ @Deprecated
+ public void setPageTitle(String pageTitle) {
+ if (pageTitle != null)
+ baseProperties.put(WebClient.PAGE_TITLE, pageTitle);
+ }
+
+ /** Returns a new map used to customise and entry point. */
+ public Map<String, String> customise(String pageTitle) {
+ Map<String, String> custom = new HashMap<>(getBaseProperties());
+ if (pageTitle != null)
+ custom.put(WebClient.PAGE_TITLE, pageTitle);
+ return custom;
+ }
+
+ @Deprecated
+ public void setE4Xmi(String e4Xmi) {
+ this.e4Xmi = e4Xmi;
+ }
+
+ @Deprecated
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public void setLifeCycleUri(String lifeCycleUri) {
+ this.lifeCycleUri = lifeCycleUri;
+ }
+
+ protected BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ protected void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public String getContextName() {
+ return contextName;
+ }
+
+ public void setContextName(String contextName) {
+ this.contextName = contextName;
+ }
+
+ public void init(BundleContext bundleContext, Map<String, Object> properties) {
+ this.bundleContext = bundleContext;
+ for (String key : properties.keySet()) {
+ Object value = properties.get(key);
+ if (value != null)
+ baseProperties.put(key, value.toString());
+ }
+
+ if (properties.containsKey(CONTEXT_NAME_PROPERTY)) {
+ assert properties.get(CONTEXT_NAME_PROPERTY) != null;
+ contextName = properties.get(CONTEXT_NAME_PROPERTY).toString();
+ } else {
+ contextName = "<unknown context>";
+ }
+ }
+
+ public void destroy(Map<String, Object> properties) {
+
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.rap;
+
+import org.eclipse.rap.rwt.application.Application;
+
+/**
+ * Access to canonical views of the core CMS concepts, useful for devleopers and
+ * operators.
+ */
+public class CmsE4AdminApp extends AbstractRapE4App {
+ @Override
+ protected void addEntryPoints(Application application) {
+ addE4EntryPoint(application, "/devops", "org.argeo.cms.e4/e4xmi/cms-devops.e4xmi",
+ customise("Argeo CMS DevOps"));
+ addE4EntryPoint(application, "/ego", "org.argeo.cms.e4/e4xmi/cms-ego.e4xmi", customise("Argeo CMS Ego"));
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.rap;
+
+import java.security.PrivilegedAction;
+
+import javax.security.auth.Subject;
+
+import org.eclipse.rap.e4.E4ApplicationConfig;
+import org.eclipse.rap.e4.E4EntryPointFactory;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+
+public class CmsE4EntryPointFactory extends E4EntryPointFactory {
+ public final static String DEFAULT_LIFECYCLE_URI = "bundleclass://org.argeo.cms.e4.rap/org.argeo.cms.e4.rap.CmsLoginLifecycle";
+
+ public CmsE4EntryPointFactory(E4ApplicationConfig config) {
+ super(config);
+ }
+
+ public CmsE4EntryPointFactory(String e4Xmi, String lifeCycleUri) {
+ super(defaultConfig(e4Xmi, lifeCycleUri));
+ }
+
+ public CmsE4EntryPointFactory(String e4Xmi) {
+ this(e4Xmi, DEFAULT_LIFECYCLE_URI);
+ }
+
+ public static E4ApplicationConfig defaultConfig(String e4Xmi, String lifeCycleUri) {
+ E4ApplicationConfig config = new E4ApplicationConfig(e4Xmi, lifeCycleUri, null, null, false, true, true);
+ return config;
+ }
+
+ @Override
+ public EntryPoint create() {
+ EntryPoint ep = createEntryPoint();
+ EntryPoint authEp = new EntryPoint() {
+
+ @Override
+ public int createUI() {
+ Subject subject = new Subject();
+ return Subject.doAs(subject, new PrivilegedAction<Integer>() {
+
+ @Override
+ public Integer run() {
+ // SPNEGO
+ // 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");
+ // }
+
+ JavaScriptExecutor jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
+ Integer exitCode = ep.createUI();
+ jsExecutor.execute("location.reload()");
+ return exitCode;
+ }
+
+ });
+ }
+ };
+ return authEp;
+ }
+
+ protected EntryPoint createEntryPoint() {
+ return super.create();
+ }
+}
--- /dev/null
+package org.argeo.cms.e4.rap;
+
+import java.security.AccessController;
+import java.util.UUID;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.api.cms.ux.UxContext;
+import org.argeo.cms.auth.CurrentUser;
+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.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
+import org.eclipse.e4.ui.workbench.lifecycle.PreSave;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.client.service.BrowserNavigation;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+@SuppressWarnings("restriction")
+public class CmsLoginLifecycle implements CmsView {
+ private final static CmsLog log = CmsLog.getLog(CmsLoginLifecycle.class);
+
+ private UxContext uxContext;
+ private CmsImageManager imageManager;
+
+ private LoginContext loginContext;
+ private BrowserNavigation browserNavigation;
+
+ private String state = null;
+ private String uid;
+
+ @PostContextCreate
+ boolean login(final IEventBroker eventBroker) {
+ uid = UUID.randomUUID().toString();
+ browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
+ if (browserNavigation != null)
+ browserNavigation.addBrowserNavigationListener(new BrowserNavigationListener() {
+ private static final long serialVersionUID = -3668136623771902865L;
+
+ @Override
+ public void navigated(BrowserNavigationEvent event) {
+ state = event.getState();
+ if (uxContext != null)// is logged in
+ stateChanged();
+ }
+ });
+
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ Display display = Display.getCurrent();
+// UiContext.setData(CmsView.KEY, this);
+ // FIXME get CMS context
+ CmsLoginShell loginShell = new CmsLoginShell(this, null);
+ CmsSwtUtils.registerCmsView(loginShell.getShell(), this);
+ loginShell.setSubject(subject);
+ try {
+ // try pre-auth
+ loginContext = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER, subject, loginShell);
+ loginContext.login();
+ } catch (LoginException e) {
+ loginShell.createUi();
+ loginShell.open();
+
+ while (!loginShell.getShell().isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ }
+ if (CurrentUser.getUsername(getSubject()) == null)
+ return false;
+ uxContext = new SimpleSwtUxContext();
+ imageManager = new SimpleImageManager();
+
+ eventBroker.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE, new EventHandler() {
+ @Override
+ public void handleEvent(Event event) {
+ startupComplete();
+ eventBroker.unsubscribe(this);
+ }
+ });
+
+ // lcs.changeApplicationLocale(Locale.FRENCH);
+ return true;
+ }
+
+ @PreSave
+ void destroy() {
+ // logout();
+ }
+
+ @Override
+ public UxContext getUxContext() {
+ return uxContext;
+ }
+
+ @Override
+ public void navigateTo(String state) {
+ browserNavigation.pushState(state, state);
+ }
+
+ @Override
+ public void authChange(LoginContext loginContext) {
+ if (loginContext == null)
+ throw new IllegalArgumentException("Login context cannot be null");
+ // logout previous login context
+ // if (this.loginContext != null)
+ // try {
+ // this.loginContext.logout();
+ // } catch (LoginException e1) {
+ // System.err.println("Could not log out: " + e1);
+ // }
+ this.loginContext = loginContext;
+ }
+
+ @Override
+ public void logout() {
+ if (loginContext == null)
+ throw new IllegalStateException("Login context should not be null");
+ try {
+ CurrentUser.logoutCmsSession(loginContext.getSubject());
+ loginContext.logout();
+ } catch (LoginException e) {
+ throw new IllegalStateException("Cannot log out", e);
+ }
+ }
+
+ @Override
+ public void exception(Throwable e) {
+ String msg = "Unexpected exception in Eclipse 4 RAP";
+ log.error(msg, e);
+ CmsFeedback.show(msg, e);
+ }
+
+ @Override
+ public CmsImageManager getImageManager() {
+ return imageManager;
+ }
+
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return CurrentUser.isAnonymous(getSubject());
+ }
+
+ @Override
+ public String getUid() {
+ return uid;
+ }
+
+ // CALLBACKS
+ protected void startupComplete() {
+ }
+
+ protected void stateChanged() {
+
+ }
+
+ // GETTERS
+ protected BrowserNavigation getBrowserNavigation() {
+ return browserNavigation;
+ }
+
+ protected String getState() {
+ return state;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.rap;
+
+import java.util.Enumeration;
+
+import org.apache.commons.io.FilenameUtils;
+import org.argeo.api.cms.CmsLog;
+import org.eclipse.rap.rwt.application.Application;
+import org.osgi.framework.Bundle;
+
+/** Simple RAP app which loads all e4xmi files. */
+public class SimpleRapE4App extends AbstractRapE4App {
+ private final static CmsLog log = CmsLog.getLog(SimpleRapE4App.class);
+
+ private String baseE4xmi = "/e4xmi";
+
+ @Override
+ protected void addEntryPoints(Application application) {
+ Bundle bundle = getBundleContext().getBundle();
+ Enumeration<String> paths = bundle.getEntryPaths(baseE4xmi);
+ while (paths.hasMoreElements()) {
+ String p = paths.nextElement();
+ if (p.endsWith(".e4xmi")) {
+ String e4xmiPath = bundle.getSymbolicName() + '/' + p;
+ String name = '/' + FilenameUtils.removeExtension(FilenameUtils.getName(p));
+ addE4EntryPoint(application, name, e4xmiPath, getBaseProperties());
+ if (log.isDebugEnabled())
+ log.debug("Registered " + e4xmiPath + " as " + getContextName() + name);
+ }
+ }
+ }
+
+}
--- /dev/null
+/** Eclipse 4 RAP specific extensions. */
+package org.argeo.cms.e4.rap;
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.swt.rap.cli</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+Import-Package: \
+org.eclipse.jetty.util.component;version="[9.4,12)";resolution:=optional,\
+org.eclipse.jetty.http;version="[9.4,12)";resolution:=optional,\
+org.eclipse.jetty.io;version="[9.4,12)";resolution:=optional,\
+org.eclipse.jetty.security;version="[9.4,12)";resolution:=optional,\
+org.eclipse.jetty.server.handler;version="[9.4,12)";resolution:=optional,\
+org.eclipse.jetty.*;version="[9.4,12)";resolution:=optional,\
+*
\ No newline at end of file
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+package org.argeo.cms.swt.rap.cli;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.argeo.api.acr.spi.ProvidedRepository;
+import org.argeo.api.cli.CommandsCli;
+import org.argeo.api.cli.DescribedCommand;
+import org.argeo.api.cms.CmsApp;
+import org.argeo.api.cms.CmsContext;
+import org.argeo.cms.runtime.StaticCms;
+import org.argeo.cms.swt.app.CmsUserApp;
+import org.argeo.cms.web.CmsWebApp;
+import org.argeo.util.register.Component;
+import org.argeo.util.register.ComponentRegister;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+
+public class CmsRapCli extends CommandsCli {
+
+ public CmsRapCli(String commandName) {
+ super(commandName);
+ addCommand("user", new Launch());
+ }
+
+ @Override
+ public String getDescription() {
+ return "Argeo CMS utilities.";
+ }
+
+ public static void main(String[] args) {
+ mainImpl(new CmsRapCli("web"), args);
+ }
+
+ static class Launch implements DescribedCommand<String> {
+ private Option dataOption;
+ private Option uiOption;
+
+ @Override
+ public Options getOptions() {
+ Options options = new Options();
+ dataOption = Option.builder().longOpt("data").hasArg().required()
+ .desc("path to the writable data area (mandatory)").build();
+ uiOption = Option.builder().longOpt("ui").desc("open a user interface").build();
+ options.addOption(dataOption);
+ options.addOption(uiOption);
+ return options;
+ }
+
+ @Override
+ public String apply(List<String> args) {
+ CommandLine cl = toCommandLine(args);
+ String dataPath = cl.getOptionValue(dataOption);
+ boolean ui = cl.hasOption(uiOption);
+
+ Path instancePath = Paths.get(dataPath);
+ System.setProperty("osgi.instance.area", instancePath.toUri().toString());
+
+ StaticCms staticCms = new StaticCms() {
+ @Override
+ protected void addComponents(ComponentRegister register) {
+ if (ui) {
+ CmsUserApp cmsApp = new CmsUserApp();
+ Component<CmsUserApp> cmsAppC = new Component.Builder<>(cmsApp) //
+ .addType(CmsApp.class) //
+ .addType(CmsUserApp.class) //
+ .addDependency(register.getSingleton(CmsContext.class), cmsApp::setCmsContext, null) //
+ .addDependency(register.getSingleton(ProvidedRepository.class),
+ cmsApp::setContentRepository, null) //
+ .build(register);
+
+ CmsWebApp cmsWebApp = new CmsWebApp();
+ Component<CmsWebApp> cmsWebAppC = new Component.Builder<>(cmsWebApp) //
+ .addType(ApplicationConfiguration.class) //
+ .addDependency(cmsAppC.getType(CmsApp.class), cmsWebApp::setCmsApp, null) //
+ .build(register);
+
+ RwtRunner rwtRunner = new RwtRunner();
+ Component<RwtRunner> rwtRunnerC = new Component.Builder<>(rwtRunner) //
+ .addActivation(rwtRunner::init) //
+ .addDeactivation(rwtRunner::destroy) //
+ .addType(RwtRunner.class) //
+ .addDependency(cmsWebAppC.getType(ApplicationConfiguration.class),
+ rwtRunner::setApplicationConfiguration, null) //
+ .build(register);
+ }
+ }
+
+ };
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> staticCms.stop(), "Static CMS Shutdown"));
+ staticCms.start();
+
+ long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
+ System.out.println("Static CMS available in " + jvmUptime + " ms.");
+
+ if (ui) {
+ try {
+ // open browser in app mode
+ Thread.sleep(2000);// wait for RWT to be ready
+ Runtime.getRuntime().exec("google-chrome --app=http://localhost:"
+ + staticCms.getComponentRegister().getObject(RwtRunner.class).getEffectivePort() + "/data");
+ } catch (InterruptedException | IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ staticCms.waitForStop();
+
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Launch a static CMS.";
+ }
+
+ }
+}
--- /dev/null
+package org.argeo.cms.swt.rap.cli;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.eclipse.rap.rwt.application.AbstractEntryPoint;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.ApplicationRunner;
+import org.eclipse.rap.rwt.engine.RWTServlet;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** A minimal RWT runner based on embedded Jetty. */
+public class RwtRunner {
+
+ private final Server server;
+ private final ServerConnector serverConnector;
+ private Path tempDir;
+
+ private ApplicationConfiguration applicationConfiguration;
+
+ public RwtRunner() {
+ server = new Server(new QueuedThreadPool(10, 1));
+ serverConnector = new ServerConnector(server);
+ serverConnector.setPort(0);
+ server.setConnectors(new Connector[] { serverConnector });
+ }
+
+ protected Control createUi(Composite parent, Object context) {
+ return new Label(parent, 0);
+ }
+
+ public void init() {
+ Objects.requireNonNull(applicationConfiguration);
+
+ ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ context.setContextPath("/");
+ server.setHandler(context);
+
+ String entryPoint = "data";
+
+ // rwt-resources requires a file system
+ try {
+ tempDir = Files.createTempDirectory("argeo-rwtRunner");
+ context.setBaseResource(Resource.newResource(tempDir.resolve("www").toString()));
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot create temporary directory", e);
+ }
+ context.addEventListener(new ServletContextListener() {
+ ApplicationRunner applicationRunner;
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ applicationRunner = new ApplicationRunner(applicationConfiguration, sce.getServletContext());
+ applicationRunner.start();
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ applicationRunner.stop();
+ }
+ });
+
+ context.addServlet(new ServletHolder(new RWTServlet()), "/" + entryPoint);
+
+ // Required to serve rwt-resources. It is important that this is last.
+ ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class);
+ context.addServlet(holderPwd, "/");
+
+ try {
+ server.start();
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot start Jetty server", e);
+ }
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> destroy(), "Jetty shutdown"));
+
+ long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
+ System.out.println("RWT App available in " + jvmUptime + " ms, on port " + getEffectivePort());
+ }
+
+ public void destroy() {
+ try {
+ serverConnector.close();
+ server.stop();
+ // TODO delete temp dir
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public Integer getEffectivePort() {
+ return serverConnector.getLocalPort();
+ }
+
+ public void waitFor() throws InterruptedException {
+ server.join();
+ }
+
+ public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
+ this.applicationConfiguration = applicationConfiguration;
+ }
+
+ public static void main(String[] args) throws Exception {
+ RwtRunner rwtRunner = new RwtRunner();
+
+ String entryPoint = "app";
+ ApplicationConfiguration applicationConfiguration = (application) -> application.addEntryPoint("/" + entryPoint,
+ () -> new AbstractEntryPoint() {
+ private static final long serialVersionUID = 5678385921969090733L;
+
+ @Override
+ protected void createContents(Composite parent) {
+ Label label = new Label(parent, 0);
+ label.setText("Hello world!");
+ }
+ }, null);
+
+ rwtRunner.setApplicationConfiguration(applicationConfiguration);
+ rwtRunner.init();
+
+ // open browser in app mode
+ Thread.sleep(2000);// wait for RWT to be ready
+ Runtime.getRuntime().exec("google-chrome --app=http://localhost:" + rwtRunner.getEffectivePort() + "/app");
+
+ rwtRunner.waitFor();
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.ui.rap</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="CMS Web App Factory">
+ <implementation class="org.argeo.cms.web.osgi.CmsWebAppFactory"/>
+ <reference bind="addCmsApp" cardinality="0..n" interface="org.argeo.api.cms.CmsApp" name="CmsApp" policy="dynamic" unbind="removeCmsApp"/>
+ <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
+</scr:component>
--- /dev/null
+Import-Package:\
+org.argeo.api.acr,\
+org.eclipse.swt,\
+org.argeo.eclipse.ui,\
+javax.jcr.nodetype,\
+javax.jcr.security,\
+org.eclipse.swt.graphics,\
+javax.servlet.*;version="[3,5)",\
+*
+
+Service-Component: OSGI-INF/cmsWebAppFactory.xml
+
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/cmsWebAppFactory.xml
+source.. = src/
+additional.bundles = org.argeo.ext.slf4j,\
+ org.slf4j.api
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.script.Invocable;
+import javax.script.ScriptException;
+
+import org.argeo.api.cms.CmsConstants;
+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.web.SimpleErgonomics;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.application.EntryPointFactory;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.BundleContext;
+
+public class AppUi implements CmsUiProvider, Branding {
+ private final CmsScriptApp app;
+
+ private CmsUiProvider ui;
+ private String createUi;
+ private Object impl;
+ private String script;
+ // private Branding branding = new Branding();
+
+ private EntryPointFactory factory;
+
+ // Branding
+ private String themeId;
+ private String additionalHeaders;
+ private String bodyHtml;
+ private String pageTitle;
+ private String pageOverflow;
+ private String favicon;
+
+ public AppUi(CmsScriptApp app) {
+ this.app = app;
+ }
+
+ public AppUi(CmsScriptApp app, String scriptPath) {
+ this.app = app;
+ this.ui = new ScriptUi((BundleContext) app.getScriptEngine().get(CmsScriptRwtApplication.BC),
+ app.getScriptEngine(), scriptPath);
+ }
+
+ public AppUi(CmsScriptApp app, CmsUiProvider uiProvider) {
+ this.app = app;
+ this.ui = uiProvider;
+ }
+
+ public AppUi(CmsScriptApp app, EntryPointFactory factory) {
+ this.app = app;
+ this.factory = factory;
+ }
+
+ public void apply(Repository repository, Application application, Branding appBranding, String path) {
+ Map<String, String> factoryProperties = new HashMap<>();
+ if (appBranding != null)
+ appBranding.applyBranding(factoryProperties);
+ applyBranding(factoryProperties);
+ if (factory != null) {
+ application.addEntryPoint("/" + path, factory, factoryProperties);
+ } else {
+ EntryPointFactory entryPointFactory = new EntryPointFactory() {
+ @Override
+ public EntryPoint create() {
+ SimpleErgonomics ergonomics = new SimpleErgonomics(repository, CmsConstants.SYS_WORKSPACE,
+ "/home/root/argeo:keyring", AppUi.this, factoryProperties);
+// CmsUiProvider header = app.getHeader();
+// if (header != null)
+// ergonomics.setHeader(header);
+ app.applySides(ergonomics);
+ Integer headerHeight = app.getHeaderHeight();
+ if (headerHeight != null)
+ ergonomics.setHeaderHeight(headerHeight);
+ return ergonomics;
+ }
+ };
+ application.addEntryPoint("/" + path, entryPointFactory, factoryProperties);
+ }
+ }
+
+ public void setUi(CmsUiProvider uiProvider) {
+ this.ui = uiProvider;
+ }
+
+ public void applyBranding(Map<String, String> properties) {
+ if (themeId != null)
+ properties.put(WebClient.THEME_ID, themeId);
+ if (additionalHeaders != null)
+ properties.put(WebClient.HEAD_HTML, additionalHeaders);
+ if (bodyHtml != null)
+ properties.put(WebClient.BODY_HTML, bodyHtml);
+ if (pageTitle != null)
+ properties.put(WebClient.PAGE_TITLE, pageTitle);
+ if (pageOverflow != null)
+ properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
+ if (favicon != null)
+ properties.put(WebClient.FAVICON, favicon);
+ }
+
+ // public Branding getBranding() {
+ // return branding;
+ // }
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ CmsPane cmsPane = new CmsPane(parent, SWT.NONE);
+
+ if (false) {
+ // QA
+ CmsSwtUtils.style(cmsPane.getQaArea(), "qa");
+ Button reload = new Button(cmsPane.getQaArea(), SWT.FLAT);
+ CmsSwtUtils.style(reload, "qa");
+ reload.setText("Reload");
+ reload.addSelectionListener(new Selected() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ new Thread() {
+ @Override
+ public void run() {
+ app.reload();
+ }
+ }.start();
+ RWT.getClient().getService(JavaScriptExecutor.class)
+ .execute("setTimeout('location.reload()',1000)");
+ }
+ });
+
+ // Support
+ CmsSwtUtils.style(cmsPane.getSupportArea(), "support");
+ Label msg = new Label(cmsPane.getSupportArea(), SWT.NONE);
+ CmsSwtUtils.style(msg, "support");
+ msg.setText("UNSUPPORTED DEVELOPMENT VERSION");
+ }
+
+ if (ui != null) {
+ ui.createUi(cmsPane.getMainArea(), context);
+ }
+ if (createUi != null) {
+ Invocable invocable = (Invocable) app.getScriptEngine();
+ try {
+ invocable.invokeFunction(createUi, cmsPane.getMainArea(), context);
+
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ if (impl != null) {
+ Invocable invocable = (Invocable) app.getScriptEngine();
+ try {
+ invocable.invokeMethod(impl, "createUi", cmsPane.getMainArea(), context);
+
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ // Invocable invocable = (Invocable) app.getScriptEngine();
+ // try {
+ // invocable.invokeMethod(AppUi.this, "initUi", parent, context);
+ //
+ // } catch (NoSuchMethodException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // } catch (ScriptException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+
+ return null;
+ }
+
+ public void setCreateUi(String createUi) {
+ this.createUi = createUi;
+ }
+
+ public void setImpl(Object impl) {
+ this.impl = impl;
+ }
+
+ public Object getImpl() {
+ return impl;
+ }
+
+ public String getScript() {
+ return script;
+ }
+
+ public void setScript(String script) {
+ this.script = script;
+ }
+
+ // Branding
+ public String getThemeId() {
+ return themeId;
+ }
+
+ public void setThemeId(String themeId) {
+ this.themeId = themeId;
+ }
+
+ public String getAdditionalHeaders() {
+ return additionalHeaders;
+ }
+
+ public void setAdditionalHeaders(String additionalHeaders) {
+ this.additionalHeaders = additionalHeaders;
+ }
+
+ public String getBodyHtml() {
+ return bodyHtml;
+ }
+
+ public void setBodyHtml(String bodyHtml) {
+ this.bodyHtml = bodyHtml;
+ }
+
+ public String getPageTitle() {
+ return pageTitle;
+ }
+
+ public void setPageTitle(String pageTitle) {
+ this.pageTitle = pageTitle;
+ }
+
+ public String getPageOverflow() {
+ return pageOverflow;
+ }
+
+ public void setPageOverflow(String pageOverflow) {
+ this.pageOverflow = pageOverflow;
+ }
+
+ public String getFavicon() {
+ return favicon;
+ }
+
+ public void setFavicon(String favicon) {
+ this.favicon = favicon;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.util.Map;
+
+public interface Branding {
+ public void applyBranding(Map<String, String> properties);
+
+ public String getThemeId();
+
+ public String getAdditionalHeaders();
+
+ public String getBodyHtml();
+
+ public String getPageTitle();
+
+ public String getPageOverflow();
+
+ public String getFavicon();
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.script.ScriptEngine;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsTheme;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.ui.CmsUiConstants;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.web.BundleResourceLoader;
+import org.argeo.cms.web.SimpleErgonomics;
+import org.argeo.cms.web.WebThemeUtils;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.Application.OperationMode;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+
+public class CmsScriptApp implements Branding {
+ public final static String CONTEXT_NAME = "contextName";
+
+ ServiceRegistration<ApplicationConfiguration> appConfigReg;
+
+ private ScriptEngine scriptEngine;
+
+ private final static CmsLog log = CmsLog.getLog(CmsScriptApp.class);
+
+ private String webPath;
+ private String repo = "(cn=node)";
+
+ // private Branding branding = new Branding();
+ private CmsTheme theme;
+
+ private List<String> resources = new ArrayList<>();
+
+ private Map<String, AppUi> ui = new HashMap<>();
+
+ private CmsUiProvider header;
+ private Integer headerHeight = null;
+ private CmsUiProvider lead;
+ private CmsUiProvider end;
+ private CmsUiProvider footer;
+
+ // Branding
+ private String themeId;
+ private String additionalHeaders;
+ private String bodyHtml;
+ private String pageTitle;
+ private String pageOverflow;
+ private String favicon;
+
+ public CmsScriptApp(ScriptEngine scriptEngine) {
+ super();
+ this.scriptEngine = scriptEngine;
+ }
+
+ public void apply(BundleContext bundleContext, Repository repository, Application application) {
+ BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
+
+ application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+ // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
+
+ application.setExceptionHandler(new CmsExceptionHandler());
+
+ // loading animated gif
+ application.addResource(CmsUiConstants.LOADING_IMAGE, createResourceLoader(CmsUiConstants.LOADING_IMAGE));
+ // empty image
+ application.addResource(CmsUiConstants.NO_IMAGE, createResourceLoader(CmsUiConstants.NO_IMAGE));
+
+ for (String resource : resources) {
+ application.addResource(resource, bundleRL);
+ if (log.isTraceEnabled())
+ log.trace("Resource " + resource);
+ }
+
+ if (theme != null) {
+ WebThemeUtils.apply(application, theme);
+ String themeHeaders = theme.getHtmlHeaders();
+ if (themeHeaders != null) {
+ if (additionalHeaders == null)
+ additionalHeaders = themeHeaders;
+ else
+ additionalHeaders = themeHeaders + "\n" + additionalHeaders;
+ }
+ themeId = theme.getThemeId();
+ }
+
+ // client JavaScript
+ Bundle appBundle = bundleRL.getBundle();
+ BundleContext bc = appBundle.getBundleContext();
+ HttpService httpService = bc.getService(bc.getServiceReference(HttpService.class));
+ HttpContext httpContext = new BundleHttpContext(bc);
+ Enumeration<URL> themeResources = appBundle.findEntries("/js/", "*", true);
+ if (themeResources != null)
+ bundleResources: while (themeResources.hasMoreElements()) {
+ try {
+ String name = themeResources.nextElement().getPath();
+ if (name.endsWith("/"))
+ continue bundleResources;
+ String alias = "/" + getWebPath() + name;
+
+ httpService.registerResources(alias, name, httpContext);
+ if (log.isDebugEnabled())
+ log.debug("Mapped " + name + " to alias " + alias);
+
+ } catch (NamespaceException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ // App UIs
+ for (String appUiName : ui.keySet()) {
+ AppUi appUi = ui.get(appUiName);
+ appUi.apply(repository, application, this, appUiName);
+
+ }
+
+ }
+
+ public void applySides(SimpleErgonomics simpleErgonomics) {
+ simpleErgonomics.setHeader(header);
+ simpleErgonomics.setLead(lead);
+ simpleErgonomics.setEnd(end);
+ simpleErgonomics.setFooter(footer);
+ }
+
+ public void register(BundleContext bundleContext, ApplicationConfiguration appConfig) {
+ Hashtable<String, String> props = new Hashtable<>();
+ props.put(CONTEXT_NAME, webPath);
+ appConfigReg = bundleContext.registerService(ApplicationConfiguration.class, appConfig, props);
+ }
+
+ public void reload() {
+ BundleContext bundleContext = appConfigReg.getReference().getBundle().getBundleContext();
+ ApplicationConfiguration appConfig = bundleContext.getService(appConfigReg.getReference());
+ appConfigReg.unregister();
+ register(bundleContext, appConfig);
+
+ // BundleContext bundleContext = (BundleContext)
+ // getScriptEngine().get("bundleContext");
+ // try {
+ // Bundle bundle = bundleContext.getBundle();
+ // bundle.stop();
+ // bundle.start();
+ // } catch (BundleException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+ }
+
+ private static ResourceLoader createResourceLoader(final String resourceName) {
+ return new ResourceLoader() {
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ return getClass().getClassLoader().getResourceAsStream(resourceName);
+ }
+ };
+ }
+
+ public List<String> getResources() {
+ return resources;
+ }
+
+ public AppUi newUi(String name) {
+ if (ui.containsKey(name))
+ throw new IllegalArgumentException("There is already an UI named " + name);
+ AppUi appUi = new AppUi(this);
+ // appUi.setApp(this);
+ ui.put(name, appUi);
+ return appUi;
+ }
+
+ public void addUi(String name, AppUi appUi) {
+ if (ui.containsKey(name))
+ throw new IllegalArgumentException("There is already an UI named " + name);
+ // appUi.setApp(this);
+ ui.put(name, appUi);
+ }
+
+ public void applyBranding(Map<String, String> properties) {
+ if (themeId != null)
+ properties.put(WebClient.THEME_ID, themeId);
+ if (additionalHeaders != null)
+ properties.put(WebClient.HEAD_HTML, additionalHeaders);
+ if (bodyHtml != null)
+ properties.put(WebClient.BODY_HTML, bodyHtml);
+ if (pageTitle != null)
+ properties.put(WebClient.PAGE_TITLE, pageTitle);
+ if (pageOverflow != null)
+ properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
+ if (favicon != null)
+ properties.put(WebClient.FAVICON, favicon);
+ }
+
+ class CmsExceptionHandler implements ExceptionHandler {
+
+ @Override
+ public void handleException(Throwable throwable) {
+ // TODO be smarter
+ CmsUiUtils.getCmsView().exception(throwable);
+ }
+
+ }
+
+ // public Branding getBranding() {
+ // return branding;
+ // }
+
+ ScriptEngine getScriptEngine() {
+ return scriptEngine;
+ }
+
+ public static String toJson(Node node) {
+ try {
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+ PropertyIterator pit = node.getProperties();
+ int count = 0;
+ while (pit.hasNext()) {
+ Property p = pit.nextProperty();
+ int type = p.getType();
+ if (type == PropertyType.REFERENCE || type == PropertyType.WEAKREFERENCE || type == PropertyType.PATH) {
+ Node ref = p.getNode();
+ if (count != 0)
+ sb.append(',');
+ // TODO limit depth?
+ sb.append(toJson(ref));
+ count++;
+ } else if (!p.isMultiple()) {
+ if (count != 0)
+ sb.append(',');
+ sb.append('\"').append(p.getName()).append("\":\"").append(p.getString()).append('\"');
+ count++;
+ }
+ }
+ sb.append('}');
+ return sb.toString();
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot convert " + node + " to JSON", e);
+ }
+ }
+
+ public void fromJson(Node node, String json) {
+ // TODO
+ }
+
+ public CmsTheme getTheme() {
+ return theme;
+ }
+
+ public void setTheme(CmsTheme theme) {
+ this.theme = theme;
+ }
+
+ public String getWebPath() {
+ return webPath;
+ }
+
+ public void setWebPath(String context) {
+ this.webPath = context;
+ }
+
+ public String getRepo() {
+ return repo;
+ }
+
+ public void setRepo(String repo) {
+ this.repo = repo;
+ }
+
+ public Map<String, AppUi> getUi() {
+ return ui;
+ }
+
+ public void setUi(Map<String, AppUi> ui) {
+ this.ui = ui;
+ }
+
+ // Branding
+ public String getThemeId() {
+ return themeId;
+ }
+
+ public void setThemeId(String themeId) {
+ this.themeId = themeId;
+ }
+
+ public String getAdditionalHeaders() {
+ return additionalHeaders;
+ }
+
+ public void setAdditionalHeaders(String additionalHeaders) {
+ this.additionalHeaders = additionalHeaders;
+ }
+
+ public String getBodyHtml() {
+ return bodyHtml;
+ }
+
+ public void setBodyHtml(String bodyHtml) {
+ this.bodyHtml = bodyHtml;
+ }
+
+ public String getPageTitle() {
+ return pageTitle;
+ }
+
+ public void setPageTitle(String pageTitle) {
+ this.pageTitle = pageTitle;
+ }
+
+ public String getPageOverflow() {
+ return pageOverflow;
+ }
+
+ public void setPageOverflow(String pageOverflow) {
+ this.pageOverflow = pageOverflow;
+ }
+
+ public String getFavicon() {
+ return favicon;
+ }
+
+ public void setFavicon(String favicon) {
+ this.favicon = favicon;
+ }
+
+ public CmsUiProvider getHeader() {
+ return header;
+ }
+
+ public void setHeader(CmsUiProvider header) {
+ this.header = header;
+ }
+
+ public Integer getHeaderHeight() {
+ return headerHeight;
+ }
+
+ public void setHeaderHeight(Integer headerHeight) {
+ this.headerHeight = headerHeight;
+ }
+
+ public CmsUiProvider getLead() {
+ return lead;
+ }
+
+ public void setLead(CmsUiProvider lead) {
+ this.lead = lead;
+ }
+
+ public CmsUiProvider getEnd() {
+ return end;
+ }
+
+ public void setEnd(CmsUiProvider end) {
+ this.end = end;
+ }
+
+ public CmsUiProvider getFooter() {
+ return footer;
+ }
+
+ public void setFooter(CmsUiProvider footer) {
+ this.footer = footer;
+ }
+
+ static class BundleHttpContext implements HttpContext {
+ private BundleContext bundleContext;
+
+ public BundleHttpContext(BundleContext bundleContext) {
+ super();
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ // TODO Auto-generated method stub
+ return true;
+ }
+
+ @Override
+ public URL getResource(String name) {
+
+ return bundleContext.getBundle().getEntry(name);
+ }
+
+ @Override
+ public String getMimeType(String name) {
+ return null;
+ }
+
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+
+import javax.jcr.Repository;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.swt.CmsException;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.wiring.BundleWiring;
+
+public class CmsScriptRwtApplication implements ApplicationConfiguration {
+ public final static String APP = "APP";
+ public final static String BC = "BC";
+
+ private final CmsLog log = CmsLog.getLog(CmsScriptRwtApplication.class);
+
+ BundleContext bundleContext;
+ Repository repository;
+
+ ScriptEngine engine;
+
+ public void init(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
+ ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
+ try {
+// Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
+// ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
+// engine = scriptEngineManager.getEngineByName("JavaScript");
+// if (engine == null) {// Nashorn
+// Thread.currentThread().setContextClassLoader(originalCcl);
+// scriptEngineManager = new ScriptEngineManager();
+// Thread.currentThread().setContextClassLoader(bundleCl);
+// engine = scriptEngineManager.getEngineByName("JavaScript");
+// }
+ engine = loadScriptEngine(originalCcl, bundleCl);
+
+ // Load script
+ URL appUrl = bundleContext.getBundle().getEntry("cms/app.js");
+ // System.out.println("Loading " + appUrl);
+ // System.out.println("Loading " + appUrl.getHost());
+ // System.out.println("Loading " + appUrl.getPath());
+
+ CmsScriptApp app = new CmsScriptApp(engine);
+ engine.put(APP, app);
+ engine.put(BC, bundleContext);
+ try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+ engine.eval(reader);
+ } catch (IOException | ScriptException e) {
+ throw new CmsException("Cannot execute " + appUrl, e);
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("CMS script app initialized from " + appUrl);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ Thread.currentThread().setContextClassLoader(originalCcl);
+ }
+ }
+
+ public void destroy(BundleContext bundleContext) {
+ engine = null;
+ }
+
+ @Override
+ public void configure(Application application) {
+ load(application);
+ }
+
+ void load(Application application) {
+ CmsScriptApp app = getApp();
+ app.apply(bundleContext, repository, application);
+ if (log.isDebugEnabled())
+ log.debug("CMS script app loaded to " + app.getWebPath());
+ }
+
+ CmsScriptApp getApp() {
+ if (engine == null)
+ throw new IllegalStateException("CMS script app is not initialized");
+ return (CmsScriptApp) engine.get(APP);
+ }
+
+ void update() {
+
+ try {
+ bundleContext.getBundle().update();
+ } catch (BundleException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ private static ScriptEngine loadScriptEngine(ClassLoader originalCcl, ClassLoader bundleCl) {
+ Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
+ ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
+ ScriptEngine engine = scriptEngineManager.getEngineByName("JavaScript");
+ if (engine == null) {// Nashorn
+ Thread.currentThread().setContextClassLoader(originalCcl);
+ scriptEngineManager = new ScriptEngineManager();
+ Thread.currentThread().setContextClassLoader(bundleCl);
+ engine = scriptEngineManager.getEngineByName("JavaScript");
+ }
+ return engine;
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import javax.jcr.Repository;
+
+import org.argeo.api.cms.CmsLog;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class ScriptAppActivator implements BundleActivator {
+ private final static CmsLog log = CmsLog.getLog(ScriptAppActivator.class);
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ try {
+ CmsScriptRwtApplication appConfig = new CmsScriptRwtApplication();
+ appConfig.init(context);
+ CmsScriptApp app = appConfig.getApp();
+ ServiceTracker<Repository, Repository> repoSt = new ServiceTracker<Repository, Repository>(context,
+ FrameworkUtil.createFilter("(&" + app.getRepo() + "(objectClass=javax.jcr.Repository))"), null) {
+
+ @Override
+ public Repository addingService(ServiceReference<Repository> reference) {
+ Repository repository = super.addingService(reference);
+ appConfig.setRepository(repository);
+ CmsScriptApp app = appConfig.getApp();
+ app.register(context, appConfig);
+ return repository;
+ }
+
+ };
+ repoSt.open();
+ } catch (Exception e) {
+ log.error("Cannot initialise script bundle " + context.getBundle().getSymbolicName(), e);
+ throw e;
+ }
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.net.URL;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.BundleContext;
+
+class ScriptUi implements CmsUiProvider {
+ private final static CmsLog log = CmsLog.getLog(ScriptUi.class);
+
+ private boolean development = true;
+ private ScriptEngine scriptEngine;
+
+ private URL appUrl;
+ // private BundleContext bundleContext;
+ // private String path;
+
+ // private Bindings bindings;
+ // private String script;
+
+ public ScriptUi(BundleContext bundleContext,ScriptEngine scriptEngine, String path) {
+ this.scriptEngine = scriptEngine;
+//// ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
+// ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
+// ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
+// try {
+//// Thread.currentThread().setContextClassLoader(bundleCl);
+//// scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
+//// scriptEngine.put(CmsScriptRwtApplication.BC, bundleContext);
+// scriptEngine = CmsScriptRwtApplication.loadScriptEngine(originalCcl, bundleCl);
+//
+// } catch (Exception e) {
+// e.printStackTrace();
+// } finally {
+// Thread.currentThread().setContextClassLoader(originalCcl);
+// }
+ this.appUrl = bundleContext.getBundle().getEntry(path);
+ load();
+ }
+
+ private void load() {
+// try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+// scriptEngine.eval(reader);
+// } catch (IOException | ScriptException e) {
+// log.warn("Cannot execute " + appUrl, e);
+// }
+
+ try {
+ scriptEngine.eval("load('" + appUrl + "')");
+ } catch (ScriptException e) {
+ log.warn("Cannot execute " + appUrl, e);
+ }
+
+ }
+
+ // public ScriptUiProvider(ScriptEngine scriptEngine, String script) throws
+ // ScriptException {
+ // super();
+ // this.scriptEngine = scriptEngine;
+ // this.script = script;
+ // bindings = scriptEngine.createBindings();
+ // scriptEngine.eval(script, bindings);
+ // }
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ long begin = System.currentTimeMillis();
+ // if (bindings == null) {
+ // bindings = scriptEngine.createBindings();
+ // try {
+ // scriptEngine.eval(script, bindings);
+ // } catch (ScriptException e) {
+ // log.warn("Cannot evaluate script", e);
+ // }
+ // }
+ // Bindings bindings = scriptEngine.createBindings();
+ // bindings.put("parent", parent);
+ // bindings.put("context", context);
+ // URL appUrl = bundleContext.getBundle().getEntry(path);
+ // try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+ // scriptEngine.eval(reader,bindings);
+ // } catch (IOException | ScriptException e) {
+ // log.warn("Cannot execute " + appUrl, e);
+ // }
+
+ if (development)
+ load();
+
+ Invocable invocable = (Invocable) scriptEngine;
+ try {
+ invocable.invokeFunction("createUi", parent, context);
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ long duration = System.currentTimeMillis() - begin;
+ if (log.isTraceEnabled())
+ log.trace(appUrl + " UI in " + duration + " ms");
+ return null;
+ }
+
+}
--- /dev/null
+// CMS
+var ScrolledPage = Java.type('org.argeo.cms.ui.widgets.ScrolledPage');
+
+var CmsScriptApp = Java.type('org.argeo.cms.ui.script.CmsScriptApp');
+var AppUi = Java.type('org.argeo.cms.ui.script.AppUi');
+var Theme = Java.type('org.argeo.cms.ui.script.Theme');
+var ScriptUi = Java.type('org.argeo.cms.ui.script.ScriptUi');
+var CmsUtils = Java.type('org.argeo.cms.ui.util.CmsUiUtils');
+var SimpleCmsHeader = Java.type('org.argeo.cms.ui.util.SimpleCmsHeader');
+var CmsLink = Java.type('org.argeo.cms.ui.util.CmsLink');
+var MenuLink = Java.type('org.argeo.cms.ui.util.MenuLink');
+var UserMenuLink = Java.type('org.argeo.cms.ui.util.UserMenuLink');
+
+// SWT
+var SWT = Java.type('org.eclipse.swt.SWT');
+var Composite = Java.type('org.eclipse.swt.widgets.Composite');
+var Label = Java.type('org.eclipse.swt.widgets.Label');
+var Button = Java.type('org.eclipse.swt.widgets.Button');
+var Text = Java.type('org.eclipse.swt.widgets.Text');
+var Browser = Java.type('org.eclipse.swt.browser.Browser');
+
+var FillLayout = Java.type('org.eclipse.swt.layout.FillLayout');
+var GridLayout = Java.type('org.eclipse.swt.layout.GridLayout');
+var RowLayout = Java.type('org.eclipse.swt.layout.RowLayout');
+var FormLayout = Java.type('org.eclipse.swt.layout.FormLayout');
+var GridData = Java.type('org.eclipse.swt.layout.GridData');
+
+function loadNode(node) {
+ var json = CmsScriptApp.toJson(node)
+ var fromJson = JSON.parse(json)
+ return fromJson
+}
+
+function newArea(parent, style, layout) {
+ var control = new Composite(parent, SWT.NONE)
+ control.setLayout(layout)
+ CmsUtils.style(control, style)
+ return control
+}
+
+function newLabel(parent, style, text) {
+ var control = new Label(parent, SWT.WRAP)
+ control.setText(text)
+ CmsUtils.style(control, style)
+ CmsUtils.markup(control)
+ return control
+}
+
+function newButton(parent, style, text) {
+ var control = new Button(parent, SWT.FLAT)
+ control.setText(text)
+ CmsUtils.style(control, style)
+ CmsUtils.markup(control)
+ return control
+}
+
+function newFormLabel(parent, style, text) {
+ return newLabel(parent, style, '<b>' + text + '</b>')
+}
+
+function newText(parent, style, msg) {
+ var control = new Text(parent, SWT.NONE)
+ control.setMessage(msg)
+ CmsUtils.style(control, style)
+ return control
+}
+
+function newScrolledPage(parent) {
+ var scrolled = new ScrolledPage(parent, SWT.NONE)
+ scrolled.setLayoutData(CmsUtils.fillAll())
+ scrolled.setLayout(CmsUtils.noSpaceGridLayout())
+ var page = new Composite(scrolled, SWT.NONE)
+ page.setLayout(CmsUtils.noSpaceGridLayout())
+ page.setBackgroundMode(SWT.INHERIT_NONE)
+ return page
+}
+
+function gridData(control) {
+ var gridData = new GridData()
+ control.setLayoutData(gridData)
+ return gridData
+}
+
+function gridData(control, hAlign, vAlign) {
+ var gridData = new GridData(hAlign, vAlign, false, false)
+ control.setLayoutData(gridData)
+ return gridData
+}
+
+// print(__FILE__, __LINE__, __DIR__)
--- /dev/null
+/** Argeo CMS user interface scripting. */
+package org.argeo.cms.ui.script;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.web;
+
+import static org.argeo.util.directory.ldap.SharedSecret.X_SHARED_SECRET;
+
+import java.io.IOException;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+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.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.RemoteAuthCallback;
+import org.argeo.cms.auth.RemoteAuthCallbackHandler;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.cms.servlet.ServletHttpResponse;
+import org.argeo.cms.swt.CmsException;
+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.util.directory.ldap.AuthPassword;
+import org.argeo.util.directory.ldap.SharedSecret;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.AbstractEntryPoint;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.client.service.BrowserNavigation;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/** Manages history and navigation */
+@Deprecated
+public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implements CmsView {
+ private static final long serialVersionUID = 906558779562569784L;
+
+ private final CmsLog log = CmsLog.getLog(AbstractCmsEntryPoint.class);
+
+ // private final Subject subject;
+ private LoginContext loginContext;
+
+ private final Repository repository;
+ private final String workspace;
+ private final String defaultPath;
+ private final Map<String, String> factoryProperties;
+
+ // Current state
+ private Session session;
+ private Node node;
+ private String nodePath;// useful when changing auth
+ private String state;
+ private Throwable exception;
+
+ // Client services
+ private final JavaScriptExecutor jsExecutor;
+ private final BrowserNavigation browserNavigation;
+
+ public AbstractCmsEntryPoint(Repository repository, String workspace, String defaultPath,
+ Map<String, String> factoryProperties) {
+ this.repository = repository;
+ this.workspace = workspace;
+ this.defaultPath = defaultPath;
+ this.factoryProperties = new HashMap<String, String>(factoryProperties);
+ // subject = new Subject();
+
+ // Initial login
+ LoginContext lc;
+ try {
+ lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER,
+ new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
+ new ServletHttpResponse(UiContext.getHttpResponse())));
+ lc.login();
+ } catch (LoginException e) {
+ try {
+ lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS);
+ lc.login();
+ } catch (LoginException e1) {
+ throw new CmsException("Cannot log in as anonymous", e1);
+ }
+ }
+ authChange(lc);
+
+ jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
+ browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
+ if (browserNavigation != null)
+ browserNavigation.addBrowserNavigationListener(new CmsNavigationListener());
+ }
+
+ @Override
+ protected Shell createShell(Display display) {
+ Shell shell = super.createShell(display);
+ shell.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_SHELL);
+ display.disposeExec(new Runnable() {
+
+ @Override
+ public void run() {
+ if (log.isTraceEnabled())
+ log.trace("Logging out " + session);
+ JcrUtils.logoutQuietly(session);
+ }
+ });
+ return shell;
+ }
+
+ @Override
+ protected final void createContents(final Composite parent) {
+ // UiContext.setData(CmsView.KEY, this);
+ CmsSwtUtils.registerCmsView(parent.getShell(), this);
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ try {
+ initUi(parent);
+ } catch (Exception e) {
+ throw new CmsException("Cannot create entrypoint contents", e);
+ }
+ return null;
+ }
+ });
+ }
+
+ /** Create UI */
+ protected abstract void initUi(Composite parent);
+
+ /** Recreate UI after navigation or auth change */
+ protected abstract void refresh();
+
+ /**
+ * The node to return when no node was found (for authenticated users and
+ * anonymous)
+ */
+// private Node getDefaultNode(Session session) throws RepositoryException {
+// if (!session.hasPermission(defaultPath, "read")) {
+// String userId = session.getUserID();
+// if (userId.equals(NodeConstants.ROLE_ANONYMOUS))
+// // TODO throw a special exception
+// throw new CmsException("Login required");
+// else
+// throw new CmsException("Unauthorized");
+// }
+// return session.getNode(defaultPath);
+// }
+
+ protected String getBaseTitle() {
+ return factoryProperties.get(WebClient.PAGE_TITLE);
+ }
+
+ public void navigateTo(String state) {
+ exception = null;
+ String title = setState(state);
+ doRefresh();
+ if (browserNavigation != null)
+ browserNavigation.pushState(state, title);
+ }
+
+ // @Override
+ // public synchronized Subject getSubject() {
+ // return subject;
+ // }
+
+ // @Override
+ // public LoginContext getLoginContext() {
+ // return loginContext;
+ // }
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return CurrentUser.isAnonymous(getSubject());
+ }
+
+ @Override
+ public synchronized void logout() {
+ if (loginContext == null)
+ throw new CmsException("Login context should not be null");
+ try {
+ CurrentUser.logoutCmsSession(loginContext.getSubject());
+ loginContext.logout();
+ LoginContext anonymousLc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS);
+ anonymousLc.login();
+ authChange(anonymousLc);
+ } catch (LoginException e) {
+ log.error("Cannot logout", e);
+ }
+ }
+
+ @Override
+ public synchronized void authChange(LoginContext lc) {
+ if (lc == 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 = lc;
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+
+ @Override
+ public Void run() {
+ try {
+ JcrUtils.logoutQuietly(session);
+ session = repository.login(workspace);
+ if (nodePath != null)
+ try {
+ node = session.getNode(nodePath);
+ } catch (PathNotFoundException e) {
+ navigateTo("~");
+ }
+
+ // refresh UI
+ doRefresh();
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot perform auth change", e);
+ }
+ return null;
+ }
+
+ });
+ }
+
+ @Override
+ public void exception(final Throwable e) {
+ AbstractCmsEntryPoint.this.exception = e;
+ log.error("Unexpected exception in CMS", e);
+ doRefresh();
+ }
+
+ protected synchronized void doRefresh() {
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ refresh();
+ return null;
+ }
+ });
+ }
+
+ /** Sets the state of the entry point and retrieve the related JCR node. */
+ protected synchronized String setState(String newState) {
+ String previousState = this.state;
+
+ String newNodePath = null;
+ String prefix = null;
+ this.state = newState;
+ if (newState.equals("~"))
+ this.state = "";
+
+ try {
+ int firstSlash = state.indexOf('/');
+ if (firstSlash == 0) {
+ newNodePath = state;
+ prefix = "";
+ } else if (firstSlash > 0) {
+ prefix = state.substring(0, firstSlash);
+ newNodePath = state.substring(firstSlash);
+ } else {
+ newNodePath = defaultPath;
+ prefix = state;
+
+ }
+
+ // auth
+ int colonIndex = prefix.indexOf('$');
+ if (colonIndex > 0) {
+ SharedSecret token = new SharedSecret(new AuthPassword(X_SHARED_SECRET + '$' + prefix)) {
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ super.handle(callbacks);
+ // handle HTTP context
+ for (Callback callback : callbacks) {
+ if (callback instanceof RemoteAuthCallback) {
+ ((RemoteAuthCallback) callback)
+ .setRequest(new ServletHttpRequest(UiContext.getHttpRequest()));
+ ((RemoteAuthCallback) callback)
+ .setResponse(new ServletHttpResponse(UiContext.getHttpResponse()));
+ }
+ }
+ }
+ };
+ LoginContext lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER, token);
+ lc.login();
+ authChange(lc);// sets the node as well
+ // } else {
+ // // TODO check consistency
+ // }
+ } else {
+ Node newNode = null;
+ if (session.nodeExists(newNodePath))
+ newNode = session.getNode(newNodePath);
+ else {
+// throw new CmsException("Data " + newNodePath + " does not exist");
+ newNode = null;
+ }
+ setNode(newNode);
+ }
+ String title = publishMetaData(getNode());
+
+ if (log.isTraceEnabled())
+ log.trace("node=" + newNodePath + ", state=" + state + " (prefix=" + prefix + ")");
+
+ return title;
+ } catch (Exception e) {
+ log.error("Cannot set state '" + state + "'", e);
+ if (state.equals("") || newState.equals("~") || newState.equals(previousState))
+ return "Unrecoverable exception : " + e.getClass().getSimpleName();
+ if (previousState.equals(""))
+ previousState = "~";
+ navigateTo(previousState);
+ throw new CmsException("Unexpected issue when accessing #" + newState, e);
+ }
+ }
+
+ private String publishMetaData(Node node) throws RepositoryException {
+ // Title
+ String title;
+ if (node != null && node.isNodeType(NodeType.MIX_TITLE) && node.hasProperty(Property.JCR_TITLE))
+ title = node.getProperty(Property.JCR_TITLE).getString() + " - " + getBaseTitle();
+ else
+ title = getBaseTitle();
+
+ HttpServletRequest request = UiContext.getHttpRequest();
+ if (request == null)
+ return null;
+
+ StringBuilder js = new StringBuilder();
+ if (title == null)
+ title = "";
+ title = title.replace("'", "\\'");// sanitize
+ js.append("document.title = '" + title + "';");
+ jsExecutor.execute(js.toString());
+ return title;
+ }
+
+ // Simply remove some illegal character
+ // private String clean(String stringToClean) {
+ // return stringToClean.replaceAll("'", "").replaceAll("\\n", "")
+ // .replaceAll("\\t", "");
+ // }
+
+ protected synchronized Node getNode() {
+ return node;
+ }
+
+ private synchronized void setNode(Node node) throws RepositoryException {
+ this.node = node;
+ this.nodePath = node == null ? null : node.getPath();
+ }
+
+ protected String getState() {
+ return state;
+ }
+
+ protected Throwable getException() {
+ return exception;
+ }
+
+ protected void resetException() {
+ exception = null;
+ }
+
+ protected Session getSession() {
+ return session;
+ }
+
+ private class CmsNavigationListener implements BrowserNavigationListener {
+ private static final long serialVersionUID = -3591018803430389270L;
+
+ @Override
+ public void navigated(BrowserNavigationEvent event) {
+ setState(event.getState());
+ doRefresh();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.web;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+
+/** {@link ResourceLoader} implementation wrapping an {@link Bundle}. */
+public class BundleResourceLoader implements ResourceLoader {
+ private final Bundle bundle;
+
+ public BundleResourceLoader(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ URL res = bundle.getEntry(resourceName);
+ if (res == null) {
+ res = bundle.getResource(resourceName);
+ if (res == null)
+ throw new IllegalArgumentException(
+ "Resource " + resourceName + " not found in bundle " + bundle.getSymbolicName());
+ }
+ return res.openStream();
+ }
+
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.argeo.api.cms.ux.CmsTheme;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+
+/** A RAP {@link ResourceLoader} based on a {@link CmsTheme}. */
+public class CmsThemeResourceLoader implements ResourceLoader {
+ private final CmsTheme theme;
+
+ public CmsThemeResourceLoader(CmsTheme theme) {
+ super();
+ this.theme = theme;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ return theme.getResourceAsStream(resourceName);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.argeo.api.cms.CmsApp;
+import org.argeo.api.cms.CmsAppListener;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsTheme;
+import org.argeo.api.cms.ux.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;
+import org.eclipse.rap.rwt.application.Application.OperationMode;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.event.EventAdmin;
+
+/** An RWT web app integrating with a {@link CmsApp}. */
+public class CmsWebApp implements ApplicationConfiguration, ExceptionHandler, CmsAppListener {
+ private final static CmsLog log = CmsLog.getLog(CmsWebApp.class);
+
+ private BundleContext bundleContext;
+ private CmsApp cmsApp;
+// private String cmsAppId;
+ private EventAdmin eventAdmin;
+
+ private ServiceRegistration<ApplicationConfiguration> rwtAppReg;
+
+ private final static String CONTEXT_NAME = "contextName";
+ private String contextName;
+
+ private final static String FAVICON_PNG = "favicon.png";
+
+ public void init(BundleContext bundleContext, Map<String, String> properties) {
+ this.bundleContext = bundleContext;
+ contextName = properties.get(CONTEXT_NAME);
+ if (cmsApp != null) {
+ if (cmsApp.allThemesAvailable())
+ publishWebApp();
+ }
+ }
+
+ public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+ if (cmsApp != null) {
+ cmsApp.removeCmsAppListener(this);
+ cmsApp = null;
+ }
+ }
+
+ @Override
+ public void configure(Application application) {
+ // TODO make it configurable?
+ // SWT compatibility is required for:
+ // - Browser.execute()
+ // - blocking dialogs
+ application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+ for (String uiName : cmsApp.getUiNames()) {
+ CmsTheme theme = cmsApp.getTheme(uiName);
+ if (theme != null)
+ WebThemeUtils.apply(application, theme);
+ }
+
+ Map<String, String> properties = new HashMap<>();
+ addEntryPoints(application, properties);
+ application.setExceptionHandler(this);
+ }
+
+ @Override
+ public void handleException(Throwable throwable) {
+ Display display = Display.getCurrent();
+ if (display != null && !display.isDisposed()) {
+ CmsView cmsView = CmsSwtUtils.getCmsView(display.getActiveShell());
+ cmsView.exception(throwable);
+ } else {
+ log.error("Unexpected exception outside an UI thread", throwable);
+ }
+
+ }
+
+ protected void addEntryPoints(Application application, Map<String, String> commonProperties) {
+ for (String uiName : cmsApp.getUiNames()) {
+ Map<String, String> properties = new HashMap<>(commonProperties);
+ CmsTheme theme = cmsApp.getTheme(uiName);
+ if (theme != null) {
+ properties.put(WebClient.THEME_ID, theme.getThemeId());
+ properties.put(WebClient.HEAD_HTML, theme.getHtmlHeaders());
+ properties.put(WebClient.BODY_HTML, theme.getBodyHtml());
+ Set<String> imagePaths = theme.getImagesPaths();
+ if (imagePaths.contains(FAVICON_PNG)) {
+ properties.put(WebClient.FAVICON, FAVICON_PNG);
+ }
+ } else {
+ properties.put(WebClient.THEME_ID, RWT.DEFAULT_THEME_ID);
+ }
+ String entryPointName = !uiName.equals("") ? "/" + uiName : "/";
+ application.addEntryPoint(entryPointName, () -> {
+ CmsWebEntryPoint entryPoint = new CmsWebEntryPoint(this, uiName);
+ entryPoint.setEventAdmin(eventAdmin);
+ return entryPoint;
+ }, properties);
+ if (log.isDebugEnabled())
+ log.info("Added web entry point " + (contextName != null ? "/" + contextName : "") + entryPointName);
+ }
+// if (log.isDebugEnabled())
+// log.debug("Published CMS web app /" + (contextName != null ? contextName : ""));
+ }
+
+ CmsApp getCmsApp() {
+ return cmsApp;
+ }
+
+ BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void setCmsApp(CmsApp cmsApp) {
+ this.cmsApp = cmsApp;
+// this.cmsAppId = properties.get(Constants.SERVICE_PID);
+ this.cmsApp.addCmsAppListener(this);
+ }
+
+ public void unsetCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+ if (!contextName.equals(this.contextName))
+ return;
+ if (this.cmsApp != null) {
+ this.cmsApp.removeCmsAppListener(this);
+ }
+ if (rwtAppReg != null)
+ rwtAppReg.unregister();
+ this.cmsApp = null;
+ }
+
+ @Override
+ public void themingUpdated() {
+ if (cmsApp != null && cmsApp.allThemesAvailable())
+ publishWebApp();
+ }
+
+ protected void publishWebApp() {
+ Dictionary<String, Object> regProps = LangUtils.dict(CONTEXT_NAME, contextName);
+ if (rwtAppReg != null)
+ rwtAppReg.unregister();
+ if (bundleContext != null) {
+ rwtAppReg = bundleContext.registerService(ApplicationConfiguration.class, this, regProps);
+ if (log.isDebugEnabled())
+ log.debug("Publishing CMS web app /" + (contextName != null ? contextName : "") + " ...");
+ }
+ }
+
+ public void setEventAdmin(EventAdmin eventAdmin) {
+ this.eventAdmin = eventAdmin;
+ }
+
+ public void setContextName(String contextName) {
+ this.contextName = contextName;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
+
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.api.cms.CmsApp;
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsSession;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.api.cms.ux.CmsUi;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.api.cms.ux.UxContext;
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.RemoteAuthCallbackHandler;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.cms.servlet.ServletHttpResponse;
+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.eclipse.ui.specific.UiContext;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.client.service.BrowserNavigation;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
+import org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTError;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+/** The {@link CmsView} for a {@link CmsWebApp}. */
+@SuppressWarnings("restriction")
+public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationListener {
+ private static final long serialVersionUID = 7733510691684570402L;
+ private final static CmsLog log = CmsLog.getLog(CmsWebEntryPoint.class);
+
+ private EventAdmin eventAdmin;
+
+ private final CmsWebApp cmsWebApp;
+ private final String uiName;
+
+ private LoginContext loginContext;
+ private String state;
+ private Throwable exception;
+ private UxContext uxContext;
+ private CmsImageManager imageManager;
+
+ private Display display;
+ private CmsUi ui;
+
+ private String uid;
+
+ // Client services
+ // private final JavaScriptExecutor jsExecutor;
+ private final BrowserNavigation browserNavigation;
+
+ /** Experimental OS-like multi windows. */
+ private boolean multipleShells = false;
+
+ public CmsWebEntryPoint(CmsWebApp cmsWebApp, String uiName) {
+ assert cmsWebApp != null;
+ assert uiName != null;
+ this.cmsWebApp = cmsWebApp;
+ this.uiName = uiName;
+ uid = UUID.randomUUID().toString();
+
+ // Initial login
+ LoginContext lc;
+ try {
+ lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER,
+ new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
+ new ServletHttpResponse(UiContext.getHttpResponse())));
+ lc.login();
+ } catch (LoginException e) {
+ try {
+ lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS,
+ new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
+ new ServletHttpResponse(UiContext.getHttpResponse())));
+ lc.login();
+ } catch (LoginException e1) {
+ throw new IllegalStateException("Cannot log in as anonymous", e1);
+ }
+ }
+ authChange(lc);
+
+ // jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
+ browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
+ if (browserNavigation != null)
+ browserNavigation.addBrowserNavigationListener(this);
+ }
+
+ protected void createContents(Composite parent) {
+ Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ try {
+ uxContext = new SimpleSwtUxContext();
+ imageManager = new DefaultImageManager();
+ CmsSession cmsSession = getCmsSession();
+ if (cmsSession != null) {
+ UiContext.setLocale(cmsSession.getLocale());
+ LocaleUtils.setThreadLocale(cmsSession.getLocale());
+ } else {
+ Locale rwtLocale = RWT.getUISession().getLocale();
+ LocaleUtils.setThreadLocale(rwtLocale);
+ }
+ parent.setData(CmsApp.UI_NAME_PROPERTY, uiName);
+ display = parent.getDisplay();
+ ui = cmsWebApp.getCmsApp().initUi(parent);
+ 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);
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot create entrypoint contents", e);
+ }
+ return null;
+ }
+ });
+ }
+
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
+ public <T> T doAs(PrivilegedAction<T> action) {
+ return Subject.doAs(getSubject(), action);
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return CurrentUser.isAnonymous(getSubject());
+ }
+
+ @Override
+ public synchronized void logout() {
+ if (loginContext == null)
+ throw new IllegalArgumentException("Login context should not be null");
+ try {
+ CurrentUser.logoutCmsSession(loginContext.getSubject());
+ loginContext.logout();
+ LoginContext anonymousLc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS,
+ new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
+ new ServletHttpResponse(UiContext.getHttpResponse())));
+ anonymousLc.login();
+ authChange(anonymousLc);
+ } catch (LoginException e) {
+ log.error("Cannot logout", e);
+ }
+ }
+
+ @Override
+ public synchronized void authChange(LoginContext lc) {
+ if (lc == null)
+ throw new IllegalArgumentException("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 = lc;
+ doRefresh();
+ }
+
+ @Override
+ public void exception(final Throwable e) {
+ if (e instanceof SWTError) {
+ SWTError swtError = (SWTError) e;
+ if (swtError.code == SWT.ERROR_FUNCTION_DISPOSED)
+ return;
+ }
+ display.syncExec(() -> {
+// CmsFeedback.show("Unexpected exception in CMS", e);
+ exception = e;
+ log.error("Unexpected exception in CMS", e);
+ doRefresh();
+ });
+ }
+
+ protected synchronized void doRefresh() {
+ if (ui != null)
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ if (exception != null) {
+ // TODO internationalise
+ CmsFeedback.show("Unexpected exception", exception);
+ exception = null;
+ // TODO report
+ }
+ cmsWebApp.getCmsApp().refreshUi(ui, state);
+ return null;
+ }
+ });
+ }
+
+ /** Sets the state of the entry point and retrieve the related JCR node. */
+ protected String setState(String newState) {
+ cmsWebApp.getCmsApp().setState(ui, newState);
+ state = newState;
+ return null;
+ }
+
+ @Override
+ public UxContext getUxContext() {
+ return uxContext;
+ }
+
+ @Override
+ public String getUid() {
+ return uid;
+ }
+
+ @Override
+ public void navigateTo(String state) {
+ exception = null;
+ String title = setState(state);
+ if (title != null)
+ doRefresh();
+ if (browserNavigation != null)
+ browserNavigation.pushState(state, title);
+ }
+
+ public CmsImageManager getImageManager() {
+ return imageManager;
+ }
+
+ @Override
+ public void navigated(BrowserNavigationEvent event) {
+ setState(event.getState());
+ // doRefresh();
+ }
+
+ @Override
+ public void sendEvent(String topic, Map<String, Object> properties) {
+ if (properties == null)
+ properties = new HashMap<>();
+ if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
+ throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
+ + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
+ properties.put(CMS_VIEW_UID_PROPERTY, uid);
+ eventAdmin.sendEvent(new Event(topic, properties));
+ }
+
+ @Override
+ public void stateChanged(String state, String title) {
+ browserNavigation.pushState(state, title);
+ }
+
+ @Override
+ public CmsSession getCmsSession() {
+ CmsSession cmsSession = cmsWebApp.getCmsApp().getCmsContext().getCmsSession(getSubject());
+ if (cmsSession == null)
+ throw new IllegalStateException("No CMS session available for " + getSubject());
+ return cmsSession;
+ }
+
+ @Override
+ public Object getData(String key) {
+ if (ui != null) {
+ return ui.getData(key);
+ } else {
+ throw new IllegalStateException("UI is not initialized");
+ }
+ }
+
+ @Override
+ public void setData(String key, Object value) {
+ if (ui != null) {
+ ui.setData(key, value);
+ } else {
+ throw new IllegalStateException("UI is not initialized");
+ }
+ }
+
+ /*
+ * EntryPoint IMPLEMENTATION
+ */
+
+ @Override
+ public int createUI() {
+ Display display = new Display();
+ Shell shell = createShell(display);
+ shell.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ CmsSwtUtils.registerCmsView(shell, this);
+ createContents(shell);
+ shell.layout();
+// if (shell.getMaximized()) {
+// shell.layout();
+// } else {
+//// shell.pack();
+// }
+ shell.open();
+ if (getApplicationContext().getLifeCycleFactory().getLifeCycle() instanceof RWTLifeCycle) {
+ eventLoop: while (!shell.isDisposed()) {
+ try {
+ Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ return null;
+ }
+ });
+ } catch (Throwable e) {
+ if (e instanceof SWTError) {
+ SWTError swtError = (SWTError) e;
+ if (swtError.code == SWT.ERROR_FUNCTION_DISPOSED) {
+ log.error("Unexpected SWT error in event loop, ignoring it. " + e.getMessage());
+ continue eventLoop;
+ } else {
+ log.error("Unexpected SWT error in event loop, shutting down...", e);
+ break eventLoop;
+ }
+ } else if (e instanceof ThreadDeath) {
+ throw (ThreadDeath) e;
+ } else if (e instanceof Error) {
+ log.error("Unexpected error in event loop, shutting down...", e);
+ break eventLoop;
+ } else {
+ log.error("Unexpected exception in event loop, ignoring it. " + e.getMessage());
+ continue eventLoop;
+ }
+ }
+ }
+ if (!display.isDisposed())
+ display.dispose();
+ }
+ return 0;
+ }
+
+ protected Shell createShell(Display display) {
+ Shell shell;
+ if (!multipleShells) {
+ shell = new Shell(display, SWT.NO_TRIM);
+ shell.setMaximized(true);
+ } else {
+ shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setSize(800, 600);
+ }
+ return shell;
+ }
+
+ public void setEventAdmin(EventAdmin eventAdmin) {
+ this.eventAdmin = eventAdmin;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import static org.argeo.cms.osgi.BundleCmsTheme.CMS_THEME_BUNDLE_PROPERTY;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.osgi.framework.BundleContext;
+
+/** Lightweight web app using only RWT and not the whole Eclipse platform. */
+public class MinimalWebApp implements ApplicationConfiguration {
+
+ private BundleCmsTheme theme;
+
+ public void init(BundleContext bundleContext, Map<String, Object> properties) {
+ if (properties.containsKey(CMS_THEME_BUNDLE_PROPERTY)) {
+ String cmsThemeBundle = properties.get(CMS_THEME_BUNDLE_PROPERTY).toString();
+ theme = new BundleCmsTheme(bundleContext, cmsThemeBundle);
+ }
+ }
+
+ public void destroy() {
+
+ }
+
+ /** To be overridden. Does nothing by default. */
+ protected void addEntryPoints(Application application, Map<String, String> properties) {
+
+ }
+
+ @Override
+ public void configure(Application application) {
+ if (theme != null)
+ WebThemeUtils.apply(application, theme);
+
+ Map<String, String> properties = new HashMap<>();
+ if (theme != null) {
+ properties.put(WebClient.THEME_ID, theme.getThemeId());
+ properties.put(WebClient.HEAD_HTML, theme.getHtmlHeaders());
+ } else {
+ properties.put(WebClient.THEME_ID, RWT.DEFAULT_THEME_ID);
+ }
+ addEntryPoints(application, properties);
+
+ }
+
+ public void setTheme(BundleCmsTheme theme) {
+ this.theme = theme;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+import javax.jcr.version.VersionManager;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.ui.CmsUiConstants;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.LifeCycleUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.util.StyleSheetResourceLoader;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.Application.OperationMode;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.application.EntryPointFactory;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/** A basic generic app based on {@link SimpleErgonomics}. */
+@Deprecated
+public class SimpleApp implements CmsUiConstants, ApplicationConfiguration {
+ private final static CmsLog log = CmsLog.getLog(SimpleApp.class);
+
+ private String contextName = null;
+
+ private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
+ private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
+
+ private List<String> resources = new ArrayList<String>();
+
+ private BundleContext bundleContext;
+
+ private Repository repository;
+ private String workspace = null;
+ private String jcrBasePath = "/";
+ private List<String> roPrincipals = Arrays.asList(CmsConstants.ROLE_ANONYMOUS, CmsConstants.ROLE_USER);
+ private List<String> rwPrincipals = Arrays.asList(CmsConstants.ROLE_USER);
+
+ private CmsUiProvider header;
+ private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
+
+ private Integer headerHeight = 40;
+
+ private ServiceRegistration<ApplicationConfiguration> appReg;
+
+ public void configure(Application application) {
+ try {
+ BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
+
+ application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+ // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
+
+ application.setExceptionHandler(new CmsExceptionHandler());
+
+ // loading animated gif
+ application.addResource(LOADING_IMAGE, createResourceLoader(LOADING_IMAGE));
+ // empty image
+ application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
+
+ for (String resource : resources) {
+ application.addResource(resource, bundleRL);
+ if (log.isTraceEnabled())
+ log.trace("Resource " + resource);
+ }
+
+ Map<String, String> defaultBranding = null;
+ if (branding.containsKey("*"))
+ defaultBranding = branding.get("*");
+ // String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
+
+ // entry points
+ for (String page : pages.keySet()) {
+ Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(defaultBranding)
+ : new HashMap<String, String>();
+ if (branding.containsKey(page)) {
+ properties.putAll(branding.get(page));
+ }
+ // favicon
+ if (properties.containsKey(WebClient.FAVICON)) {
+ String themeId = defaultBranding.get(WebClient.THEME_ID);
+ Bundle themeBundle = findThemeBundle(bundleContext, themeId);
+ String faviconRelPath = properties.get(WebClient.FAVICON);
+ application.addResource(faviconRelPath,
+ new BundleResourceLoader(themeBundle != null ? themeBundle : bundleContext.getBundle()));
+ if (log.isTraceEnabled())
+ log.trace("Favicon " + faviconRelPath);
+
+ }
+
+ // page title
+ if (!properties.containsKey(WebClient.PAGE_TITLE)) {
+ if (page.length() > 0)
+ properties.put(WebClient.PAGE_TITLE, Character.toUpperCase(page.charAt(0)) + page.substring(1));
+ }
+
+ // default body HTML
+ if (!properties.containsKey(WebClient.BODY_HTML))
+ properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
+
+ //
+ // ADD ENTRY POINT
+ //
+ application.addEntryPoint("/" + page,
+ new CmsEntryPointFactory(pages.get(page), repository, workspace, properties), properties);
+ log.info("Page /" + page);
+ }
+
+ // stylesheets and themes
+ Set<Bundle> themeBundles = new HashSet<>();
+ for (String themeId : styleSheets.keySet()) {
+ Bundle themeBundle = findThemeBundle(bundleContext, themeId);
+ StyleSheetResourceLoader styleSheetRL = new StyleSheetResourceLoader(
+ themeBundle != null ? themeBundle : bundleContext.getBundle());
+ if (themeBundle != null)
+ themeBundles.add(themeBundle);
+ List<String> cssLst = styleSheets.get(themeId);
+ if (log.isDebugEnabled())
+ log.debug("Theme " + themeId);
+ for (String css : cssLst) {
+ application.addStyleSheet(themeId, css, styleSheetRL);
+ if (log.isDebugEnabled())
+ log.debug(" CSS " + css);
+ }
+
+ }
+ for (Bundle themeBundle : themeBundles) {
+ BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
+ SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.png");
+ SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.gif");
+ SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.jpg");
+ }
+ } catch (RuntimeException e) {
+ // Easier access to initialisation errors
+ log.error("Unexpected exception when configuring RWT application.", e);
+ throw e;
+ }
+ }
+
+ public void init() throws RepositoryException {
+ Session session = null;
+ try {
+ session = CmsJcrUtils.openDataAdminSession(repository, workspace);
+ // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
+ VersionManager vm = session.getWorkspace().getVersionManager();
+ JcrUtils.mkdirs(session, jcrBasePath);
+ session.save();
+ if (!vm.isCheckedOut(jcrBasePath))
+ vm.checkout(jcrBasePath);
+ for (String principal : rwPrincipals)
+ JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_WRITE);
+ for (String principal : roPrincipals)
+ JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_READ);
+
+ for (String pageName : pages.keySet()) {
+ try {
+ initPage(session, pages.get(pageName));
+ session.save();
+ } catch (Exception e) {
+ throw new CmsException("Cannot initialize page " + pageName, e);
+ }
+ }
+
+ } finally {
+ JcrUtils.logoutQuietly(session);
+ }
+
+ // publish to OSGi
+ register();
+ }
+
+ protected void initPage(Session adminSession, CmsUiProvider page) throws RepositoryException {
+ if (page instanceof LifeCycleUiProvider)
+ ((LifeCycleUiProvider) page).init(adminSession);
+ }
+
+ public void destroy() {
+ for (String pageName : pages.keySet()) {
+ try {
+ CmsUiProvider page = pages.get(pageName);
+ if (page instanceof LifeCycleUiProvider)
+ ((LifeCycleUiProvider) page).destroy();
+ } catch (Exception e) {
+ log.error("Cannot destroy page " + pageName, e);
+ }
+ }
+ }
+
+ protected void register() {
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ if (contextName != null)
+ props.put("contextName", contextName);
+ appReg = bundleContext.registerService(ApplicationConfiguration.class, this, props);
+ if (log.isDebugEnabled())
+ log.debug("Registered " + (contextName == null ? "/" : contextName));
+ }
+
+ protected void unregister() {
+ appReg.unregister();
+ if (log.isDebugEnabled())
+ log.debug("Unregistered " + (contextName == null ? "/" : contextName));
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public void setWorkspace(String workspace) {
+ this.workspace = workspace;
+ }
+
+ public void setHeader(CmsUiProvider header) {
+ this.header = header;
+ }
+
+ public void setPages(Map<String, CmsUiProvider> pages) {
+ this.pages = pages;
+ }
+
+ public void setJcrBasePath(String basePath) {
+ this.jcrBasePath = basePath;
+ }
+
+ public void setRoPrincipals(List<String> roPrincipals) {
+ this.roPrincipals = roPrincipals;
+ }
+
+ public void setRwPrincipals(List<String> rwPrincipals) {
+ this.rwPrincipals = rwPrincipals;
+ }
+
+ public void setHeaderHeight(Integer headerHeight) {
+ this.headerHeight = headerHeight;
+ }
+
+ public void setBranding(Map<String, Map<String, String>> branding) {
+ this.branding = branding;
+ }
+
+ public void setStyleSheets(Map<String, List<String>> styleSheets) {
+ this.styleSheets = styleSheets;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public void setResources(List<String> resources) {
+ this.resources = resources;
+ }
+
+ public void setContextName(String contextName) {
+ this.contextName = contextName;
+ }
+
+ private static void addThemeResources(Application application, Bundle themeBundle, BundleResourceLoader themeBRL,
+ String pattern) {
+ Enumeration<URL> themeResources = themeBundle.findEntries("/", pattern, true);
+ if (themeResources == null)
+ return;
+ while (themeResources.hasMoreElements()) {
+ String resource = themeResources.nextElement().getPath();
+ // remove first '/' so that RWT registers it
+ resource = resource.substring(1);
+ if (!resource.endsWith("/")) {
+ application.addResource(resource, themeBRL);
+ if (log.isTraceEnabled())
+ log.trace("Registered " + resource + " from theme " + themeBundle);
+ }
+
+ }
+
+ }
+
+ 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;
+ }
+
+ class CmsExceptionHandler implements ExceptionHandler {
+
+ @Override
+ public void handleException(Throwable throwable) {
+ // TODO be smarter
+ CmsUiUtils.getCmsView().exception(throwable);
+ }
+
+ }
+
+ private class CmsEntryPointFactory implements EntryPointFactory {
+ private final CmsUiProvider page;
+ private final Repository repository;
+ private final String workspace;
+ private final Map<String, String> properties;
+
+ public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace,
+ Map<String, String> properties) {
+ this.page = page;
+ this.repository = repository;
+ this.workspace = workspace;
+ this.properties = properties;
+ }
+
+ @Override
+ public EntryPoint create() {
+ SimpleErgonomics entryPoint = new SimpleErgonomics(repository, workspace, jcrBasePath, page, properties) {
+ private static final long serialVersionUID = -637940404865527290L;
+
+ @Override
+ protected void createAdminArea(Composite parent) {
+ Composite adminArea = new Composite(parent, SWT.NONE);
+ adminArea.setLayout(new FillLayout());
+ Button refresh = new Button(adminArea, SWT.PUSH);
+ refresh.setText("Reload App");
+ refresh.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -7671999525536351366L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ long timeBeforeReload = 1000;
+ RWT.getClient().getService(JavaScriptExecutor.class).execute(
+ "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload + ");");
+ reloadApp();
+ }
+ });
+ }
+ };
+ // entryPoint.setState("");
+ entryPoint.setHeader(header);
+ entryPoint.setHeaderHeight(headerHeight);
+ // CmsSession.current.set(entryPoint);
+ return entryPoint;
+ }
+
+ private void reloadApp() {
+ new Thread("Refresh app") {
+ @Override
+ public void run() {
+ unregister();
+ register();
+ }
+ }.start();
+ }
+ }
+
+ private static ResourceLoader createResourceLoader(final String resourceName) {
+ return new ResourceLoader() {
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ return getClass().getClassLoader().getResourceAsStream(resourceName);
+ }
+ };
+ }
+
+ // private static ResourceLoader createUrlResourceLoader(final URL url) {
+ // return new ResourceLoader() {
+ // public InputStream getResourceAsStream(String resourceName)
+ // throws IOException {
+ // return url.openStream();
+ // }
+ // };
+ // }
+
+ /*
+ * TEXTS
+ */
+ private static String DEFAULT_LOADING_BODY = "<div"
+ + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
+ + "<img src=\"./rwt-resources/" + LOADING_IMAGE
+ + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import java.util.Map;
+import java.util.UUID;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.api.cms.ux.UxContext;
+import org.argeo.cms.swt.CmsException;
+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.util.DefaultImageManager;
+import org.argeo.cms.ui.util.SystemNotifications;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Simple header/body ergonomics. */
+@Deprecated
+public class SimpleErgonomics extends AbstractCmsEntryPoint {
+ private static final long serialVersionUID = 8743413921359548523L;
+
+ private final static CmsLog log = CmsLog.getLog(SimpleErgonomics.class);
+
+ private boolean uiInitialized = false;
+ private Composite headerArea;
+ private Composite leftArea;
+ private Composite rightArea;
+ private Composite footerArea;
+ private Composite bodyArea;
+ private final CmsUiProvider uiProvider;
+
+ private CmsUiProvider header;
+ private Integer headerHeight = 0;
+ private Integer footerHeight = 0;
+ private CmsUiProvider lead;
+ private CmsUiProvider end;
+ private CmsUiProvider footer;
+
+ private CmsImageManager imageManager = new DefaultImageManager();
+ private UxContext uxContext = null;
+ private String uid;
+
+ public SimpleErgonomics(Repository repository, String workspace, String defaultPath, CmsUiProvider uiProvider,
+ Map<String, String> factoryProperties) {
+ super(repository, workspace, defaultPath, factoryProperties);
+ this.uiProvider = uiProvider;
+ }
+
+ @Override
+ protected void initUi(Composite parent) {
+ uid = UUID.randomUUID().toString();
+ parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ parent.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, false)));
+
+ uxContext = new SimpleSwtUxContext();
+ if (!getUxContext().isMasterData())
+ createAdminArea(parent);
+ headerArea = new Composite(parent, SWT.NONE);
+ headerArea.setLayout(new FillLayout());
+ GridData headerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
+ headerData.heightHint = headerHeight;
+ headerArea.setLayoutData(headerData);
+
+ // TODO: bi-directional
+ leftArea = new Composite(parent, SWT.NONE);
+ leftArea.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
+ leftArea.setLayout(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(CmsSwtUtils.noSpaceGridLayout());
+
+ // TODO: bi-directional
+ rightArea = new Composite(parent, SWT.NONE);
+ rightArea.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
+ rightArea.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+ footerArea = new Composite(parent, SWT.NONE);
+ // footerArea.setLayout(new FillLayout());
+ GridData footerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
+ footerData.heightHint = footerHeight;
+ footerArea.setLayoutData(footerData);
+
+ uiInitialized = true;
+ refresh();
+ }
+
+ @Override
+ protected void refresh() {
+ if (!uiInitialized)
+ return;
+ if (getState() == null)
+ setState("");
+ refreshSides();
+ refreshBody();
+ if (log.isTraceEnabled())
+ log.trace("UI refreshed " + getNode());
+ }
+
+ protected void createAdminArea(Composite parent) {
+ }
+
+ @Deprecated
+ protected void refreshHeader() {
+ if (header == null)
+ return;
+
+ for (Control child : headerArea.getChildren())
+ child.dispose();
+ try {
+ header.createUi(headerArea, getNode());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh header", e);
+ }
+ headerArea.layout(true, true);
+ }
+
+ protected void refreshSides() {
+ refresh(headerArea, header, CmsStyles.CMS_HEADER);
+ refresh(leftArea, lead, CmsStyles.CMS_LEAD);
+ refresh(rightArea, end, CmsStyles.CMS_END);
+ refresh(footerArea, footer, CmsStyles.CMS_FOOTER);
+ }
+
+ private void refresh(Composite area, CmsUiProvider uiProvider, String style) {
+ if (uiProvider == null)
+ return;
+
+ for (Control child : area.getChildren())
+ child.dispose();
+ CmsSwtUtils.style(area, style);
+ try {
+ uiProvider.createUi(area, getNode());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh header", e);
+ }
+ area.layout(true, true);
+ }
+
+ protected void refreshBody() {
+ // Exception
+ Throwable exception = getException();
+ if (exception != null) {
+ SystemNotifications systemNotifications = new SystemNotifications(bodyArea);
+ systemNotifications.notifyException(exception);
+ resetException();
+ return;
+ // TODO report
+ }
+
+ // clear
+ for (Control child : bodyArea.getChildren())
+ child.dispose();
+ bodyArea.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+ try {
+ Node node = getNode();
+// if (node == null)
+// log.error("Context cannot be null");
+// else
+ uiProvider.createUi(bodyArea, node);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh body", e);
+ }
+
+ bodyArea.layout(true, true);
+ }
+
+ @Override
+ public UxContext getUxContext() {
+ return uxContext;
+ }
+ @Override
+ public String getUid() {
+ return uid;
+ }
+
+ public CmsImageManager getImageManager() {
+ return imageManager;
+ }
+
+ public void setHeader(CmsUiProvider header) {
+ this.header = header;
+ }
+
+ public void setHeaderHeight(Integer headerHeight) {
+ this.headerHeight = headerHeight;
+ }
+
+ public void setImageManager(CmsImageManager imageManager) {
+ this.imageManager = imageManager;
+ }
+
+ public CmsUiProvider getLead() {
+ return lead;
+ }
+
+ public void setLead(CmsUiProvider lead) {
+ this.lead = lead;
+ }
+
+ public CmsUiProvider getEnd() {
+ return end;
+ }
+
+ public void setEnd(CmsUiProvider end) {
+ this.end = end;
+ }
+
+ public CmsUiProvider getFooter() {
+ return footer;
+ }
+
+ public void setFooter(CmsUiProvider footer) {
+ this.footer = footer;
+ }
+
+ public CmsUiProvider getHeader() {
+ return header;
+ }
+
+ public void setFooterHeight(Integer footerHeight) {
+ this.footerHeight = footerHeight;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsTheme;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+
+/** Web specific utilities around theming. */
+public class WebThemeUtils {
+ private final static CmsLog log = CmsLog.getLog(WebThemeUtils.class);
+
+ public static void apply(Application application, CmsTheme theme) {
+ ResourceLoader resourceLoader = new CmsThemeResourceLoader(theme);
+ resources: for (String path : theme.getImagesPaths()) {
+ if (path.startsWith("target/"))
+ continue resources; // skip maven output
+ application.addResource(path, resourceLoader);
+ if (log.isTraceEnabled())
+ log.trace("Theme " + theme.getThemeId() + ": added resource " + path);
+ }
+ for (String path : theme.getRapCssPaths()) {
+ application.addStyleSheet(theme.getThemeId(), path, resourceLoader);
+ if (log.isDebugEnabled())
+ log.debug("Theme " + theme.getThemeId() + ": added RAP CSS " + path);
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web.osgi;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.argeo.api.cms.CmsApp;
+import org.argeo.cms.web.CmsWebApp;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.event.EventAdmin;
+
+/** Publish a CmsApp as a RAP application. */
+public class CmsWebAppFactory {
+ private BundleContext bundleContext = FrameworkUtil.getBundle(CmsWebAppFactory.class).getBundleContext();
+ private final static String CONTEXT_NAME = "contextName";
+
+ private EventAdmin eventAdmin;
+
+ private Map<String, CmsWebApp> registrations = Collections.synchronizedMap(new HashMap<>());
+
+ public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+ if (contextName != null) {
+ CmsWebApp cmsWebApp = new CmsWebApp();
+ cmsWebApp.setEventAdmin(eventAdmin);
+ cmsWebApp.setCmsApp(cmsApp);
+ Hashtable<String, String> serviceProperties = new Hashtable<>();
+ if (!contextName.equals(""))
+ serviceProperties.put(CONTEXT_NAME, contextName);
+ cmsWebApp.init(bundleContext, serviceProperties);
+ registrations.put(contextName, cmsWebApp);
+ }
+ }
+
+ public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+ if (contextName != null) {
+ CmsWebApp cmsWebApp = registrations.get(contextName);
+ if (cmsWebApp != null) {
+ cmsWebApp.destroy(bundleContext, new HashMap<>());
+ cmsWebApp.unsetCmsApp(cmsApp, properties);
+ } else {
+ // TODO log warning
+ }
+ }
+ }
+
+ public void setEventAdmin(EventAdmin eventAdmin) {
+ this.eventAdmin = eventAdmin;
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src" />
+ <classpathentry kind="con"
+ path="org.eclipse.pde.core.requiredPlugins" />
+ <classpathentry kind="con"
+ path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11" />
+ <classpathentry kind="output" path="bin" />
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.swt.specific.rap</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+Import-Package: org.eclipse.swt,\
+org.eclipse.jface.dialogs,\
+org.eclipse.swt.events,\
+javax.servlet.http;version="[3,5)",\
+*
--- /dev/null
+source.. = src/
+output.. = bin/
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import java.awt.image.BufferedImage;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+
+public class BufferedImageDisplay extends Composite {
+ private static final long serialVersionUID = 4541163690514461514L;
+ private BufferedImage image;
+
+ public BufferedImageDisplay(Composite parent, int style) {
+ super(parent, SWT.NO_BACKGROUND);
+ }
+
+ public void setImage(BufferedImage image) {
+ this.image = image;
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+
+public class CmsFileDialog extends FileDialog {
+ private static final long serialVersionUID = -7540791204102318801L;
+
+ public CmsFileDialog(Shell parent, int style) {
+ super(parent, style);
+ }
+
+ public CmsFileDialog(Shell parent) {
+ super(parent);
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Composite;
+
+public class CmsFileUpload extends FileUpload {
+ private static final long serialVersionUID = 8027963992680980549L;
+
+ public CmsFileUpload(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ public void setText(String text) {
+ super.setText(text);
+ }
+
+ @Override
+ public String getFileName() {
+ return super.getFileName();
+ }
+
+ @Override
+ public String[] getFileNames() {
+ return super.getFileNames();
+ }
+
+ @Override
+ public void addSelectionListener(SelectionListener listener) {
+ super.addSelectionListener(listener);
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import org.eclipse.jface.viewers.AbstractTableViewer;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.widgets.Widget;
+
+/** Static utilities to bridge differences between RCP and RAP */
+public class EclipseUiSpecificUtils {
+
+ public static void setStyleData(Widget widget, Object data) {
+ widget.setData(RWT.CUSTOM_VARIANT, data);
+ }
+
+ public static Object getStyleData(Widget widget) {
+ return widget.getData(RWT.CUSTOM_VARIANT);
+ }
+
+ public static void setMarkupData(Widget widget) {
+ widget.setData(RWT.MARKUP_ENABLED, true);
+ }
+
+ public static void setMarkupValidationDisabledData(Widget widget) {
+ widget.setData("org.eclipse.rap.rwt.markupValidationDisabled", Boolean.TRUE);
+ }
+
+ /**
+ * TootlTip support is supported only for {@link AbstractTableViewer} in RAP
+ */
+ public static void enableToolTipSupport(Viewer viewer) {
+ if (viewer instanceof ColumnViewer)
+ ColumnViewerToolTipSupport.enableFor((ColumnViewer) viewer);
+ }
+
+ private EclipseUiSpecificUtils() {
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.rap.fileupload.FileDetails;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.client.ClientFile;
+import org.eclipse.rap.rwt.client.service.ClientFileUploader;
+import org.eclipse.rap.rwt.dnd.ClientFileTransfer;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.DropTargetAdapter;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.widgets.Control;
+
+/** Configures a {@link Control} to receive files drop from the client OS. */
+public class FileDropAdapter {
+
+ public void prepareDropTarget(Control control, DropTarget dropTarget) {
+ dropTarget.setTransfer(new Transfer[] { ClientFileTransfer.getInstance() });
+ dropTarget.addDropListener(new DropTargetAdapter() {
+ private static final long serialVersionUID = 5361645765549463168L;
+
+ @Override
+ public void dropAccept(DropTargetEvent event) {
+ if (!ClientFileTransfer.getInstance().isSupportedType(event.currentDataType)) {
+ event.detail = DND.DROP_NONE;
+ }
+ }
+
+ @Override
+ public void drop(DropTargetEvent event) {
+ handleFileDrop(control, event);
+ }
+ });
+ }
+
+ public void handleFileDrop(Control control, DropTargetEvent event) {
+ ClientFile[] clientFiles = (ClientFile[]) event.data;
+ ClientFileUploader service = RWT.getClient().getService(ClientFileUploader.class);
+// DiskFileUploadReceiver receiver = new DiskFileUploadReceiver();
+ FileUploadReceiver receiver = new FileUploadReceiver() {
+
+ @Override
+ public void receive(InputStream stream, FileDetails details) throws IOException {
+ control.getDisplay().syncExec(() -> {
+ try {
+ processUpload(stream, details.getFileName(), details.getContentType());
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot process upload of " + details.getFileName(), e);
+ }
+ });
+ }
+ };
+ FileUploadHandler handler = new FileUploadHandler(receiver);
+// handler.setMaxFileSize( sizeLimit );
+// handler.setUploadTimeLimit( timeLimit );
+ service.submit(handler.getUploadUrl(), clientFiles);
+// for (File file : receiver.getTargetFiles()) {
+// paths.add(file.toPath());
+// }
+ }
+
+ /** Executed in UI thread */
+ protected void processUpload(InputStream in, String fileName, String contentType) throws IOException {
+
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.widgets.Display;
+
+/** Singleton class providing single sources infos about the UI context. */
+public class UiContext {
+ /** Can be null, thus indicating that we are not in a web context. */
+ public static HttpServletRequest getHttpRequest() {
+ return RWT.getRequest();
+ }
+
+ public static HttpServletResponse getHttpResponse() {
+ return RWT.getResponse();
+ }
+
+ public static Locale getLocale() {
+ if (Display.getCurrent() != null)
+ return RWT.getUISession().getLocale();
+ else
+ return Locale.getDefault();
+ }
+
+ public static void setLocale(Locale locale) {
+ if (Display.getCurrent() != null)
+ RWT.getUISession().setLocale(locale);
+ else
+ Locale.setDefault(locale);
+ }
+
+ /** Can always be null */
+ @SuppressWarnings("unchecked")
+ public static <T> T getData(String key) {
+ Display display = getDisplay();
+ if (display == null)
+ return null;
+ return (T) display.getData(key);
+ }
+
+ public static void setData(String key, Object value) {
+ Display display = getDisplay();
+ if (display == null)
+ throw new IllegalStateException("Not display available");
+ display.setData(key, value);
+ }
+
+ private static Display getDisplay() {
+ return Display.getCurrent();
+ }
+
+ private UiContext() {
+ }
+
+}
--- /dev/null
+/** Eclipse RAP-specific SWT/JFace utilities, to simplify single-sourcing. */
+package org.argeo.eclipse.ui.specific;
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
+/exec
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.e4.rcp</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
--- /dev/null
+eclipse.preferences.version=1
+pluginProject.extensions=false
+resolve.requirebundle=false
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="ASCII"?>
+<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:advanced="http://www.eclipse.org/ui/2010/UIModel/application/ui/advanced" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmi:id="_c4iAgCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.application">
+ <children xsi:type="basic:TrimmedWindow" xmi:id="_hSGBwCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.trimmedwindow.argeocompanion" label="Argeo Companion">
+ <children xsi:type="advanced:PerspectiveStack" xmi:id="_nxzQICnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.perspectivestack.0">
+ <children xsi:type="advanced:Perspective" xmi:id="_oI_oICnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.perspective.cmsadmin" label="CMS Admin">
+ <children xsi:type="basic:PartSashContainer" xmi:id="_qc16ECnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.partsashcontainer.0" horizontal="true">
+ <children xsi:type="basic:PartStack" xmi:id="_RE87kDsXEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.rcp.partstack.1">
+ <children xsi:type="basic:Part" xmi:id="_V1WvgDsXEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.rcp.part.files" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.files.NodeFsBrowserView" label="Files"/>
+ <children xsi:type="basic:Part" xmi:id="_vOqDQCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.part.jcr" containerData="4000" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR"/>
+ </children>
+ <children xsi:type="basic:PartStack" xmi:id="_0eRiwCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.partstack.0" containerData="6000">
+ <tags>editorArea</tags>
+ </children>
+ </children>
+ </children>
+ </children>
+ </children>
+ <descriptors xmi:id="__9SDsC8JEeq0koquN4xGyg" elementId="org.argeo.cms.e4.partdescriptor.nodeEditor" allowMultiple="true" category="editorArea" closeable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrNodeEditor"/>
+ <addons xmi:id="_c4iAgSnCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
+ <addons xmi:id="_c4iAginCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
+ <addons xmi:id="_c4iAgynCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
+ <addons xmi:id="_c4iAhCnCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
+ <addons xmi:id="_c4iAhSnCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
+ <addons xmi:id="_c4iAhinCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
+ <addons xmi:id="_c4iAhynCEei1F8sdBz8Mpw" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
+</application:Application>
--- /dev/null
+argeo.osgi.start.2.node=\
+org.eclipse.equinox.http.servlet,\
+org.eclipse.equinox.metatype,\
+org.eclipse.equinox.cm,\
+org.argeo.init
+
+argeo.osgi.start.3.node=\
+org.argeo.cms,\
+org.argeo.cms.jcr,\
+
+applicationXMI=org.argeo.cms.e4.rcp/argeo-companion.e4xmi
+lifeCycleURI=bundleclass://org.argeo.cms.e4.rcp/org.argeo.cms.e4.rcp.CmsRcpLifeCycle
+clearPersistedState=true
+#argeo.cms.desktop.inTray=true
+
+# Remote node:
+#argeo.node.repo.labeledUri=http://root:demo@localhost:7070/jcr/node
+
+# Logging
+log.org.argeo=DEBUG
+
+argeo.node.useradmin.uris=os:///
+eclipse.application=org.argeo.cms.e4.rcp.CmsE4Application
--- /dev/null
+Bundle-SymbolicName: org.argeo.cms.e4.rcp;singleton=true
+
+Require-Bundle: org.eclipse.core.runtime
+
+Import-Package: !org.eclipse.core.runtime,\
+org.eclipse.swt,\
+*
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ argeo-companion.e4xmi
+source.. = src/
--- /dev/null
+log4j.rootLogger=WARN, development
+
+## Levels
+log4j.logger.org.argeo=DEBUG
+log4j.logger.org.argeo.jackrabbit.remote.ExtendedDispatcherServlet=WARN
+log4j.logger.org.argeo.server.webextender.TomcatDeployer=INFO
+
+#log4j.logger.org.springframework.security=DEBUG
+#log4j.logger.org.apache.commons.exec=DEBUG
+#log4j.logger.org.apache.jackrabbit.webdav=DEBUG
+#log4j.logger.org.apache.jackrabbit.remote=DEBUG
+#log4j.logger.org.apache.jackrabbit.core.observation=DEBUG
+
+log4j.logger.org.apache.catalina=INFO
+log4j.logger.org.apache.coyote=INFO
+
+log4j.logger.org.apache.directory=INFO
+log4j.logger.org.apache.directory.server=ERROR
+log4j.logger.org.apache.jackrabbit.core.query.lucene=ERROR
+
+## Appenders
+# console is set to be a ConsoleAppender.
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+
+# console uses PatternLayout.
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c - [%t]%n
+
+# development appender (slow!)
+log4j.appender.development=org.apache.log4j.ConsoleAppender
+log4j.appender.development.layout=org.apache.log4j.PatternLayout
+log4j.appender.development.layout.ConversionPattern=%d{HH:mm:ss} [%16.16t] %5p %m (%F:%L) %c%n
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ id="CmsE4Application"
+ name="CMS E4 Application"
+ point="org.eclipse.core.runtime.applications">
+ <application
+ cardinality="singleton-global"
+ thread="main"
+ visible="true">
+ <run class="org.argeo.cms.e4.rcp.CmsE4Application"></run>
+ </application>
+ </extension>
+</plugin>
--- /dev/null
+package org.argeo.cms.e4.rcp;
+
+import java.security.PrivilegedExceptionAction;
+import java.util.UUID;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.api.cms.ux.UxContext;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.SimpleSwtUxContext;
+import org.argeo.cms.swt.auth.CmsLoginShell;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.swt.widgets.Display;
+
+public class CmsE4Application implements IApplication, CmsView {
+ private LoginContext loginContext;
+ private IApplication e4Application;
+ private UxContext uxContext;
+ private String uid;
+
+ @Override
+ public Object start(IApplicationContext context) throws Exception {
+ // TODO wait for CMS to be ready
+ Thread.sleep(5000);
+
+ uid = UUID.randomUUID().toString();
+ Subject subject = new Subject();
+ Display display = createDisplay();
+ CmsLoginShell loginShell = new CmsLoginShell(this, null);
+ // TODO customize CmsLoginShell to be smaller and centered
+ loginShell.setSubject(subject);
+ try {
+ // try pre-auth
+ loginContext = new LoginContext(CmsAuth.LOGIN_CONTEXT_SINGLE_USER, subject, loginShell);
+ loginContext.login();
+ } catch (LoginException e) {
+ e.printStackTrace();
+ loginShell.createUi();
+ loginShell.open();
+
+ while (!loginShell.getShell().isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ }
+ if (CurrentUser.getUsername(getSubject()) == null)
+ throw new IllegalStateException("Cannot log in");
+
+ // try {
+ // CallbackHandler callbackHandler = new DefaultLoginDialog(
+ // display.getActiveShell());
+ // loginContext = new LoginContext(
+ // NodeConstants.LOGIN_CONTEXT_SINGLE_USER, subject,
+ // callbackHandler);
+ // } catch (LoginException e1) {
+ // throw new CmsException("Cannot initialize login context", e1);
+ // }
+ //
+ // // login
+ // try {
+ // loginContext.login();
+ // subject = loginContext.getSubject();
+ // } catch (LoginException e) {
+ // e.printStackTrace();
+ // display.dispose();
+ // try {
+ // Thread.sleep(2000);
+ // } catch (InterruptedException e1) {
+ // // silent
+ // }
+ // return null;
+ // }
+
+ uxContext = new SimpleSwtUxContext();
+ // UiContext.setData(CmsView.KEY, this);
+ CmsSwtUtils.registerCmsView(loginShell.getShell(), this);
+ e4Application = getApplication(null);
+ Object res = Subject.doAs(subject, new PrivilegedExceptionAction<Object>() {
+
+ @Override
+ public Object run() throws Exception {
+ return e4Application.start(context);
+ }
+
+ });
+ return res;
+ }
+
+ @Override
+ public void stop() {
+ if (e4Application != null)
+ e4Application.stop();
+ }
+
+ static IApplication getApplication(String[] args) {
+ IExtension extension = Platform.getExtensionRegistry().getExtension(Platform.PI_RUNTIME,
+ Platform.PT_APPLICATIONS, "org.eclipse.e4.ui.workbench.swt.E4Application");
+ try {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ if (elements.length > 0) {
+ IConfigurationElement[] runs = elements[0].getChildren("run");
+ if (runs.length > 0) {
+ Object runnable;
+ runnable = runs[0].createExecutableExtension("class");
+ if (runnable instanceof IApplication)
+ return (IApplication) runnable;
+ }
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot find e4 application", e);
+ }
+ throw new IllegalStateException("Cannot find e4 application");
+ }
+
+ public static Display createDisplay() {
+ Display.setAppName("Argeo CMS RCP");
+
+ // create the display
+ Display newDisplay = Display.getCurrent();
+ if (newDisplay == null) {
+ newDisplay = new Display();
+ }
+ // Set the priority higher than normal so as to be higher
+ // than the JobManager.
+ Thread.currentThread().setPriority(Math.min(Thread.MAX_PRIORITY, Thread.NORM_PRIORITY + 1));
+ return newDisplay;
+ }
+
+ //
+ // CMS VIEW
+ //
+
+ @Override
+ public UxContext getUxContext() {
+ return uxContext;
+ }
+
+ @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) {
+ // System.err.println("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 CmsImageManager getImageManager() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return CurrentUser.isAnonymous(getSubject());
+ }
+
+ @Override
+ public String getUid() {
+ return uid;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.e4.rcp;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
+import org.eclipse.e4.ui.workbench.lifecycle.PreSave;
+import org.eclipse.e4.ui.workbench.lifecycle.ProcessAdditions;
+import org.eclipse.e4.ui.workbench.lifecycle.ProcessRemovals;
+
+@SuppressWarnings("restriction")
+public class CmsRcpLifeCycle {
+
+ @PostContextCreate
+ void postContextCreate(IEclipseContext workbenchContext) {
+ }
+
+ @PreSave
+ void preSave(IEclipseContext workbenchContext) {
+ }
+
+ @ProcessAdditions
+ void processAdditions(IEclipseContext workbenchContext) {
+ }
+
+ @ProcessRemovals
+ void processRemovals(IEclipseContext workbenchContext) {
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.swt.rcp.cli</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+package org.argeo.cms.swt.rcp.cli;
+
+import java.lang.management.ManagementFactory;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.concurrent.ForkJoinPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.argeo.api.acr.spi.ProvidedRepository;
+import org.argeo.api.cli.CommandsCli;
+import org.argeo.api.cli.DescribedCommand;
+import org.argeo.api.cms.CmsApp;
+import org.argeo.cms.runtime.StaticCms;
+import org.argeo.cms.swt.app.CmsUserApp;
+import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
+import org.argeo.util.register.Component;
+import org.argeo.util.register.ComponentRegister;
+
+public class CmsCli extends CommandsCli {
+
+ public CmsCli(String commandName) {
+ super(commandName);
+ addCommand("static", new Launch());
+ }
+
+ @Override
+ public String getDescription() {
+ return "Argeo CMS utilities.";
+ }
+
+ static class Launch implements DescribedCommand<String> {
+ private Option dataOption;
+ private Option uiOption;
+
+ @Override
+ public Options getOptions() {
+ Options options = new Options();
+ dataOption = Option.builder().longOpt("data").hasArg().required()
+ .desc("path to the writable data area (mandatory)").build();
+ uiOption = Option.builder().longOpt("ui").desc("open a user interface").build();
+ options.addOption(dataOption);
+ options.addOption(uiOption);
+ return options;
+ }
+
+ @Override
+ public String apply(List<String> args) {
+ CommandLine cl = toCommandLine(args);
+ String dataPath = cl.getOptionValue(dataOption);
+ boolean ui = cl.hasOption(uiOption);
+
+ Path instancePath = Paths.get(dataPath);
+ System.setProperty("osgi.instance.area", instancePath.toUri().toString());
+
+ StaticCms staticCms = new StaticCms() {
+ @Override
+ protected void addComponents(ComponentRegister register) {
+ if (ui) {
+ Component<? extends ProvidedRepository> contentRepositoryC = register
+ .find(ProvidedRepository.class, null).first();
+ CmsUserApp cmsApp = new CmsUserApp();
+ Component<CmsUserApp> cmsAppC = new Component.Builder<>(cmsApp) //
+ .addType(CmsApp.class) //
+ .addType(CmsUserApp.class) //
+ .addDependency(contentRepositoryC.getType(ProvidedRepository.class),
+ cmsApp::setContentRepository, null) //
+ .build(register);
+
+ CmsRcpDisplayFactory displayFactory = new CmsRcpDisplayFactory();
+ Component<CmsRcpDisplayFactory> displayFactoryC = new Component.Builder<>(displayFactory) //
+ .addActivation(displayFactory::init) //
+ .addDeactivation(displayFactory::destroy) //
+ .build(register);
+
+ }
+ }
+
+ @Override
+ protected void postActivation(ComponentRegister register) {
+ if (ui) {
+ Component<? extends CmsUserApp> cmsAppC = register.find(CmsUserApp.class, null).first();
+ CmsRcpDisplayFactory.openCmsApp(null, cmsAppC.get(), "data", (e) -> {
+ // asynchronous in order to avoid deadlock in UI thread
+ ForkJoinPool.commonPool().execute(() -> stop());
+ });
+ }
+ }
+
+ };
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> staticCms.stop(), "Static CMS Shutdown"));
+ staticCms.start();
+
+ long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
+ System.out.println("Static CMS available in " + jvmUptime + " ms.");
+
+ staticCms.waitForStop();
+
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Launch a static CMS.";
+ }
+
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.ui.rcp</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="CMS RCP Display Factory">
+ <implementation class="org.argeo.cms.ui.rcp.CmsRcpDisplayFactory"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="CMS RCP Servlet Factory">
+ <implementation class="org.argeo.cms.ui.rcp.servlet.CmsRcpServletFactory"/>
+ <reference bind="addCmsApp" cardinality="0..n" interface="org.argeo.api.cms.CmsApp" name="CmsApp" policy="dynamic" unbind="removeCmsApp"/>
+ <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
+ <reference bind="setHttpService" cardinality="1..1" interface="org.osgi.service.http.HttpService" name="HttpService" policy="static"/>
+</scr:component>
--- /dev/null
+
+Import-Package:\
+org.argeo.cms.auth,\
+org.eclipse.swt,\
+org.eclipse.swt.graphics,\
+org.w3c.css.sac,\
+*
+
+Service-Component:\
+OSGI-INF/cmsRcpDisplayFactory.xml,\
+OSGI-INF/cmsRcpServletFactory.xml
+
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/,\
+ OSGI-INF/cmsRcpServletFactory.xml
+source.. = src/
--- /dev/null
+package org.argeo.cms.ui.rcp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.api.cms.CmsApp;
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsSession;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.api.cms.ux.CmsTheme;
+import org.argeo.api.cms.ux.CmsUi;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.api.cms.ux.UxContext;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.e4.ui.css.core.engine.CSSEngine;
+import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler;
+import org.eclipse.e4.ui.css.swt.engine.CSSSWTEngineImpl;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+/** Runs a {@link CmsApp} as an SWT desktop application. */
+@SuppressWarnings("restriction")
+public class CmsRcpApp implements CmsView {
+ private final static CmsLog log = CmsLog.getLog(CmsRcpApp.class);
+
+ // private BundleContext bundleContext =
+ // FrameworkUtil.getBundle(CmsRcpApp.class).getBundleContext();
+
+ private Shell shell;
+ private CmsApp cmsApp;
+
+ // CMS View
+ private String uid;
+ private LoginContext loginContext;
+
+ private EventAdmin eventAdmin;
+
+ private CSSEngine cssEngine;
+
+ private CmsUi ui;
+ // TODO make it configurable
+ private String uiName = "desktop";
+
+ public CmsRcpApp(String uiName) {
+ uid = UUID.randomUUID().toString();
+ this.uiName = uiName;
+ }
+
+ public void initRcpApp() {
+ Display display = Display.getCurrent();
+ shell = new Shell(display);
+ shell.setText("Argeo CMS");
+ Composite parent = shell;
+ parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+ CmsSwtUtils.registerCmsView(shell, CmsRcpApp.this);
+
+ try {
+ loginContext = new LoginContext(CmsAuth.SINGLE_USER.getLoginContextName());
+ loginContext.login();
+ } catch (LoginException e) {
+ throw new IllegalStateException("Could not log in.", e);
+ }
+ if (log.isDebugEnabled())
+ log.debug("Logged in to desktop: " + loginContext.getSubject());
+
+ Subject.doAs(loginContext.getSubject(), (PrivilegedAction<Void>) () -> {
+
+ // TODO factorise with web app
+ parent.setData(CmsApp.UI_NAME_PROPERTY, uiName);
+ ui = cmsApp.initUi(parent);
+ 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.
+ cmsApp.refreshUi(ui, null);
+
+ // Styling
+ CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
+ if (theme != null) {
+ cssEngine = new CSSSWTEngineImpl(display);
+ for (String path : theme.getSwtCssPaths()) {
+ try (InputStream in = theme.loadPath(path)) {
+ cssEngine.parseStyleSheet(in);
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot load stylesheet " + path, e);
+ }
+ }
+ cssEngine.setErrorHandler(new CSSErrorHandler() {
+ public void error(Exception e) {
+ log.error("SWT styling error: ", e);
+ }
+ });
+ applyStyles(shell);
+ }
+ shell.layout(true, true);
+
+ shell.open();
+ return null;
+ });
+ }
+
+ /*
+ * CMS VIEW
+ */
+
+ @Override
+ public String getUid() {
+ return uid;
+ }
+
+ @Override
+ public UxContext getUxContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void navigateTo(String state) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void authChange(LoginContext loginContext) {
+ }
+
+ @Override
+ public void logout() {
+ if (loginContext != null)
+ try {
+ loginContext.logout();
+ } catch (LoginException e) {
+ log.error("Cannot log out", e);
+ }
+ }
+
+ @Override
+ public void exception(Throwable e) {
+ log.error("Unexpected exception in CMS RCP", e);
+ }
+
+ @Override
+ public CmsImageManager getImageManager() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public CmsSession getCmsSession() {
+ CmsSession cmsSession = cmsApp.getCmsContext().getCmsSession(getSubject());
+ return cmsSession;
+ }
+
+ @Override
+ public Object getData(String key) {
+ if (ui != null) {
+ return ui.getData(key);
+ } else {
+ throw new IllegalStateException("UI is not initialized");
+ }
+ }
+
+ @Override
+ public void setData(String key, Object value) {
+ if (ui != null) {
+ ui.setData(key, value);
+ } else {
+ throw new IllegalStateException("UI is not initialized");
+ }
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return false;
+ }
+
+ @Override
+ public void applyStyles(Object node) {
+ if (cssEngine != null)
+ cssEngine.applyStyles(node, true);
+ }
+
+ @Override
+ public void sendEvent(String topic, Map<String, Object> properties) {
+ if (properties == null)
+ properties = new HashMap<>();
+ if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
+ throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
+ + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
+ properties.put(CMS_VIEW_UID_PROPERTY, uid);
+ eventAdmin.sendEvent(new Event(topic, properties));
+ }
+
+ public <T> T doAs(PrivilegedAction<T> action) {
+ return Subject.doAs(getSubject(), action);
+ }
+
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
+ public Shell getShell() {
+ return shell;
+ }
+
+ /*
+ * DEPENDENCY INJECTION
+ */
+ public void setCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ this.cmsApp = cmsApp;
+ }
+
+ public void unsetCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ this.cmsApp = null;
+ }
+
+ public void setEventAdmin(EventAdmin eventAdmin) {
+ this.eventAdmin = eventAdmin;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.rcp;
+
+import java.nio.file.Path;
+
+import org.argeo.api.cms.CmsApp;
+import org.argeo.util.OS;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.service.event.EventAdmin;
+import org.eclipse.swt.events.DisposeListener;
+
+/** Creates the SWT {@link Display} in a dedicated thread. */
+public class CmsRcpDisplayFactory {
+ /** File name in a run directory */
+ private final static String ARGEO_RCP_URL = "argeo.rcp.url";
+
+ /** There is only one display in RCP mode */
+ private static Display display;
+
+ private CmsUiThread uiThread;
+
+ private boolean shutdown = false;
+
+ public void init() {
+ uiThread = new CmsUiThread();
+ uiThread.start();
+ while (display == null)
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // silent
+ }
+ }
+
+ public void destroy() {
+ shutdown = true;
+ display.wake();
+ try {
+ uiThread.join();
+ } catch (InterruptedException e) {
+ // silent
+ } finally {
+ uiThread = null;
+ }
+ }
+
+ class CmsUiThread extends Thread {
+
+ public CmsUiThread() {
+ super("CMS UI");
+ }
+
+ @Override
+ public void run() {
+ display = Display.getDefault();
+ display.setRuntimeExceptionHandler((e) -> e.printStackTrace());
+ display.setErrorHandler((e) -> e.printStackTrace());
+
+// for (String contextName : cmsApps.keySet()) {
+// openCmsApp(contextName);
+// }
+
+ while (!shutdown) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ display.dispose();
+ display = null;
+ }
+ }
+
+ public static Display getDisplay() {
+ return display;
+ }
+
+ public static void openCmsApp(EventAdmin eventAdmin, CmsApp cmsApp, String uiName,
+ DisposeListener disposeListener) {
+ CmsRcpDisplayFactory.getDisplay().syncExec(() -> {
+ CmsRcpApp cmsRcpApp = new CmsRcpApp(uiName);
+ cmsRcpApp.setEventAdmin(eventAdmin);
+ cmsRcpApp.setCmsApp(cmsApp, null);
+ cmsRcpApp.initRcpApp();
+ if (disposeListener != null)
+ cmsRcpApp.getShell().addDisposeListener(disposeListener);
+ });
+ }
+
+ public static Path getUrlRunFile() {
+ return OS.getRunDir().resolve(CmsRcpDisplayFactory.ARGEO_RCP_URL);
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.rcp.servlet;
+
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.Objects;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.argeo.api.cms.CmsApp;
+import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
+import org.osgi.service.event.EventAdmin;
+
+/** Open the related app when called. */
+public class CmsRcpServlet extends HttpServlet {
+ private static final long serialVersionUID = -3944472431354848923L;
+ private final static Logger logger = System.getLogger(CmsRcpServlet.class.getName());
+
+ private CmsApp cmsApp;
+ private EventAdmin eventAdmin;
+
+ public CmsRcpServlet(EventAdmin eventAdmin, CmsApp cmsApp) {
+ Objects.requireNonNull(eventAdmin);
+ Objects.requireNonNull(cmsApp);
+ this.cmsApp = cmsApp;
+ this.eventAdmin = eventAdmin;
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String path = req.getPathInfo();
+ String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
+ CmsRcpDisplayFactory.openCmsApp(eventAdmin, cmsApp, uiName, null);
+ logger.log(Level.DEBUG, "Opened RCP UI " + uiName + " of CMS App " + req.getServletPath());
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.rcp.servlet;
+
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.net.DatagramSocket;
+import java.net.ServerSocket;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import javax.servlet.Servlet;
+
+import org.argeo.api.cms.CmsApp;
+import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.http.HttpService;
+
+/** Publishes one {@link CmsRcpServlet} per {@link CmsApp}. */
+public class CmsRcpServletFactory {
+ private final static Logger logger = System.getLogger(CmsRcpServletFactory.class.getName());
+
+ private BundleContext bundleContext = FrameworkUtil.getBundle(CmsRcpServletFactory.class).getBundleContext();
+
+ private CompletableFuture<EventAdmin> eventAdmin = new CompletableFuture<>();
+
+ private Map<String, ServiceRegistration<Servlet>> registrations = Collections.synchronizedMap(new HashMap<>());
+
+ public void init() {
+
+ }
+
+ public void destroy() {
+ Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
+ try {
+ if (Files.exists(runFile)) {
+ Files.delete(runFile);
+ }
+ } catch (IOException e) {
+ logger.log(Level.ERROR, "Cannot delete " + runFile, e);
+ }
+ }
+
+ public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+ if (contextName != null) {
+ eventAdmin.thenAccept((eventAdmin) -> {
+ CmsRcpServlet servlet = new CmsRcpServlet(eventAdmin, cmsApp);
+ Hashtable<String, String> serviceProperties = new Hashtable<>();
+ serviceProperties.put("osgi.http.whiteboard.servlet.pattern", "/" + contextName + "/*");
+ ServiceRegistration<Servlet> sr = bundleContext.registerService(Servlet.class, servlet,
+ serviceProperties);
+ registrations.put(contextName, sr);
+ });
+ }
+ }
+
+ public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+ if (contextName != null) {
+ ServiceRegistration<Servlet> sr = registrations.get(contextName);
+ sr.unregister();
+ }
+ }
+
+ public void setEventAdmin(EventAdmin eventAdmin) {
+ this.eventAdmin.complete(eventAdmin);
+ }
+
+ public void setHttpService(HttpService httpService, Map<String, Object> properties) {
+ Integer httpPort = Integer.parseInt(properties.get("http.port").toString());
+ String baseUrl = "http://localhost:" + httpPort + "/";
+ Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
+ try {
+ if (!Files.exists(runFile)) {
+ Files.createDirectories(runFile.getParent());
+ // TODO give read permission only to the owner
+ Files.createFile(runFile);
+ } else {
+ URI uri = URI.create(Files.readString(runFile));
+ if (!httpPort.equals(uri.getPort()))
+ if (!isPortAvailable(uri.getPort())) {
+ throw new IllegalStateException("Another CMS is running on " + runFile);
+ } else {
+ logger.log(Level.WARNING,
+ "Run file " + runFile + " found but port of " + uri + " is available. Overwriting...");
+ }
+ }
+ Files.writeString(runFile, baseUrl, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write run file to " + runFile, e);
+ }
+ logger.log(Level.DEBUG, "RCP available under " + baseUrl + ", written to " + runFile);
+ }
+
+ protected boolean isPortAvailable(int port) {
+ ServerSocket ss = null;
+ DatagramSocket ds = null;
+ try {
+ ss = new ServerSocket(port);
+ ss.setReuseAddress(true);
+ ds = new DatagramSocket(port);
+ ds.setReuseAddress(true);
+ return true;
+ } catch (IOException e) {
+ } finally {
+ if (ds != null) {
+ ds.close();
+ }
+
+ if (ss != null) {
+ try {
+ ss.close();
+ } catch (IOException e) {
+ /* should not be thrown */
+ }
+ }
+ }
+
+ return false;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src" />
+ <classpathentry kind="con"
+ path="org.eclipse.pde.core.requiredPlugins" />
+ <classpathentry kind="con"
+ path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" />
+ <classpathentry kind="output" path="bin" />
+</classpath>
--- /dev/null
+/target/
+/bin/
+*.log
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.swt.specific.rcp</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+Import-Package: \
+!java.*,\
+org.apache.commons.io,\
+org.eclipse.core.commands,\
+!org.eclipse.core.runtime,\
+!org.eclipse.ui.plugin,\
+org.eclipse.swt,\
+javax.servlet.http;version="[3,5)",\
+javax.servlet;version="[3,5)",\
+*
+
+Export-Package: org.argeo.*,\
+org.eclipse.rap.fileupload.*;version="3.10",\
+org.eclipse.rap.rwt.*;version="3.10"
+
+# Was !org.eclipse.core.commands,\ why ?
+
+#Bundle-Activator: org.argeo.eclipse.ui.ArgeoUiPlugin
+#Bundle-ActivationPolicy: lazy
+#Ignore-Package: org.eclipse.core.commands
\ No newline at end of file
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/
--- /dev/null
+package org.argeo.eclipse.ui.rcp.internal.rwt;
+
+import org.eclipse.rap.rwt.client.Client;
+import org.eclipse.rap.rwt.client.service.BrowserNavigation;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
+import org.eclipse.rap.rwt.client.service.ClientService;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+
+public class RcpClient implements Client {
+
+ @Override
+ public <T extends ClientService> T getService(Class<T> type) {
+ if (type.isAssignableFrom(JavaScriptExecutor.class))
+ return (T) javaScriptExecutor;
+ else if (type.isAssignableFrom(BrowserNavigation.class))
+ return (T) browserNavigation;
+ else
+ return null;
+ }
+
+ private JavaScriptExecutor javaScriptExecutor = new JavaScriptExecutor() {
+
+ @Override
+ public void execute(String code) {
+ // TODO Auto-generated method stub
+
+ }
+ };
+ private BrowserNavigation browserNavigation = new BrowserNavigation() {
+
+ @Override
+ public void pushState(String state, String title) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void addBrowserNavigationListener(
+ BrowserNavigationListener listener) {
+ // TODO Auto-generated method stub
+
+ }
+ };
+}
--- /dev/null
+package org.argeo.eclipse.ui.rcp.internal.rwt;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.io.IOUtils;
+import org.eclipse.rap.rwt.service.ResourceManager;
+
+public class RcpResourceManager implements ResourceManager {
+ private Map<String, byte[]> register = Collections
+ .synchronizedMap(new TreeMap<String, byte[]>());
+
+ @Override
+ public void register(String name, InputStream in) {
+ try {
+ register.put(name, IOUtils.toByteArray(in));
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot register " + name, e);
+ }
+ }
+
+ @Override
+ public boolean unregister(String name) {
+ return register.remove(name) != null;
+ }
+
+ @Override
+ public InputStream getRegisteredContent(String name) {
+ return new ByteArrayInputStream(register.get(name));
+ }
+
+ @Override
+ public String getLocation(String name) {
+ return name;
+ }
+
+ @Override
+ public boolean isRegistered(String name) {
+ return register.containsKey(name);
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JPanel;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.awt.SWT_AWT;
+import org.eclipse.swt.widgets.Composite;
+
+public class BufferedImageDisplay extends Composite {
+ private BufferedImage image;
+
+ public BufferedImageDisplay(Composite parent, int style) {
+ super(parent, SWT.EMBEDDED | SWT.NO_BACKGROUND);
+ Frame frame = SWT_AWT.new_Frame(this);
+ frame.setLayout(new BorderLayout());
+ frame.add(new JPanel() {
+ private static final long serialVersionUID = 8924410573598922364L;
+
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ if (image != null)
+ g.drawImage(image, 0, 0, this);
+ }
+
+ }, BorderLayout.CENTER);
+ frame.setVisible(true);
+ }
+
+ public void setImage(BufferedImage image) {
+ this.image = image;
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+
+public class CmsFileDialog extends FileDialog {
+ public CmsFileDialog(Shell parent, int style) {
+ super(parent, style);
+ }
+
+ public CmsFileDialog(Shell parent) {
+ super(parent);
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Composite;
+
+public class CmsFileUpload extends FileUpload {
+ public CmsFileUpload(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ public void setText(String text) {
+ super.setText(text);
+ }
+
+ @Override
+ public String getFileName() {
+ return super.getFileName();
+ }
+
+ @Override
+ public String[] getFileNames() {
+ return super.getFileNames();
+ }
+
+ @Override
+ public void addSelectionListener(SelectionListener listener) {
+ super.addSelectionListener(listener);
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+/** RCP specific {@link NLS} to be extended */
+public class DefaultNLS {// extends NLS {
+// public final static String DEFAULT_BUNDLE_LOCATION = "/properties/plugin";
+//
+// public DefaultNLS() {
+// this(DEFAULT_BUNDLE_LOCATION);
+// }
+//
+// public DefaultNLS(String bundleName) {
+// NLS.initializeMessages(bundleName, getClass());
+// }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+/** Constants which are specific to RWT.*/
+public interface EclipseUiConstants {
+ final static String CSS_CLASS = "org.eclipse.e4.ui.css.CssClassName";
+ final static String MARKUP_SUPPORT = null;
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.widgets.Widget;
+
+/** Static utilities to bridge differences between RCP and RAP */
+public class EclipseUiSpecificUtils {
+ private final static String CSS_CLASS = "org.eclipse.e4.ui.css.CssClassName";
+
+ public static void setStyleData(Widget widget, Object data) {
+ widget.setData(CSS_CLASS, data);
+ }
+
+ public static Object getStyleData(Widget widget) {
+ return widget.getData(CSS_CLASS);
+ }
+
+ public static void setMarkupData(Widget widget) {
+ // does nothing
+ }
+
+ public static void setMarkupValidationDisabledData(Widget widget) {
+ // does nothing
+ }
+
+ /**
+ * TootlTip support is supported for {@link ColumnViewer} in RCP
+ *
+ * @see ColumnViewerToolTipSupport#enableFor(Viewer)
+ */
+ public static void enableToolTipSupport(Viewer viewer) {
+ if (viewer instanceof ColumnViewer)
+ ColumnViewerToolTipSupport.enableFor((ColumnViewer) viewer);
+ }
+
+ private EclipseUiSpecificUtils() {
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.DropTargetAdapter;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.FileTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.widgets.Control;
+
+public class FileDropAdapter {
+
+ public void prepareDropTarget(Control control, DropTarget dropTarget) {
+ dropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() });
+ dropTarget.addDropListener(new DropTargetAdapter() {
+ @Override
+ public void dropAccept(DropTargetEvent event) {
+ if (!FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
+ event.detail = DND.DROP_NONE;
+ }
+ }
+
+ @Override
+ public void drop(DropTargetEvent event) {
+ handleFileDrop(control, event);
+ }
+ });
+ }
+
+ public void handleFileDrop(Control control, DropTargetEvent event) {
+ String fileList[] = null;
+ FileTransfer ft = FileTransfer.getInstance();
+ if (ft.isSupportedType(event.currentDataType)) {
+ fileList = (String[]) event.data;
+ }
+ System.out.println(Arrays.toString(fileList));
+ }
+
+ /** Executed in UI thread */
+ protected void processUpload(InputStream in, String fileName, String contentType) throws IOException {
+
+ }
+
+}
--- /dev/null
+package org.argeo.eclipse.ui.specific;
+
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.swt.widgets.Display;
+
+/** Singleton class providing single sources infos about the UI context. */
+public class UiContext {
+
+ public static HttpServletRequest getHttpRequest() {
+ return null;
+ }
+
+ public static HttpServletResponse getHttpResponse() {
+ return null;
+ }
+
+ public static Locale getLocale() {
+ return Locale.getDefault();
+ }
+
+ public static void setLocale(Locale locale) {
+ Locale.setDefault(locale);
+ }
+
+ /** Can always be null */
+ @SuppressWarnings("unchecked")
+ public static <T> T getData(String key) {
+ Display display = getDisplay();
+ if (display == null)
+ return null;
+ return (T) display.getData(key);
+ }
+
+ public static void setData(String key, Object value) {
+ Display display = getDisplay();
+ if (display == null)
+ throw new IllegalStateException("Not display available");
+ display.setData(key, value);
+ }
+
+ private static Display getDisplay() {
+ return Display.getCurrent();
+ }
+
+ private UiContext() {
+ }
+
+}
--- /dev/null
+package org.eclipse.rap.fileupload;
+
+public interface FileDetails {
+ String getContentType();
+
+ long getContentLength();
+
+ String getFileName();
+}
--- /dev/null
+package org.eclipse.rap.fileupload;
+
+import java.util.EventObject;
+
+public abstract class FileUploadEvent extends EventObject {
+
+ private static final long serialVersionUID = 1L;
+
+ protected FileUploadEvent(FileUploadHandler source) {
+ super(source);
+ }
+
+ public abstract FileDetails[] getFileDetails();
+
+ public abstract long getContentLength();
+
+ public abstract long getBytesRead();
+
+ public abstract Exception getException();
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.fileupload;
+
+/**
+ * A file upload handler is used to accept file uploads from a client. After
+ * creating a file upload handler, the server will accept file uploads to the
+ * URL returned by <code>getUploadUrl()</code>. Upload listeners can be attached
+ * to react on progress. When the upload has finished, a FileUploadHandler has
+ * to be disposed of by calling its <code>dispose()</code> method.
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class FileUploadHandler {
+
+ public FileUploadHandler(FileUploadReceiver fileUploadReceiver) {
+ }
+
+ public void dispose() {
+
+ }
+
+ public void addUploadListener(FileUploadListener listener) {
+
+ }
+
+ public String getUploadUrl() {
+ return null;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.fileupload;
+
+import org.eclipse.swt.widgets.Display;
+
+
+/**
+ * Listener to react on progress and completion of a file upload.
+ * <p>
+ * <strong>Note:</strong> This listener will be called from a different thread than the UI thread.
+ * Implementations must use {@link Display#asyncExec(Runnable)} to access the UI.
+ * </p>
+ *
+ * @see FileUploadEvent
+ */
+public interface FileUploadListener {
+
+ /**
+ * Called when new information about an in-progress upload is available.
+ *
+ * @param event event object that contains information about the uploaded file
+ * @see FileUploadEvent#getBytesRead()
+ */
+ void uploadProgress( FileUploadEvent event );
+
+ /**
+ * Called when a file upload has finished successfully.
+ *
+ * @param event event object that contains information about the uploaded file
+ * @see FileUploadEvent
+ */
+ void uploadFinished( FileUploadEvent event );
+
+ /**
+ * Called when a file upload failed.
+ *
+ * @param event event object that contains information about the uploaded file
+ * @see FileUploadEvent#getErrorMessage()
+ */
+ void uploadFailed( FileUploadEvent event );
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.fileupload;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * Instances of this interface are responsible for reading and processing the data from a file
+ * upload.
+ */
+public abstract class FileUploadReceiver {
+
+ /**
+ * Reads and processes all data from the provided input stream.
+ *
+ * @param stream the stream to read from
+ * @param details the details of the uploaded file like file name, content-type and size
+ * @throws IOException if an input / output error occurs
+ */
+ public abstract void receive( InputStream stream, FileDetails details ) throws IOException;
+
+}
--- /dev/null
+package org.eclipse.rap.rwt;
+
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.argeo.eclipse.ui.rcp.internal.rwt.RcpClient;
+import org.argeo.eclipse.ui.rcp.internal.rwt.RcpResourceManager;
+import org.eclipse.rap.rwt.client.Client;
+import org.eclipse.rap.rwt.service.ResourceManager;
+
+public class RWT {
+ public final static String CUSTOM_VARIANT = "argeo-rcp:CUSTOM_VARIANT";
+ public final static String MARKUP_ENABLED = "argeo-rcp:MARKUP_ENABLED";
+ public static final String TOOLTIP_MARKUP_ENABLED = "argeo-rcp:TOOLTIP_MARKUP_ENABLED";
+ public final static String CUSTOM_ITEM_HEIGHT = "argeo-rcp:CUSTOM_ITEM_HEIGHT";
+ public final static String ACTIVE_KEYS = "argeo-rcp:ACTIVE_KEYS";
+ public final static String CANCEL_KEYS = "argeo-rcp:CANCEL_KEYS";
+ public final static String DEFAULT_THEME_ID = "argeo-rcp:DEFAULT_THEME_ID";
+
+ public final static int HYPERLINK = 0;
+
+ private static Locale locale = Locale.getDefault();
+ private static RcpClient client = new RcpClient();
+ private static ResourceManager resourceManager = new RcpResourceManager();
+ static {
+
+ }
+
+ public static Locale getLocale() {
+ return locale;
+ }
+
+ public static HttpServletRequest getRequest() {
+ return null;
+ }
+
+ public static ResourceManager getResourceManager() {
+ return resourceManager;
+ }
+
+ public static Client getClient() {
+ return client;
+ }
+}
--- /dev/null
+package org.eclipse.rap.rwt;
+
+public class SingletonUtil {
+ public static <T> T getSessionInstance(Class<T> clss) {
+ return null;
+ }
+}
--- /dev/null
+package org.eclipse.rap.rwt.application;
+
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public abstract class AbstractEntryPoint implements EntryPoint {
+ private Display display;
+ private Shell shell;
+
+ protected Shell createShell(Display display) {
+ return new Shell(display);
+ }
+
+ protected void createContents(Composite parent) {
+
+ }
+
+ public int createUI() {
+ display = new Display();
+ shell = createShell(display);
+ shell.setLayout(new GridLayout(1, false));
+ createContents(shell);
+ if (shell.getMaximized()) {
+ shell.layout();
+ } else {
+ shell.pack();
+ }
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ return 0;
+ }
+
+ protected Shell getShell() {
+ return shell;
+ }
+}
--- /dev/null
+package org.eclipse.rap.rwt.application;
+
+import java.util.Map;
+
+import org.eclipse.rap.rwt.service.ResourceLoader;
+
+public interface Application {
+ public static enum OperationMode {
+ JEE_COMPATIBILITY, SWT_COMPATIBILITY,
+ }
+
+ void setOperationMode(OperationMode operationMode);
+
+ void addResource(String name, ResourceLoader resourceLoader);
+
+ void setExceptionHandler(ExceptionHandler exceptionHandler);
+
+ void addEntryPoint(String path, EntryPointFactory entryPointFactory,
+ Map<String, String> properties);
+
+ void addEntryPoint(String path, Class<? extends EntryPoint> entryPoint,
+ Map<String, String> properties);
+
+ void addStyleSheet(String themeId, String styleSheetLocation,
+ ResourceLoader resourceLoader);
+
+}
--- /dev/null
+package org.eclipse.rap.rwt.application;
+
+public interface ApplicationConfiguration {
+ void configure(Application application);
+}
--- /dev/null
+package org.eclipse.rap.rwt.application;
+
+public interface EntryPoint {
+ int createUI();
+}
--- /dev/null
+package org.eclipse.rap.rwt.application;
+
+public interface EntryPointFactory {
+ public EntryPoint create();
+}
--- /dev/null
+package org.eclipse.rap.rwt.application;
+
+public interface ExceptionHandler {
+ public void handleException(Throwable throwable);
+}
--- /dev/null
+package org.eclipse.rap.rwt.client;
+
+import java.io.Serializable;
+
+import org.eclipse.rap.rwt.client.service.ClientService;
+
+public interface Client extends Serializable {
+
+ /**
+ * Returns this client's implementation of a given service, if available.
+ *
+ * @param type the type of the requested service, must be a subtype of ClientService
+ * @return the requested service if provided by this client, otherwise <code>null</code>
+ * @see ClientService
+ */
+ <T extends ClientService> T getService( Class<T> type );
+
+}
\ No newline at end of file
--- /dev/null
+package org.eclipse.rap.rwt.client;
+
+public interface WebClient {
+ public final static String FAVICON = "rcp:FAVICON";
+ public final static String PAGE_TITLE = "rcp:PAGE_TITLE";
+ public final static String BODY_HTML = "rcp:BODY_HTML";
+ public final static String THEME_ID = "rcp:THEME_ID";
+ public final static String HEAD_HTML = "rcp:HEAD_HTML";
+ public final static String PAGE_OVERFLOW = "rcp:PAGE_OVERFLOW";
+}
--- /dev/null
+package org.eclipse.rap.rwt.client.service;
+
+public interface BrowserNavigation extends ClientService {
+ void pushState(String state, String title);
+
+ void addBrowserNavigationListener(BrowserNavigationListener listener);
+}
--- /dev/null
+package org.eclipse.rap.rwt.client.service;
+
+public class BrowserNavigationEvent {
+ private String state;
+
+ public String getState() {
+ return state;
+ }
+
+}
--- /dev/null
+package org.eclipse.rap.rwt.client.service;
+
+public interface BrowserNavigationListener {
+ public void navigated(BrowserNavigationEvent event);
+}
--- /dev/null
+package org.eclipse.rap.rwt.client.service;
+
+import java.io.Serializable;
+
+public interface ClientService extends Serializable {
+}
--- /dev/null
+package org.eclipse.rap.rwt.client.service;
+
+public interface JavaScriptExecutor extends ClientService {
+ public void execute( String code );
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2012 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.rwt.client.service;
+
+/**
+ * The UrlLauncher service allows loading an URL in an external window, application or save dialog.
+ *
+ * @since 2.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface UrlLauncher extends ClientService {
+
+ /**
+ * Opens the given URL.
+ *
+ * Any HTTP URL or relative URL will be opened in a new window.
+ * Modern browser may block any attempt to open new windows, but will usually prompt the user to
+ * accept or ignore. Even if accepted, the decision may be applied to only this attempt, or only
+ * to future attempts. It could also trigger a document reload, causing a session restart.
+ *
+ * Non-HTTP URLs like "mailto" will not create a new browser window, but require the client
+ * to have a matching protocol handler registered.
+ *
+ * @param url the URL to open
+ */
+ void openURL( String url );
+
+}
--- /dev/null
+package org.eclipse.rap.rwt.service;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface ResourceLoader {
+ public InputStream getResourceAsStream(String resourceName)
+ throws IOException;
+}
--- /dev/null
+package org.eclipse.rap.rwt.service;
+
+import java.io.InputStream;
+
+public interface ResourceManager {
+ public void register(String name, InputStream in);
+
+ boolean unregister(String name);
+
+ public InputStream getRegisteredContent(String name);
+
+ public String getLocation(String name);
+
+ public boolean isRegistered(String name);
+}
--- /dev/null
+package org.eclipse.rap.rwt.service;
+
+/** Mock, does nothing as this is irrelevant for RCP. */
+public class ServerPushSession {
+ public void start() {
+
+ }
+
+ public void stop() {
+
+ }
+}
--- /dev/null
+package org.eclipse.rap.rwt.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Widget;
+
+public class DropDown {
+ private boolean visible=false;
+
+ public DropDown(Widget parent, int style) {
+ // FIXME implement a shell
+ }
+
+ public DropDown(Widget parent) {
+ this(parent, SWT.NONE);
+ }
+
+ public void setVisible(boolean visible) {
+ this.visible = visible;
+ }
+
+ public boolean isVisible() {
+ return visible;
+ }
+
+ public void setItems( String[] items ) {
+
+ }
+
+ public void setSelectionIndex( int selection ) {
+
+ }
+
+}
--- /dev/null
+package org.eclipse.rap.rwt.widgets;
+
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+
+public class FileUpload extends Composite {
+
+ public FileUpload(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ public void addSelectionListener(SelectionListener listener) {
+
+ }
+
+ public void submit(String url) {
+
+ }
+
+ public void setImage(Image image) {
+
+ }
+
+ public void setText(String text) {
+
+ }
+
+ public String getFileName() {
+ return null;
+ }
+
+ public String[] getFileNames() {
+ return null;
+ }
+
+}