Move core projects to a separate directory.
authorMathieu Baudier <mbaudier@argeo.org>
Mon, 25 Jan 2021 08:54:42 +0000 (09:54 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Mon, 25 Jan 2021 08:54:42 +0000 (09:54 +0100)
314 files changed:
core/org.argeo.entity.api/.classpath [new file with mode: 0644]
core/org.argeo.entity.api/.gitignore [new file with mode: 0644]
core/org.argeo.entity.api/.project [new file with mode: 0644]
core/org.argeo.entity.api/META-INF/.gitignore [new file with mode: 0644]
core/org.argeo.entity.api/bnd.bnd [new file with mode: 0644]
core/org.argeo.entity.api/build.properties [new file with mode: 0644]
core/org.argeo.entity.api/pom.xml [new file with mode: 0644]
core/org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java [new file with mode: 0644]
core/org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java [new file with mode: 0644]
core/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java [new file with mode: 0644]
core/org.argeo.entity.api/src/org/argeo/entity/EntityType.java [new file with mode: 0644]
core/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java [new file with mode: 0644]
core/org.argeo.entity.api/src/org/argeo/entity/JcrName.java [new file with mode: 0644]
core/org.argeo.entity.api/src/org/argeo/entity/TermsManager.java [new file with mode: 0644]
core/org.argeo.entity.api/src/org/argeo/entity/entity.cnd [new file with mode: 0644]
core/org.argeo.entity.core/.classpath [new file with mode: 0644]
core/org.argeo.entity.core/.gitignore [new file with mode: 0644]
core/org.argeo.entity.core/.project [new file with mode: 0644]
core/org.argeo.entity.core/META-INF/.gitignore [new file with mode: 0644]
core/org.argeo.entity.core/bnd.bnd [new file with mode: 0644]
core/org.argeo.entity.core/build.properties [new file with mode: 0644]
core/org.argeo.entity.core/pom.xml [new file with mode: 0644]
core/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java [new file with mode: 0644]
core/org.argeo.entity.ui/.classpath [new file with mode: 0644]
core/org.argeo.entity.ui/.gitignore [new file with mode: 0644]
core/org.argeo.entity.ui/.project [new file with mode: 0644]
core/org.argeo.entity.ui/META-INF/.gitignore [new file with mode: 0644]
core/org.argeo.entity.ui/bnd.bnd [new file with mode: 0644]
core/org.argeo.entity.ui/build.properties [new file with mode: 0644]
core/org.argeo.entity.ui/pom.xml [new file with mode: 0644]
core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java [new file with mode: 0644]
core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java [new file with mode: 0644]
core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java [new file with mode: 0644]
core/org.argeo.suite.core/.classpath [new file with mode: 0644]
core/org.argeo.suite.core/.gitignore [new file with mode: 0644]
core/org.argeo.suite.core/.project [new file with mode: 0644]
core/org.argeo.suite.core/META-INF/.gitignore [new file with mode: 0644]
core/org.argeo.suite.core/OSGI-INF/maintenanceService.xml [new file with mode: 0644]
core/org.argeo.suite.core/OSGI-INF/termsManager.xml [new file with mode: 0644]
core/org.argeo.suite.core/bnd.bnd [new file with mode: 0644]
core/org.argeo.suite.core/build.properties [new file with mode: 0644]
core/org.argeo.suite.core/pom.xml [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/RankingKey.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/core/CustomMaintenanceService.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java [new file with mode: 0644]
core/org.argeo.suite.core/src/org/argeo/suite/util/XPathUtils.java [new file with mode: 0644]
core/org.argeo.suite.theme.default/.gitignore [new file with mode: 0644]
core/org.argeo.suite.theme.default/.project [new file with mode: 0644]
core/org.argeo.suite.theme.default/META-INF/.gitignore [new file with mode: 0644]
core/org.argeo.suite.theme.default/OSGI-INF/cmsTheme.xml [new file with mode: 0644]
core/org.argeo.suite.theme.default/bnd.bnd [new file with mode: 0644]
core/org.argeo.suite.theme.default/build.properties [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/add.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/close.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/dashboard.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/delete.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/document.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/documents.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/folder.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/inbox.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/location.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/logout.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/map.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/organisation.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/people.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/person.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/refresh.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/save.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/search.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/settings.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/tag.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/task.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/16/user.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/add.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/close.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/dashboard.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/delete.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/document.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/documents.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/folder.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/inbox.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/location.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/logout.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/map.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/organisation.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/people.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/person.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/save.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/search.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/settings.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/tag.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/task.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/icons/types/32/user.png [new file with mode: 0644]
core/org.argeo.suite.theme.default/pom.xml [new file with mode: 0644]
core/org.argeo.suite.theme.default/rap/work.css [new file with mode: 0644]
core/org.argeo.suite.theme.default/swt/app.css [new file with mode: 0644]
core/org.argeo.suite.ui.rap/.gitignore [new file with mode: 0644]
core/org.argeo.suite.ui.rap/.project [new file with mode: 0644]
core/org.argeo.suite.ui.rap/META-INF/.gitignore [new file with mode: 0644]
core/org.argeo.suite.ui.rap/OSGI-INF/cmsWebApp.xml [new file with mode: 0644]
core/org.argeo.suite.ui.rap/bnd.bnd [new file with mode: 0644]
core/org.argeo.suite.ui.rap/build.properties [new file with mode: 0644]
core/org.argeo.suite.ui.rap/pom.xml [new file with mode: 0644]
core/org.argeo.suite.ui/.classpath [new file with mode: 0644]
core/org.argeo.suite.ui/.gitignore [new file with mode: 0644]
core/org.argeo.suite.ui/.project [new file with mode: 0644]
core/org.argeo.suite.ui/META-INF/.gitignore [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/cmsApp.xml [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/dashboard.xml [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/dashboardLayer.xml [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/header.xml [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/l10n/bundle.properties [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/l10n/bundle_de.properties [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/l10n/bundle_fr.properties [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/leadPane.xml [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/loginScreen.xml [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/recentItems.xml [new file with mode: 0644]
core/org.argeo.suite.ui/bnd.bnd [new file with mode: 0644]
core/org.argeo.suite.ui/build.properties [new file with mode: 0644]
core/org.argeo.suite.ui/config/cmsApp.properties [new file with mode: 0644]
core/org.argeo.suite.ui/config/dashboard.properties [new file with mode: 0644]
core/org.argeo.suite.ui/config/dashboardLayer.properties [new file with mode: 0644]
core/org.argeo.suite.ui/config/header.properties [new file with mode: 0644]
core/org.argeo.suite.ui/config/leadPane.properties [new file with mode: 0644]
core/org.argeo.suite.ui/config/loginScreen.properties [new file with mode: 0644]
core/org.argeo.suite.ui/config/recentItems.properties [new file with mode: 0644]
core/org.argeo.suite.ui/pom.xml [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/AdminEntryArea.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultDashboard.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteEvent.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteIcon.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteMsg.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteStyle.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUserUiProvider.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonPage.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonWizard.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewUserWizard.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/DelayedText.java [new file with mode: 0644]
core/pom.xml [new file with mode: 0644]
org.argeo.entity.api/.classpath [deleted file]
org.argeo.entity.api/.gitignore [deleted file]
org.argeo.entity.api/.project [deleted file]
org.argeo.entity.api/META-INF/.gitignore [deleted file]
org.argeo.entity.api/bnd.bnd [deleted file]
org.argeo.entity.api/build.properties [deleted file]
org.argeo.entity.api/pom.xml [deleted file]
org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java [deleted file]
org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java [deleted file]
org.argeo.entity.api/src/org/argeo/entity/EntityNames.java [deleted file]
org.argeo.entity.api/src/org/argeo/entity/EntityType.java [deleted file]
org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java [deleted file]
org.argeo.entity.api/src/org/argeo/entity/JcrName.java [deleted file]
org.argeo.entity.api/src/org/argeo/entity/TermsManager.java [deleted file]
org.argeo.entity.api/src/org/argeo/entity/entity.cnd [deleted file]
org.argeo.entity.core/.classpath [deleted file]
org.argeo.entity.core/.gitignore [deleted file]
org.argeo.entity.core/.project [deleted file]
org.argeo.entity.core/META-INF/.gitignore [deleted file]
org.argeo.entity.core/bnd.bnd [deleted file]
org.argeo.entity.core/build.properties [deleted file]
org.argeo.entity.core/pom.xml [deleted file]
org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java [deleted file]
org.argeo.entity.ui/.classpath [deleted file]
org.argeo.entity.ui/.gitignore [deleted file]
org.argeo.entity.ui/.project [deleted file]
org.argeo.entity.ui/META-INF/.gitignore [deleted file]
org.argeo.entity.ui/bnd.bnd [deleted file]
org.argeo.entity.ui/build.properties [deleted file]
org.argeo.entity.ui/pom.xml [deleted file]
org.argeo.entity.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java [deleted file]
org.argeo.entity.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java [deleted file]
org.argeo.entity.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java [deleted file]
org.argeo.suite.core/.classpath [deleted file]
org.argeo.suite.core/.gitignore [deleted file]
org.argeo.suite.core/.project [deleted file]
org.argeo.suite.core/META-INF/.gitignore [deleted file]
org.argeo.suite.core/OSGI-INF/maintenanceService.xml [deleted file]
org.argeo.suite.core/OSGI-INF/termsManager.xml [deleted file]
org.argeo.suite.core/bnd.bnd [deleted file]
org.argeo.suite.core/build.properties [deleted file]
org.argeo.suite.core/pom.xml [deleted file]
org.argeo.suite.core/src/org/argeo/suite/RankedObject.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/RankingKey.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/core/CustomMaintenanceService.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java [deleted file]
org.argeo.suite.core/src/org/argeo/suite/util/XPathUtils.java [deleted file]
org.argeo.suite.theme.default/.gitignore [deleted file]
org.argeo.suite.theme.default/.project [deleted file]
org.argeo.suite.theme.default/META-INF/.gitignore [deleted file]
org.argeo.suite.theme.default/OSGI-INF/cmsTheme.xml [deleted file]
org.argeo.suite.theme.default/bnd.bnd [deleted file]
org.argeo.suite.theme.default/build.properties [deleted file]
org.argeo.suite.theme.default/icons/types/16/add.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/close.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/dashboard.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/delete.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/document.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/documents.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/folder.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/inbox.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/location.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/logout.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/map.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/organisation.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/people.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/person.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/refresh.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/save.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/search.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/settings.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/tag.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/task.png [deleted file]
org.argeo.suite.theme.default/icons/types/16/user.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/add.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/close.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/dashboard.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/delete.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/document.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/documents.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/folder.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/inbox.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/location.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/logout.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/map.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/organisation.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/people.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/person.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/save.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/search.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/settings.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/tag.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/task.png [deleted file]
org.argeo.suite.theme.default/icons/types/32/user.png [deleted file]
org.argeo.suite.theme.default/pom.xml [deleted file]
org.argeo.suite.theme.default/rap/work.css [deleted file]
org.argeo.suite.theme.default/swt/app.css [deleted file]
org.argeo.suite.ui.rap/.gitignore [deleted file]
org.argeo.suite.ui.rap/.project [deleted file]
org.argeo.suite.ui.rap/META-INF/.gitignore [deleted file]
org.argeo.suite.ui.rap/OSGI-INF/cmsWebApp.xml [deleted file]
org.argeo.suite.ui.rap/bnd.bnd [deleted file]
org.argeo.suite.ui.rap/build.properties [deleted file]
org.argeo.suite.ui.rap/pom.xml [deleted file]
org.argeo.suite.ui/.classpath [deleted file]
org.argeo.suite.ui/.gitignore [deleted file]
org.argeo.suite.ui/.project [deleted file]
org.argeo.suite.ui/META-INF/.gitignore [deleted file]
org.argeo.suite.ui/OSGI-INF/cmsApp.xml [deleted file]
org.argeo.suite.ui/OSGI-INF/dashboard.xml [deleted file]
org.argeo.suite.ui/OSGI-INF/dashboardLayer.xml [deleted file]
org.argeo.suite.ui/OSGI-INF/header.xml [deleted file]
org.argeo.suite.ui/OSGI-INF/l10n/bundle.properties [deleted file]
org.argeo.suite.ui/OSGI-INF/l10n/bundle_de.properties [deleted file]
org.argeo.suite.ui/OSGI-INF/l10n/bundle_fr.properties [deleted file]
org.argeo.suite.ui/OSGI-INF/leadPane.xml [deleted file]
org.argeo.suite.ui/OSGI-INF/loginScreen.xml [deleted file]
org.argeo.suite.ui/OSGI-INF/recentItems.xml [deleted file]
org.argeo.suite.ui/bnd.bnd [deleted file]
org.argeo.suite.ui/build.properties [deleted file]
org.argeo.suite.ui/config/cmsApp.properties [deleted file]
org.argeo.suite.ui/config/dashboard.properties [deleted file]
org.argeo.suite.ui/config/dashboardLayer.properties [deleted file]
org.argeo.suite.ui/config/header.properties [deleted file]
org.argeo.suite.ui/config/leadPane.properties [deleted file]
org.argeo.suite.ui/config/loginScreen.properties [deleted file]
org.argeo.suite.ui/config/recentItems.properties [deleted file]
org.argeo.suite.ui/pom.xml [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/AdminEntryArea.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultDashboard.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteEvent.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteIcon.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteMsg.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteStyle.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUserUiProvider.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonPage.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonWizard.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewUserWizard.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java [deleted file]
org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/DelayedText.java [deleted file]
pom.xml

diff --git a/core/org.argeo.entity.api/.classpath b/core/org.argeo.entity.api/.classpath
new file mode 100644 (file)
index 0000000..e801ebf
--- /dev/null
@@ -0,0 +1,7 @@
+<?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>
diff --git a/core/org.argeo.entity.api/.gitignore b/core/org.argeo.entity.api/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/core/org.argeo.entity.api/.project b/core/org.argeo.entity.api/.project
new file mode 100644 (file)
index 0000000..1269cce
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.entity.api</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/core/org.argeo.entity.api/META-INF/.gitignore b/core/org.argeo.entity.api/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/core/org.argeo.entity.api/bnd.bnd b/core/org.argeo.entity.api/bnd.bnd
new file mode 100644 (file)
index 0000000..ab46172
--- /dev/null
@@ -0,0 +1,5 @@
+Require-Capability:\
+cms.datamodel;filter:="(name=jcrx)"
+
+Provide-Capability:\
+cms.datamodel; name=entity; cnd=/org/argeo/entity/entity.cnd
diff --git a/core/org.argeo.entity.api/build.properties b/core/org.argeo.entity.api/build.properties
new file mode 100644 (file)
index 0000000..34d2e4d
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/core/org.argeo.entity.api/pom.xml b/core/org.argeo.entity.api/pom.xml
new file mode 100644 (file)
index 0000000..dc13fe7
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.suite</groupId>
+               <artifactId>core</artifactId>
+               <version>2.1.18-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.entity.api</artifactId>
+       <name>Entity API</name>
+       <packaging>jar</packaging>
+       <dependencies>
+               <!-- Argeo Commons -->
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.enterprise</artifactId>
+                       <version>${version.argeo-commons}</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/core/org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java b/core/org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java
new file mode 100644 (file)
index 0000000..f7a2de8
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.entity;
+
+/** Constant related to entities, typically used in an OSGi context. */
+public interface EntityConstants {
+       final static String TYPE = "entity.type";
+       final static String DEFAULT_EDITORY_ID = "entity.defaultEditorId";
+
+}
diff --git a/core/org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java b/core/org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java
new file mode 100644 (file)
index 0000000..08aff61
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.entity;
+
+import javax.jcr.Node;
+
+/** The definition of an entity, a composite configurable data structure. */
+public interface EntityDefinition {
+       String getEditorId(Node entity);
+
+       String getType();
+}
diff --git a/core/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java b/core/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java
new file mode 100644 (file)
index 0000000..ede7447
--- /dev/null
@@ -0,0 +1,61 @@
+package org.argeo.entity;
+
+import org.argeo.naming.LdapAttrs;
+
+/** Constants used to name entity structures. */
+public interface EntityNames {
+       @Deprecated
+       final String FORM_BASE = "form";
+       final String SUBMISSIONS_BASE = "submissions";
+       @Deprecated
+       final String TERM = "term";
+       final String NAME = "name";
+
+//     final String ENTITY_DEFINITIONS_PATH = "/entity";
+       @Deprecated
+       final String TYPOLOGIES_PATH = "/" + TERM;
+       /** Administrative units. */
+       final String ADM = "adm";
+
+       final String ENTITY_TYPE = "entity:type";
+       // final String ENTITY_UID = "entity:uid";
+       // final String ENTITY_NAME = "entity:name";
+
+       // GENERIC CONCEPTS
+       /** The language which is relevant. */
+       final String XML_LANG = "xml:lang";
+       /** The date which is relevant. */
+       final String ENTITY_DATE = "entity:date";
+       @Deprecated
+       final String ENTITY_RELATED_TO = "entity:relatedTo";
+
+       // DEFAULT FOLDER NAMES
+       final String MEDIA = "media";
+       final String FILES = "files";
+
+       // LDAP-LIKE ENTITIES
+       @Deprecated
+       final String DISPLAY_NAME = LdapAttrs.displayName.property();
+       // Persons
+       @Deprecated
+       final String GIVEN_NAME = LdapAttrs.givenName.property();
+       @Deprecated
+       final String SURNAME = LdapAttrs.sn.property();
+       @Deprecated
+       final String EMAIL = LdapAttrs.mail.property();
+       @Deprecated
+       final String OU = LdapAttrs.ou.property();
+
+       // WGS84
+       final String GEO_LAT = "geo:lat";
+       final String GEO_LONG = "geo:long";
+       final String GEO_ALT = "geo:alt";
+
+       // SVG
+       final String SVG_WIDTH = "svg:width";
+       final String SVG_HEIGHT = "svg:height";
+       final String SVG_LENGTH = "svg:length";
+       final String SVG_UNIT = "svg:unit";
+       final String SVG_DUR = "svg:dur";
+       final String SVG_DIRECTION = "svg:direction";
+}
diff --git a/core/org.argeo.entity.api/src/org/argeo/entity/EntityType.java b/core/org.argeo.entity.api/src/org/argeo/entity/EntityType.java
new file mode 100644 (file)
index 0000000..ecd6330
--- /dev/null
@@ -0,0 +1,40 @@
+package org.argeo.entity;
+
+/** Types related to entities. */
+public enum EntityType implements JcrName {
+       // entity
+       entity, local, relatedTo,
+       // typology
+       typologies, terms, term,
+       // form
+       form, formSet, formSubmission,
+       // graphics
+       box,
+       // geography
+       geopoint, bearing,
+       // ldap
+       person, user;
+
+       @Override
+       public String getPrefix() {
+               return prefix();
+       }
+
+       public static String prefix() {
+               return "entity";
+       }
+
+       public String basePath() {
+               return '/' + name();
+       }
+
+       @Override
+       public String getNamespace() {
+               return namespace();
+       }
+
+       public static String namespace() {
+               return "http://www.argeo.org/ns/entity";
+       }
+
+}
diff --git a/core/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java b/core/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java
new file mode 100644 (file)
index 0000000..ef35147
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.entity;
+
+/** Types related to entities. */
+@Deprecated
+public interface EntityTypes {
+       final static String ENTITY_ENTITY = "entity:entity";
+       final static String ENTITY_DEFINITION = "entity:definition";
+
+       final static String ENTITY_PERSON = "entity:person";
+}
diff --git a/core/org.argeo.entity.api/src/org/argeo/entity/JcrName.java b/core/org.argeo.entity.api/src/org/argeo/entity/JcrName.java
new file mode 100644 (file)
index 0000000..322c42e
--- /dev/null
@@ -0,0 +1,30 @@
+package org.argeo.entity;
+
+import java.util.function.Supplier;
+
+/** Can be applied to {@link Enum}s in order to generate prefixed names. */
+@FunctionalInterface
+public interface JcrName extends Supplier<String> {
+       String name();
+
+       default String getPrefix() {
+               return null;
+       }
+
+       default String getNamespace() {
+               return null;
+       }
+
+       @Override
+       default String get() {
+               String prefix = getPrefix();
+               return prefix != null ? prefix + ":" + name() : name();
+       }
+
+       default String withNamespace() {
+               String namespace = getNamespace();
+               if (namespace == null)
+                       throw new UnsupportedOperationException("No namespace is specified for " + getClass());
+               return "{" + namespace + "}" + name();
+       }
+}
diff --git a/core/org.argeo.entity.api/src/org/argeo/entity/TermsManager.java b/core/org.argeo.entity.api/src/org/argeo/entity/TermsManager.java
new file mode 100644 (file)
index 0000000..a2b5951
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.entity;
+
+import java.util.List;
+
+/** Provides optimised access and utilities around terms typologies. */
+public interface TermsManager {
+       List<String> listAllTerms(String typology);
+}
diff --git a/core/org.argeo.entity.api/src/org/argeo/entity/entity.cnd b/core/org.argeo.entity.api/src/org/argeo/entity/entity.cnd
new file mode 100644 (file)
index 0000000..b30657d
--- /dev/null
@@ -0,0 +1,99 @@
+// Standard namespaces
+<xsd = "http://www.w3.org/2001/XMLSchema">
+<h = "http://www.w3.org/1999/xhtml">
+// see https://www.w3.org/2003/01/geo/
+<geo = "http://www.w3.org/2003/01/geo/wgs84_pos#">
+<svg = "http://www.w3.org/2000/svg">
+
+<ldap = "http://www.argeo.org/ns/ldap">
+<entity = 'http://www.argeo.org/ns/entity'>
+
+[entity:entity] > mix:created, mix:referenceable
+mixin
+
+[entity:local] > entity:entity
+mixin
+- entity:type (String) m
+
+[entity:relatedTo]
+mixin
++ entity:relatedTo (nt:address) *
+
+//
+// ENTITY DEFINITION
+//
+//[entity:definition] > entity:composite, mix:created, mix:lastModified, mix:referenceable
+//- entity:type (String) multiple
+
+//[entity:part]
+
+//[entity:reference]
+
+//[entity:composite]
+//orderable
+//+ * (entity:part)
+//+ * (entity:reference)
+//+ * (entity:composite)
+
+//
+// TYPOLOGY
+//
+[entity:typologies]
++ * (entity:terms) = entity:terms
+
+[entity:term]
+orderable
+- name (NAME) m
+- * (*)
++ term (entity:term) = entity:term *
+
+[entity:terms] > mix:referenceable
+orderable
++ term (entity:term) = entity:term *
+
+//
+// FORM
+//
+[entity:form]
+mixin
+
+[entity:formSubmission]
+mixin
+
+[entity:formSet] > mix:title
+mixin
+
+//
+// GRAPHICS
+//
+[entity:box]
+mixin
+- svg:width (DOUBLE)
+- svg:height (DOUBLE)
+- svg:length (DOUBLE)
+- svg:unit (STRING)
+- svg:dur (DOUBLE)
+
+// LDAP-LIKE ENTITIES
+// A real person
+[entity:person] > entity:entity
+mixin
+- ldap:sn (String)
+- ldap:givenName (String)
+- ldap:mail (String) *
+
+[entity:user] > entity:person
+mixin
+- ldap:distinguishedName (String)
+- ldap:uid (String)
+
+// GEOGRAPHY
+[entity:geopoint]
+mixin
+- geo:long (DOUBLE)
+- geo:lat (DOUBLE)
+- geo:alt (DOUBLE)
+
+[entity:bearing]
+mixin
+- svg:direction (DOUBLE)
diff --git a/core/org.argeo.entity.core/.classpath b/core/org.argeo.entity.core/.classpath
new file mode 100644 (file)
index 0000000..e801ebf
--- /dev/null
@@ -0,0 +1,7 @@
+<?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>
diff --git a/core/org.argeo.entity.core/.gitignore b/core/org.argeo.entity.core/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/core/org.argeo.entity.core/.project b/core/org.argeo.entity.core/.project
new file mode 100644 (file)
index 0000000..1acff84
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.entity.core</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>
diff --git a/core/org.argeo.entity.core/META-INF/.gitignore b/core/org.argeo.entity.core/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/core/org.argeo.entity.core/bnd.bnd b/core/org.argeo.entity.core/bnd.bnd
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/core/org.argeo.entity.core/build.properties b/core/org.argeo.entity.core/build.properties
new file mode 100644 (file)
index 0000000..34d2e4d
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/core/org.argeo.entity.core/pom.xml b/core/org.argeo.entity.core/pom.xml
new file mode 100644 (file)
index 0000000..af56710
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.suite</groupId>
+               <artifactId>core</artifactId>
+               <version>2.1.18-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.entity.core</artifactId>
+       <name>Entity Reference Implementation</name>
+       <packaging>jar</packaging>
+       <dependencies>
+               <dependency>
+                       <groupId>org.argeo.suite</groupId>
+                       <artifactId>org.argeo.entity.api</artifactId>
+                       <version>2.1.18-SNAPSHOT</version>
+               </dependency>
+
+               <!-- Argeo Commons -->
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.cms</artifactId>
+                       <version>${version.argeo-commons}</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/core/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java b/core/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java
new file mode 100644 (file)
index 0000000..7fd26d1
--- /dev/null
@@ -0,0 +1,73 @@
+package org.argeo.entity.core;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.NodeUtils;
+import org.argeo.entity.EntityConstants;
+import org.argeo.entity.EntityDefinition;
+import org.argeo.jcr.Jcr;
+import org.osgi.framework.BundleContext;
+
+/** An entity definition based on a JCR data structure. */
+public class JcrEntityDefinition implements EntityDefinition {
+       private Repository repository;
+
+       private String type;
+       private String defaultEditoryId;
+
+       public void init(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
+               Session adminSession = NodeUtils.openDataAdminSession(repository, null);
+               try {
+                       type = properties.get(EntityConstants.TYPE);
+                       if (type == null)
+                               throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set.");
+                       defaultEditoryId = properties.get(EntityConstants.DEFAULT_EDITORY_ID);
+//                     String definitionPath = EntityNames.ENTITY_DEFINITIONS_PATH + '/' + type;
+//                     if (!adminSession.itemExists(definitionPath)) {
+//                             Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath, EntityTypes.ENTITY_DEFINITION);
+////                           entityDefinition.addMixin(EntityTypes.ENTITY_DEFINITION);
+//                             adminSession.save();
+//                     }
+                       initJcr(adminSession);
+               } finally {
+                       Jcr.logout(adminSession);
+               }
+       }
+
+       /** To be overridden in order to perform additional initialisations. */
+       protected void initJcr(Session adminSession) throws RepositoryException {
+
+       }
+
+       public void destroy(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
+
+       }
+
+       @Override
+       public String getEditorId(Node entity) {
+               return defaultEditoryId;
+       }
+
+       @Override
+       public String getType() {
+               return type;
+       }
+
+       protected Repository getRepository() {
+               return repository;
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+       public String toString() {
+               return "Entity Definition " + getType();
+       }
+
+}
diff --git a/core/org.argeo.entity.ui/.classpath b/core/org.argeo.entity.ui/.classpath
new file mode 100644 (file)
index 0000000..e801ebf
--- /dev/null
@@ -0,0 +1,7 @@
+<?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>
diff --git a/core/org.argeo.entity.ui/.gitignore b/core/org.argeo.entity.ui/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/core/org.argeo.entity.ui/.project b/core/org.argeo.entity.ui/.project
new file mode 100644 (file)
index 0000000..a1f7177
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.entity.ui</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>
diff --git a/core/org.argeo.entity.ui/META-INF/.gitignore b/core/org.argeo.entity.ui/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/core/org.argeo.entity.ui/bnd.bnd b/core/org.argeo.entity.ui/bnd.bnd
new file mode 100644 (file)
index 0000000..e7cd4cb
--- /dev/null
@@ -0,0 +1,3 @@
+Import-Package:\
+org.eclipse.swt,\
+*
\ No newline at end of file
diff --git a/core/org.argeo.entity.ui/build.properties b/core/org.argeo.entity.ui/build.properties
new file mode 100644 (file)
index 0000000..34d2e4d
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/core/org.argeo.entity.ui/pom.xml b/core/org.argeo.entity.ui/pom.xml
new file mode 100644 (file)
index 0000000..be62b14
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.suite</groupId>
+               <artifactId>core</artifactId>
+               <version>2.1.18-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.entity.ui</artifactId>
+       <name>Entity UI</name>
+       <packaging>jar</packaging>
+       <dependencies>
+               <dependency>
+                       <groupId>org.argeo.suite</groupId>
+                       <artifactId>org.argeo.entity.core</artifactId>
+                       <version>2.1.18-SNAPSHOT</version>
+               </dependency>
+
+               <!-- Argeo Commons -->
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.cms.ui</artifactId>
+                       <version>${version.argeo-commons}</version>
+               </dependency>
+
+               <!-- Specific -->
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.eclipse.ui.rap</artifactId>
+                       <version>2.1.91-SNAPSHOT</version>
+                       <scope>provided</scope>
+               </dependency>
+
+               <!-- Eclipse E4 -->
+               <dependency>
+                       <groupId>org.argeo.tp</groupId>
+                       <artifactId>argeo-tp-rap-e4</artifactId>
+                       <version>${version.argeo-tp}</version>
+                       <type>pom</type>
+                       <scope>provided</scope>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java b/core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java
new file mode 100644 (file)
index 0000000..a7f240f
--- /dev/null
@@ -0,0 +1,109 @@
+package org.argeo.entity.ui.forms;
+
+import javax.jcr.Item;
+
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.util.CmsIcon;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.entity.TermsManager;
+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.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** Common logic between single and mutliple terms editable part. */
+public abstract class AbstractTermsPart extends StyledControl implements EditablePart {
+       private static final long serialVersionUID = -5497097995341927710L;
+       protected final TermsManager termsManager;
+       protected final String typology;
+
+       protected final boolean editable;
+
+       private CmsIcon deleteIcon;
+       private CmsIcon addIcon;
+       private CmsIcon cancelIcon;
+
+       private Color highlightColor;
+       private Composite highlight;
+
+       protected final CmsTheme theme;
+
+       public AbstractTermsPart(Composite parent, int style, Item item, TermsManager termsManager,
+                       String typology) {
+               super(parent, style, item);
+               this.termsManager = termsManager;
+               this.typology = typology;
+               this.theme = CmsTheme.getCmsTheme(parent);
+               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
+               highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
+       }
+
+       protected void createHighlight(Composite block) {
+               highlight = new Composite(block, SWT.NONE);
+               highlight.setBackground(highlightColor);
+               GridData highlightGd = new GridData(SWT.FILL, SWT.FILL, false, false);
+               highlightGd.widthHint = 5;
+               highlightGd.heightHint = 3;
+               highlight.setLayoutData(highlightGd);
+
+       }
+
+       protected String getTermLabel(String name) {
+               return name;
+       }
+
+       protected abstract void refresh(ContextOverlay contextArea, String filter, Text txt);
+
+       protected boolean isTermSelectable(String term) {
+               return true;
+       }
+
+       protected void processTermListLabel(String term, Label label) {
+
+       }
+
+       //
+       // STYLING
+       //
+       public void setDeleteIcon(CmsIcon deleteIcon) {
+               this.deleteIcon = deleteIcon;
+       }
+
+       public void setAddIcon(CmsIcon addIcon) {
+               this.addIcon = addIcon;
+       }
+
+       public void setCancelIcon(CmsIcon cancelIcon) {
+               this.cancelIcon = cancelIcon;
+       }
+
+       protected TermsManager getTermsManager() {
+               return termsManager;
+       }
+
+       protected void styleDelete(ToolItem deleteItem) {
+               if (deleteIcon != null)
+                       deleteItem.setImage(deleteIcon.getSmallIcon(theme));
+               else
+                       deleteItem.setText("-");
+       }
+
+       protected void styleCancel(ToolItem cancelItem) {
+               if (cancelIcon != null)
+                       cancelItem.setImage(cancelIcon.getSmallIcon(theme));
+               else
+                       cancelItem.setText("X");
+       }
+
+       protected void styleAdd(ToolItem addItem) {
+               if (addIcon != null)
+                       addItem.setImage(addIcon.getSmallIcon(theme));
+               else
+                       addItem.setText("+");
+       }
+}
diff --git a/core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java b/core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java
new file mode 100644 (file)
index 0000000..1a12e90
--- /dev/null
@@ -0,0 +1,173 @@
+package org.argeo.entity.ui.forms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Item;
+
+import org.argeo.cms.ui.forms.FormStyle;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+import org.argeo.eclipse.ui.MouseDoubleClick;
+import org.argeo.eclipse.ui.MouseDown;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.entity.TermsManager;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** {@link EditablePart} for multiple terms. */
+public class MultiTermsPart extends AbstractTermsPart {
+       private static final long serialVersionUID = -4961135649177920808L;
+
+       public MultiTermsPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
+               super(parent, style, item, termsManager, typology);
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               Composite placeholder = new Composite(box, SWT.NONE);
+               RowLayout rl = new RowLayout(SWT.HORIZONTAL | SWT.WRAP);
+               placeholder.setLayout(rl);
+               List<String> currentValue = Jcr.getMultiple(getNode(), typology);
+               if (currentValue != null && !currentValue.isEmpty())
+                       for (String value : currentValue) {
+                               Composite block = new Composite(placeholder, SWT.NONE);
+                               block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
+                               Label lbl = new Label(block, SWT.SINGLE);
+                               String display = getTermLabel(value);
+                               lbl.setText(display);
+                               CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
+                               if (editable)
+                                       lbl.addMouseListener((MouseDoubleClick) (e) -> {
+                                               startEditing();
+                                       });
+                               if (isEditing()) {
+                                       ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+                                       ToolItem deleteItem = new ToolItem(toolBar, SWT.FLAT);
+                                       styleDelete(deleteItem);
+                                       deleteItem.addSelectionListener((Selected) (e) -> {
+                                               // we retrieve them again here because they may have changed
+                                               List<String> curr = Jcr.getMultiple(getNode(), typology);
+                                               List<String> newValue = new ArrayList<>();
+                                               for (String v : curr) {
+                                                       if (!v.equals(value))
+                                                               newValue.add(v);
+                                               }
+                                               Jcr.set(getNode(), typology, newValue);
+                                               Jcr.save(getNode());
+                                               block.dispose();
+                                               layout(true, true);
+                                       });
+
+                               }
+                       }
+               else {// empty
+                       if (editable && !isEditing()) {
+                               ToolBar toolBar = new ToolBar(placeholder, SWT.HORIZONTAL);
+                               ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
+                               styleAdd(addItem);
+                               addItem.addSelectionListener((Selected) (e) -> {
+                                       startEditing();
+                               });
+                       }
+               }
+
+               if (isEditing()) {
+                       Composite block = new Composite(placeholder, SWT.NONE);
+                       block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
+
+                       createHighlight(block);
+
+                       Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
+                       txt.setLayoutData(CmsUiUtils.fillWidth());
+//                     txt.setMessage("[new]");
+
+                       CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
+
+                       ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+                       ToolItem cancelItem = new ToolItem(toolBar, SWT.FLAT);
+                       styleCancel(cancelItem);
+                       cancelItem.addSelectionListener((Selected) (e) -> {
+                               stopEditing();
+                       });
+
+                       ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
+                               private static final long serialVersionUID = -7980078594405384874L;
+
+                               @Override
+                               protected void onHide() {
+                                       stopEditing();
+                               }
+                       };
+                       contextOverlay.setLayout(new GridLayout());
+                       // filter
+                       txt.addModifyListener((e) -> {
+                               String filter = txt.getText().toLowerCase();
+                               if ("".equals(filter.trim()))
+                                       filter = null;
+                               refresh(contextOverlay, filter, txt);
+                       });
+                       txt.addFocusListener(new FocusListener() {
+                               private static final long serialVersionUID = -6024501573409619949L;
+
+                               @Override
+                               public void focusLost(FocusEvent event) {
+//                                     if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
+//                                             getDisplay().asyncExec(() -> stopEditing());
+                               }
+
+                               @Override
+                               public void focusGained(FocusEvent event) {
+                                       // txt.setText("");
+                                       if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
+                                               refresh(contextOverlay, null, txt);
+                               }
+                       });
+                       layout(new Control[] { txt });
+                       // getDisplay().asyncExec(() -> txt.setFocus());
+               }
+               return placeholder;
+       }
+
+       @Override
+       protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
+               CmsUiUtils.clear(contextArea);
+               List<String> terms = termsManager.listAllTerms(typology);
+               List<String> currentValue = Jcr.getMultiple(getNode(), typology);
+               terms: for (String term : terms) {
+                       if (currentValue != null && currentValue.contains(term))
+                               continue terms;
+                       String display = getTermLabel(term);
+                       if (filter != null && !display.toLowerCase().contains(filter))
+                               continue terms;
+                       Label termL = new Label(contextArea, SWT.WRAP);
+                       termL.setText(display);
+                       processTermListLabel(term, termL);
+                       if (isTermSelectable(term))
+                               termL.addMouseListener((MouseDown) (e) -> {
+                                       List<String> newValue = new ArrayList<>();
+                                       List<String> curr = Jcr.getMultiple(getNode(), typology);
+                                       if (currentValue != null)
+                                               newValue.addAll(curr);
+                                       newValue.add(term);
+                                       Jcr.set(getNode(), typology, newValue);
+                                       Jcr.save(getNode());
+                                       contextArea.hide();
+                                       stopEditing();
+                               });
+               }
+               contextArea.show();
+       }
+
+}
diff --git a/core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java b/core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java
new file mode 100644 (file)
index 0000000..e9fad04
--- /dev/null
@@ -0,0 +1,143 @@
+package org.argeo.entity.ui.forms;
+
+import java.util.List;
+
+import javax.jcr.Item;
+
+import org.argeo.cms.ui.forms.FormStyle;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+import org.argeo.eclipse.ui.MouseDoubleClick;
+import org.argeo.eclipse.ui.MouseDown;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.entity.TermsManager;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+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;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** {@link EditablePart} for terms. */
+public class SingleTermPart extends AbstractTermsPart {
+       private static final long serialVersionUID = -4961135649177920808L;
+
+       public SingleTermPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
+               super(parent, style, item, termsManager, typology);
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               if (isEditing()) {
+                       Composite block = new Composite(box, SWT.NONE);
+                       block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
+
+                       createHighlight(block);
+
+                       Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
+                       CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
+
+                       ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+                       ToolItem deleteItem = new ToolItem(toolBar, SWT.PUSH);
+                       styleDelete(deleteItem);
+                       deleteItem.addSelectionListener((Selected) (e) -> {
+                               Jcr.set(getNode(), typology, null);
+                               Jcr.save(getNode());
+                               stopEditing();
+                       });
+                       ToolItem cancelItem = new ToolItem(toolBar, SWT.PUSH);
+                       styleCancel(cancelItem);
+                       cancelItem.addSelectionListener((Selected) (e) -> {
+                               stopEditing();
+                       });
+
+                       ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
+                               private static final long serialVersionUID = -7980078594405384874L;
+
+                               @Override
+                               protected void onHide() {
+                                       stopEditing();
+                               }
+                       };
+                       contextOverlay.setLayout(new GridLayout());
+                       // filter
+                       txt.addModifyListener((e) -> {
+                               String filter = txt.getText().toLowerCase();
+                               if ("".equals(filter.trim()))
+                                       filter = null;
+                               refresh(contextOverlay, filter, txt);
+                       });
+                       txt.addFocusListener(new FocusListener() {
+                               private static final long serialVersionUID = -6024501573409619949L;
+
+                               @Override
+                               public void focusLost(FocusEvent event) {
+//                                     if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
+//                                             getDisplay().asyncExec(() -> stopEditing());
+                               }
+
+                               @Override
+                               public void focusGained(FocusEvent event) {
+                                       // txt.setText("");
+                                       if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
+                                               refresh(contextOverlay, null, txt);
+                               }
+                       });
+                       layout(new Control[] { block });
+                       getDisplay().asyncExec(() -> txt.setFocus());
+                       return block;
+               } else {
+                       Composite block = new Composite(box, SWT.NONE);
+                       block.setLayout(CmsUiUtils.noSpaceGridLayout(2));
+                       String currentValue = Jcr.get(getNode(), typology);
+                       if (currentValue != null) {
+                               Label lbl = new Label(block, SWT.SINGLE);
+                               String display = getTermLabel(currentValue);
+                               lbl.setText(display);
+                               CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
+
+                               lbl.addMouseListener((MouseDoubleClick) (e) -> {
+                                       startEditing();
+                               });
+                       } else {
+                               ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+                               ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
+                               styleAdd(addItem);
+                               addItem.addSelectionListener((Selected) (e) -> {
+                                       startEditing();
+                               });
+                       }
+                       return block;
+               }
+       }
+
+       @Override
+       protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
+               CmsUiUtils.clear(contextArea);
+               List<String> terms = termsManager.listAllTerms(typology);
+               terms: for (String term : terms) {
+                       String display = getTermLabel(term);
+                       if (filter != null && !display.toLowerCase().contains(filter))
+                               continue terms;
+                       Label termL = new Label(contextArea, SWT.WRAP);
+                       termL.setText(display);
+                       processTermListLabel(term, termL);
+                       if (isTermSelectable(term))
+                               termL.addMouseListener((MouseDown) (e) -> {
+                                       Jcr.set(getNode(), typology, term);
+                                       Jcr.save(getNode());
+                                       contextArea.hide();
+                                       stopEditing();
+                               });
+               }
+               contextArea.show();
+               // txt.setFocus();
+       }
+
+}
diff --git a/core/org.argeo.suite.core/.classpath b/core/org.argeo.suite.core/.classpath
new file mode 100644 (file)
index 0000000..e801ebf
--- /dev/null
@@ -0,0 +1,7 @@
+<?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>
diff --git a/core/org.argeo.suite.core/.gitignore b/core/org.argeo.suite.core/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/core/org.argeo.suite.core/.project b/core/org.argeo.suite.core/.project
new file mode 100644 (file)
index 0000000..ab084af
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.suite.core</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>
diff --git a/core/org.argeo.suite.core/META-INF/.gitignore b/core/org.argeo.suite.core/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/core/org.argeo.suite.core/OSGI-INF/maintenanceService.xml b/core/org.argeo.suite.core/OSGI-INF/maintenanceService.xml
new file mode 100644 (file)
index 0000000..2d495c8
--- /dev/null
@@ -0,0 +1,7 @@
+<?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="Suite Maintenance Service">
+   <implementation class="org.argeo.suite.core.SuiteMaintenanceService"/>
+   <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
+   <reference bind="setUserTransaction" cardinality="1..1" interface="javax.transaction.UserTransaction" name="UserTransaction" policy="static"/>
+   <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
+</scr:component>
diff --git a/core/org.argeo.suite.core/OSGI-INF/termsManager.xml b/core/org.argeo.suite.core/OSGI-INF/termsManager.xml
new file mode 100644 (file)
index 0000000..3e6d4c6
--- /dev/null
@@ -0,0 +1,8 @@
+<?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="Suite Terms Manager">
+   <implementation class="org.argeo.suite.core.SuiteTermsManager"/>
+   <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
+   <service>
+      <provide interface="org.argeo.entity.TermsManager"/>
+   </service>
+</scr:component>
diff --git a/core/org.argeo.suite.core/bnd.bnd b/core/org.argeo.suite.core/bnd.bnd
new file mode 100644 (file)
index 0000000..1b9efff
--- /dev/null
@@ -0,0 +1,14 @@
+Bundle-ActivationPolicy: lazy
+
+Service-Component:\
+OSGI-INF/termsManager.xml,\
+OSGI-INF/maintenanceService.xml
+
+Import-Package:\
+javax.transaction,\
+org.osgi.service.useradmin,\
+javax.jcr.nodetype,\
+javax.jcr.security,\
+org.argeo.api,\
+org.argeo.entity,\
+*
\ No newline at end of file
diff --git a/core/org.argeo.suite.core/build.properties b/core/org.argeo.suite.core/build.properties
new file mode 100644 (file)
index 0000000..6210e84
--- /dev/null
@@ -0,0 +1,5 @@
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               OSGI-INF/
+source.. = src/
diff --git a/core/org.argeo.suite.core/pom.xml b/core/org.argeo.suite.core/pom.xml
new file mode 100644 (file)
index 0000000..11bc02b
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.suite</groupId>
+               <artifactId>core</artifactId>
+               <version>2.1.18-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.suite.core</artifactId>
+       <name>Suite Core</name>
+       <packaging>jar</packaging>
+       <dependencies>
+               <dependency>
+                       <groupId>org.argeo.suite</groupId>
+                       <artifactId>org.argeo.entity.core</artifactId>
+                       <version>2.1.18-SNAPSHOT</version>
+               </dependency>
+
+               <!-- Argeo Commons -->
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.cms</artifactId>
+                       <version>${version.argeo-commons}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.maintenance</artifactId>
+                       <version>${version.argeo-commons}</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java b/core/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java
new file mode 100644 (file)
index 0000000..bfba46e
--- /dev/null
@@ -0,0 +1,98 @@
+package org.argeo.suite;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A container for an object whose relevance can be ranked. Typically used in an
+ * OSGi context with the service.ranking property.
+ */
+public class RankedObject<T> {
+       private final static Log log = LogFactory.getLog(RankedObject.class);
+
+       private final static String SERVICE_RANKING = "service.ranking";
+//     private final static String SERVICE_ID = "service.id";
+
+       private T object;
+       private Map<String, Object> properties;
+       private final Long rank;
+
+       public RankedObject(T object, Map<String, Object> properties) {
+               this(object, properties, extractRanking(properties));
+       }
+
+       public RankedObject(T object, Map<String, Object> properties, Long rank) {
+               super();
+               this.object = object;
+               this.properties = properties;
+               this.rank = rank;
+       }
+
+       private static Long extractRanking(Map<String, Object> properties) {
+               if (properties == null)
+                       return 0l;
+               if (properties.containsKey(SERVICE_RANKING))
+                       return Long.valueOf(properties.get(SERVICE_RANKING).toString());
+//             else if (properties.containsKey(SERVICE_ID))
+//                     return (Long) properties.get(SERVICE_ID);
+               else
+                       return 0l;
+       }
+
+       public T get() {
+               return object;
+       }
+
+       public Map<String, Object> getProperties() {
+               return properties;
+       }
+
+       public Long getRank() {
+               return rank;
+       }
+
+       @Override
+       public int hashCode() {
+               return object.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (!(obj instanceof RankedObject))
+                       return false;
+               RankedObject<?> other = (RankedObject<?>) obj;
+               return rank.equals(other.rank) && object.equals(other.object);
+       }
+
+       @Override
+       public String toString() {
+               return object.getClass().getName() + " with rank " + rank;
+       }
+
+       public static <K, T> RankedObject<T> putIfHigherRank(Map<K, RankedObject<T>> map, K key, T object,
+                       Map<String, Object> properties) {
+               RankedObject<T> rankedObject = new RankedObject<>(object, properties);
+               if (!map.containsKey(key)) {
+                       map.put(key, rankedObject);
+                       if (log.isTraceEnabled())
+                               log.trace(
+                                               "Added " + key + " as " + object.getClass().getName() + " with rank " + rankedObject.getRank());
+                       return rankedObject;
+               } else {
+                       RankedObject<T> current = map.get(key);
+                       if (current.getRank() <= rankedObject.getRank()) {
+                               map.put(key, rankedObject);
+                               if (log.isTraceEnabled())
+                                       log.trace("Replaced " + key + " by " + object.getClass().getName() + " with rank "
+                                                       + rankedObject.getRank());
+                               return rankedObject;
+                       } else {
+                               return current;
+                       }
+               }
+
+       }
+
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/RankingKey.java b/core/org.argeo.suite.core/src/org/argeo/suite/RankingKey.java
new file mode 100644 (file)
index 0000000..e099195
--- /dev/null
@@ -0,0 +1,160 @@
+package org.argeo.suite;
+
+import java.util.Map;
+
+/**
+ * Key used to classify and filter available components (typically provided by
+ * OSGi services).
+ */
+@Deprecated
+public class RankingKey implements Comparable<RankingKey> {
+       public final static String SERVICE_PID = "service.pid";
+       public final static String SERVICE_ID = "service.id";
+       public final static String SERVICE_RANKING = "service.ranking";
+       public final static String DATA_TYPE = "data.type";
+
+       private String pid;
+       private Integer ranking = 0;
+       private Long id = 0l;
+       private String dataType;
+       private String dataPath;
+
+       public RankingKey(String pid, Integer ranking, Long id, String dataType, String dataPath) {
+               super();
+               this.pid = pid;
+               this.ranking = ranking;
+               this.id = id;
+               this.dataType = dataType;
+               this.dataPath = dataPath;
+       }
+
+       public RankingKey(Map<String, Object> properties) {
+               this.pid = properties.containsKey(SERVICE_PID) ? properties.get(SERVICE_PID).toString() : null;
+               this.ranking = properties.containsKey(SERVICE_RANKING)
+                               ? Integer.parseInt(properties.get(SERVICE_RANKING).toString())
+                               : 0;
+               this.id = properties.containsKey(SERVICE_ID) ? (Long) properties.get(SERVICE_ID) : null;
+
+               // Argeo specific
+               this.dataType = properties.containsKey(DATA_TYPE) ? properties.get(DATA_TYPE).toString() : null;
+       }
+
+       @Override
+       public int hashCode() {
+               Integer result = 0;
+               if (pid != null)
+                       result = +pid.hashCode();
+               if (ranking != null)
+                       result = +ranking;
+               if (dataType != null)
+                       result = +dataType.hashCode();
+               return result;
+       }
+
+       @Override
+       protected Object clone() throws CloneNotSupportedException {
+               return new RankingKey(pid, ranking, id, dataType, dataPath);
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder sb = new StringBuilder("");
+               if (pid != null)
+                       sb.append(pid);
+               if (ranking != null && ranking != 0)
+                       sb.append(' ').append(ranking);
+               if (dataType != null)
+                       sb.append(' ').append(dataType);
+               return sb.toString();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (!(obj instanceof RankingKey))
+                       return false;
+               RankingKey other = (RankingKey) obj;
+               return equalsOrBothNull(pid, other.pid) && equalsOrBothNull(ranking, other.ranking)
+                               && equalsOrBothNull(id, other.id) && equalsOrBothNull(dataType, other.dataType)
+                               && equalsOrBothNull(dataPath, other.dataPath);
+       }
+
+       @Override
+       public int compareTo(RankingKey o) {
+               if (pid != null && o.pid != null) {
+                       if (pid.equals(o.pid)) {
+                               if (ranking.equals(o.ranking))
+                                       if (id != null && o.id != null)
+                                               return id.compareTo(o.id);
+                                       else
+                                               return 0;
+                               else
+                                       return ranking.compareTo(o.ranking);
+                       } else {
+                               return pid.compareTo(o.pid);
+                       }
+
+               } else {
+                       if (dataType != null && o.dataType != null) {
+                               if (dataType.equals(o.dataType)) {
+                                       // TODO factorise
+                                       if (ranking.equals(o.ranking))
+                                               if (id != null && o.id != null)
+                                                       return id.compareTo(o.id);
+                                               else
+                                                       return 0;
+                                       else
+                                               return ranking.compareTo(o.ranking);
+                               } else {
+                                       return dataPath.compareTo(o.dataType);
+                               }
+                       }
+               }
+               return -1;
+       }
+
+       public String getPid() {
+               return pid;
+       }
+
+       public Integer getRanking() {
+               return ranking;
+       }
+
+       public Long getId() {
+               return id;
+       }
+
+       public String getDataType() {
+               return dataType;
+       }
+
+       public String getDataPath() {
+               return dataPath;
+       }
+
+       public static RankingKey minPid(String pid) {
+               return new RankingKey(pid, Integer.MIN_VALUE, null, null, null);
+       }
+
+       public static RankingKey maxPid(String pid) {
+               return new RankingKey(pid, Integer.MAX_VALUE, null, null, null);
+       }
+
+       public static RankingKey minDataType(String dataType) {
+               return new RankingKey(null, Integer.MIN_VALUE, null, dataType, null);
+       }
+
+       public static RankingKey maxDataType(String dataType) {
+               return new RankingKey(null, Integer.MAX_VALUE, null, dataType, null);
+       }
+
+       private static boolean equalsOrBothNull(Object o1, Object o2) {
+               if (o1 == null && o2 == null)
+                       return true;
+               if (o1 == null && o2 != null)
+                       return false;
+               if (o1 != null && o2 == null)
+                       return false;
+               return o2.equals(o1);
+       }
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java b/core/org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java
new file mode 100644 (file)
index 0000000..382f50c
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.suite;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.naming.Distinguished;
+import org.argeo.naming.LdapAttrs;
+
+/** Office specific roles used in the code */
+public enum SuiteRole implements Distinguished {
+       coworker, manager;
+
+       public String getRolePrefix() {
+               return "org.argeo.suite";
+       }
+
+       public String dn() {
+               return new StringBuilder(LdapAttrs.cn.name()).append("=").append(getRolePrefix()).append(".").append(name())
+                               .append(",").append(NodeConstants.ROLES_BASEDN).toString();
+       }
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java b/core/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java
new file mode 100644 (file)
index 0000000..e63b515
--- /dev/null
@@ -0,0 +1,99 @@
+package org.argeo.suite;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.Privilege;
+import javax.naming.ldap.LdapName;
+import javax.security.auth.x500.X500Principal;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.auth.CmsSession;
+import org.argeo.entity.EntityType;
+import org.argeo.jackrabbit.security.JackrabbitSecurityUtils;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.naming.LdapAttrs;
+
+/** Utilities around the Argeo Suite APIs. */
+public class SuiteUtils {
+
+       public static String getUserNodePath(LdapName userDn) {
+               String uid = userDn.getRdn(userDn.size() - 1).getValue().toString();
+               return EntityType.user.basePath() + '/' + uid;
+       }
+
+       public static Node getOrCreateUserNode(Session adminSession, LdapName userDn) {
+               try {
+                       Node usersBase = adminSession.getNode(EntityType.user.basePath());
+                       String uid = userDn.getRdn(userDn.size() - 1).getValue().toString();
+                       Node userNode;
+                       if (!usersBase.hasNode(uid)) {
+                               userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
+                               userNode.addMixin(EntityType.user.get());
+                               userNode.addMixin(NodeType.MIX_CREATED);
+                               userNode.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString());
+                               userNode.setProperty(LdapAttrs.uid.property(), uid);
+                               adminSession.save();
+                               JackrabbitSecurityUtils.denyPrivilege(adminSession, userNode.getPath(), SuiteRole.coworker.dn(),
+                                               Privilege.JCR_READ);
+                               JcrUtils.addPrivilege(adminSession, userNode.getPath(), new X500Principal(userDn.toString()).getName(),
+                                               Privilege.JCR_READ);
+                               JcrUtils.addPrivilege(adminSession, userNode.getPath(), NodeConstants.ROLE_USER_ADMIN,
+                                               Privilege.JCR_ALL);
+                       } else {
+                               userNode = usersBase.getNode(uid);
+                       }
+                       return userNode;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot create user node for " + userDn, e);
+               }
+       }
+
+       public static Node getCmsSessionNode(Session session, CmsSession cmsSession) {
+               try {
+                       return session.getNode(getUserNodePath(cmsSession.getUserDn()) + '/' + cmsSession.getUuid().toString());
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get session dir for " + cmsSession, e);
+               }
+       }
+
+       public static Node getOrCreateCmsSessionNode(Session adminSession, CmsSession cmsSession) {
+               try {
+                       LdapName userDn = cmsSession.getUserDn();
+//                     String uid = userDn.get(userDn.size() - 1);
+                       Node userNode = getOrCreateUserNode(adminSession, userDn);
+//                     if (!usersBase.hasNode(uid)) {
+//                             userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
+//                             userNode.addMixin(EntityType.user.get());
+//                             userNode.addMixin(NodeType.MIX_CREATED);
+//                             usersBase.setProperty(LdapAttrs.uid.property(), uid);
+//                             usersBase.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString());
+//                             adminSession.save();
+//                     } else {
+//                             userNode = usersBase.getNode(uid);
+//                     }
+                       String cmsSessionUuid = cmsSession.getUuid().toString();
+                       Node cmsSessionNode;
+                       if (!userNode.hasNode(cmsSessionUuid)) {
+                               cmsSessionNode = userNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED);
+                               cmsSessionNode.addMixin(NodeType.MIX_CREATED);
+                               adminSession.save();
+                               JcrUtils.addPrivilege(adminSession, cmsSessionNode.getPath(), cmsSession.getUserRole(),
+                                               Privilege.JCR_ALL);
+                       } else {
+                               cmsSessionNode = userNode.getNode(cmsSessionUuid);
+                       }
+                       return cmsSessionNode;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot create session dir for " + cmsSession, e);
+               }
+       }
+
+       /** Singleton. */
+       private SuiteUtils() {
+
+       }
+
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/core/CustomMaintenanceService.java b/core/org.argeo.suite.core/src/org/argeo/suite/core/CustomMaintenanceService.java
new file mode 100644 (file)
index 0000000..b6e997a
--- /dev/null
@@ -0,0 +1,72 @@
+package org.argeo.suite.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.ItemExistsException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.maintenance.AbstractMaintenanceService;
+
+/** Base for custom initialisations. */
+public abstract class CustomMaintenanceService extends AbstractMaintenanceService {
+       private final static Log log = LogFactory.getLog(AbstractMaintenanceService.class);
+
+       protected List<String> getTypologies() {
+               return new ArrayList<>();
+       }
+
+       protected String getTypologiesLoadBase() {
+               return "/sys/terms";
+       }
+
+       protected void loadTypologies(Node customBaseNode) throws RepositoryException, IOException {
+               List<String> typologies = getTypologies();
+               if (!typologies.isEmpty()) {
+                       Node termsBase = JcrUtils.getOrAdd(customBaseNode, EntityType.terms.name(), EntityType.typologies.get());
+                       for (String terms : typologies) {
+                               loadTerms(termsBase, terms);
+                       }
+                       termsBase.getSession().save();
+               }
+       }
+
+       protected void loadTerms(Node termsBase, String name) throws IOException, RepositoryException {
+               try {
+                       if (termsBase.hasNode(name))
+                               return;
+
+                       String termsLoadPath = getTypologiesLoadBase() + '/' + name + ".xml";
+                       URL termsUrl = getClass().getClassLoader().getResource(termsLoadPath);
+                       if (termsUrl == null)
+                               throw new IllegalArgumentException("Terms '" + name + "' not found.");
+                       try (InputStream in = termsUrl.openStream()) {
+                               termsBase.getSession().importXML(termsBase.getPath(), in,
+                                               ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+                       } catch (ItemExistsException e) {
+                               log.warn("Terms " + name + " exists with another UUID, removing it...");
+                               termsBase.getNode(name).remove();
+                               try (InputStream in = termsUrl.openStream()) {
+                                       termsBase.getSession().importXML(termsBase.getPath(), in,
+                                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+                               }
+                       }
+                       if (log.isDebugEnabled())
+                               log.debug("Terms '" + name + "' loaded.");
+                       termsBase.getSession().save();
+               } catch (RepositoryException | IOException e) {
+                       log.error("Cannot load terms '" + name + "': " + e.getMessage());
+                       throw e;
+               }
+       }
+
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java b/core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java
new file mode 100644 (file)
index 0000000..b217373
--- /dev/null
@@ -0,0 +1,39 @@
+package org.argeo.suite.core;
+
+import java.io.IOException;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.Privilege;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.maintenance.AbstractMaintenanceService;
+
+/** Initialises an Argeo Suite backend. */
+public class SuiteMaintenanceService extends AbstractMaintenanceService {
+
+       @Override
+       public boolean prepareJcrTree(Session adminSession) throws RepositoryException, IOException {
+               boolean modified = false;
+               Node rootNode = adminSession.getRootNode();
+               if (!rootNode.hasNode(EntityType.user.name())) {
+                       rootNode.addNode(EntityType.user.name(), NodeType.NT_UNSTRUCTURED);
+                       modified = true;
+               }
+               if (modified)
+                       adminSession.save();
+               return modified;
+       }
+
+       @Override
+       public void configurePrivileges(Session adminSession) throws RepositoryException {
+               JcrUtils.addPrivilege(adminSession, EntityType.user.basePath(), NodeConstants.ROLE_USER_ADMIN,
+                               Privilege.JCR_ALL);
+               //JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), Privilege.JCR_READ);
+       }
+
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java b/core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java
new file mode 100644 (file)
index 0000000..0c03dc5
--- /dev/null
@@ -0,0 +1,55 @@
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
+ */
+class SuiteTerm {
+       private final String name;
+       private final String relativePath;
+       private final SuiteTypology typology;
+       private final String id;
+
+       private final SuiteTerm parentTerm;
+       private final List<SuiteTerm> subTerms = new ArrayList<>();
+
+       SuiteTerm(SuiteTypology typology, String relativePath, SuiteTerm parentTerm) {
+               this.typology = typology;
+               this.parentTerm = parentTerm;
+               this.relativePath = relativePath;
+               int index = relativePath.lastIndexOf('/');
+               if (index > 0) {
+                       this.name = relativePath.substring(index);
+               } else {
+                       this.name = relativePath;
+               }
+               id = typology.getName() + '/' + relativePath;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public String getRelativePath() {
+               return relativePath;
+       }
+
+       SuiteTypology getTypology() {
+               return typology;
+       }
+
+       public String getId() {
+               return id;
+       }
+
+       List<SuiteTerm> getSubTerms() {
+               return subTerms;
+       }
+
+       SuiteTerm getParentTerm() {
+               return parentTerm;
+       }
+
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java b/core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java
new file mode 100644 (file)
index 0000000..1362f94
--- /dev/null
@@ -0,0 +1,96 @@
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.entity.EntityNames;
+import org.argeo.entity.EntityType;
+import org.argeo.entity.TermsManager;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+
+/** Argeo Suite implementation of terms manager. */
+public class SuiteTermsManager implements TermsManager {
+       private final Map<String, SuiteTerm> terms = new HashMap<>();
+       private final Map<String, SuiteTypology> typologies = new HashMap<>();
+
+       // JCR
+       private Repository repository;
+       private Session adminSession;
+
+       public void init() {
+               adminSession = NodeUtils.openDataAdminSession(repository, NodeConstants.SYS_WORKSPACE);
+       }
+
+       @Override
+       public List<String> listAllTerms(String typology) {
+               List<String> res = new ArrayList<>();
+               SuiteTypology t = getTypology(typology);
+               for (SuiteTerm term : t.getAllTerms()) {
+                       res.add(term.getId());
+               }
+               return res;
+       }
+
+       SuiteTypology getTypology(String typology) {
+               SuiteTypology t = typologies.get(typology);
+               if (t == null) {
+                       Node termsNode = Jcr.getNode(adminSession, "SELECT * FROM [{0}] WHERE NAME()=\"{1}\"",
+                                       EntityType.terms.get(), typology);
+                       if (termsNode == null)
+                               throw new IllegalArgumentException("Typology " + typology + " not found.");
+                       t = loadTypology(termsNode);
+               }
+               return t;
+       }
+
+       SuiteTypology loadTypology(Node termsNode) {
+               try {
+                       SuiteTypology typology = new SuiteTypology(termsNode);
+                       for (Node termNode : Jcr.iterate(termsNode.getNodes())) {
+                               if (termNode.isNodeType(EntityType.term.get())) {
+                                       SuiteTerm term = loadTerm(typology, termNode, null);
+                                       if (!term.getSubTerms().isEmpty())
+                                               typology.markNotFlat();
+                                       typology.getSubTerms().add(term);
+                               }
+                       }
+                       typologies.put(typology.getName(), typology);
+                       return typology;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot load typology from " + termsNode, e);
+               }
+       }
+
+       SuiteTerm loadTerm(SuiteTypology typology, Node termNode, SuiteTerm parentTerm) throws RepositoryException {
+               String name = termNode.getProperty(EntityNames.NAME).getString();
+               String relativePath = parentTerm == null ? name : parentTerm.getRelativePath() + '/' + name;
+               SuiteTerm term = new SuiteTerm(typology, relativePath, parentTerm);
+               terms.put(term.getId(), term);
+               for (Node subTermNode : Jcr.iterate(termNode.getNodes())) {
+                       if (termNode.isNodeType(EntityType.term.get())) {
+                               SuiteTerm subTerm = loadTerm(typology, subTermNode, term);
+                               term.getSubTerms().add(subTerm);
+                       }
+               }
+               return term;
+       }
+
+       public void destroy() {
+               Jcr.logout(adminSession);
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java b/core/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java
new file mode 100644 (file)
index 0000000..e84066c
--- /dev/null
@@ -0,0 +1,64 @@
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.jcr.Jcr;
+
+/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
+class SuiteTypology {
+       private final String name;
+       private final Node node;
+       private boolean isFlat = true;
+
+       private final List<SuiteTerm> subTerms = new ArrayList<>();
+
+       public SuiteTypology(Node node) {
+               this.node = node;
+               this.name = Jcr.getName(this.node);
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public Node getNode() {
+               return node;
+       }
+
+       void markNotFlat() {
+               if (isFlat)
+                       isFlat = false;
+       }
+
+       public boolean isFlat() {
+               return isFlat;
+       }
+
+       public List<SuiteTerm> getSubTerms() {
+               return subTerms;
+       }
+
+       public List<SuiteTerm> getAllTerms() {
+               if (isFlat)
+                       return subTerms;
+               else {
+                       List<SuiteTerm> terms = new ArrayList<>();
+                       for (SuiteTerm subTerm : subTerms) {
+                               terms.add(subTerm);
+                               collectSubTerms(terms, subTerm);
+                       }
+                       return terms;
+               }
+       }
+
+       private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
+               for (SuiteTerm subTerm : term.getSubTerms()) {
+                       terms.add(subTerm);
+                       collectSubTerms(terms, subTerm);
+               }
+       }
+
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java b/core/org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java
new file mode 100644 (file)
index 0000000..53e73f3
--- /dev/null
@@ -0,0 +1,355 @@
+package org.argeo.suite.library;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.argeo.util.DigestUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/** Parses a .docx document, trying its best to extract text and table data. */
+public class DocxExtractor {
+       final static String T = "t";
+       final static String TC = "tc";
+       final static String TR = "tr";
+       final static String TBL = "tbl";
+       final static String P = "p";
+       static boolean debug = false;
+
+       final static String PROOF_ERR = "proofErr";
+       final static String TYPE = "type";
+       final static String SPELL_START = "spellStart";
+       final static String SPELL_END = "spellEnd";
+
+       protected List<Tbl> tables = new ArrayList<>();
+       protected List<String> text = new ArrayList<>();
+       protected Map<String, byte[]> media = new TreeMap<>();
+       private Set<String> mediaDigests = new HashSet<>();
+
+       protected void processTextItem(List<String> lines, String str) {
+               lines.add(str);
+       }
+
+       protected boolean skipMedia(String digest) {
+               return false;
+       }
+
+       class DocxHandler extends DefaultHandler {
+
+               private StringBuilder buffer = new StringBuilder();
+               private Tbl currentTbl = null;
+
+               boolean inSpellErr = false;
+               boolean inParagraph = false;
+
+               @Override
+               public void startElement(String uri, String name, String qName, Attributes attributes) throws SAXException {
+                       // System.out.println(localName + " " + qName + " " + uri.hashCode());
+                       if (P.equals(name)) {
+                               if (debug && currentTbl == null)
+                                       System.out.println("# START PARA");
+                               inParagraph = true;
+                       } else if (PROOF_ERR.equals(name)) {
+                               String type = attributes.getValue(uri, TYPE);
+                               if (SPELL_START.equals(type))
+                                       inSpellErr = true;
+                               else if (SPELL_END.equals(type))
+                                       inSpellErr = false;
+
+                       } else if (TBL.equals(name)) {
+                               if (currentTbl != null) {
+                                       Tbl childTbl = new Tbl();
+                                       childTbl.parentTbl = currentTbl;
+                                       currentTbl = childTbl;
+                                       // throw new IllegalStateException("Already an active table");
+                               } else {
+                                       currentTbl = new Tbl();
+                               }
+                       }
+               }
+
+               @Override
+               public void endElement(String uri, String name, String qName) throws SAXException {
+                       if (name.equals(T)) {
+//                             if (inSpellErr) {
+//                                     // do not reset the buffer
+//                                     return;
+//                             }
+
+                               if (currentTbl != null) {
+                                       currentTbl.appendText(buffer.toString());
+                               } else {
+                                       String str = buffer.toString();
+                                       // replace NO-BREAK SPACE by regular space.
+                                       str = str.replace('\u00A0', ' ');
+                                       str = str.strip();
+                                       if (!"".equals(str)) {
+                                               processTextItem(text, str);
+                                       }
+                               }
+                       } else if (name.equals(P)) {
+                               if (debug && currentTbl == null)
+                                       System.out.println("# END PARA");
+                               if (currentTbl != null) {
+                                       currentTbl.currentRow.current.text.append('\n');
+                               } else {
+
+                               }
+                               inParagraph = false;
+                       } else if (name.equals(TC)) {
+                               if (currentTbl != null)
+                                       currentTbl.closeColumn();
+                       } else if (name.equals(TR)) {
+                               if (currentTbl != null)
+                                       currentTbl.closeRow();
+                       } else if (name.equals(TBL)) {
+                               if (currentTbl != null) {
+                                       tables.add(currentTbl);
+                                       if (currentTbl.parentTbl != null)
+                                               currentTbl = currentTbl.parentTbl;
+                                       else
+                                               currentTbl = null;
+                               } else {
+                                       throw new IllegalStateException("Closing a table while none was open.");
+                               }
+                       }
+                       // reset the buffer
+                       buffer.setLength(0);
+               }
+
+               @Override
+               public void characters(char[] ch, int start, int length) throws SAXException {
+                       buffer.append(ch, start, length);
+               }
+
+       }
+
+       public static class Tbl {
+               Tbl parentTbl = null;
+               Tr currentRow = new Tr();
+               List<Tr> rows = new ArrayList<>();
+
+               void appendText(String str) {
+                       currentRow.current.text.append(str);
+               }
+
+               void closeColumn() {
+                       currentRow.columns.add(currentRow.current);
+                       currentRow.current = new Tc();
+               }
+
+               void closeRow() {
+                       rows.add(currentRow);
+                       currentRow = new Tr();
+               }
+
+               public List<Tr> getRows() {
+                       return rows;
+               }
+
+               @Override
+               public String toString() {
+                       StringBuilder sb = new StringBuilder();
+                       for (Tr tr : rows) {
+                               String txt = tr.toString();
+                               sb.append(txt).append('\n');
+                       }
+                       return sb.toString();
+               }
+       }
+
+       public static class Tr {
+               Tc current = new Tc();
+               List<Tc> columns = new ArrayList<>();
+
+               @Override
+               public String toString() {
+                       StringBuilder sb = new StringBuilder();
+                       for (Tc tc : columns) {
+                               sb.append("\"").append(tc.toString()).append("\"").append(',');
+                       }
+                       return sb.toString();
+               }
+
+               public List<Tc> getColumns() {
+                       return columns;
+               }
+
+       }
+
+       public static class Tc {
+               StringBuilder text = new StringBuilder();
+
+               @Override
+               public String toString() {
+                       return text.toString().trim();
+               }
+
+       }
+
+       protected void parse(Reader in) {
+               try {
+                       SAXParserFactory spf = SAXParserFactory.newInstance();
+                       spf.setNamespaceAware(true);
+                       SAXParser saxParser = spf.newSAXParser();
+                       XMLReader xmlReader = saxParser.getXMLReader();
+                       xmlReader.setContentHandler(new DocxHandler());
+                       xmlReader.parse(new InputSource(in));
+               } catch (ParserConfigurationException | SAXException | IOException e) {
+                       throw new RuntimeException("Cannot parse document", e);
+               }
+       }
+
+       public List<String> getText() {
+               return text;
+       }
+
+       public List<Tbl> getTables() {
+               return tables;
+       }
+
+       public Map<String, byte[]> getMedia() {
+               return media;
+       }
+
+       public void load(ZipInputStream zIn) {
+               try {
+                       ZipEntry entry = null;
+                       while ((entry = zIn.getNextEntry()) != null) {
+                               if ("word/document.xml".equals(entry.getName())) {
+                                       try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+                                               byte[] buffer = new byte[2048];
+                                               int len = 0;
+                                               while ((len = zIn.read(buffer)) > 0) {
+                                                       out.write(buffer, 0, len);
+                                               }
+                                               try (Reader reader = new InputStreamReader(new ByteArrayInputStream(out.toByteArray()),
+                                                               StandardCharsets.UTF_8)) {
+                                                       parse(reader);
+                                               }
+                                       }
+                               } else if (entry.getName().startsWith("word/media")) {
+                                       String fileName = entry.getName().substring(entry.getName().lastIndexOf('/') + 1);
+                                       int dotIndex = fileName.lastIndexOf('.');
+                                       String ext = fileName.substring(dotIndex + 1).toLowerCase();
+                                       // we ignore .jfif
+                                       if ("jpeg".equals(ext))
+                                               ext = "jpg";
+                                       fileName = fileName.substring(0, dotIndex) + "." + ext;
+                                       switch (ext) {
+                                       case "png":
+                                       case "jpg":
+                                       case "gif":
+                                       case "bmp":
+                                       case "tiff":
+                                               try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+                                                       byte[] buffer = new byte[2048];
+                                                       int len = 0;
+                                                       while ((len = zIn.read(buffer)) > 0) {
+                                                               out.write(buffer, 0, len);
+                                                       }
+                                                       byte[] bytes = out.toByteArray();
+                                                       String digest = DigestUtils.digest(DigestUtils.MD5, bytes);
+                                                       if (skipMedia(digest))
+                                                               break;
+                                                       if (!mediaDigests.contains(digest)) {
+                                                               media.put(fileName, bytes);
+                                                               mediaDigests.add(digest);
+                                                       }
+                                               }
+                                               break;
+                                       default:
+                                               break;
+                                       }
+                               } else {
+                                       // System.out.println(entry.getName());
+                               }
+                       }
+               } catch (IOException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+               // throw new IllegalArgumentException("No document.xml found");
+
+       }
+
+//     public static Reader extractDocumentXml(ZipInputStream zIn) throws IOException {
+//             ZipEntry entry = null;
+//             while ((entry = zIn.getNextEntry()) != null) {
+//                     if ("word/document.xml".equals(entry.getName())) {
+//                             try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+//                                     byte[] buffer = new byte[2048];
+//                                     int len = 0;
+//                                     while ((len = zIn.read(buffer)) > 0) {
+//                                             out.write(buffer, 0, len);
+//                                     }
+//                                     return new InputStreamReader(new ByteArrayInputStream(out.toByteArray()), StandardCharsets.UTF_8);
+//                             }
+//                     } else {
+//                             System.out.println(entry.getName());
+//                     }
+//             }
+//             throw new IllegalArgumentException("No document.xml found");
+//     }
+
+//     protected static ZipInputStream openAsZip(String file) throws IOException {
+//             ZipInputStream zIn;
+//             Path path = Paths.get(file);
+//             zIn = new ZipInputStream(Files.newInputStream(path));
+//             return zIn;
+//     }
+
+       public static void main(String[] args) throws IOException {
+               if (args.length == 0)
+                       throw new IllegalArgumentException("Provide a file path");
+               Path p = Paths.get(args[0]);
+
+               DocxExtractor importer = new DocxExtractor();
+               try (ZipInputStream zIn = new ZipInputStream(Files.newInputStream(p))) {
+                       importer.load(zIn);
+               }
+               // display
+               System.out.println("## TEXT");
+               for (int i = 0; i < importer.text.size(); i++) {
+                       String str = importer.text.get(i);
+                       System.out.println(str);
+               }
+
+               System.out.println("\n");
+
+               for (int i = 0; i < importer.tables.size(); i++) {
+                       Tbl tbl = importer.tables.get(i);
+                       System.out.println("## TABLE " + i);
+                       System.out.println(tbl);
+               }
+
+               System.out.println("## MEDIA");
+               for (String fileName : importer.media.keySet()) {
+                       int sizeKb = importer.media.get(fileName).length / 1024;
+                       System.out.println(fileName + " " + sizeKb + " kB");
+               }
+       }
+
+}
diff --git a/core/org.argeo.suite.core/src/org/argeo/suite/util/XPathUtils.java b/core/org.argeo.suite.core/src/org/argeo/suite/util/XPathUtils.java
new file mode 100644 (file)
index 0000000..66d9aa0
--- /dev/null
@@ -0,0 +1,177 @@
+package org.argeo.suite.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.util.ISO9075;
+
+/** Ease XPath generation for JCR requests */
+public class XPathUtils {
+       private final static Log log = LogFactory.getLog(XPathUtils.class);
+
+       private final static String QUERY_XPATH = "xpath";
+
+       public static String descendantFrom(String parentPath) {
+               if (notEmpty(parentPath)) {
+                       if ("/".equals(parentPath))
+                               parentPath = "";
+                       // Hardcoded dependency to Jackrabbit. Remove
+                       String result = "/jcr:root" + ISO9075.encodePath(parentPath);
+                       if (log.isTraceEnabled()) {
+                               String result2 = "/jcr:root" + parentPath;
+                               if (!result2.equals(result))
+                                       log.warn("Encoded Path " + result2 + " --> " + result);
+                       }
+                       return result;
+               } else
+                       return "";
+       }
+
+       public static String localAnd(String... conditions) {
+               StringBuilder builder = new StringBuilder();
+               for (String condition : conditions) {
+                       if (notEmpty(condition)) {
+                               builder.append(" ").append(condition).append(" and ");
+                       }
+               }
+               if (builder.length() > 3)
+                       return builder.substring(0, builder.length() - 4);
+               else
+                       return "";
+       }
+
+       public static String xPathNot(String condition) {
+               if (notEmpty(condition))
+                       return "not(" + condition + ")";
+               else
+                       return "";
+       }
+
+       public static String getFreeTextConstraint(String filter) throws RepositoryException {
+               StringBuilder builder = new StringBuilder();
+               if (notEmpty(filter)) {
+                       String[] strs = filter.trim().split(" ");
+                       for (String token : strs) {
+                               builder.append("jcr:contains(.,'*" + encodeXPathStringValue(token) + "*') and ");
+                       }
+                       return builder.substring(0, builder.length() - 4);
+               }
+               return "";
+       }
+
+       public static String getPropertyContains(String propertyName, String filter) throws RepositoryException {
+               if (notEmpty(filter))
+                       return "jcr:contains(@" + propertyName + ",'*" + encodeXPathStringValue(filter) + "*')";
+               return "";
+       }
+
+       private final static DateFormat jcrRefFormatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'+02:00'");
+
+       /**
+        * @param propertyName
+        * @param calendar       the reference date
+        * @param lowerOrGreater "&lt;", "&gt;" TODO validate "&gt;="
+        * @return
+        * @throws RepositoryException
+        */
+       public static String getPropertyDateComparaison(String propertyName, Calendar cal, String lowerOrGreater)
+                       throws RepositoryException {
+               if (cal != null) {
+                       String jcrDateStr = jcrRefFormatter.format(cal.getTime());
+
+                       // jcrDateStr = "2015-08-03T05:00:03:000Z";
+                       String result = "@" + propertyName + " " + lowerOrGreater + " xs:dateTime('" + jcrDateStr + "')";
+                       return result;
+               }
+               return "";
+       }
+
+       public static String getPropertyEquals(String propertyName, String value) {
+               if (notEmpty(value))
+                       return "@" + propertyName + "='" + encodeXPathStringValue(value) + "'";
+               return "";
+       }
+
+       public static String encodeXPathStringValue(String propertyValue) {
+               // TODO implement safer mechanism to escape invalid characters
+               // Also check why we have used this regex in ResourceSerrviceImpl l 474
+               // String cleanedKey = key.replaceAll("(?:')", "''");
+               String result = propertyValue.replaceAll("'", "''");
+               return result;
+       }
+
+       public static void andAppend(StringBuilder builder, String condition) {
+               if (notEmpty(condition)) {
+                       builder.append(condition);
+                       builder.append(" and ");
+               }
+       }
+
+       public static void appendOrderByProperties(StringBuilder builder, boolean ascending, String... propertyNames) {
+               if (propertyNames.length > 0) {
+                       builder.append(" order by ");
+                       for (String propName : propertyNames)
+                               builder.append("@").append(propName).append(", ");
+                       builder = builder.delete(builder.length() - 2, builder.length());
+                       if (ascending)
+                               builder.append(" ascending ");
+                       else
+                               builder.append(" descending ");
+               }
+       }
+
+       public static void appendAndPropStringCondition(StringBuilder builder, String propertyName, String filter)
+                       throws RepositoryException {
+               if (notEmpty(filter)) {
+                       andAppend(builder, getPropertyContains(propertyName, filter));
+               }
+       }
+
+       public static void appendAndNotPropStringCondition(StringBuilder builder, String propertyName, String filter)
+                       throws RepositoryException {
+               if (notEmpty(filter)) {
+                       String cond = getPropertyContains(propertyName, filter);
+                       builder.append(xPathNot(cond));
+                       builder.append(" and ");
+               }
+       }
+
+       public static Query createQuery(Session session, String queryString) throws RepositoryException {
+               QueryManager queryManager = session.getWorkspace().getQueryManager();
+               // Localise JCR properties for XPATH
+               queryString = localiseJcrItemNames(queryString);
+               return queryManager.createQuery(queryString, QUERY_XPATH);
+       }
+
+       private final static String NS_JCR = "\\{http://www.jcp.org/jcr/1.0\\}";
+       private final static String NS_NT = "\\{http://www.jcp.org/jcr/nt/1.0\\}";
+       private final static String NS_MIX = "\\{http://www.jcp.org/jcr/mix/1.0\\}";
+
+       /**
+        * Replace the generic namespace with the local "jcr:", "nt:", "mix:" values. It
+        * is a workaround that must be later cleaned
+        */
+       public static String localiseJcrItemNames(String name) {
+               name = name.replaceAll(NS_JCR, "jcr:");
+               name = name.replaceAll(NS_NT, "nt:");
+               name = name.replaceAll(NS_MIX, "mix:");
+               return name;
+       }
+
+       private static boolean notEmpty(String stringToTest) {
+               return !(stringToTest == null || "".equals(stringToTest.trim()));
+       }
+
+       /** Singleton. */
+       private XPathUtils() {
+
+       }
+}
diff --git a/core/org.argeo.suite.theme.default/.gitignore b/core/org.argeo.suite.theme.default/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/core/org.argeo.suite.theme.default/.project b/core/org.argeo.suite.theme.default/.project
new file mode 100644 (file)
index 0000000..d157155
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.suite.theme.default</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <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>
+       </natures>
+</projectDescription>
diff --git a/core/org.argeo.suite.theme.default/META-INF/.gitignore b/core/org.argeo.suite.theme.default/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/core/org.argeo.suite.theme.default/OSGI-INF/cmsTheme.xml b/core/org.argeo.suite.theme.default/OSGI-INF/cmsTheme.xml
new file mode 100644 (file)
index 0000000..66b8c44
--- /dev/null
@@ -0,0 +1,7 @@
+<?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="Argeo Suite Default Theme">
+   <implementation class="org.argeo.cms.ui.util.BundleCmsTheme"/>
+   <service>
+      <provide interface="org.argeo.cms.ui.CmsTheme"/>
+   </service>
+</scr:component>
diff --git a/core/org.argeo.suite.theme.default/bnd.bnd b/core/org.argeo.suite.theme.default/bnd.bnd
new file mode 100644 (file)
index 0000000..6c4a97c
--- /dev/null
@@ -0,0 +1,6 @@
+Service-Component:\
+OSGI-INF/cmsTheme.xml
+
+Import-Package:\
+org.argeo.cms.ui.util,\
+*
\ No newline at end of file
diff --git a/core/org.argeo.suite.theme.default/build.properties b/core/org.argeo.suite.theme.default/build.properties
new file mode 100644 (file)
index 0000000..9cb37cd
--- /dev/null
@@ -0,0 +1,3 @@
+bin.includes = META-INF/,\
+               icons/,\
+               OSGI-INF/
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/add.png b/core/org.argeo.suite.theme.default/icons/types/16/add.png
new file mode 100644 (file)
index 0000000..5c06bf0
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/add.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/close.png b/core/org.argeo.suite.theme.default/icons/types/16/close.png
new file mode 100644 (file)
index 0000000..af85e1a
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/close.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/dashboard.png b/core/org.argeo.suite.theme.default/icons/types/16/dashboard.png
new file mode 100644 (file)
index 0000000..1235592
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/dashboard.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/delete.png b/core/org.argeo.suite.theme.default/icons/types/16/delete.png
new file mode 100644 (file)
index 0000000..dd2f428
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/delete.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/document.png b/core/org.argeo.suite.theme.default/icons/types/16/document.png
new file mode 100644 (file)
index 0000000..b168263
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/document.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/documents.png b/core/org.argeo.suite.theme.default/icons/types/16/documents.png
new file mode 100644 (file)
index 0000000..56deec5
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/documents.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/folder.png b/core/org.argeo.suite.theme.default/icons/types/16/folder.png
new file mode 100644 (file)
index 0000000..fefbb40
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/folder.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/inbox.png b/core/org.argeo.suite.theme.default/icons/types/16/inbox.png
new file mode 100644 (file)
index 0000000..d1aa6af
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/inbox.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/location.png b/core/org.argeo.suite.theme.default/icons/types/16/location.png
new file mode 100644 (file)
index 0000000..17c7070
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/location.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/logout.png b/core/org.argeo.suite.theme.default/icons/types/16/logout.png
new file mode 100644 (file)
index 0000000..f685ea9
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/logout.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/map.png b/core/org.argeo.suite.theme.default/icons/types/16/map.png
new file mode 100644 (file)
index 0000000..99690e6
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/map.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/organisation.png b/core/org.argeo.suite.theme.default/icons/types/16/organisation.png
new file mode 100644 (file)
index 0000000..2e81a6c
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/organisation.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/people.png b/core/org.argeo.suite.theme.default/icons/types/16/people.png
new file mode 100644 (file)
index 0000000..925d571
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/people.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/person.png b/core/org.argeo.suite.theme.default/icons/types/16/person.png
new file mode 100644 (file)
index 0000000..8f518e1
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/person.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/refresh.png b/core/org.argeo.suite.theme.default/icons/types/16/refresh.png
new file mode 100644 (file)
index 0000000..0d39107
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/refresh.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/save.png b/core/org.argeo.suite.theme.default/icons/types/16/save.png
new file mode 100644 (file)
index 0000000..1c58ada
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/save.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/search.png b/core/org.argeo.suite.theme.default/icons/types/16/search.png
new file mode 100644 (file)
index 0000000..d32874b
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/search.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/settings.png b/core/org.argeo.suite.theme.default/icons/types/16/settings.png
new file mode 100644 (file)
index 0000000..ac2d8c9
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/settings.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/tag.png b/core/org.argeo.suite.theme.default/icons/types/16/tag.png
new file mode 100644 (file)
index 0000000..cefdbb9
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/tag.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/task.png b/core/org.argeo.suite.theme.default/icons/types/16/task.png
new file mode 100644 (file)
index 0000000..eeb7e01
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/task.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/16/user.png b/core/org.argeo.suite.theme.default/icons/types/16/user.png
new file mode 100644 (file)
index 0000000..13a8f76
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/16/user.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/add.png b/core/org.argeo.suite.theme.default/icons/types/32/add.png
new file mode 100644 (file)
index 0000000..15feb20
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/add.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/close.png b/core/org.argeo.suite.theme.default/icons/types/32/close.png
new file mode 100644 (file)
index 0000000..d0729a5
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/close.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/dashboard.png b/core/org.argeo.suite.theme.default/icons/types/32/dashboard.png
new file mode 100644 (file)
index 0000000..4c24f43
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/dashboard.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/delete.png b/core/org.argeo.suite.theme.default/icons/types/32/delete.png
new file mode 100644 (file)
index 0000000..2ee3d88
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/delete.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/document.png b/core/org.argeo.suite.theme.default/icons/types/32/document.png
new file mode 100644 (file)
index 0000000..a4653fa
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/document.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/documents.png b/core/org.argeo.suite.theme.default/icons/types/32/documents.png
new file mode 100644 (file)
index 0000000..29db972
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/documents.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/folder.png b/core/org.argeo.suite.theme.default/icons/types/32/folder.png
new file mode 100644 (file)
index 0000000..b98fc84
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/folder.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/inbox.png b/core/org.argeo.suite.theme.default/icons/types/32/inbox.png
new file mode 100644 (file)
index 0000000..7583c99
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/inbox.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/location.png b/core/org.argeo.suite.theme.default/icons/types/32/location.png
new file mode 100644 (file)
index 0000000..d9207f1
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/location.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/logout.png b/core/org.argeo.suite.theme.default/icons/types/32/logout.png
new file mode 100644 (file)
index 0000000..2d8024f
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/logout.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/map.png b/core/org.argeo.suite.theme.default/icons/types/32/map.png
new file mode 100644 (file)
index 0000000..9a82a96
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/map.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/organisation.png b/core/org.argeo.suite.theme.default/icons/types/32/organisation.png
new file mode 100644 (file)
index 0000000..62890c2
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/organisation.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/people.png b/core/org.argeo.suite.theme.default/icons/types/32/people.png
new file mode 100644 (file)
index 0000000..5f53288
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/people.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/person.png b/core/org.argeo.suite.theme.default/icons/types/32/person.png
new file mode 100644 (file)
index 0000000..a6c5f1d
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/person.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/save.png b/core/org.argeo.suite.theme.default/icons/types/32/save.png
new file mode 100644 (file)
index 0000000..d7597d1
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/save.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/search.png b/core/org.argeo.suite.theme.default/icons/types/32/search.png
new file mode 100644 (file)
index 0000000..8d89a4a
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/search.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/settings.png b/core/org.argeo.suite.theme.default/icons/types/32/settings.png
new file mode 100644 (file)
index 0000000..4e3fa20
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/settings.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/tag.png b/core/org.argeo.suite.theme.default/icons/types/32/tag.png
new file mode 100644 (file)
index 0000000..907e216
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/tag.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/task.png b/core/org.argeo.suite.theme.default/icons/types/32/task.png
new file mode 100644 (file)
index 0000000..b6bd243
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/task.png differ
diff --git a/core/org.argeo.suite.theme.default/icons/types/32/user.png b/core/org.argeo.suite.theme.default/icons/types/32/user.png
new file mode 100644 (file)
index 0000000..50fd404
Binary files /dev/null and b/core/org.argeo.suite.theme.default/icons/types/32/user.png differ
diff --git a/core/org.argeo.suite.theme.default/pom.xml b/core/org.argeo.suite.theme.default/pom.xml
new file mode 100644 (file)
index 0000000..9c81005
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.suite</groupId>
+               <artifactId>core</artifactId>
+               <version>2.1.18-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.suite.theme.default</artifactId>
+       <name>Suite Default Theme</name>
+       <packaging>jar</packaging>
+       <dependencies>
+       </dependencies>
+</project>
diff --git a/core/org.argeo.suite.theme.default/rap/work.css b/core/org.argeo.suite.theme.default/rap/work.css
new file mode 100644 (file)
index 0000000..c0aaeb1
--- /dev/null
@@ -0,0 +1,181 @@
+.argeo-suite-header {
+       color: white;
+       background-color: #00294b;
+}
+
+.argeo-suite-headerTitle {
+       font: bold 18px sans-serif;
+       color: white;
+       background-color: #00294b;
+}
+
+.argeo-suite-leadPane {
+       background-color: #eee;
+}
+
+Label.argeo-suite-leadPane {
+       font: 14px sans-serif;
+       color: #888;
+       background-color: #eee;
+}
+
+Button.argeo-suite-leadPane:hover {
+       cursor:pointer;
+}
+
+.argeo-suite-recentItems {
+       font: bold 14px sans-serif;
+       color: white;
+       background-color: #00294b;
+       padding: 8px 16px;
+}
+
+.argeo-suite-titleContainer {
+       background-color: #00294b;
+       padding: 6px 8px 4px 8px;
+}
+
+.argeo-suite-titleLabel {
+       font: bold 14px sans-serif;
+       color: white;
+       background-color: #00294b;
+}
+
+.argeo-suite-subTitleLabel {
+       font: italic 14px sans-serif;
+       color: #777;
+       padding: 4px 8px;
+}
+
+.argeo-suite-simpleLabel {
+       font: bold 14px sans-serif;
+       padding: 0px;
+}
+
+.argeo-suite-simpleText {
+       font: 14px sans-serif;
+       padding: 0px;
+}
+
+.argeo-suite-titleCell {
+       font: bold 14px sans-serif;
+       background-color: #ddd;
+}
+
+.argeo-suite-inlineButton {
+       padding: 0px 4px;
+       font: 12px sans-serif;
+       border: 1px solid white;
+       color: white;
+       background-image: none;
+       background-color: #00294b;
+}
+
+.argeo-suite-inlineButton:hover {
+       color: #00294b;
+       background-color: white;
+}
+
+Composite.argeo-suite-mainTabBody {
+       background-color: #eee;
+       border: 1px solid #bbb;
+}
+
+.argeo-suite-mainTab {
+       background-color: #eee;
+       border: 1px solid #888;
+}
+
+ToolItem.argeo-suite-mainTab {
+       border: none;
+       background-color: #eee;
+}
+
+ToolItem.argeo-suite-mainTab:hover {
+       background-color: #eee;
+}
+
+
+Button.argeo-suite-mainTab {
+       border: 1px solid #eee;
+       background-color: #eee;
+}
+
+.argeo-suite-mainTab:hover {
+       background-color: #eee;
+}
+
+Button.argeo-suite-mainTab:hover {
+       cursor: pointer;
+       background-color: #eee;
+}
+
+.argeo-suite-mainTabSelected {
+       font: bold 14px sans-serif;
+       color: white;
+       /*background-color: #00294b;*/
+       background-color: #5882b5;
+       border:1px solid #888;
+}
+
+ToolItem.argeo-suite-mainTabSelected {
+       border: none;
+}
+
+ToolItem.argeo-suite-mainTabSelected:hover {
+       background-color: #5882b5;
+}
+
+Button.argeo-suite-mainTabSelected {
+       border: none;
+}
+
+Sash {
+  border: 1px solid white;
+  background-image: none;
+  background-color: white;
+}
+
+Sash:hover {
+  border: 1px solid #5882b5;
+  background-color: #5882b5;
+}
+
+TreeItem{
+       background-color:#fff;
+}
+
+Tree-RowOverlay:selected {
+       color:#fff;
+       background-color:#5882b5;
+}
+
+TableItem{
+       background-color:#fff;
+}
+
+Table-RowOverlay:selected {
+       color:#fff;
+       background-color:#5882b5;
+}
+
+.argeo-suite-navigationBar{
+       background-color:#ddd;
+}
+
+.argeo-suite-navigationTitle{
+       background-color:#ddd;
+       font:bold 14px sans-serif;
+}
+
+.argeo-suite-navigationButton{
+       color:#777;
+       background-color:#ddd;
+       font:bold 14px sans-serif;
+}
+
+.argeo-suite-navigationButton:hover{
+       cursor:pointer;
+       color:#ddd;
+       background-color:#777;
+}
diff --git a/core/org.argeo.suite.theme.default/swt/app.css b/core/org.argeo.suite.theme.default/swt/app.css
new file mode 100644 (file)
index 0000000..4ac745d
--- /dev/null
@@ -0,0 +1,129 @@
+.argeo-suite-header {
+       color: white;
+       background-color: #00294b;
+}
+
+.argeo-suite-headerTitle {
+       font: bold 14px sans-serif;
+       color: white;
+       background-color: #00294b;
+}
+
+.argeo-suite-leadPane {
+       background-color: #eee;
+}
+
+Label.argeo-suite-leadPane {
+       font: 11px sans-serif;
+       color: #888;
+       background-color: #eee;
+}
+
+Button.argeo-suite-leadPane:hover {
+       cursor: pointer;
+}
+
+.argeo-suite-recentItems {
+       font: bold 13px sans-serif;
+       color: white;
+       background-color: #00294b;
+       padding: 8px 16px;
+}
+
+.argeo-suite-titleContainer {
+       background-color: #00294b;
+}
+
+.argeo-suite-titleLabel {
+       font: bold 13px sans-serif;
+       margin: 6px 8px 4px 8px;
+       color: white;
+       background-color: #00294b;
+}
+
+.argeo-suite-subTitleLabel {
+       font: italic 14px sans-serif;
+       color: #777;
+       margin: 4px 8px;
+}
+
+.argeo-suite-formLine {
+       padding: 4px 8px 4px 16px;
+}
+
+.argeo-suite-simpleLabel {
+       font: normal 11px sans-serif;
+       border: 8px solid #eee;
+}
+
+.argeo-suite-simpleText {
+       
+}
+
+.argeo-suite-simpleInput {
+       padding: 4px 8px 4px 8px;
+}
+
+.argeo-suite-titleCell {
+       font: bold 11px sans-serif;
+       background-color: #ddd;
+}
+
+.argeo-suite-inlineButton {
+       padding: 0px 4px;
+       font: 12px sans-serif;
+       border: 1px solid white;
+       color: white;
+       background-image: none;
+       background-color: #00294b;
+}
+
+.argeo-suite-inlineButton:hover {
+       color: #00294b;
+       background-color: white;
+}
+
+Composite.argeo-suite-mainTabBody {
+       background-color: #eee;
+       border: 1px solid #bbb;
+}
+
+.argeo-suite-mainTab {
+       background-color: #eee;
+       border: 1px solid #bbb;
+}
+
+ToolItem.argeo-suite-mainTab {
+       border: none;
+       background-color: #eee;
+}
+
+Button.argeo-suite-mainTab {
+       border: none;
+       background-color: #eee;
+}
+
+.argeo-suite-mainTab:hover {
+       background-color: #eee;
+}
+
+Button.argeo-suite-mainTab:hover {
+       cursor: pointer;
+       background-color: #eee;
+}
+
+.argeo-suite-mainTabSelected {
+       font: bold 14px sans-serif;
+       color: white;
+       /*background-color: #00294b;*/
+       background-color: #5882b5;
+       border: 1px solid #00294b;
+}
+
+ToolItem.argeo-suite-mainTabSelected {
+       border: none;
+}
+
+Button.argeo-suite-mainTabSelected {
+       border: none;
+}
\ No newline at end of file
diff --git a/core/org.argeo.suite.ui.rap/.gitignore b/core/org.argeo.suite.ui.rap/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/core/org.argeo.suite.ui.rap/.project b/core/org.argeo.suite.ui.rap/.project
new file mode 100644 (file)
index 0000000..eff6bb0
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.suite.ui.rap</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <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>
+       </natures>
+</projectDescription>
diff --git a/core/org.argeo.suite.ui.rap/META-INF/.gitignore b/core/org.argeo.suite.ui.rap/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/core/org.argeo.suite.ui.rap/OSGI-INF/cmsWebApp.xml b/core/org.argeo.suite.ui.rap/OSGI-INF/cmsWebApp.xml
new file mode 100644 (file)
index 0000000..4dfdcff
--- /dev/null
@@ -0,0 +1,7 @@
+<?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="Argeo Suite Web App">
+   <implementation class="org.argeo.cms.web.CmsWebApp"/>
+   <property name="contextName" type="String" value="argeo"/>
+   <reference bind="setCmsApp" cardinality="1..1" interface="org.argeo.cms.ui.CmsApp" name="CmsApp" policy="dynamic" target="(service.pid=argeo.suite.ui.app)" unbind="unsetCmsApp"/>
+   <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
+</scr:component>
diff --git a/core/org.argeo.suite.ui.rap/bnd.bnd b/core/org.argeo.suite.ui.rap/bnd.bnd
new file mode 100644 (file)
index 0000000..35b671b
--- /dev/null
@@ -0,0 +1,6 @@
+Service-Component: OSGI-INF/cmsWebApp.xml
+
+Import-Package:\
+org.argeo.cms.web,\
+org.eclipse.rap.rwt.application,\
+*
diff --git a/core/org.argeo.suite.ui.rap/build.properties b/core/org.argeo.suite.ui.rap/build.properties
new file mode 100644 (file)
index 0000000..6210e84
--- /dev/null
@@ -0,0 +1,5 @@
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               OSGI-INF/
+source.. = src/
diff --git a/core/org.argeo.suite.ui.rap/pom.xml b/core/org.argeo.suite.ui.rap/pom.xml
new file mode 100644 (file)
index 0000000..4316afa
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.suite</groupId>
+               <artifactId>core</artifactId>
+               <version>2.1.18-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.suite.ui.rap</artifactId>
+       <name>Suite UI RAP</name>
+       <packaging>jar</packaging>
+       <dependencies>
+               <dependency>
+                       <groupId>org.argeo.suite</groupId>
+                       <artifactId>org.argeo.suite.ui</artifactId>
+                       <version>2.1.18-SNAPSHOT</version>
+               </dependency>
+
+               <!-- Eclipse E4 -->
+               <dependency>
+                       <groupId>org.argeo.tp</groupId>
+                       <artifactId>argeo-tp-rap-e4</artifactId>
+                       <version>${version.argeo-tp}</version>
+                       <type>pom</type>
+                       <scope>provided</scope>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/core/org.argeo.suite.ui/.classpath b/core/org.argeo.suite.ui/.classpath
new file mode 100644 (file)
index 0000000..e801ebf
--- /dev/null
@@ -0,0 +1,7 @@
+<?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>
diff --git a/core/org.argeo.suite.ui/.gitignore b/core/org.argeo.suite.ui/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/core/org.argeo.suite.ui/.project b/core/org.argeo.suite.ui/.project
new file mode 100644 (file)
index 0000000..7146bab
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.suite.ui</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>
diff --git a/core/org.argeo.suite.ui/META-INF/.gitignore b/core/org.argeo.suite.ui/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/core/org.argeo.suite.ui/OSGI-INF/cmsApp.xml b/core/org.argeo.suite.ui/OSGI-INF/cmsApp.xml
new file mode 100644 (file)
index 0000000..e42eeeb
--- /dev/null
@@ -0,0 +1,14 @@
+<?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="Argeo Suite App">
+   <implementation class="org.argeo.suite.ui.SuiteApp"/>
+   <service>
+      <provide interface="org.argeo.cms.ui.CmsApp"/>
+      <provide interface="org.osgi.service.event.EventHandler"/>
+   </service>
+   <properties entry="config/cmsApp.properties"/>
+   <reference bind="addUiProvider" cardinality="0..n" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" unbind="removeUiProvider"/>
+   <reference bind="addTheme" cardinality="1..n" interface="org.argeo.cms.ui.CmsTheme" name="CmsTheme" policy="dynamic" unbind="removeTheme"/>
+   <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="dynamic" target="(cn=ego)"/>
+   <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
+   <reference bind="setCmsUserManager" cardinality="1..1" interface="org.argeo.cms.CmsUserManager" name="CmsUserManager" policy="static"/>
+</scr:component>
diff --git a/core/org.argeo.suite.ui/OSGI-INF/dashboard.xml b/core/org.argeo.suite.ui/OSGI-INF/dashboard.xml
new file mode 100644 (file)
index 0000000..f678b5b
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default Dashboard">
+   <implementation class="org.argeo.suite.ui.DefaultDashboard"/>
+   <service>
+      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+   </service>
+   <properties entry="config/dashboard.properties"/>
+</scr:component>
diff --git a/core/org.argeo.suite.ui/OSGI-INF/dashboardLayer.xml b/core/org.argeo.suite.ui/OSGI-INF/dashboardLayer.xml
new file mode 100644 (file)
index 0000000..b60eafc
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Dashboard Layer">
+   <implementation class="org.argeo.suite.ui.DefaultEditionLayer"/>
+   <service>
+      <provide interface="org.argeo.suite.ui.SuiteLayer"/>
+   </service>
+   <properties entry="config/dashboardLayer.properties"/>
+   <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.suite.ui.recentItems)"/>
+</scr:component>
diff --git a/core/org.argeo.suite.ui/OSGI-INF/header.xml b/core/org.argeo.suite.ui/OSGI-INF/header.xml
new file mode 100644 (file)
index 0000000..a8fc66d
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Work Header">
+   <implementation class="org.argeo.suite.ui.DefaultHeader"/>
+   <service>
+      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+      <provide interface="org.osgi.service.cm.ManagedService"/>
+   </service>
+   <properties entry="config/header.properties"/>
+</scr:component>
diff --git a/core/org.argeo.suite.ui/OSGI-INF/l10n/bundle.properties b/core/org.argeo.suite.ui/OSGI-INF/l10n/bundle.properties
new file mode 100644 (file)
index 0000000..3d08155
--- /dev/null
@@ -0,0 +1,98 @@
+dashboard=dashboard
+people=contacts
+documents=documents
+locations=locations
+recentItems=recent items
+
+appTitle=Argeo Suite
+
+#
+# PEOPLE
+# org.argeo.people.ui.PeopleMsg
+#
+person=Person
+organisation=Organisation
+
+# NewPersonWizard
+firstName=First Name
+lastName=Last Name
+salutation=Salutation
+email=Email
+personWizardWindowTitle=New person
+personWizardPageTitle=Create a contact
+
+# NewOrgWizard
+legalName=Legal name
+legalForm=Legal form
+vatId=VAT ID
+orgWizardWindowTitle=New organisation
+orgWizardPageTitle=Create an organisation
+
+
+# ContextAddressComposite
+chooseAnOrganisation=Choose an organisation
+street=Street
+streetComplement=Street complement
+zipCode=Zip code
+city=City
+state=State
+country=Country
+geopoint=Geopoint
+
+# FilteredOrderableEntityTable
+filterHelp=Type filter criterion separated by a space
+
+# BankAccountComposite
+accountHolder=Account holder
+bankName=Bank name
+currency=Currency
+accountNumber=Account number
+bankNumber=Bank number
+BIC=BIC
+IBAN=IBAN
+
+# EditJobDialog
+position=Role
+chosenItem=Chose item
+department=Department
+isPrimary=Is primary
+searchAndChooseEntity=Search and choose a corresponding entity
+
+# ContactListCTab (e4)
+notes=Notes
+addAContact=Add a contact
+contactValue=Contact value
+linkedCompany=Linked company
+
+# OrgAdminInfoCTab (e4)
+paymentAccount=Payment account
+
+# OrgEditor (e4)
+orgDetails=Details
+orgActivityLog=Activity log
+team=Team
+orgAdmin=Admin.
+
+# PersonEditor (e4)
+personDetails=Contact details
+personActivityLog=Activity log
+personOrgs=Organisations
+personSecurity=Security
+
+# PersonSecurityCTab (e4)
+resetPassword=Reset password
+
+# Generic
+label=Label
+aCustomLabel=A custom label
+description=Description
+value=Value
+name=Name
+primary=Primary
+add=Add
+save=Save
+pickUp=Pick up
+
+# Tags
+confirmNewTag=Tag #{0} is not yet registered. Are you sure you want to create it?
+cannotCreateTag=Tag #{0} is not yet registered and you don't have enough rights to create it.
diff --git a/core/org.argeo.suite.ui/OSGI-INF/l10n/bundle_de.properties b/core/org.argeo.suite.ui/OSGI-INF/l10n/bundle_de.properties
new file mode 100644 (file)
index 0000000..0af19c2
--- /dev/null
@@ -0,0 +1,98 @@
+dashboard=dashboard
+people=Kontakte
+documents=Dokumente
+locations=Orte
+recentItems=neulich
+
+appTitle=Argeo Suite
+
+#
+# PEOPLE
+# org.argeo.people.ui.PeopleMsg
+#
+person=Person
+organisation=Organisation
+
+# NewPersonWizard
+firstName=Vorname
+lastName=Nachname
+salutation=Salutation
+email=E-Mail
+personWizardWindowTitle=Neue Person
+personWizardPageTitle=Kontakt erstellen
+
+# NewOrgWizard
+legalName=Name
+legalForm=Geschäftsform
+vatId=Ust ID
+orgWizardWindowTitle=Neue Organisation
+orgWizardPageTitle=Organisation erstellen
+
+
+# ContextAddressComposite
+chooseAnOrganisation=Organisation wählen
+street=Strasse
+streetComplement=Strasse Zusatz
+zipCode=PLZ
+city=Stadt
+state=Bundesland
+country=Land
+geopoint=Geopoint
+
+# FilteredOrderableEntityTable
+filterHelp=Type filter criterion separated by a space
+
+# BankAccountComposite
+accountHolder=Kontoinhaber 
+bankName=Name der Bank
+currency=Währung
+accountNumber=Kontonummer
+bankNumber=BLZ
+BIC=BIC
+IBAN=IBAN
+
+# EditJobDialog
+position=Rolle
+chosenItem=Auswahl
+department=Abteilung
+isPrimary=Ist Primär
+searchAndChooseEntity=Suche und wähle ein zugehöriges Objekt
+
+# ContactListCTab (e4)
+notes=Bemerkungen
+addAContact=Kontakt hinzufügen
+contactValue=Kontakt value
+linkedCompany=zugehörige Firma
+
+# OrgAdminInfoCTab (e4)
+paymentAccount=Geschäftskonto
+
+# OrgEditor (e4)
+orgDetails=Details
+orgActivityLog=Aktivitäten Log
+team=Team
+orgAdmin=Admin.
+
+# PersonEditor (e4)
+personDetails=Kontakt Daten
+personActivityLog=Aktivitäten Log
+personOrgs=Organisationen
+personSecurity=Sicherheit
+
+# PersonSecurityCTab (e4)
+resetPassword=Passwort zurücksetzen
+
+# Generic
+label=Beschriftung
+aCustomLabel=Eine spezifische Beschriftung
+description=Beschreibung
+value=Wert
+name=Name
+primary=Haupt-
+add=Hinzufügen
+save=Speichern
+pickUp=Aussuchen
+
+# Tags
+confirmNewTag=Das Hashtag '{0}' existiert noch nicht. WollenSie es hinzufügen?
+cannotCreateTag=Das Hashtag '{0}' existiert nicht uns Sie haben nicht die Rechte, um es hinzufügen.
diff --git a/core/org.argeo.suite.ui/OSGI-INF/l10n/bundle_fr.properties b/core/org.argeo.suite.ui/OSGI-INF/l10n/bundle_fr.properties
new file mode 100644 (file)
index 0000000..225e5fd
--- /dev/null
@@ -0,0 +1,102 @@
+dashboard=dashboard
+people=contacts
+documents=documents
+locations=lieux
+recentItems=récent
+
+appTitle=Argeo Suite
+
+#
+# GENERIC
+#
+
+#
+# PEOPLE
+# org.argeo.people.ui.PeopleMsg
+#
+person=Personne
+organisation=Organisation
+
+# NewPersonWizard
+firstName=Prénom
+lastName=Nom
+salutation=Salutation
+email=Email
+personWizardWindowTitle=Nouvelle personne
+personWizardPageTitle=Créer un contact
+
+# NewOrgWizard
+legalName=Nom
+legalForm=Forme légale
+vatId=ID TVA
+orgWizardWindowTitle=Nouvelle organisation
+orgWizardPageTitle=Créer une organisation
+
+
+# ContextAddressComposite
+chooseAnOrganisation=Choisir une organisation
+street=Rue
+streetComplement=Complément rue
+zipCode=Code postal
+city=Ville
+state=État
+country=Pays
+geopoint=Géocoordonnées
+
+# FilteredOrderableEntityTable
+filterHelp=Sasir les critères de filtrage séparés par des espaces 
+
+# BankAccountComposite
+accountHolder=Propriétaire du compte
+bankName=Nom de la banque
+currency=Devise
+accountNumber=Numéro de compte
+bankNumber=Numéro de banque
+BIC=BIC
+IBAN=IBAN
+
+# EditJobDialog
+position=Rôle
+chosenItem=Choisir une Ã©lément
+department=Service
+isPrimary=Principal
+searchAndChooseEntity=Cherhcer et choisir l'entitée correspondante
+
+# ContactListCTab (e4)
+notes=Notes
+addAContact=Ajouter un contact
+contactValue=Valeur
+linkedCompany=Entreprise liée
+
+# OrgAdminInfoCTab (e4)
+paymentAccount=Compte de paiement
+
+# OrgEditor (e4)
+orgDetails=Détails
+orgActivityLog=Activités
+team=Équipe
+orgAdmin=Admin.
+
+# PersonEditor (e4)
+personDetails=Détails du contact
+personActivityLog=Activités
+personOrgs=Organisations
+personSecurity=Accès
+
+# PersonSecurityCTab (e4)
+resetPassword=Force le mot de passe
+
+# Generic
+label=Étiquette
+aCustomLabel=Une Ã©tiquette spécifique
+description=Description
+value=Valeur
+name=Nom
+primary=Principal
+add=Ajouter
+save=Sauver
+pickUp=Choisir
+
+# Tags
+confirmNewTag=Le tag #{0} n'existe pas encore. Voulez-vous le créer?
+cannotCreateTag=Le tag #{0} n'existe pas encore et vous n'avez pas les droits pour le créer.
diff --git a/core/org.argeo.suite.ui/OSGI-INF/leadPane.xml b/core/org.argeo.suite.ui/OSGI-INF/leadPane.xml
new file mode 100644 (file)
index 0000000..9d3f2dd
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Lead Pane">
+   <implementation class="org.argeo.suite.ui.DefaultLeadPane"/>
+   <service>
+      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+   </service>
+   <properties entry="config/leadPane.properties"/>
+   <property name="defaultLayers" type="String">argeo.suite.ui.dashboardLayer
+argeo.documents.ui.documentsLayer
+   </property>
+   <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
+</scr:component>
diff --git a/core/org.argeo.suite.ui/OSGI-INF/loginScreen.xml b/core/org.argeo.suite.ui/OSGI-INF/loginScreen.xml
new file mode 100644 (file)
index 0000000..0c5377a
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default Login Screen">
+   <implementation class="org.argeo.suite.ui.DefaultLoginScreen"/>
+   <properties entry="config/loginScreen.properties"/>
+   <service>
+      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+   </service>
+</scr:component>
diff --git a/core/org.argeo.suite.ui/OSGI-INF/recentItems.xml b/core/org.argeo.suite.ui/OSGI-INF/recentItems.xml
new file mode 100644 (file)
index 0000000..8aaee16
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" name="Default Recent Items">
+   <implementation class="org.argeo.suite.ui.RecentItems"/>
+   <service>
+      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+   </service>
+   <properties entry="config/recentItems.properties"/>
+</scr:component>
diff --git a/core/org.argeo.suite.ui/bnd.bnd b/core/org.argeo.suite.ui/bnd.bnd
new file mode 100644 (file)
index 0000000..b49d736
--- /dev/null
@@ -0,0 +1,18 @@
+Service-Component:\
+OSGI-INF/cmsApp.xml,\
+OSGI-INF/header.xml,\
+OSGI-INF/leadPane.xml,\
+OSGI-INF/loginScreen.xml,\
+OSGI-INF/recentItems.xml,\
+OSGI-INF/dashboard.xml,\
+OSGI-INF/dashboardLayer.xml
+
+Import-Package:\
+org.argeo.api,\
+org.eclipse.swt,\
+org.osgi.framework,\
+org.argeo.entity,\
+org.eclipse.core.commands.common,\
+org.eclipse.jface.window,\
+org.eclipse.jface.dialogs,\
+*
diff --git a/core/org.argeo.suite.ui/build.properties b/core/org.argeo.suite.ui/build.properties
new file mode 100644 (file)
index 0000000..d829967
--- /dev/null
@@ -0,0 +1,10 @@
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               OSGI-INF/,\
+               config/,\
+               OSGI-INF/loginScreen.xml,\
+               OSGI-INF/dashboard.xml,\
+               OSGI-INF/recentItems.xml,\
+               OSGI-INF/dashboardLayer.xml
+source.. = src/
diff --git a/core/org.argeo.suite.ui/config/cmsApp.properties b/core/org.argeo.suite.ui/config/cmsApp.properties
new file mode 100644 (file)
index 0000000..1dec00e
--- /dev/null
@@ -0,0 +1,3 @@
+service.pid=argeo.suite.ui.app
+
+event.topics=argeo/suite/*
\ No newline at end of file
diff --git a/core/org.argeo.suite.ui/config/dashboard.properties b/core/org.argeo.suite.ui/config/dashboard.properties
new file mode 100644 (file)
index 0000000..1832543
--- /dev/null
@@ -0,0 +1 @@
+service.pid=argeo.suite.ui.dashboard
diff --git a/core/org.argeo.suite.ui/config/dashboardLayer.properties b/core/org.argeo.suite.ui/config/dashboardLayer.properties
new file mode 100644 (file)
index 0000000..79abe4c
--- /dev/null
@@ -0,0 +1,4 @@
+service.pid=argeo.suite.ui.dashboardLayer
+
+title=Dashboard
+icon=dashboard
\ No newline at end of file
diff --git a/core/org.argeo.suite.ui/config/header.properties b/core/org.argeo.suite.ui/config/header.properties
new file mode 100644 (file)
index 0000000..034d5f5
--- /dev/null
@@ -0,0 +1,4 @@
+service.pid=argeo.suite.ui.header
+argeo.suite.ui=true
+
+argeo.suite.ui.header.title=%appTitle
\ No newline at end of file
diff --git a/core/org.argeo.suite.ui/config/leadPane.properties b/core/org.argeo.suite.ui/config/leadPane.properties
new file mode 100644 (file)
index 0000000..0d7b193
--- /dev/null
@@ -0,0 +1 @@
+service.pid=argeo.suite.ui.leadPane
diff --git a/core/org.argeo.suite.ui/config/loginScreen.properties b/core/org.argeo.suite.ui/config/loginScreen.properties
new file mode 100644 (file)
index 0000000..332614d
--- /dev/null
@@ -0,0 +1 @@
+service.pid=argeo.suite.ui.loginScreen
diff --git a/core/org.argeo.suite.ui/config/recentItems.properties b/core/org.argeo.suite.ui/config/recentItems.properties
new file mode 100644 (file)
index 0000000..7321c55
--- /dev/null
@@ -0,0 +1 @@
+service.pid=argeo.suite.ui.recentItems
diff --git a/core/org.argeo.suite.ui/pom.xml b/core/org.argeo.suite.ui/pom.xml
new file mode 100644 (file)
index 0000000..82656e2
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.suite</groupId>
+               <artifactId>core</artifactId>
+               <version>2.1.18-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.suite.ui</artifactId>
+       <name>Suite UI</name>
+       <packaging>jar</packaging>
+       <dependencies>
+               <dependency>
+                       <groupId>org.argeo.suite</groupId>
+                       <artifactId>org.argeo.suite.core</artifactId>
+                       <version>2.1.18-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.argeo.suite</groupId>
+                       <artifactId>org.argeo.entity.ui</artifactId>
+                       <version>2.1.18-SNAPSHOT</version>
+               </dependency>
+
+               <!-- Argeo Commons -->
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.eclipse.ui</artifactId>
+                       <version>${version.argeo-commons}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.eclipse.ui.rap</artifactId>
+                       <version>${version.argeo-commons}</version>
+                       <scope>provided</scope>
+               </dependency>
+
+               <!-- Eclipse E4 -->
+               <dependency>
+                       <groupId>org.argeo.tp</groupId>
+                       <artifactId>argeo-tp-rap-e4</artifactId>
+                       <version>${version.argeo-tp}</version>
+                       <type>pom</type>
+                       <scope>provided</scope>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/AdminEntryArea.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/AdminEntryArea.java
new file mode 100644 (file)
index 0000000..8c75f22
--- /dev/null
@@ -0,0 +1,182 @@
+package org.argeo.suite.ui;
+
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.dialogs.CmsWizardDialog;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.naming.LdapAttrs;
+import org.argeo.suite.SuiteRole;
+import org.argeo.suite.ui.dialogs.NewUserWizard;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.Wizard;
+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.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.osgi.service.useradmin.User;
+
+/** Entry to the admin area. */
+public class AdminEntryArea implements CmsUiProvider {
+
+       private CmsUserManager cmsUserManager;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsTheme theme = CmsTheme.getCmsTheme(parent);
+               parent.setLayout(new GridLayout());
+               TableViewer usersViewer = new TableViewer(parent);
+               usersViewer.setContentProvider(new UsersContentProvider());
+
+               TableViewerColumn idCol = new TableViewerColumn(usersViewer, SWT.NONE);
+               idCol.getColumn().setWidth(70);
+               idCol.setLabelProvider(new ColumnLabelProvider() {
+
+                       @Override
+                       public String getText(Object element) {
+
+                               return getUserProperty(element, LdapAttrs.uid.name());
+                       }
+               });
+
+               TableViewerColumn givenNameCol = new TableViewerColumn(usersViewer, SWT.NONE);
+               givenNameCol.getColumn().setWidth(150);
+               givenNameCol.setLabelProvider(new ColumnLabelProvider() {
+
+                       @Override
+                       public String getText(Object element) {
+
+                               return getUserProperty(element, LdapAttrs.givenName.name());
+                       }
+               });
+
+               TableViewerColumn snCol = new TableViewerColumn(usersViewer, SWT.NONE);
+               snCol.getColumn().setWidth(150);
+               snCol.setLabelProvider(new ColumnLabelProvider() {
+
+                       @Override
+                       public String getText(Object element) {
+
+                               return getUserProperty(element, LdapAttrs.sn.name());
+                       }
+               });
+
+               TableViewerColumn mailCol = new TableViewerColumn(usersViewer, SWT.NONE);
+               mailCol.getColumn().setWidth(400);
+               mailCol.setLabelProvider(new ColumnLabelProvider() {
+
+                       @Override
+                       public String getText(Object element) {
+
+                               return getUserProperty(element, LdapAttrs.mail.name());
+                       }
+               });
+
+               Composite bottom = new Composite(parent, SWT.NONE);
+               bottom.setLayoutData(CmsUiUtils.fillWidth());
+               bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
+               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
+               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               deleteItem.setEnabled(false);
+//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
+               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
+               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+               usersViewer.addDoubleClickListener(new IDoubleClickListener() {
+
+                       @Override
+                       public void doubleClick(DoubleClickEvent event) {
+                               User user = (User) usersViewer.getStructuredSelection().getFirstElement();
+                               if (user != null) {
+//                                     Node userNode = getOrCreateUserNode(user, context);
+                                       CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
+                                                       SuiteEvent.eventProperties(user));
+                               }
+
+                       }
+               });
+               usersViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               User user = (User) usersViewer.getStructuredSelection().getFirstElement();
+                               if (user != null) {
+//                                     Node userNode = getOrCreateUserNode(user, context);
+                                       CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
+                                                       SuiteEvent.eventProperties(user));
+                                       deleteItem.setEnabled(true);
+                               } else {
+                                       deleteItem.setEnabled(false);
+                               }
+                       }
+               });
+
+               addItem.addSelectionListener((Selected) (e) -> {
+                       // SuiteUtils.getOrCreateUserNode(adminSession, userDn);
+                       Wizard wizard = new NewUserWizard(null);
+                       CmsWizardDialog dialog = new CmsWizardDialog(parent.getShell(), wizard);
+                       // WizardDialog dialog = new WizardDialog(shell, wizard);
+                       if (dialog.open() == Window.OK) {
+                               // TODO create
+                       }
+               });
+
+               usersViewer.getTable().setLayoutData(CmsUiUtils.fillAll());
+               usersViewer.setInput(cmsUserManager);
+
+               return usersViewer.getTable();
+       }
+
+//     private Node getOrCreateUserNode(User user, Node context) {
+//             return JcrUtils.mkdirs(Jcr.getSession(context),
+//                             "/" + EntityType.user.name() + "/" + getUserProperty(user, LdapAttrs.uid.name()),
+//                             EntityType.user.get());
+//     }
+
+       private String getUserProperty(Object element, String key) {
+               Object value = ((User) element).getProperties().get(key);
+               return value != null ? value.toString() : null;
+       }
+
+       class UsersContentProvider implements IStructuredContentProvider {
+
+               @Override
+               public Object[] getElements(Object inputElement) {
+                       CmsUserManager cum = (CmsUserManager) inputElement;
+                       Set<User> users = cum.listUsersInGroup(SuiteRole.coworker.dn(), null);
+                       return users.toArray();
+               }
+
+               @Override
+               public void dispose() {
+               }
+
+               @Override
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+               }
+
+       }
+
+       public void setCmsUserManager(CmsUserManager cmsUserManager) {
+               this.cmsUserManager = cmsUserManager;
+       }
+
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultDashboard.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultDashboard.java
new file mode 100644 (file)
index 0000000..9835b67
--- /dev/null
@@ -0,0 +1,31 @@
+package org.argeo.suite.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Provides a dashboard. */
+public class DefaultDashboard implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               parent.setLayout(new GridLayout());
+               CmsView cmsView = CmsView.getCmsView(parent);
+               if (cmsView.isAnonymous())
+                       throw new IllegalStateException("No user is not logged in");
+
+               Label lbl = new Label(parent, SWT.NONE);
+               lbl.setText("Welcome " + CurrentUser.getDisplayName() + "!");
+
+               return lbl;
+       }
+
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java
new file mode 100644 (file)
index 0000000..7b8bb3e
--- /dev/null
@@ -0,0 +1,144 @@
+package org.argeo.suite.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.widgets.TabbedArea;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** An app layer based on an entry area and an editor area. */
+public class DefaultEditionLayer implements SuiteLayer {
+       private CmsUiProvider entryArea;
+       private CmsUiProvider workArea;
+       private List<String> weights = new ArrayList<>();
+       private boolean startMaximized = false;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               if (entryArea != null) {
+                       SashFormEditionArea sashFormEditionArea = new SashFormEditionArea(parent, parent.getStyle());
+                       entryArea.createUi(sashFormEditionArea.getEntryArea(), context);
+                       if (this.workArea != null) {
+                               this.workArea.createUi(sashFormEditionArea.getEditorArea(), context);
+                       }
+                       return sashFormEditionArea;
+               } else {
+                       if (this.workArea != null) {
+                               Composite area = new Composite(parent, SWT.NONE);
+                               this.workArea.createUi(area, context);
+                               return area;
+                       }
+                       CmsTheme theme = CmsTheme.getCmsTheme(parent);
+                       TabbedArea tabbedArea = createTabbedArea(parent, theme);
+                       return tabbedArea;
+               }
+       }
+
+       @Override
+       public void view(CmsUiProvider uiProvider, Composite workArea, Node context) {
+               TabbedArea tabbedArea;
+               if (workArea instanceof SashFormEditionArea) {
+                       tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
+               } else if (workArea instanceof TabbedArea) {
+                       tabbedArea = (TabbedArea) workArea;
+               } else
+                       throw new IllegalArgumentException("Unsupported work area " + workArea.getClass().getName());
+               tabbedArea.view(uiProvider, context);
+       }
+
+       @Override
+       public void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
+               TabbedArea tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
+               tabbedArea.open(uiProvider, context);
+       }
+
+       public void init(Map<String, Object> properties) {
+               weights = LangUtils.toStringList(properties.get(Property.weights.name()));
+               startMaximized = properties.containsKey(Property.startMaximized.name())
+                               && "true".equals(properties.get(Property.startMaximized.name()));
+       }
+
+       public void setEntryArea(CmsUiProvider entryArea) {
+               this.entryArea = entryArea;
+       }
+
+       public void setWorkArea(CmsUiProvider workArea) {
+               this.workArea = workArea;
+       }
+
+       TabbedArea createTabbedArea(Composite parent, CmsTheme theme) {
+               TabbedArea tabbedArea = new TabbedArea(parent, SWT.NONE);
+               tabbedArea.setBodyStyle(SuiteStyle.mainTabBody.style());
+               tabbedArea.setTabStyle(SuiteStyle.mainTab.style());
+               tabbedArea.setTabSelectedStyle(SuiteStyle.mainTabSelected.style());
+               tabbedArea.setCloseIcon(SuiteIcon.close.getSmallIcon(theme));
+               tabbedArea.setLayoutData(CmsUiUtils.fillAll());
+               return tabbedArea;
+       }
+
+       /** A work area based on an entry area and and a tabbed area. */
+       class SashFormEditionArea extends SashForm {
+               private static final long serialVersionUID = 2219125778722702618L;
+               private CmsTheme theme;
+               private Composite entryArea;
+               private Composite editorArea;
+               private TabbedArea tabbedArea;
+
+               SashFormEditionArea(Composite parent, int style) {
+                       super(parent, SWT.HORIZONTAL);
+                       theme = CmsTheme.getCmsTheme(parent);
+
+                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
+                               editorArea = new Composite(this, SWT.BORDER);
+                               entryArea = new Composite(this, SWT.BORDER);
+                       } else {
+                               entryArea = new Composite(this, SWT.NONE);
+                               editorArea = new Composite(this, SWT.NONE);
+                       }
+
+                       if (weights.size() != 0) {
+                               int[] actualWeight = new int[weights.size()];
+                               for (int i = 0; i < weights.size(); i++) {
+                                       actualWeight[i] = Integer.parseInt(weights.get(i));
+                               }
+                               setWeights(actualWeight);
+                       } else {
+                               int[] actualWeights = new int[] { 3000, 7000 };
+                               setWeights(actualWeights);
+                       }
+                       if (startMaximized)
+                               setMaximizedControl(editorArea);
+                       editorArea.setLayout(new GridLayout());
+
+                       if (DefaultEditionLayer.this.workArea == null) {
+                               tabbedArea = createTabbedArea(editorArea, theme);
+                       }
+
+               }
+
+               Composite getEntryArea() {
+                       return entryArea;
+               }
+
+               TabbedArea getTabbedArea() {
+                       return tabbedArea;
+               }
+
+               Composite getEditorArea() {
+                       return editorArea;
+               }
+
+       }
+}
\ No newline at end of file
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java
new file mode 100644 (file)
index 0000000..a251e14
--- /dev/null
@@ -0,0 +1,97 @@
+package org.argeo.suite.ui;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+public class DefaultHeader implements CmsUiProvider, ManagedService {
+       public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title";
+       private Map<String, String> properties;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsView cmsView = CmsView.getCmsView(parent);
+               CmsTheme theme = CmsTheme.getCmsTheme(parent);
+
+               parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, true)));
+
+               // TODO right to left
+               Composite lead = new Composite(parent, SWT.NONE);
+               CmsUiUtils.style(lead, SuiteStyle.header);
+               lead.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false));
+               lead.setLayout(new GridLayout());
+               Label lbl = new Label(lead, SWT.NONE);
+               String title = properties.get(TITLE_PROPERTY);
+               lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString()
+                               : title);
+               CmsUiUtils.style(lbl, SuiteStyle.headerTitle);
+               lbl.setLayoutData(CmsUiUtils.fillWidth());
+
+               Composite middle = new Composite(parent, SWT.NONE);
+               CmsUiUtils.style(middle, SuiteStyle.header);
+               middle.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
+               middle.setLayout(new GridLayout());
+
+               Composite end = new Composite(parent, SWT.NONE);
+               CmsUiUtils.style(end, SuiteStyle.header);
+               end.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, false));
+
+               if (!cmsView.isAnonymous()) {
+                       end.setLayout(new GridLayout(2, false));
+                       Label userL = new Label(end, SWT.NONE);
+                       CmsUiUtils.style(userL, SuiteStyle.header);
+                       userL.setText(CurrentUser.getDisplayName());
+                       Button logoutB = new Button(end, SWT.FLAT);
+//                     CmsUiUtils.style(logoutB, SuiteStyle.header);
+                       logoutB.setImage(SuiteIcon.logout.getSmallIcon(theme));
+                       logoutB.addSelectionListener(new SelectionAdapter() {
+                               private static final long serialVersionUID = 7116760083964201233L;
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       cmsView.logout();
+                               }
+
+                       });
+               } else {
+                       end.setLayout(new GridLayout(1, false));
+                       // required in order to avoid wrong height after logout
+                       new Label(end, SWT.NONE).setText("");
+
+               }
+               return lbl;
+       }
+
+       public void init(Map<String, String> properties) {
+               this.properties = new TreeMap<>(properties);
+       }
+
+       @Override
+       public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+               if (properties != null)
+                       this.properties.putAll(LangUtils.dictToStringMap(properties));
+       }
+
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java
new file mode 100644 (file)
index 0000000..a207e7a
--- /dev/null
@@ -0,0 +1,130 @@
+package org.argeo.suite.ui;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.Localized;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.suite.RankedObject;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.Constants;
+
+/** Side pane listing various perspectives. */
+public class DefaultLeadPane implements CmsUiProvider {
+       private final static Log log = LogFactory.getLog(DefaultLeadPane.class);
+
+       public static enum Property {
+               defaultLayers, adminLayers;
+       }
+
+       private Map<String, RankedObject<SuiteLayer>> layers = Collections.synchronizedSortedMap(new TreeMap<>());
+       private String[] defaultLayers;
+       private String[] adminLayers;
+
+       @Override
+       public Control createUi(Composite parent, Node node) throws RepositoryException {
+               CmsView cmsView = CmsView.getCmsView(parent);
+               GridLayout layout = new GridLayout();
+               layout.verticalSpacing = 10;
+               layout.marginTop = 10;
+               layout.marginLeft = 10;
+               layout.marginRight = 10;
+               parent.setLayout(layout);
+
+               Button first = null;
+               for (String layerId : defaultLayers) {
+                       if (layers.containsKey(layerId)) {
+                               RankedObject<SuiteLayer> layerObj = layers.get(layerId);
+
+                               // TODO deal with i10n
+                               String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
+                               Localized title = null;
+                               if (titleStr != null)
+                                       title = new Localized.Untranslated(titleStr);
+
+                               String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
+                               SuiteIcon icon = null;
+                               if (iconName != null)
+                                       icon = SuiteIcon.valueOf(iconName);
+
+                               Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon);
+                               if (first == null)
+                                       first = b;
+                       }
+               }
+
+               // TODO factorise
+               boolean isAdmin = cmsView.doAs(() -> CurrentUser.isInRole(NodeConstants.ROLE_USER_ADMIN));
+               if (isAdmin && adminLayers != null)
+                       for (String layerId : adminLayers) {
+                               if (layers.containsKey(layerId)) {
+                                       RankedObject<SuiteLayer> layerObj = layers.get(layerId);
+
+                                       // TODO deal with i10n
+                                       String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
+                                       Localized title = null;
+                                       if (titleStr != null)
+                                               title = new Localized.Untranslated(titleStr);
+
+                                       String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
+                                       SuiteIcon icon = null;
+                                       if (iconName != null)
+                                               icon = SuiteIcon.valueOf(iconName);
+
+                                       Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon);
+                                       if (first == null)
+                                               first = b;
+                               }
+                       }
+
+//             Button dashboardB = createButton(parent, SuiteMsg.dashboard.name(), SuiteMsg.dashboard, SuiteIcon.dashboard);
+               if (!cmsView.isAnonymous()) {
+//                     createButton(parent, SuiteMsg.documents.name(), SuiteMsg.documents, SuiteIcon.documents);
+//                     createButton(parent, SuiteMsg.people.name(), SuiteMsg.people, SuiteIcon.people);
+//                     createButton(parent, SuiteMsg.locations.name(), SuiteMsg.locations, SuiteIcon.location);
+               }
+               return first;
+       }
+
+       public void init(Map<String, Object> properties) {
+               defaultLayers = (String[]) properties.get(Property.defaultLayers.toString());
+               if (defaultLayers == null)
+                       throw new IllegalArgumentException("Default layers must be set.");
+               if (log.isDebugEnabled())
+                       log.debug("Default layers: " + Arrays.asList(defaultLayers));
+               adminLayers = (String[]) properties.get(Property.adminLayers.toString());
+               if (log.isDebugEnabled() && adminLayers != null)
+                       log.debug("Admin layers: " + Arrays.asList(adminLayers));
+       }
+
+       public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
+               if (properties.containsKey(Constants.SERVICE_PID)) {
+                       String pid = (String) properties.get(Constants.SERVICE_PID);
+                       RankedObject.putIfHigherRank(layers, pid, layer, properties);
+               }
+       }
+
+       public void removeLayer(SuiteLayer layer, Map<String, Object> properties) {
+               if (properties.containsKey(Constants.SERVICE_PID)) {
+                       String pid = (String) properties.get(Constants.SERVICE_PID);
+                       if (layers.containsKey(pid)) {
+                               if (layers.get(pid).equals(new RankedObject<SuiteLayer>(layer, properties))) {
+                                       layers.remove(pid);
+                               }
+                       }
+               }
+       }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java
new file mode 100644 (file)
index 0000000..3757a19
--- /dev/null
@@ -0,0 +1,34 @@
+package org.argeo.suite.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.widgets.auth.CmsLogin;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Provides a login screen. */
+public class DefaultLoginScreen implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsView cmsView = CmsView.getCmsView(parent);
+               if (!cmsView.isAnonymous())
+                       throw new IllegalStateException(CurrentUser.getUsername() + " is already logged in");
+
+               parent.setLayout(new GridLayout());
+               Composite loginArea = new Composite(parent, SWT.NONE);
+               loginArea.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+               
+               CmsLogin cmsLogin = new CmsLogin(cmsView);
+               cmsLogin.createUi(loginArea);
+               return cmsLogin.getCredentialsBlock();
+       }
+
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java
new file mode 100644 (file)
index 0000000..b9aa5b7
--- /dev/null
@@ -0,0 +1,366 @@
+package org.argeo.suite.ui;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.suite.ui.widgets.DelayedText;
+import org.argeo.suite.util.XPathUtils;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** List recent items. */
+public class RecentItems implements CmsUiProvider {
+       private final static int SEARCH_TEXT_DELAY = 800;
+       private final static int SEARCH_DEFAULT_LIMIT = 100;
+
+       private CmsTheme theme;
+
+       private String entityType;
+
+       static enum Property {
+               entityTypes;
+       }
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               theme = CmsTheme.getCmsTheme(parent);
+               parent.setLayout(new GridLayout());
+//             parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+               parent.setLayout(new GridLayout());
+
+//             Composite top = new Composite(parent, SWT.BORDER);
+//             CmsUiUtils.style(top, SuiteStyle.recentItems);
+//             top.setLayoutData(CmsUiUtils.fillWidth());
+//             top.setLayout(CmsUiUtils.noSpaceGridLayout(2));
+//             Label lbl = new Label(top, SWT.FLAT);
+//             lbl.setLayoutData(CmsUiUtils.fillWidth());
+//             lbl.setText(SuiteMsg.recentItems.lead());
+//             CmsUiUtils.style(lbl, SuiteStyle.recentItems);
+//
+//             ToolBar topToolBar = new ToolBar(top, SWT.NONE);
+//             ToolItem addItem = new ToolItem(topToolBar, SWT.FLAT);
+////           CmsUiUtils.style(addItem, SuiteStyle.recentItems);
+//             addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+
+               if (context == null)
+                       return null;
+               SingleEntityViewer entityViewer = new SingleEntityViewer(parent, SWT.NONE, context.getSession());
+               entityViewer.createUi();
+               entityViewer.getViewer().getTable().setLayoutData(CmsUiUtils.fillAll());
+
+               Composite bottom = new Composite(parent, SWT.NONE);
+               bottom.setLayoutData(CmsUiUtils.fillWidth());
+               bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
+               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
+               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               deleteItem.setEnabled(false);
+//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
+               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
+               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+               entityViewer.getViewer().addDoubleClickListener(new IDoubleClickListener() {
+
+                       @Override
+                       public void doubleClick(DoubleClickEvent event) {
+                               Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
+                               if (node != null)
+                                       CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
+                                                       SuiteEvent.eventProperties(node));
+
+                       }
+               });
+               entityViewer.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
+                               if (node != null) {
+                                       CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
+                                                       SuiteEvent.eventProperties(node));
+                                       deleteItem.setEnabled(true);
+                               } else {
+                                       deleteItem.setEnabled(false);
+                               }
+                       }
+               });
+
+               return entityViewer.filterTxt;
+
+       }
+
+       public void init(Map<String, String> properties) {
+               // TODO manage multiple entities
+               entityType = properties.get(Property.entityTypes.name());
+       }
+
+       class SingleEntityViewer {
+               Composite parent;
+               Text filterTxt;
+               TableViewer viewer;
+               Session session;
+
+               public SingleEntityViewer(Composite parent, int style, Session session) {
+                       this.parent = parent;
+                       this.session = session;
+               }
+
+               public void createUi() {
+                       // MainLayout
+                       addFilterPanel(parent);
+                       viewer = createListPart(parent, new SingleEntityLabelProvider());
+                       refreshFilteredList();
+
+                       try {
+                               String[] nodeTypes = entityType != null && entityType.contains(":") ? new String[] { entityType }
+                                               : null;
+                               session.getWorkspace().getObservationManager().addEventListener(new EventListener() {
+
+                                       @Override
+                                       public void onEvent(EventIterator events) {
+                                               parent.getDisplay().asyncExec(() -> refreshFilteredList());
+                                       }
+                               }, Event.PROPERTY_CHANGED | Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED, "/", true,
+                                               null, nodeTypes, false);
+                       } catch (RepositoryException e) {
+                               throw new IllegalStateException("Cannot add JCR observer", e);
+                       }
+
+               }
+
+               private void addFilterPanel(Composite parent) {
+                       // Use a delayed text: the query won't be done until the user stop
+                       // typing for 800ms
+                       int style = SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL;
+                       DelayedText delayedText = new DelayedText(parent, style, SEARCH_TEXT_DELAY);
+                       filterTxt = delayedText.getText();
+                       filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
+
+                       // final ServerPushSession pushSession = new ServerPushSession();
+                       delayedText.addDelayedModifyListener(null, new ModifyListener() {
+                               private static final long serialVersionUID = 5003010530960334977L;
+
+                               public void modifyText(ModifyEvent event) {
+                                       delayedText.getText().getDisplay().asyncExec(new Runnable() {
+                                               @Override
+                                               public void run() {
+                                                       refreshFilteredList();
+                                               }
+                                       });
+                                       // pushSession.stop();
+                               }
+                       });
+
+                       // Jump to the first item of the list using the down arrow
+                       filterTxt.addKeyListener(new KeyListener() {
+                               private static final long serialVersionUID = -4523394262771183968L;
+
+                               @Override
+                               public void keyReleased(KeyEvent e) {
+                               }
+
+                               @Override
+                               public void keyPressed(KeyEvent e) {
+                                       // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
+                                       // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
+                                       if (e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.TAB) {
+//                                     Object first = entityViewer.getElementAt(0);
+//                                     if (first != null) {
+//                                             entityViewer.getTable().setFocus();
+//                                             entityViewer.setSelection(new StructuredSelection(first), true);
+//                                     }
+                                               e.doit = false;
+                                       }
+                               }
+                       });
+
+                       parent.addDisposeListener((e) -> {
+                               delayedText.close();
+                       });
+               }
+
+               protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) {
+//                     parent.setLayout(new GridLayout());
+//                     parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+                       Composite tableComposite = new Composite(parent, SWT.NONE);
+                       GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL
+                                       | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
+                       tableComposite.setLayoutData(gd);
+
+                       TableViewer viewer = new TableViewer(tableComposite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+                       viewer.setLabelProvider(labelProvider);
+
+                       TableColumn singleColumn = new TableColumn(viewer.getTable(), SWT.V_SCROLL);
+                       TableColumnLayout tableColumnLayout = new TableColumnLayout();
+                       tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(85));
+                       tableComposite.setLayout(tableColumnLayout);
+
+                       // Corresponding table & style
+                       Table table = viewer.getTable();
+//                     Listener[] mouseDownListeners = table.getListeners(SWT.MouseDown);
+//                     for (Listener listener :  table.getListeners(SWT.MouseDown))
+//                             table.removeListener(SWT.MouseDown, listener);
+//                     for (Listener listener :  table.getListeners(SWT.MouseUp))
+//                             table.removeListener(SWT.MouseUp, listener);
+//                     for (Listener listener :  table.getListeners(SWT.MouseDoubleClick))
+//                             table.removeListener(SWT.MouseDoubleClick, listener);
+//                     
+//                     table.addMouseListener(new MouseListener() {
+//
+//                             @Override
+//                             public void mouseUp(MouseEvent e) {
+//                                     System.out.println("Mouse up: "+e);
+//                             }
+//
+//                             @Override
+//                             public void mouseDown(MouseEvent e) {
+//                                     System.out.println("Mouse down: "+e);
+//                             }
+//
+//                             @Override
+//                             public void mouseDoubleClick(MouseEvent e) {
+//                                     System.out.println("Mouse double: "+e);
+//
+//                             }
+//                     });
+                       table.setLinesVisible(true);
+                       table.setHeaderVisible(false);
+                       // CmsUiUtils.markup(table);
+                       // CmsUiUtils.setItemHeight(table, 26);
+
+                       viewer.setContentProvider(new BasicNodeListContentProvider());
+                       return viewer;
+               }
+
+//             public boolean setFocus() {
+//                     refreshFilteredList();
+//                     return parent.setFocus();
+//             }
+
+               public void forceRefresh(Object object) {
+                       refreshFilteredList();
+               }
+
+               protected void refreshFilteredList() {
+                       try {
+                               String filter = filterTxt.getText();
+                               // Prevents the query on the full repository
+                               // if (isEmpty(filter)) {
+                               // entityViewer.setInput(null);
+                               // return;
+                               // }
+
+                               // XPATH Query
+                               String xpathQueryStr;
+                               if (entityType != null) {
+                                       int indexColumn = entityType.indexOf(':');
+                                       if (indexColumn > 0) {// JCR node type
+                                               xpathQueryStr = "//element(*, " + entityType + ") order by @jcr:created descending";
+                                       } else {
+                                               xpathQueryStr = entityType.contains(":") ? "//element(*, " + entityType + ")"
+                                                               : "//element(*, " + EntityType.entity.get() + ")[@entity:type='" + entityType + "']";
+                                       }
+                               } else {
+                                       xpathQueryStr = "//element(*, " + EntityType.entity.get() + ")";
+                               }
+//                     String xpathQueryStr = "//element(*, " + ConnectTypes.CONNECT_ENTITY + ")";
+                               String xpathFilter = XPathUtils.getFreeTextConstraint(filter);
+                               if (notEmpty(xpathFilter))
+                                       xpathQueryStr += "[" + xpathFilter + "]";
+
+//                             long begin = System.currentTimeMillis();
+                               // session.refresh(false);
+                               Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
+
+                               xpathQuery.setLimit(SEARCH_DEFAULT_LIMIT);
+                               QueryResult result = xpathQuery.execute();
+
+                               NodeIterator nit = result.getNodes();
+                               viewer.setInput(JcrUtils.nodeIteratorToList(nit));
+//                             if (log.isTraceEnabled()) {
+//                                     long end = System.currentTimeMillis();
+//                                     log.trace("Quick Search - Found: " + nit.getSize() + " in " + (end - begin)
+//                                                     + " ms by executing XPath query (" + xpathQueryStr + ").");
+//                             }
+                       } catch (RepositoryException e) {
+                               throw new IllegalStateException("Unable to list entities", e);
+                       }
+               }
+
+               public TableViewer getViewer() {
+                       return viewer;
+               }
+
+               class SingleEntityLabelProvider extends ColumnLabelProvider {
+                       private static final long serialVersionUID = -2209337675781795677L;
+
+                       @Override
+                       public String getText(Object element) {
+                               return Jcr.getTitle((Node) element);
+                       }
+
+               }
+
+               class BasicNodeListContentProvider implements IStructuredContentProvider {
+                       private static final long serialVersionUID = 1L;
+                       // keep a cache of the Nodes in the content provider to be able to
+                       // manage long request
+                       private List<Node> nodes;
+
+                       public void dispose() {
+                       }
+
+                       /** Expects a list of nodes as a new input */
+                       @SuppressWarnings("unchecked")
+                       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+                               nodes = (List<Node>) newInput;
+                       }
+
+                       public Object[] getElements(Object arg0) {
+                               return nodes.toArray();
+                       }
+               }
+       }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java
new file mode 100644 (file)
index 0000000..dbed853
--- /dev/null
@@ -0,0 +1,517 @@
+package org.argeo.suite.ui;
+
+import static org.argeo.cms.ui.CmsView.CMS_VIEW_UID_PROPERTY;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeUtils;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.auth.CmsSession;
+import org.argeo.cms.ui.AbstractCmsApp;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.dialogs.CmsFeedback;
+import org.argeo.cms.ui.util.CmsEvent;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.argeo.entity.EntityConstants;
+import org.argeo.entity.EntityNames;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.Jcr;
+import org.argeo.suite.RankedObject;
+import org.argeo.suite.SuiteUtils;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.Constants;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+import org.osgi.service.useradmin.User;
+
+/** The Argeo Suite App. */
+public class SuiteApp extends AbstractCmsApp implements EventHandler {
+       private final static Log log = LogFactory.getLog(SuiteApp.class);
+
+       public final static String PUBLIC_BASE_PATH_PROPERTY = "publicBasePath";
+       public final static String DEFAULT_UI_NAME_PROPERTY = "defaultUiName";
+       public final static String DEFAULT_THEME_ID_PROPERTY = "defaultThemeId";
+
+       private String publicBasePath = null;
+
+       private String pidPrefix;
+       private String headerPid;
+       private String leadPanePid;
+       private String loginScreenPid;
+//     private String DASHBOARD_PID = pidPrefix + "dashboard";
+//     private String RECENT_ITEMS_PID = pidPrefix + "recentItems";
+
+       private String defaultUiName = "app";
+       private String defaultThemeId = "org.argeo.suite.theme.default";
+
+       private Map<String, RankedObject<CmsUiProvider>> uiProvidersByPid = Collections.synchronizedMap(new HashMap<>());
+       private Map<String, RankedObject<CmsUiProvider>> uiProvidersByType = Collections.synchronizedMap(new HashMap<>());
+       private Map<String, RankedObject<SuiteLayer>> layersByPid = Collections.synchronizedSortedMap(new TreeMap<>());
+       private Map<String, RankedObject<SuiteLayer>> layersByType = Collections.synchronizedSortedMap(new TreeMap<>());
+
+       private CmsUserManager cmsUserManager;
+
+       // TODO make more optimal or via CmsSession/CmsView
+       private Map<String, SuiteUi> managedUis = new HashMap<>();
+
+//     private CmsUiProvider headerPart = null;
+
+       public void init(Map<String, Object> properties) {
+               if (log.isDebugEnabled())
+                       log.info("Argeo Suite App started");
+
+               if (properties.containsKey(DEFAULT_UI_NAME_PROPERTY))
+                       defaultUiName = LangUtils.get(properties, DEFAULT_UI_NAME_PROPERTY);
+               if (properties.containsKey(DEFAULT_THEME_ID_PROPERTY))
+                       defaultThemeId = LangUtils.get(properties, DEFAULT_THEME_ID_PROPERTY);
+               publicBasePath = LangUtils.get(properties, PUBLIC_BASE_PATH_PROPERTY);
+
+               if (properties.containsKey(Constants.SERVICE_PID)) {
+                       String servicePid = properties.get(Constants.SERVICE_PID).toString();
+                       if (servicePid.endsWith(".app")) {
+                               pidPrefix = servicePid.substring(0, servicePid.length() - "app".length());
+                       }
+               }
+
+               if (pidPrefix == null)
+                       throw new IllegalArgumentException("PID prefix must be set.");
+
+               headerPid = pidPrefix + "header";
+               leadPanePid = pidPrefix + "leadPane";
+               loginScreenPid = pidPrefix + "loginScreen";
+       }
+
+       public void destroy(Map<String, Object> properties) {
+               for (SuiteUi ui : managedUis.values())
+                       if (!ui.isDisposed())
+                               ui.dispose();
+               if (log.isDebugEnabled())
+                       log.info("Argeo Suite App stopped");
+
+       }
+
+       @Override
+       public Set<String> getUiNames() {
+               HashSet<String> uiNames = new HashSet<>();
+               uiNames.add(defaultUiName);
+               return uiNames;
+       }
+
+       @Override
+       public Composite initUi(Composite parent) {
+               String uiName = parent.getData(UI_NAME_PROPERTY) != null ? parent.getData(UI_NAME_PROPERTY).toString() : null;
+               CmsView cmsView = CmsView.getCmsView(parent);
+               if (cmsView == null)
+                       throw new IllegalStateException("No CMS view is registered.");
+               CmsTheme theme = getTheme(uiName);
+               if (theme != null)
+                       CmsTheme.registerCmsTheme(parent.getShell(), theme);
+               SuiteUi argeoSuiteUi = new SuiteUi(parent, SWT.INHERIT_DEFAULT);
+               String uid = cmsView.getUid();
+               managedUis.put(uid, argeoSuiteUi);
+               argeoSuiteUi.addDisposeListener((e) -> {
+                       managedUis.remove(uid);
+                       if (log.isDebugEnabled())
+                               log.debug("Suite UI " + uid + " has been disposed.");
+               });
+               refreshUi(argeoSuiteUi, null);
+               return argeoSuiteUi;
+       }
+
+       @Override
+       public String getThemeId(String uiName) {
+               return defaultThemeId;
+       }
+
+       @Override
+       public void refreshUi(Composite parent, String state) {
+               try {
+                       Node context = null;
+                       SuiteUi ui = (SuiteUi) parent;
+                       CmsView cmsView = CmsView.getCmsView(parent);
+                       if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login
+                               ui.logout();
+                               refreshPart(findUiProvider(headerPid), ui.getHeader(), context);
+                               ui.refreshBelowHeader(false);
+                               refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context);
+                               ui.layout(true, true);
+                       } else {
+                               CmsSession cmsSession = cmsView.getCmsSession();
+                               if (ui.getUserDir() == null) {
+                                       if (cmsView.isAnonymous()) {
+                                               assert publicBasePath != null;
+                                               ui.initSessions(getRepository(), publicBasePath);
+                                       } else {
+                                               Session adminSession = null;
+                                               try {
+                                                       adminSession = NodeUtils.openDataAdminSession(getRepository(), null);
+                                                       Node userDir = SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
+                                                       ui.initSessions(getRepository(), userDir.getPath());
+                                               } finally {
+                                                       Jcr.logout(adminSession);
+                                               }
+                                       }
+                               }
+                               initLocale(cmsSession);
+                               context = stateToNode(ui, state);
+                               if (context == null)
+                                       context = ui.getUserDir();
+
+                               refreshPart(findUiProvider(headerPid), ui.getHeader(), context);
+                               ui.refreshBelowHeader(true);
+                               for (String key : layersByPid.keySet()) {
+                                       SuiteLayer layer = layersByPid.get(key).get();
+                                       ui.addLayer(key, layer);
+                               }
+                               refreshPart(findUiProvider(leadPanePid), ui.getLeadPane(), context);
+                               ui.layout(true, true);
+                               setState(parent, state);
+                       }
+               } catch (Exception e) {
+                       CmsFeedback.show("Unexpected exception", e);
+               }
+       }
+
+       private void initLocale(CmsSession cmsSession) {
+               if (cmsSession == null)
+                       return;
+               Locale locale = cmsSession.getLocale();
+               UiContext.setLocale(locale);
+               LocaleUtils.setThreadLocale(locale);
+
+       }
+
+       private void refreshPart(CmsUiProvider uiProvider, Composite part, Node context) {
+               CmsUiUtils.clear(part);
+               uiProvider.createUiPart(part, context);
+       }
+
+       private CmsUiProvider findUiProvider(String pid) {
+               if (!uiProvidersByPid.containsKey(pid))
+                       throw new IllegalArgumentException("No UI provider registered as " + pid);
+               return uiProvidersByPid.get(pid).get();
+       }
+
+       private <T> T findByType(Map<String, RankedObject<T>> byType, Node context) {
+               if (context == null)
+                       throw new IllegalArgumentException("A node should be provided");
+               try {
+                       // mixins
+                       Set<String> types = new TreeSet<>();
+                       for (NodeType nodeType : context.getMixinNodeTypes()) {
+                               String typeName = nodeType.getName();
+                               if (byType.containsKey(typeName)) {
+                                       types.add(typeName);
+                               }
+                       }
+                       // primary node type
+                       {
+                               NodeType nodeType = context.getPrimaryNodeType();
+                               String typeName = nodeType.getName();
+                               if (byType.containsKey(typeName)) {
+                                       types.add(typeName);
+                               }
+                               for (NodeType mixin : nodeType.getDeclaredSupertypes()) {
+                                       if (byType.containsKey(mixin.getName())) {
+                                               types.add(mixin.getName());
+                                       }
+                               }
+                       }
+                       // entity type
+                       if (context.isNodeType(EntityType.entity.get())) {
+                               if (context.hasProperty(EntityNames.ENTITY_TYPE)) {
+                                       String typeName = context.getProperty(EntityNames.ENTITY_TYPE).getString();
+                                       if (byType.containsKey(typeName)) {
+                                               types.add(typeName);
+                                       }
+                               }
+                       }
+
+//                     if (context.getPath().equals("/")) {// root node
+//                             types.add("nt:folder");
+//                     }
+                       if (NodeUtils.isUserHome(context) && byType.containsKey("nt:folder")) {// home node
+                               types.add("nt:folder");
+                       }
+
+                       if (types.size() == 0)
+                               throw new IllegalArgumentException("No type found for " + context);
+                       String type = types.iterator().next();
+                       if (!byType.containsKey(type))
+                               throw new IllegalArgumentException("No component found for " + context + " with type " + type);
+                       return byType.get(type).get();
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException(e);
+               }
+       }
+
+       @Override
+       public void setState(Composite parent, String state) {
+               if (state == null || state.equals("~"))
+                       return;
+               if (!state.startsWith("/") && !state.equals("~")) {
+                       if (parent instanceof SuiteUi) {
+                               SuiteUi ui = (SuiteUi) parent;
+                               String currentLayerId = ui.getCurrentLayerId();
+                               if (state.equals(currentLayerId))
+                                       return; // does nothing
+                               else {
+                                       Map<String, Object> properties = new HashMap<>();
+                                       properties.put(SuiteEvent.LAYER, state);
+                                       ui.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), properties);
+                               }
+                       }
+                       return;
+               }
+               SuiteUi suiteUi = (SuiteUi) parent;
+               Node node = stateToNode(suiteUi, state);
+               if (node == null) {
+                       suiteUi.getCmsView().navigateTo("~");
+               } else {
+                       suiteUi.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), SuiteEvent.eventProperties(node));
+                       suiteUi.getCmsView().sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(node));
+               }
+       }
+
+       private String nodeToState(Node node) {
+               return '/' + Jcr.getWorkspaceName(node) + Jcr.getPath(node);
+       }
+
+       private Node stateToNode(SuiteUi suiteUi, String state) {
+               if (suiteUi == null)
+                       return null;
+               if (state == null || !state.startsWith("/"))
+                       return null;
+
+               String path = state.substring(1);
+               String workspace;
+               if (path.equals("")) {
+                       workspace = null;
+                       path = "/";
+               } else {
+                       int index = path.indexOf('/');
+                       if (index == 0) {
+                               log.error("Cannot interpret " + state);
+//                             cmsView.navigateTo("~");
+                               return null;
+                       } else if (index > 0) {
+                               workspace = path.substring(0, index);
+                               path = path.substring(index);
+                       } else {// index<0, assuming root node
+                               workspace = path;
+                               path = "/";
+                       }
+               }
+               Session session = suiteUi.getSession(workspace);
+               if (session == null)
+                       return null;
+               Node node = Jcr.getNode(session, path);
+               return node;
+       }
+
+       /*
+        * Events management
+        */
+
+       @Override
+       public void handleEvent(Event event) {
+
+               // Specific UI related events
+               SuiteUi ui = getRelatedUi(event);
+               if (ui == null)
+                       return;
+               try {
+//                     String currentLayerId = ui.getCurrentLayerId();
+//                     SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null;
+                       if (isTopic(event, SuiteEvent.refreshPart)) {
+                               Node node = getNode(ui, event);
+                               if (node == null)
+                                       return;
+                               CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
+                               SuiteLayer layer = findByType(layersByType, node);
+                               ui.switchToLayer(layer, node);
+                               ui.getCmsView().runAs(() -> layer.view(uiProvider, ui.getCurrentWorkArea(), node));
+                               ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node));
+                       } else if (isTopic(event, SuiteEvent.openNewPart)) {
+                               Node node = getNode(ui, event);
+                               if (node == null)
+                                       return;
+                               CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
+                               SuiteLayer layer = findByType(layersByType, node);
+                               ui.switchToLayer(layer, node);
+                               ui.getCmsView().runAs(() -> layer.open(uiProvider, ui.getCurrentWorkArea(), node));
+                               ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node));
+                       } else if (isTopic(event, SuiteEvent.switchLayer)) {
+                               String layerId = get(event, SuiteEvent.LAYER);
+                               if (layerId != null) {
+//                                     ui.switchToLayer(layerId, ui.getUserDir());
+                                       ui.getCmsView().runAs(() -> ui.switchToLayer(layerId, ui.getUserDir()));
+                                       ui.getCmsView().navigateTo(layerId);
+                               } else {
+                                       Node node = getNode(ui, event);
+                                       if (node != null) {
+                                               SuiteLayer layer = findByType(layersByType, node);
+                                               ui.getCmsView().runAs(() -> ui.switchToLayer(layer, node));
+                                       }
+                               }
+                       }
+               } catch (Exception e) {
+                       log.error("Cannot handle event " + event, e);
+//                     CmsView.getCmsView(ui).exception(e);
+               }
+
+       }
+
+       private Node getNode(SuiteUi ui, Event event) {
+               String nodePath = get(event, SuiteEvent.NODE_PATH);
+               String workspaceName = get(event, SuiteEvent.WORKSPACE);
+               Session session = ui.getSession(workspaceName);
+               Node node;
+               if (nodePath == null) {
+                       // look for a user
+                       String username = get(event, SuiteEvent.USERNAME);
+                       if (username == null)
+                               return null;
+                       User user = cmsUserManager.getUser(username);
+                       if (user == null)
+                               return null;
+                       LdapName userDn;
+                       try {
+                               userDn = new LdapName(user.getName());
+                       } catch (InvalidNameException e) {
+                               throw new IllegalArgumentException("Badly formatted username", e);
+                       }
+                       String userNodePath = SuiteUtils.getUserNodePath(userDn);
+                       if (Jcr.itemExists(session, userNodePath))
+                               node = Jcr.getNode(session, userNodePath);
+                       else {
+                               Session adminSession = null;
+                               try {
+                                       adminSession = NodeUtils.openDataAdminSession(getRepository(), workspaceName);
+                                       SuiteUtils.getOrCreateUserNode(adminSession, userDn);
+                               } finally {
+                                       Jcr.logout(adminSession);
+                               }
+                               node = Jcr.getNode(session, userNodePath);
+                       }
+               } else {
+                       node = Jcr.getNode(session, nodePath);
+               }
+               return node;
+       }
+
+       private SuiteUi getRelatedUi(Event event) {
+               return managedUis.get(get(event, CMS_VIEW_UID_PROPERTY));
+       }
+
+       private static boolean isTopic(Event event, CmsEvent cmsEvent) {
+               return event.getTopic().equals(cmsEvent.topic());
+       }
+
+       private static String get(Event event, String key) {
+               Object value = event.getProperty(key);
+               if (value == null)
+                       return null;
+//                     throw new IllegalArgumentException("Property " + key + " must be set");
+               return value.toString();
+
+       }
+
+       /*
+        * Dependency injection.
+        */
+
+       public void addUiProvider(CmsUiProvider uiProvider, Map<String, Object> properties) {
+               if (properties.containsKey(Constants.SERVICE_PID)) {
+                       String pid = (String) properties.get(Constants.SERVICE_PID);
+                       RankedObject.putIfHigherRank(uiProvidersByPid, pid, uiProvider, properties);
+               }
+               if (properties.containsKey(EntityConstants.TYPE)) {
+                       List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
+                       for (String type : types)
+                               RankedObject.putIfHigherRank(uiProvidersByType, type, uiProvider, properties);
+               }
+       }
+
+       public void removeUiProvider(CmsUiProvider uiProvider, Map<String, Object> properties) {
+               if (properties.containsKey(Constants.SERVICE_PID)) {
+                       String pid = (String) properties.get(Constants.SERVICE_PID);
+                       if (uiProvidersByPid.containsKey(pid)) {
+                               if (uiProvidersByPid.get(pid).equals(new RankedObject<CmsUiProvider>(uiProvider, properties))) {
+                                       uiProvidersByPid.remove(pid);
+                               }
+                       }
+               }
+               if (properties.containsKey(EntityConstants.TYPE)) {
+                       List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
+                       for (String type : types) {
+                               if (uiProvidersByType.containsKey(type)) {
+                                       if (uiProvidersByType.get(type).equals(new RankedObject<CmsUiProvider>(uiProvider, properties))) {
+                                               uiProvidersByType.remove(type);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
+               if (properties.containsKey(Constants.SERVICE_PID)) {
+                       String pid = (String) properties.get(Constants.SERVICE_PID);
+                       RankedObject.putIfHigherRank(layersByPid, pid, layer, properties);
+               }
+               if (properties.containsKey(EntityConstants.TYPE)) {
+                       List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
+                       for (String type : types)
+                               RankedObject.putIfHigherRank(layersByType, type, layer, properties);
+               }
+       }
+
+       public void removeLayer(SuiteLayer layer, Map<String, Object> properties) {
+               if (properties.containsKey(Constants.SERVICE_PID)) {
+                       String pid = (String) properties.get(Constants.SERVICE_PID);
+                       if (layersByPid.containsKey(pid)) {
+                               if (layersByPid.get(pid).equals(new RankedObject<SuiteLayer>(layer, properties))) {
+                                       layersByPid.remove(pid);
+                               }
+                       }
+               }
+               if (properties.containsKey(EntityConstants.TYPE)) {
+                       List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
+                       for (String type : types) {
+                               if (layersByType.containsKey(type)) {
+                                       if (layersByType.get(type).equals(new RankedObject<CmsUiProvider>(layer, properties))) {
+                                               layersByType.remove(type);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public void setCmsUserManager(CmsUserManager cmsUserManager) {
+               this.cmsUserManager = cmsUserManager;
+       }
+
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteEvent.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteEvent.java
new file mode 100644 (file)
index 0000000..563cd21
--- /dev/null
@@ -0,0 +1,38 @@
+package org.argeo.suite.ui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.util.CmsEvent;
+import org.argeo.jcr.Jcr;
+import org.osgi.service.useradmin.User;
+
+/** Events specific to Argeo Suite. */
+public enum SuiteEvent implements CmsEvent {
+       openNewPart, refreshPart, switchLayer;
+
+       public final static String LAYER = "layer";
+//     public final static String NODE_ID = "nodeId";
+       public final static String NODE_PATH = "path";
+       public final static String USERNAME = "username";
+       public final static String WORKSPACE = "workspace";
+
+       public String getTopicBase() {
+               return "argeo/suite/ui";
+       }
+
+       public static Map<String, Object> eventProperties(Node node) {
+               Map<String, Object> properties = new HashMap<>();
+               properties.put(NODE_PATH, Jcr.getPath(node));
+               properties.put(WORKSPACE, Jcr.getWorkspaceName(node));
+               return properties;
+       }
+
+       public static Map<String, Object> eventProperties(User user) {
+               Map<String, Object> properties = new HashMap<>();
+               properties.put(USERNAME, user.getName());
+               return properties;
+       }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteIcon.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteIcon.java
new file mode 100644 (file)
index 0000000..e40ba5a
--- /dev/null
@@ -0,0 +1,16 @@
+package org.argeo.suite.ui;
+
+import org.argeo.cms.ui.util.CmsIcon;
+
+/** Icon names used by Argeo Suite. */
+public enum SuiteIcon implements CmsIcon {
+       add, save, close, search, delete, logout, dashboard,
+       // people
+       people, person, organisation,
+       // library
+       documents, document, folder,
+       // admin and settings
+       settings, user,
+       // misc
+       task, tag, location, inbox, map;
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java
new file mode 100644 (file)
index 0000000..8af7611
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.suite.ui;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.widgets.Composite;
+
+/** An UI layer for the main work area. */
+public interface SuiteLayer extends CmsUiProvider {
+       static enum Property {
+               title, icon, weights, startMaximized;
+       }
+
+       void view(CmsUiProvider uiProvider, Composite workArea, Node context);
+
+       default void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
+               view(uiProvider, workArea, context);
+       }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteMsg.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteMsg.java
new file mode 100644 (file)
index 0000000..3b376db
--- /dev/null
@@ -0,0 +1,34 @@
+package org.argeo.suite.ui;
+
+import org.argeo.cms.Localized;
+
+/** Localized messages. */
+public enum SuiteMsg implements Localized {
+       dashboard, people, documents, locations, recentItems,
+       // NewPersonWizard
+       firstName, lastName, salutation, email, personWizardWindowTitle, personWizardPageTitle,
+       // NewOrgWizard
+       orgWizardWindowTitle, orgWizardPageTitle, legalName, legalForm, vatId,
+       // ContextAddressComposite
+       chooseAnOrganisation, street, streetComplement, zipCode, city, state, country, geopoint,
+       // FilteredOrderableEntityTable
+       filterHelp,
+       // BankAccountComposite
+       accountHolder, bankName, currency, accountNumber, bankNumber, BIC, IBAN,
+       // EditJobDialog
+       position, chosenItem, department, isPrimary, searchAndChooseEntity,
+       // ContactListCTab (e4)
+       notes, addAContact, contactValue, linkedCompany,
+       // OrgAdminInfoCTab (e4)
+       paymentAccount,
+       // OrgEditor (e4)
+       orgDetails, orgActivityLog, team, orgAdmin,
+       // PersonEditor (e4)
+       personDetails, personActivityLog, personOrgs, personSecurity,
+       // PersonSecurityCTab (e4)
+       resetPassword,
+       // Generic
+       label, aCustomLabel, description, value, name, primary, add, save, pickup,
+       // Tag
+       confirmNewTag, cannotCreateTag;
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteStyle.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteStyle.java
new file mode 100644 (file)
index 0000000..5183fa4
--- /dev/null
@@ -0,0 +1,31 @@
+package org.argeo.suite.ui;
+
+import org.argeo.cms.ui.util.CmsStyle;
+
+/** Styles used by Argeo Suite work UI. */
+public enum SuiteStyle implements CmsStyle {
+       // Header
+       header, headerTitle, headerMenu, headerMenuItem,
+       // Recent items
+       recentItems,
+       // Lead pane
+       leadPane, leadPaneItem, leadPaneSectionTitle, leadPaneSubSectionTitle,
+       // Group composite
+       titleContainer, titleLabel, subTitleLabel, formLine, formColumn, navigationBar, navigationTitle, navigationButton,
+       // Forms elements
+       simpleLabel, simpleText, simpleInput,
+       // table
+       titleCell,
+       // layers
+       workArea,
+       // tabbed area
+       mainTabBody, mainTabSelected, mainTab,
+       // Buttons
+       inlineButton;
+
+       @Override
+       public String getClassPrefix() {
+               return "argeo-suite";
+       }
+
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java
new file mode 100644 (file)
index 0000000..b245762
--- /dev/null
@@ -0,0 +1,226 @@
+package org.argeo.suite.ui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/** The view for the default ergonomics of Argeo Suite. */
+class SuiteUi extends Composite {
+       private static final long serialVersionUID = 6207018859086689108L;
+       private final static Log log = LogFactory.getLog(SuiteUi.class);
+       private Composite header;
+       private Composite belowHeader;
+       private Composite leadPane;
+       private Composite dynamicArea;
+
+       private Session sysSession;
+//     private Session homeSession;
+       private Node userDir;
+
+       private Map<String, SuiteLayer> layers = new HashMap<>();
+       private Map<String, Composite> workAreas = new HashMap<>();
+       private String currentLayerId = null;
+
+       private CmsView cmsView;
+
+       public SuiteUi(Composite parent, int style) {
+               super(parent, style);
+               cmsView = CmsView.getCmsView(parent);
+               this.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+               header = new Composite(this, SWT.NONE);
+               header.setLayout(CmsUiUtils.noSpaceGridLayout());
+               CmsUiUtils.style(header, SuiteStyle.header);
+               header.setLayoutData(CmsUiUtils.fillWidth());
+
+               belowHeader = new Composite(this, SWT.NONE);
+               belowHeader.setLayoutData(CmsUiUtils.fillAll());
+       }
+
+       public void refreshBelowHeader(boolean initApp) {
+               CmsUiUtils.clear(belowHeader);
+               int style = getStyle();
+               if (initApp) {
+                       belowHeader.setLayout(CmsUiUtils.noSpaceGridLayout(2));
+
+                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
+                               dynamicArea = new Composite(belowHeader, SWT.NONE);
+                               leadPane = new Composite(belowHeader, SWT.NONE);
+                       } else {
+                               leadPane = new Composite(belowHeader, SWT.NONE);
+                               dynamicArea = new Composite(belowHeader, SWT.NONE);
+                       }
+                       leadPane.setLayoutData(CmsUiUtils.fillHeight());
+                       leadPane.setLayout(CmsUiUtils.noSpaceGridLayout());
+                       CmsUiUtils.style(leadPane, SuiteStyle.leadPane);
+
+                       dynamicArea.setLayoutData(CmsUiUtils.fillAll());
+                       dynamicArea.setLayout(new FormLayout());
+
+               } else {
+                       belowHeader.setLayout(CmsUiUtils.noSpaceGridLayout());
+               }
+       }
+
+       /*
+        * LAYERS
+        */
+
+       Composite getCurrentWorkArea() {
+               if (currentLayerId == null)
+                       throw new IllegalStateException("No current layer");
+               return workAreas.get(currentLayerId);
+       }
+
+       String getCurrentLayerId() {
+               return currentLayerId;
+       }
+
+       private Composite getLayer(String id, Node context) {
+               if (!layers.containsKey(id))
+                       return null;
+               if (!workAreas.containsKey(id))
+                       initLayer(id, layers.get(id), context);
+               return workAreas.get(id);
+       }
+
+       Composite switchToLayer(String layerId, Node context) {
+               Composite current = null;
+               if (currentLayerId != null) {
+                       current = getCurrentWorkArea();
+                       if (currentLayerId.equals(layerId))
+                               return current;
+               }
+               if (context == null) {
+                       if (!cmsView.isAnonymous())
+                               context = userDir;
+               }
+               Composite toShow = getLayer(layerId, context);
+               if (toShow != null) {
+                       currentLayerId = layerId;
+                       if (!isDisposed()) {
+//                             getDisplay().syncExec(() -> {
+                               if (!toShow.isDisposed()) {
+                                       toShow.moveAbove(null);
+                               } else {
+                                       log.warn("Cannot show work area because it is disposed.");
+                                       toShow = initLayer(layerId, layers.get(layerId), context);
+                                       toShow.moveAbove(null);
+                               }
+                               dynamicArea.layout(true, true);
+//                             });
+                       }
+                       return toShow;
+               } else {
+                       return current;
+               }
+       }
+
+       Composite switchToLayer(SuiteLayer layer, Node context) {
+               // TODO make it more robust
+               for (String layerId : layers.keySet()) {
+                       SuiteLayer l = layers.get(layerId);
+                       if (layer == l) {
+                               return switchToLayer(layerId, context);
+                       }
+               }
+               throw new IllegalArgumentException("Layer is not registered.");
+       }
+
+       void addLayer(String id, SuiteLayer layer) {
+               layers.put(id, layer);
+       }
+
+       void removeLayer(String id) {
+               layers.remove(id);
+               if (workAreas.containsKey(id)) {
+                       Composite workArea = workAreas.remove(id);
+                       if (!workArea.isDisposed())
+                               workArea.dispose();
+               }
+       }
+
+       protected Composite initLayer(String id, SuiteLayer layer, Node context) {
+               Composite workArea = cmsView.doAs(() -> (Composite) layer.createUiPart(dynamicArea, context));
+               CmsUiUtils.style(workArea, SuiteStyle.workArea);
+               workArea.setLayoutData(CmsUiUtils.coverAll());
+               workAreas.put(id, workArea);
+               return workArea;
+       }
+
+       synchronized void logout() {
+               userDir = null;
+               Jcr.logout(sysSession);
+//             Jcr.logout(homeSession);
+               currentLayerId = null;
+               workAreas.clear();
+       }
+
+       /*
+        * GETTERS / SETTERS
+        */
+
+       Composite getHeader() {
+               return header;
+       }
+
+       Composite getLeadPane() {
+               return leadPane;
+       }
+
+       Composite getBelowHeader() {
+               return belowHeader;
+       }
+
+//     Session getSysSession() {
+//             return sysSession;
+//     }
+//
+       synchronized void initSessions(Repository repository, String userDirPath) throws RepositoryException {
+               this.sysSession = repository.login();
+//             this.homeSession = repository.login(NodeConstants.HOME_WORKSPACE);
+               userDir = sysSession.getNode(userDirPath);
+               addDisposeListener((e) -> {
+                       Jcr.logout(sysSession);
+//                     Jcr.logout(homeSession);
+               });
+       }
+
+       Node getUserDir() {
+               return userDir;
+       }
+
+       Session getSysSession() {
+               return sysSession;
+       }
+
+       Session getSession(String workspaceName) {
+               if (workspaceName == null)
+                       return sysSession;
+               if (NodeConstants.SYS_WORKSPACE.equals(workspaceName))
+                       return sysSession;
+//             else if (NodeConstants.HOME_WORKSPACE.equals(workspaceName))
+//                     return homeSession;
+               else
+                       throw new IllegalArgumentException("Unknown workspace " + workspaceName);
+       }
+
+       public CmsView getCmsView() {
+               return cmsView;
+       }
+
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java
new file mode 100644 (file)
index 0000000..8e9a9d5
--- /dev/null
@@ -0,0 +1,368 @@
+package org.argeo.suite.ui;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.cms.Localized;
+import org.argeo.cms.ui.CmsEditable;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.cms.ui.dialogs.LightweightDialog;
+import org.argeo.cms.ui.util.CmsIcon;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.entity.EntityNames;
+import org.argeo.entity.EntityType;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** UI utilities related to the APAF project. */
+public class SuiteUiUtils {
+
+       /** Singleton. */
+       private SuiteUiUtils() {
+       }
+
+       /** creates a title bar composite with label and optional button */
+       public static void addTitleBar(Composite parent, String title, Boolean isEditable) {
+               Composite titleBar = new Composite(parent, SWT.NONE);
+               titleBar.setLayoutData(CmsUiUtils.fillWidth());
+               CmsUiUtils.style(titleBar, SuiteStyle.titleContainer);
+
+               titleBar.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(2, false)));
+               Label titleLbl = new Label(titleBar, SWT.NONE);
+               titleLbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
+               CmsUiUtils.style(titleLbl, SuiteStyle.titleLabel);
+               titleLbl.setText(title);
+
+               if (isEditable) {
+                       Button editBtn = new Button(titleBar, SWT.PUSH);
+                       editBtn.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+                       CmsUiUtils.style(editBtn, SuiteStyle.inlineButton);
+                       editBtn.setText("Edit");
+               }
+       }
+
+       public static Label addFormLabel(Composite parent, String label) {
+               Label lbl = new Label(parent, SWT.WRAP);
+               lbl.setText(label);
+               // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
+               CmsUiUtils.style(lbl, SuiteStyle.simpleLabel);
+               return lbl;
+       }
+
+       public static Text addFormTextField(Composite parent, String text, String message) {
+               return addFormTextField(parent, text, message, SWT.NONE);
+       }
+
+       public static Text addFormTextField(Composite parent, String text, String message, int style) {
+               Text txt = new Text(parent, style);
+               if (text != null)
+                       txt.setText(text);
+               if (message != null)
+                       txt.setMessage(message);
+               txt.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
+               CmsUiUtils.style(txt, SuiteStyle.simpleText);
+               return txt;
+       }
+
+       public static Text addFormInputField(Composite parent, String placeholder) {
+               Text txt = new Text(parent, SWT.BORDER);
+
+               GridData gridData = CmsUiUtils.fillWidth();
+               txt.setLayoutData(gridData);
+
+               if (placeholder != null)
+                       txt.setText(placeholder);
+
+               CmsUiUtils.style(txt, SuiteStyle.simpleInput);
+               return txt;
+       }
+
+       /** creates a single horizontal-block composite for key:value display */
+       public static Text addFormLine(Composite parent, String label, String text) {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(2, false));
+               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+               addFormLabel(lineComposite, label);
+               Text txt = addFormTextField(lineComposite, text, null);
+               txt.setEditable(false);
+               txt.setLayoutData(CmsUiUtils.fillWidth());
+               return txt;
+       }
+
+       public static Text addFormLine(Composite parent, String label, Node node, String property,
+                       CmsEditable cmsEditable) {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(2, false));
+               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+               addFormLabel(lineComposite, label);
+               String text = Jcr.get(node, property);
+//             int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
+               Text txt = addFormTextField(lineComposite, text, null, SWT.WRAP);
+               if (cmsEditable != null && cmsEditable.isEditing()) {
+                       txt.addModifyListener((e) -> {
+                               Jcr.set(node, property, txt.getText());
+                               Jcr.save(node);
+                       });
+               } else {
+                       txt.setEditable(false);
+               }
+               txt.setLayoutData(CmsUiUtils.fillWidth());
+               return txt;
+       }
+
+       public static Text addFormInput(Composite parent, String label, String placeholder) {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(2, false));
+               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+               addFormLabel(lineComposite, label);
+               Text txt = addFormInputField(lineComposite, placeholder);
+               txt.setLayoutData(CmsUiUtils.fillWidth());
+               return txt;
+       }
+
+       /**
+        * creates a single horizontal-block composite for key:value display, with
+        * offset value
+        */
+       public static Text addFormLine(Composite parent, String label, String text, Integer offset) {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(3, false));
+               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+               Label offsetLbl = new Label(lineComposite, SWT.NONE);
+               GridData gridData = new GridData();
+               gridData.widthHint = offset;
+               offsetLbl.setLayoutData(gridData);
+               addFormLabel(lineComposite, label);
+               Text txt = addFormTextField(lineComposite, text, null);
+               txt.setLayoutData(CmsUiUtils.fillWidth());
+               return txt;
+       }
+
+       /** creates a single vertical-block composite for key:value display */
+       public static Text addFormColumn(Composite parent, String label, String text) {
+//             Composite columnComposite = new Composite(parent, SWT.NONE);
+//             columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+//             columnComposite.setLayout(new GridLayout(1, false));
+               addFormLabel(parent, label);
+               Text txt = addFormTextField(parent, text, null);
+               txt.setEditable(false);
+               txt.setLayoutData(CmsUiUtils.fillWidth());
+               return txt;
+       }
+
+       public static Text addFormColumn(Composite parent, String label, Node node, String property,
+                       CmsEditable cmsEditable) {
+//             Composite columnComposite = new Composite(parent, SWT.NONE);
+//             columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+//             columnComposite.setLayout(new GridLayout(1, false));
+               addFormLabel(parent, label);
+               String text = Jcr.get(node, property);
+//             int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
+               Text txt = addFormTextField(parent, text, null, SWT.WRAP);
+               if (cmsEditable != null && cmsEditable.isEditing()) {
+                       txt.addModifyListener((e) -> {
+                               Jcr.set(node, property, txt.getText());
+                               Jcr.save(node);
+                       });
+               } else {
+                       txt.setEditable(false);
+               }
+               txt.setLayoutData(CmsUiUtils.fillWidth());
+               return txt;
+       }
+
+       public static Label createBoldLabel(Composite parent, Localized localized) {
+               Label label = new Label(parent, SWT.LEAD);
+               label.setText(localized.lead());
+               label.setFont(EclipseUiUtils.getBoldFont(parent));
+               label.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+               return label;
+       }
+
+       public static Label addFormPicture(Composite parent, String label, Node fileNode) throws RepositoryException {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(2, true));
+               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
+               addFormLabel(lineComposite, label);
+
+               return addPicture(lineComposite, fileNode);
+       }
+
+       public static Label addPicture(Composite parent, Node fileNode) throws RepositoryException {
+               return addPicture(parent, fileNode, null);
+       }
+
+       public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth) throws RepositoryException {
+               Node content = fileNode.getNode(Node.JCR_CONTENT);
+               // TODO move it deeper in the middleware.
+               if (!content.isNodeType(EntityType.box.get())) {
+                       if (content.getSession().hasPermission(content.getPath(), Session.ACTION_SET_PROPERTY)) {
+                               try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
+                                       ImageData imageData = new ImageData(in);
+                                       content.addMixin(EntityType.box.get());
+                                       content.setProperty(EntityNames.SVG_WIDTH, imageData.width);
+                                       content.setProperty(EntityNames.SVG_HEIGHT, imageData.height);
+                                       content.getSession().save();
+                               } catch (IOException e) {
+                                       throw new RuntimeException(e);
+                               }
+                       }
+               }
+
+               // TODO optimise
+               Long width;
+               Long height;
+               if (content.isNodeType(EntityType.box.get())) {
+                       width = content.getProperty(EntityNames.SVG_WIDTH).getLong();
+                       height = content.getProperty(EntityNames.SVG_HEIGHT).getLong();
+               } else {
+                       try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
+                               ImageData imageData = new ImageData(in);
+                               width = Long.valueOf(imageData.width);
+                               height = Long.valueOf(imageData.height);
+                       } catch (IOException e) {
+                               throw new RuntimeException(e);
+                       }
+               }
+
+               if (maxWidth != null && width > maxWidth) {
+                       Double ratio = maxWidth.doubleValue() / width.doubleValue();
+                       width = maxWidth.longValue();
+                       height = Math.round(ratio * height);
+               }
+               Label img = new Label(parent, SWT.NONE);
+               CmsUiUtils.markup(img);
+               img.setText(CmsUiUtils.img(fileNode, width.toString(), height.toString()));
+               if (parent.getLayout() instanceof GridLayout) {
+                       GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+                       gd.widthHint = width.intValue();
+                       gd.heightHint = height.intValue();
+                       img.setLayoutData(gd);
+               }
+               img.addMouseListener(new MouseListener() {
+                       private static final long serialVersionUID = -1362242049325206168L;
+
+                       @Override
+                       public void mouseUp(MouseEvent e) {
+                       }
+
+                       @Override
+                       public void mouseDown(MouseEvent e) {
+                       }
+
+                       @Override
+                       public void mouseDoubleClick(MouseEvent e) {
+                               LightweightDialog dialog = new LightweightDialog(img.getShell()) {
+
+                                       @Override
+                                       protected Control createDialogArea(Composite parent) {
+                                               parent.setLayout(new GridLayout());
+                                               ScrolledComposite scroll = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
+                                               scroll.setLayoutData(CmsUiUtils.fillAll());
+                                               scroll.setLayout(CmsUiUtils.noSpaceGridLayout());
+                                               scroll.setExpandHorizontal(true);
+                                               scroll.setExpandVertical(true);
+                                               // scroll.setAlwaysShowScrollBars(true);
+
+                                               Composite c = new Composite(scroll, SWT.NONE);
+                                               scroll.setContent(c);
+                                               c.setLayout(new GridLayout());
+                                               c.setLayoutData(CmsUiUtils.fillAll());
+                                               Label bigImg = new Label(c, SWT.NONE);
+                                               CmsUiUtils.markup(bigImg);
+                                               bigImg.setText(CmsUiUtils.img(fileNode, Jcr.get(content, EntityNames.SVG_WIDTH),
+                                                               Jcr.get(content, EntityNames.SVG_HEIGHT)));
+                                               bigImg.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+                                               return bigImg;
+                                       }
+
+                                       @Override
+                                       protected Point getInitialSize() {
+                                               Point shellSize = img.getShell().getSize();
+                                               return new Point(shellSize.x - 100, shellSize.y - 100);
+                                       }
+
+                               };
+                               dialog.open();
+                       }
+               });
+               return img;
+       }
+
+       public static Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon) {
+               CmsTheme theme = CmsTheme.getCmsTheme(parent);
+               Button button = new Button(parent, SWT.PUSH);
+               CmsUiUtils.style(button, SuiteStyle.leadPane);
+               if (icon != null)
+                       button.setImage(icon.getBigIcon(theme));
+               button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false));
+               // button.setToolTipText(msg.lead());
+               if (msg != null) {
+                       Label lbl = new Label(parent, SWT.NONE);
+                       CmsUiUtils.style(lbl, SuiteStyle.leadPane);
+                       lbl.setText(msg.lead());
+                       lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
+               }
+               CmsUiUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer);
+               return button;
+       }
+
+//     public static String createAndConfigureEntity(Shell shell, Session referenceSession, String mainMixin,
+//                     String... additionnalProps) {
+//
+//             Session tmpSession = null;
+//             Session mainSession = null;
+//             try {
+//                     // FIXME would not work if home is another physical workspace
+//                     tmpSession = referenceSession.getRepository().login(NodeConstants.HOME_WORKSPACE);
+//                     Node draftNode = null;
+//                     for (int i = 0; i < additionnalProps.length - 1; i += 2) {
+//                             draftNode.setProperty(additionnalProps[i], additionnalProps[i + 1]);
+//                     }
+//                     Wizard wizard = null;
+//                     CmsWizardDialog dialog = new CmsWizardDialog(shell, wizard);
+//                     // WizardDialog dialog = new WizardDialog(shell, wizard);
+//                     if (dialog.open() == Window.OK) {
+//                             String parentPath = null;// "/" + appService.getBaseRelPath(mainMixin);
+//                             // FIXME it should be possible to specify the workspace
+//                             mainSession = referenceSession.getRepository().login();
+//                             Node parent = mainSession.getNode(parentPath);
+//                             Node task = null;// appService.publishEntity(parent, mainMixin, draftNode);
+////                           task = appService.saveEntity(task, false);
+//                             referenceSession.refresh(true);
+//                             return task.getPath();
+//                     }
+//                     return null;
+//             } catch (RepositoryException e1) {
+//                     throw new JcrException(
+//                                     "Unable to create " + mainMixin + " entity with session " + referenceSession.toString(), e1);
+//             } finally {
+//                     JcrUtils.logoutQuietly(tmpSession);
+//                     JcrUtils.logoutQuietly(mainSession);
+//             }
+//     }
+
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUserUiProvider.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUserUiProvider.java
new file mode 100644 (file)
index 0000000..04d7a7b
--- /dev/null
@@ -0,0 +1,86 @@
+package org.argeo.suite.ui;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.naming.LdapAttrs;
+import org.eclipse.swt.SWT;
+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.Group;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.useradmin.User;
+
+/** Edit a suite user. */
+public class SuiteUserUiProvider implements CmsUiProvider {
+       private String[] availableRoles;
+       private CmsUserManager cmsUserManager;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               Section main = new Section(parent, SWT.NONE, context);
+               main.setLayoutData(CmsUiUtils.fillAll());
+
+               String uid = context.getName();
+               User user = cmsUserManager.getUserFromLocalId(uid);
+
+//             Text givenName = new Text(main, SWT.SINGLE);
+//             givenName.setText(getUserProperty(user, LdapAttrs.givenName.name()));
+               Text givenName = SuiteUiUtils.addFormInput(main, SuiteMsg.firstName.lead(),
+                               getUserProperty(user, LdapAttrs.givenName.name()));
+
+               Text sn = SuiteUiUtils.addFormInput(main, SuiteMsg.lastName.lead(), getUserProperty(user, LdapAttrs.sn.name()));
+               // sn.setText(getUserProperty(user, LdapAttrs.sn.name()));
+
+               Text email = SuiteUiUtils.addFormInput(main, SuiteMsg.email.lead(),
+                               getUserProperty(user, LdapAttrs.mail.name()));
+               // email.setText(getUserProperty(user, LdapAttrs.mail.name()));
+
+               Text uidT = SuiteUiUtils.addFormLine(main, "uid", getUserProperty(user, LdapAttrs.uid.name()));
+               uidT.setText(uid);
+
+//             Label dnL = new Label(main, SWT.NONE);
+//             dnL.setText(user.getName());
+
+               // roles
+               // Section rolesSection = new Section(main, SWT.NONE, context);
+               Group rolesSection = new Group(main, SWT.NONE);
+               rolesSection.setText("Roles");
+               rolesSection.setLayoutData(CmsUiUtils.fillWidth());
+               rolesSection.setLayout(new GridLayout());
+               // new Label(rolesSection, SWT.NONE).setText("Roles:");
+               List<String> roles = Arrays.asList(cmsUserManager.getUserRoles(user.getName()));
+               for (String role : availableRoles) {
+                       // new Label(rolesSection, SWT.NONE).setText(role);
+                       Button radio = new Button(rolesSection, SWT.CHECK);
+                       radio.setText(role);
+                       if (roles.contains(role))
+                               radio.setSelection(true);
+               }
+
+               return main;
+       }
+
+       public void setCmsUserManager(CmsUserManager cmsUserManager) {
+               this.cmsUserManager = cmsUserManager;
+       }
+
+       private String getUserProperty(Object element, String key) {
+               Object value = ((User) element).getProperties().get(key);
+               return value != null ? value.toString() : null;
+       }
+
+       public void init(Map<String, Object> properties) {
+               availableRoles = (String[]) properties.get("availableRoles");
+       }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonPage.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonPage.java
new file mode 100644 (file)
index 0000000..ddd4488
--- /dev/null
@@ -0,0 +1,72 @@
+package org.argeo.suite.ui.dialogs;
+
+import org.argeo.suite.ui.SuiteMsg;
+import org.argeo.suite.ui.SuiteUiUtils;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+public class NewPersonPage extends WizardPage {
+       private static final long serialVersionUID = -944349994177526468L;
+       protected Text lastNameTxt;
+       protected Text firstNameTxt;
+       protected Text emailTxt;
+
+       protected NewPersonPage(String pageName) {
+               super(pageName);
+               setTitle(SuiteMsg.personWizardPageTitle.lead());
+       }
+
+       @Override
+       public void createControl(Composite parent) {
+               parent.setLayout(new GridLayout(2, false));
+
+               // FirstName
+               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+               firstNameTxt = new Text(parent, SWT.BORDER);
+               firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+               // LastName
+               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+               lastNameTxt = new Text(parent, SWT.BORDER);
+               lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.email);
+               emailTxt = new Text(parent, SWT.BORDER);
+               emailTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+               ModifyListener ml = new ModifyListener() {
+                       private static final long serialVersionUID = -1628130380128946886L;
+
+                       @Override
+                       public void modifyText(ModifyEvent event) {
+                               getContainer().updateButtons();
+                       }
+               };
+
+               firstNameTxt.addModifyListener(ml);
+               lastNameTxt.addModifyListener(ml);
+               emailTxt.addModifyListener(ml);
+
+               // Don't forget this.
+               setControl(firstNameTxt);
+               firstNameTxt.setFocus();
+
+       }
+
+//     public void updateNode(Node node, PeopleService peopleService, ResourcesService resourcesService) {
+//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_LAST_NAME, PropertyType.STRING, lastNameTxt.getText());
+//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_FIRST_NAME, PropertyType.STRING,
+//                             firstNameTxt.getText());
+//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_DISPLAY_NAME, PropertyType.STRING,
+//                             firstNameTxt.getText() + " " + lastNameTxt.getText());
+//             String email = emailTxt.getText();
+//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_PRIMARY_EMAIL, PropertyType.STRING, email);
+//             PeopleJcrUtils.createEmail(resourcesService, peopleService, node, email, true, null, null);
+//     }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonWizard.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonWizard.java
new file mode 100644 (file)
index 0000000..9db5e04
--- /dev/null
@@ -0,0 +1,151 @@
+package org.argeo.suite.ui.dialogs;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
+
+import javax.jcr.Node;
+
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.suite.ui.SuiteMsg;
+import org.argeo.suite.ui.SuiteUiUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/** Ask first & last name. Update the passed node on finish */
+public class NewPersonWizard extends Wizard {
+       // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
+
+       // Context
+       private Node person;
+
+       // This page widgets
+       protected Text lastNameTxt;
+       protected Text firstNameTxt;
+       // private Button useDistinctDisplayNameBtn;
+       // private Text displayNameTxt;
+
+       public NewPersonWizard(Node person) {
+               this.person = person;
+       }
+
+       @Override
+       public void addPages() {
+               try {
+                       MainInfoPage page = new MainInfoPage("Main page");
+                       addPage(page);
+               } catch (Exception e) {
+                       throw new RuntimeException("Cannot add page to wizard", e);
+               }
+               setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
+       }
+
+       /**
+        * Called when the user click on 'Finish' in the wizard. The task is then
+        * created and the corresponding session saved.
+        */
+       @Override
+       public boolean performFinish() {
+               String lastName = lastNameTxt.getText();
+               String firstName = firstNameTxt.getText();
+               // String displayName = displayNameTxt.getText();
+               // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
+               if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
+                       MessageDialog.openError(getShell(), "Non-valid information",
+                                       "Please enter at least a name that is not empty.");
+                       return false;
+               } else {
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
+//                     String fullName = firstName + " " + lastName;
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
+                       return true;
+               }
+       }
+
+       @Override
+       public boolean performCancel() {
+               return true;
+       }
+
+       @Override
+       public boolean canFinish() {
+               String lastName = lastNameTxt.getText();
+               String firstName = firstNameTxt.getText();
+               if (isEmpty(lastName) && isEmpty(firstName)) {
+                       return false;
+               } else
+                       return true;
+       }
+
+       protected class MainInfoPage extends WizardPage {
+               private static final long serialVersionUID = 1L;
+
+               public MainInfoPage(String pageName) {
+                       super(pageName);
+                       setTitle(SuiteMsg.personWizardPageTitle.lead());
+                       // setMessage("Please enter a last name and/or a first name.");
+               }
+
+               public void createControl(Composite parent) {
+                       parent.setLayout(new GridLayout(2, false));
+
+                       // FirstName
+                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+                       firstNameTxt = new Text(parent, SWT.BORDER);
+                       // firstNameTxt.setMessage("a first name");
+                       firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       // LastName
+                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+                       lastNameTxt = new Text(parent, SWT.BORDER);
+                       // lastNameTxt.setMessage("a last name");
+                       lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       // Display Name
+                       // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
+                       // useDistinctDisplayNameBtn.setText("Define a disting display name");
+                       // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
+                       // true, false, 2, 1));
+                       //
+                       // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
+                       // displayNameTxt = new Text(parent, SWT.BORDER);
+                       // displayNameTxt.setMessage("an optional display name");
+                       // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
+                       // false));
+                       // displayNameTxt.setEnabled(false);
+                       //
+                       // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
+                       // private static final long serialVersionUID = 1L;
+                       //
+                       // @Override
+                       // public void widgetSelected(SelectionEvent e) {
+                       // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
+                       // }
+                       // });
+
+                       ModifyListener ml = new ModifyListener() {
+                               private static final long serialVersionUID = -1628130380128946886L;
+
+                               @Override
+                               public void modifyText(ModifyEvent event) {
+                                       getContainer().updateButtons();
+                               }
+                       };
+
+                       firstNameTxt.addModifyListener(ml);
+                       lastNameTxt.addModifyListener(ml);
+                       // displayNameTxt.addModifyListener(ml);
+
+                       // Don't forget this.
+                       setControl(firstNameTxt);
+                       firstNameTxt.setFocus();
+               }
+       }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewUserWizard.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewUserWizard.java
new file mode 100644 (file)
index 0000000..5b4575d
--- /dev/null
@@ -0,0 +1,151 @@
+package org.argeo.suite.ui.dialogs;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
+
+import javax.jcr.Node;
+
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.suite.ui.SuiteMsg;
+import org.argeo.suite.ui.SuiteUiUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/** Ask first & last name. Update the passed node on finish */
+public class NewUserWizard extends Wizard {
+       // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
+
+       // Context
+       private Node person;
+
+       // This page widgets
+       protected Text lastNameTxt;
+       protected Text firstNameTxt;
+       // private Button useDistinctDisplayNameBtn;
+       // private Text displayNameTxt;
+
+       public NewUserWizard(Node person) {
+               this.person = person;
+       }
+
+       @Override
+       public void addPages() {
+               try {
+                       MainInfoPage page = new MainInfoPage("Main page");
+                       addPage(page);
+               } catch (Exception e) {
+                       throw new RuntimeException("Cannot add page to wizard", e);
+               }
+               setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
+       }
+
+       /**
+        * Called when the user click on 'Finish' in the wizard. The task is then
+        * created and the corresponding session saved.
+        */
+       @Override
+       public boolean performFinish() {
+               String lastName = lastNameTxt.getText();
+               String firstName = firstNameTxt.getText();
+               // String displayName = displayNameTxt.getText();
+               // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
+               if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
+                       MessageDialog.openError(getShell(), "Non-valid information",
+                                       "Please enter at least a name that is not empty.");
+                       return false;
+               } else {
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
+//                     String fullName = firstName + " " + lastName;
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
+                       return true;
+               }
+       }
+
+       @Override
+       public boolean performCancel() {
+               return true;
+       }
+
+       @Override
+       public boolean canFinish() {
+               String lastName = lastNameTxt.getText();
+               String firstName = firstNameTxt.getText();
+               if (isEmpty(lastName) && isEmpty(firstName)) {
+                       return false;
+               } else
+                       return true;
+       }
+
+       protected class MainInfoPage extends WizardPage {
+               private static final long serialVersionUID = 1L;
+
+               public MainInfoPage(String pageName) {
+                       super(pageName);
+                       setTitle(SuiteMsg.personWizardPageTitle.lead());
+                       // setMessage("Please enter a last name and/or a first name.");
+               }
+
+               public void createControl(Composite parent) {
+                       parent.setLayout(new GridLayout(2, false));
+
+                       // FirstName
+                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+                       firstNameTxt = new Text(parent, SWT.BORDER);
+                       // firstNameTxt.setMessage("a first name");
+                       firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       // LastName
+                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+                       lastNameTxt = new Text(parent, SWT.BORDER);
+                       // lastNameTxt.setMessage("a last name");
+                       lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       // Display Name
+                       // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
+                       // useDistinctDisplayNameBtn.setText("Define a disting display name");
+                       // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
+                       // true, false, 2, 1));
+                       //
+                       // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
+                       // displayNameTxt = new Text(parent, SWT.BORDER);
+                       // displayNameTxt.setMessage("an optional display name");
+                       // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
+                       // false));
+                       // displayNameTxt.setEnabled(false);
+                       //
+                       // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
+                       // private static final long serialVersionUID = 1L;
+                       //
+                       // @Override
+                       // public void widgetSelected(SelectionEvent e) {
+                       // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
+                       // }
+                       // });
+
+                       ModifyListener ml = new ModifyListener() {
+                               private static final long serialVersionUID = -1628130380128946886L;
+
+                               @Override
+                               public void modifyText(ModifyEvent event) {
+                                       getContainer().updateButtons();
+                               }
+                       };
+
+                       firstNameTxt.addModifyListener(ml);
+                       lastNameTxt.addModifyListener(ml);
+                       // displayNameTxt.addModifyListener(ml);
+
+                       // Don't forget this.
+                       setControl(firstNameTxt);
+                       firstNameTxt.setFocus();
+               }
+       }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java
new file mode 100644 (file)
index 0000000..07f9cee
--- /dev/null
@@ -0,0 +1,133 @@
+package org.argeo.suite.ui.widgets;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+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;
+
+/**
+ * Generic popup context menu for TableViewer to enable single sourcing between
+ * CMS and Workbench
+ */
+public abstract class AbstractConnectContextMenu {
+
+       private Shell parentShell;
+       private Shell shell;
+       // Local context
+
+       private final static String KEY_ACTION_ID = "actionId";
+       private final String[] defaultActions;
+       private Map<String, Button> actionButtons = new HashMap<String, Button>();
+
+       public AbstractConnectContextMenu(Display display, String[] defaultActions) {
+               parentShell = display.getActiveShell();
+               shell = new Shell(parentShell, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+               this.defaultActions = defaultActions;
+       }
+
+       protected void createControl() {
+               shell.setLayout(EclipseUiUtils.noSpaceGridLayout());
+               Composite boxCmp = new Composite(shell, SWT.NO_FOCUS | SWT.BORDER);
+               boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
+//             CmsUiUtils.style(boxCmp, ConnectUiStyles.CONTEXT_MENU_BOX);
+               createContextMenu(boxCmp);
+               shell.addShellListener(new ActionsShellListener());
+       }
+
+       protected void createContextMenu(Composite boxCmp) {
+               ActionsSelListener asl = new ActionsSelListener();
+               for (String actionId : defaultActions) {
+                       Button btn = new Button(boxCmp, SWT.FLAT | SWT.LEAD);
+                       btn.setText(getLabel(actionId));
+                       btn.setLayoutData(EclipseUiUtils.fillWidth());
+                       CmsUiUtils.markup(btn);
+//                     CmsUiUtils.style(btn, actionId + ConnectUiStyles.BUTTON_SUFFIX);
+                       btn.setData(KEY_ACTION_ID, actionId);
+                       btn.addSelectionListener(asl);
+                       actionButtons.put(actionId, btn);
+               }
+       }
+
+       protected void setVisible(boolean visible, String... buttonIds) {
+               for (String id : buttonIds) {
+                       Button button = actionButtons.get(id);
+                       button.setVisible(visible);
+                       GridData gd = (GridData) button.getLayoutData();
+                       gd.heightHint = visible ? SWT.DEFAULT : 0;
+               }
+       }
+
+       public void show(Control source, Point location, IStructuredSelection selection) {
+               if (shell.isDisposed()) {
+                       shell = new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+                       createControl();
+               }
+               if (shell.isVisible())
+                       shell.setVisible(false);
+
+               if (aboutToShow(source, location, selection)) {
+                       shell.pack();
+                       shell.layout();
+                       if (source instanceof Control)
+                               shell.setLocation(((Control) source).toDisplay(location.x, location.y));
+                       shell.open();
+               }
+       }
+
+       protected Shell getParentShell() {
+               return parentShell;
+       }
+
+       class StyleButton extends Label {
+               private static final long serialVersionUID = 7731102609123946115L;
+
+               public StyleButton(Composite parent, int swtStyle) {
+                       super(parent, swtStyle);
+               }
+       }
+
+       class ActionsSelListener extends SelectionAdapter {
+               private static final long serialVersionUID = -1041871937815812149L;
+
+               @Override
+               public void widgetSelected(SelectionEvent e) {
+                       Object eventSource = e.getSource();
+                       if (eventSource instanceof Button) {
+                               Button pressedBtn = (Button) eventSource;
+                               performAction((String) pressedBtn.getData(KEY_ACTION_ID));
+                               shell.close();
+                       }
+               }
+       }
+
+       class ActionsShellListener extends org.eclipse.swt.events.ShellAdapter {
+               private static final long serialVersionUID = -5092341449523150827L;
+
+               @Override
+               public void shellDeactivated(ShellEvent e) {
+                       setVisible(false);
+                       shell.setVisible(false);
+                       //shell.close();
+               }
+       }
+
+       protected abstract boolean performAction(String actionId);
+
+       protected abstract boolean aboutToShow(Control source, Point location, IStructuredSelection selection);
+
+       protected abstract String getLabel(String actionId);
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java
new file mode 100644 (file)
index 0000000..ffe733e
--- /dev/null
@@ -0,0 +1,194 @@
+package org.argeo.suite.ui.widgets;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.rap.rwt.widgets.DropDown;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * Enable easy addition of a {@code DropDown} widget to a text with listeners
+ * configured
+ */
+public abstract class ConnectAbstractDropDown {
+
+       private final Text text;
+       private final DropDown dropDown;
+       private boolean modifyFromList = false;
+
+       // Current displayed text
+       private String userText = "";
+       // Current displayed list items
+       private String[] values;
+
+       // Fine tuning
+       boolean readOnly;
+       boolean refreshOnFocus;
+
+       /** Implementing classes should call refreshValues() after initialisation */
+       public ConnectAbstractDropDown(Text text) {
+               this(text, SWT.NONE, false);
+       }
+
+       /**
+        * Implementing classes should call refreshValues() after initialisation
+        * 
+        * @param text
+        * @param style
+        *            only SWT.READ_ONLY is understood, check if the entered text is
+        *            part of the legal choices.
+        */
+       public ConnectAbstractDropDown(Text text, int style) {
+               this(text, style, false);
+       }
+
+       /**
+        * Implementers should call refreshValues() once init has been done.
+        * 
+        * @param text
+        * @param style
+        *            only SWT.READ_ONLY is understood, check if the entered text is
+        *            part of the legal choices.
+        * @param refreshOnFocus
+        *            if true, the possible values are computed each time the focus is
+        *            gained. It enables, among other to fine tune the getFilteredValues
+        *            method depending on the current context
+        */
+       public ConnectAbstractDropDown(Text text, int style, boolean refreshOnFocus) {
+               this.text = text;
+               dropDown = new DropDown(text);
+               Object obj = dropDown;
+               if (obj instanceof Widget)
+                       CmsUiUtils.markup((Widget) obj);
+               readOnly = (style & SWT.READ_ONLY) != 0;
+               this.refreshOnFocus = refreshOnFocus;
+               addListeners();
+       }
+
+       /**
+        * Overwrite to force the refresh of the possible values on focus gained event
+        */
+       protected boolean refreshOnFocus() {
+               return refreshOnFocus;
+       }
+
+       public String getText() {
+               return text.getText();
+       }
+
+       public void init() {
+               refreshValues();
+       }
+
+       public void reset(String value) {
+               modifyFromList = true;
+               if (EclipseUiUtils.notEmpty(value))
+                       text.setText(value);
+               else
+                       text.setText("");
+               refreshValues();
+               modifyFromList = false;
+       }
+
+       /** Overwrite to provide specific filtering */
+       protected abstract List<String> getFilteredValues(String filter);
+
+       protected void refreshValues() {
+               List<String> filteredValues = getFilteredValues(text.getText());
+               values = filteredValues.toArray(new String[filteredValues.size()]);
+               dropDown.setItems(values);
+       }
+
+       protected void addListeners() {
+               addModifyListener();
+               addSelectionListener();
+               addDefaultSelectionListener();
+               addFocusListener();
+       }
+
+       protected void addFocusListener() {
+               text.addFocusListener(new FocusListener() {
+                       private static final long serialVersionUID = -7179112097626535946L;
+
+                       public void focusGained(FocusEvent event) {
+                               if (refreshOnFocus) {
+                                       modifyFromList = true;
+                                       refreshValues();
+                                       modifyFromList = false;
+                               }
+                               dropDown.setVisible(true);
+                       }
+
+                       public void focusLost(FocusEvent event) {
+                               dropDown.setVisible(false);
+                               if (readOnly && values != null && !Arrays.asList(values).contains(userText)) {
+                                       modifyFromList = true;
+                                       text.setText("");
+                                       refreshValues();
+                                       modifyFromList = false;
+                               }
+                       }
+               });
+       }
+
+       private void addSelectionListener() {
+               Object obj = dropDown;
+               if (obj instanceof Widget)
+                       ((Widget) obj).addListener(SWT.Selection, new Listener() {
+                               private static final long serialVersionUID = -2357157809365135142L;
+
+                               public void handleEvent(Event event) {
+                                       if (event.index != -1) {
+                                               modifyFromList = true;
+                                               text.setText(values[event.index]);
+                                               modifyFromList = false;
+                                               text.selectAll();
+                                       } else {
+                                               text.setText(userText);
+                                               text.setSelection(userText.length(), userText.length());
+                                               text.setFocus();
+                                       }
+                               }
+                       });
+       }
+
+       private void addDefaultSelectionListener() {
+               Object obj = dropDown;
+               if (obj instanceof Widget)
+                       ((Widget) obj).addListener(SWT.DefaultSelection, new Listener() {
+                               private static final long serialVersionUID = -5958008322630466068L;
+
+                               public void handleEvent(Event event) {
+                                       if (event.index != -1) {
+                                               text.setText(values[event.index]);
+                                               text.setSelection(event.text.length());
+                                               dropDown.setVisible(false);
+                                       }
+                               }
+                       });
+       }
+
+       private void addModifyListener() {
+               text.addListener(SWT.Modify, new Listener() {
+                       private static final long serialVersionUID = -4373972835244263346L;
+
+                       public void handleEvent(Event event) {
+                               if (!modifyFromList) {
+                                       userText = text.getText();
+                                       refreshValues();
+                                       if (values.length == 1)
+                                               dropDown.setSelectionIndex(0);
+                                       dropDown.setVisible(true);
+                               }
+                       }
+               });
+       }
+}
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/DelayedText.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/DelayedText.java
new file mode 100644 (file)
index 0000000..a03c250
--- /dev/null
@@ -0,0 +1,127 @@
+package org.argeo.suite.ui.widgets;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.rap.rwt.service.ServerPushSession;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Text that introduce a timer in the attached ModifyListener.
+ * 
+ * Note that corresponding ModifyEvent will *NOT* be sent in the UI thread.
+ * Calling ModifierInstance must be implemented in consequence. Note also that
+ * this delayed text only manages one listener at a time.
+ *
+ */
+public class DelayedText {
+       final int delay;
+       private Object lock = new Object();
+       private MyTimer timer = new MyTimer(DelayedText.this.toString());
+       private ModifyListener delayedModifyListener;
+       private ServerPushSession pushSession;
+
+       private Text text;
+
+       private ModifyListener modifyListener = new ModifyListener() {
+               private static final long serialVersionUID = 1117506414462641980L;
+
+               public void modifyText(ModifyEvent e) {
+                       ModifyEvent delayedEvent = null;
+                       synchronized (lock) {
+                               if (delayedModifyListener != null) {
+                                       Event tmpEvent = new Event();
+                                       tmpEvent.widget = text;
+                                       tmpEvent.display = e.display;
+                                       tmpEvent.data = e.data;
+                                       tmpEvent.time = e.time;
+                                       delayedEvent = new ModifyEvent(tmpEvent);
+                               }
+                       }
+                       final ModifyEvent timerModifyEvent = delayedEvent;
+
+                       synchronized (timer) {
+                               if (timer.timerTask != null) {
+                                       timer.timerTask.cancel();
+                                       timer.timerTask = null;
+                               }
+
+                               if (delayedEvent != null) {
+                                       timer.timerTask = new TimerTask() {
+                                               public void run() {
+                                                       synchronized (lock) {
+                                                               delayedModifyListener.modifyText(timerModifyEvent);
+                                                               // Bad approach: it is not a good idea to put a
+                                                               // display.asyncExec in a lock...
+                                                               // DelayedText.this.getDisplay().asyncExec(new
+                                                               // Runnable() {
+                                                               // @Override
+                                                               // public void run() {
+                                                               // delayedModifyListener.modifyText(timerModifyEvent);
+                                                               // }
+                                                               // }
+                                                               // );
+                                                       }
+                                                       synchronized (timer) {
+                                                               timer.timerTask = null;
+                                                       }
+                                               }
+                                       };
+                                       timer.schedule(timer.timerTask, delay);
+                                       if (pushSession != null)
+                                               pushSession.start();
+                               }
+                       }
+               };
+       };
+
+       public DelayedText(Composite parent, int style, int delayInMs) {
+               // super(parent, style);
+               text = new Text(parent, style);
+               this.delay = delayInMs;
+               text.addModifyListener(modifyListener);
+       }
+
+       /**
+        * Adds a modify text listener that will be delayed. If another Modify event
+        * happens during the waiting delay, the older event will be canceled an a new
+        * one will be scheduled after another new delay.
+        */
+       public void addDelayedModifyListener(ServerPushSession pushSession, ModifyListener listener) {
+               synchronized (lock) {
+                       delayedModifyListener = listener;
+                       this.pushSession = pushSession;
+               }
+       }
+
+       public void removeDelayedModifyListener(ModifyListener listener) {
+               synchronized (lock) {
+                       delayedModifyListener = null;
+                       pushSession = null;
+               }
+       }
+
+       private class MyTimer extends Timer {
+               private TimerTask timerTask = null;
+
+               public MyTimer(String name) {
+                       super(name);
+               }
+       }
+
+       public Text getText() {
+               return text;
+       }
+
+       public void close() {
+               if (pushSession != null)
+                       pushSession.stop();
+               if (timer != null)
+                       timer.cancel();
+       };
+
+}
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644 (file)
index 0000000..c26b10f
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.suite</groupId>
+               <artifactId>argeo-suite</artifactId>
+               <version>2.1.18-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>core</artifactId>
+       <name>Argeo Core Components</name>
+       <packaging>pom</packaging>
+       <modules>
+               <!-- Entity Framework -->
+               <module>org.argeo.entity.api</module>
+               <module>org.argeo.entity.core</module>
+               <module>org.argeo.entity.ui</module>
+
+               <!-- Argeo Suite -->
+               <module>org.argeo.suite.core</module>
+               <module>org.argeo.suite.ui</module>
+               <module>org.argeo.suite.ui.rap</module>
+               <module>org.argeo.suite.theme.default</module>
+       </modules>
+</project>
diff --git a/org.argeo.entity.api/.classpath b/org.argeo.entity.api/.classpath
deleted file mode 100644 (file)
index e801ebf..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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>
diff --git a/org.argeo.entity.api/.gitignore b/org.argeo.entity.api/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.entity.api/.project b/org.argeo.entity.api/.project
deleted file mode 100644 (file)
index 1269cce..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.entity.api</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/org.argeo.entity.api/META-INF/.gitignore b/org.argeo.entity.api/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.entity.api/bnd.bnd b/org.argeo.entity.api/bnd.bnd
deleted file mode 100644 (file)
index ab46172..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Require-Capability:\
-cms.datamodel;filter:="(name=jcrx)"
-
-Provide-Capability:\
-cms.datamodel; name=entity; cnd=/org/argeo/entity/entity.cnd
diff --git a/org.argeo.entity.api/build.properties b/org.argeo.entity.api/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/org.argeo.entity.api/pom.xml b/org.argeo.entity.api/pom.xml
deleted file mode 100644 (file)
index 8627265..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <groupId>org.argeo.suite</groupId>
-               <artifactId>argeo-suite</artifactId>
-               <version>2.1.18-SNAPSHOT</version>
-               <relativePath>..</relativePath>
-       </parent>
-       <artifactId>org.argeo.entity.api</artifactId>
-       <name>Entity API</name>
-       <packaging>jar</packaging>
-       <dependencies>
-               <!-- Argeo Commons -->
-               <dependency>
-                       <groupId>org.argeo.commons</groupId>
-                       <artifactId>org.argeo.enterprise</artifactId>
-                       <version>${version.argeo-commons}</version>
-               </dependency>
-       </dependencies>
-</project>
diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java b/org.argeo.entity.api/src/org/argeo/entity/EntityConstants.java
deleted file mode 100644 (file)
index f7a2de8..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.argeo.entity;
-
-/** Constant related to entities, typically used in an OSGi context. */
-public interface EntityConstants {
-       final static String TYPE = "entity.type";
-       final static String DEFAULT_EDITORY_ID = "entity.defaultEditorId";
-
-}
diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java b/org.argeo.entity.api/src/org/argeo/entity/EntityDefinition.java
deleted file mode 100644 (file)
index 08aff61..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.argeo.entity;
-
-import javax.jcr.Node;
-
-/** The definition of an entity, a composite configurable data structure. */
-public interface EntityDefinition {
-       String getEditorId(Node entity);
-
-       String getType();
-}
diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java b/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java
deleted file mode 100644 (file)
index ede7447..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.argeo.entity;
-
-import org.argeo.naming.LdapAttrs;
-
-/** Constants used to name entity structures. */
-public interface EntityNames {
-       @Deprecated
-       final String FORM_BASE = "form";
-       final String SUBMISSIONS_BASE = "submissions";
-       @Deprecated
-       final String TERM = "term";
-       final String NAME = "name";
-
-//     final String ENTITY_DEFINITIONS_PATH = "/entity";
-       @Deprecated
-       final String TYPOLOGIES_PATH = "/" + TERM;
-       /** Administrative units. */
-       final String ADM = "adm";
-
-       final String ENTITY_TYPE = "entity:type";
-       // final String ENTITY_UID = "entity:uid";
-       // final String ENTITY_NAME = "entity:name";
-
-       // GENERIC CONCEPTS
-       /** The language which is relevant. */
-       final String XML_LANG = "xml:lang";
-       /** The date which is relevant. */
-       final String ENTITY_DATE = "entity:date";
-       @Deprecated
-       final String ENTITY_RELATED_TO = "entity:relatedTo";
-
-       // DEFAULT FOLDER NAMES
-       final String MEDIA = "media";
-       final String FILES = "files";
-
-       // LDAP-LIKE ENTITIES
-       @Deprecated
-       final String DISPLAY_NAME = LdapAttrs.displayName.property();
-       // Persons
-       @Deprecated
-       final String GIVEN_NAME = LdapAttrs.givenName.property();
-       @Deprecated
-       final String SURNAME = LdapAttrs.sn.property();
-       @Deprecated
-       final String EMAIL = LdapAttrs.mail.property();
-       @Deprecated
-       final String OU = LdapAttrs.ou.property();
-
-       // WGS84
-       final String GEO_LAT = "geo:lat";
-       final String GEO_LONG = "geo:long";
-       final String GEO_ALT = "geo:alt";
-
-       // SVG
-       final String SVG_WIDTH = "svg:width";
-       final String SVG_HEIGHT = "svg:height";
-       final String SVG_LENGTH = "svg:length";
-       final String SVG_UNIT = "svg:unit";
-       final String SVG_DUR = "svg:dur";
-       final String SVG_DIRECTION = "svg:direction";
-}
diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityType.java b/org.argeo.entity.api/src/org/argeo/entity/EntityType.java
deleted file mode 100644 (file)
index ecd6330..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.argeo.entity;
-
-/** Types related to entities. */
-public enum EntityType implements JcrName {
-       // entity
-       entity, local, relatedTo,
-       // typology
-       typologies, terms, term,
-       // form
-       form, formSet, formSubmission,
-       // graphics
-       box,
-       // geography
-       geopoint, bearing,
-       // ldap
-       person, user;
-
-       @Override
-       public String getPrefix() {
-               return prefix();
-       }
-
-       public static String prefix() {
-               return "entity";
-       }
-
-       public String basePath() {
-               return '/' + name();
-       }
-
-       @Override
-       public String getNamespace() {
-               return namespace();
-       }
-
-       public static String namespace() {
-               return "http://www.argeo.org/ns/entity";
-       }
-
-}
diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java b/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java
deleted file mode 100644 (file)
index ef35147..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.argeo.entity;
-
-/** Types related to entities. */
-@Deprecated
-public interface EntityTypes {
-       final static String ENTITY_ENTITY = "entity:entity";
-       final static String ENTITY_DEFINITION = "entity:definition";
-
-       final static String ENTITY_PERSON = "entity:person";
-}
diff --git a/org.argeo.entity.api/src/org/argeo/entity/JcrName.java b/org.argeo.entity.api/src/org/argeo/entity/JcrName.java
deleted file mode 100644 (file)
index 322c42e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.argeo.entity;
-
-import java.util.function.Supplier;
-
-/** Can be applied to {@link Enum}s in order to generate prefixed names. */
-@FunctionalInterface
-public interface JcrName extends Supplier<String> {
-       String name();
-
-       default String getPrefix() {
-               return null;
-       }
-
-       default String getNamespace() {
-               return null;
-       }
-
-       @Override
-       default String get() {
-               String prefix = getPrefix();
-               return prefix != null ? prefix + ":" + name() : name();
-       }
-
-       default String withNamespace() {
-               String namespace = getNamespace();
-               if (namespace == null)
-                       throw new UnsupportedOperationException("No namespace is specified for " + getClass());
-               return "{" + namespace + "}" + name();
-       }
-}
diff --git a/org.argeo.entity.api/src/org/argeo/entity/TermsManager.java b/org.argeo.entity.api/src/org/argeo/entity/TermsManager.java
deleted file mode 100644 (file)
index a2b5951..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.argeo.entity;
-
-import java.util.List;
-
-/** Provides optimised access and utilities around terms typologies. */
-public interface TermsManager {
-       List<String> listAllTerms(String typology);
-}
diff --git a/org.argeo.entity.api/src/org/argeo/entity/entity.cnd b/org.argeo.entity.api/src/org/argeo/entity/entity.cnd
deleted file mode 100644 (file)
index b30657d..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// Standard namespaces
-<xsd = "http://www.w3.org/2001/XMLSchema">
-<h = "http://www.w3.org/1999/xhtml">
-// see https://www.w3.org/2003/01/geo/
-<geo = "http://www.w3.org/2003/01/geo/wgs84_pos#">
-<svg = "http://www.w3.org/2000/svg">
-
-<ldap = "http://www.argeo.org/ns/ldap">
-<entity = 'http://www.argeo.org/ns/entity'>
-
-[entity:entity] > mix:created, mix:referenceable
-mixin
-
-[entity:local] > entity:entity
-mixin
-- entity:type (String) m
-
-[entity:relatedTo]
-mixin
-+ entity:relatedTo (nt:address) *
-
-//
-// ENTITY DEFINITION
-//
-//[entity:definition] > entity:composite, mix:created, mix:lastModified, mix:referenceable
-//- entity:type (String) multiple
-
-//[entity:part]
-
-//[entity:reference]
-
-//[entity:composite]
-//orderable
-//+ * (entity:part)
-//+ * (entity:reference)
-//+ * (entity:composite)
-
-//
-// TYPOLOGY
-//
-[entity:typologies]
-+ * (entity:terms) = entity:terms
-
-[entity:term]
-orderable
-- name (NAME) m
-- * (*)
-+ term (entity:term) = entity:term *
-
-[entity:terms] > mix:referenceable
-orderable
-+ term (entity:term) = entity:term *
-
-//
-// FORM
-//
-[entity:form]
-mixin
-
-[entity:formSubmission]
-mixin
-
-[entity:formSet] > mix:title
-mixin
-
-//
-// GRAPHICS
-//
-[entity:box]
-mixin
-- svg:width (DOUBLE)
-- svg:height (DOUBLE)
-- svg:length (DOUBLE)
-- svg:unit (STRING)
-- svg:dur (DOUBLE)
-
-// LDAP-LIKE ENTITIES
-// A real person
-[entity:person] > entity:entity
-mixin
-- ldap:sn (String)
-- ldap:givenName (String)
-- ldap:mail (String) *
-
-[entity:user] > entity:person
-mixin
-- ldap:distinguishedName (String)
-- ldap:uid (String)
-
-// GEOGRAPHY
-[entity:geopoint]
-mixin
-- geo:long (DOUBLE)
-- geo:lat (DOUBLE)
-- geo:alt (DOUBLE)
-
-[entity:bearing]
-mixin
-- svg:direction (DOUBLE)
diff --git a/org.argeo.entity.core/.classpath b/org.argeo.entity.core/.classpath
deleted file mode 100644 (file)
index e801ebf..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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>
diff --git a/org.argeo.entity.core/.gitignore b/org.argeo.entity.core/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.entity.core/.project b/org.argeo.entity.core/.project
deleted file mode 100644 (file)
index 1acff84..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.entity.core</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>
diff --git a/org.argeo.entity.core/META-INF/.gitignore b/org.argeo.entity.core/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.entity.core/bnd.bnd b/org.argeo.entity.core/bnd.bnd
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/org.argeo.entity.core/build.properties b/org.argeo.entity.core/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/org.argeo.entity.core/pom.xml b/org.argeo.entity.core/pom.xml
deleted file mode 100644 (file)
index 089d049..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <groupId>org.argeo.suite</groupId>
-               <artifactId>argeo-suite</artifactId>
-               <version>2.1.18-SNAPSHOT</version>
-               <relativePath>..</relativePath>
-       </parent>
-       <artifactId>org.argeo.entity.core</artifactId>
-       <name>Entity Reference Implementation</name>
-       <packaging>jar</packaging>
-       <dependencies>
-               <dependency>
-                       <groupId>org.argeo.suite</groupId>
-                       <artifactId>org.argeo.entity.api</artifactId>
-                       <version>2.1.18-SNAPSHOT</version>
-               </dependency>
-
-               <!-- Argeo Commons -->
-               <dependency>
-                       <groupId>org.argeo.commons</groupId>
-                       <artifactId>org.argeo.cms</artifactId>
-                       <version>${version.argeo-commons}</version>
-               </dependency>
-       </dependencies>
-</project>
diff --git a/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java b/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java
deleted file mode 100644 (file)
index 7fd26d1..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.argeo.entity.core;
-
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.NodeUtils;
-import org.argeo.entity.EntityConstants;
-import org.argeo.entity.EntityDefinition;
-import org.argeo.jcr.Jcr;
-import org.osgi.framework.BundleContext;
-
-/** An entity definition based on a JCR data structure. */
-public class JcrEntityDefinition implements EntityDefinition {
-       private Repository repository;
-
-       private String type;
-       private String defaultEditoryId;
-
-       public void init(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
-               Session adminSession = NodeUtils.openDataAdminSession(repository, null);
-               try {
-                       type = properties.get(EntityConstants.TYPE);
-                       if (type == null)
-                               throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set.");
-                       defaultEditoryId = properties.get(EntityConstants.DEFAULT_EDITORY_ID);
-//                     String definitionPath = EntityNames.ENTITY_DEFINITIONS_PATH + '/' + type;
-//                     if (!adminSession.itemExists(definitionPath)) {
-//                             Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath, EntityTypes.ENTITY_DEFINITION);
-////                           entityDefinition.addMixin(EntityTypes.ENTITY_DEFINITION);
-//                             adminSession.save();
-//                     }
-                       initJcr(adminSession);
-               } finally {
-                       Jcr.logout(adminSession);
-               }
-       }
-
-       /** To be overridden in order to perform additional initialisations. */
-       protected void initJcr(Session adminSession) throws RepositoryException {
-
-       }
-
-       public void destroy(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
-
-       }
-
-       @Override
-       public String getEditorId(Node entity) {
-               return defaultEditoryId;
-       }
-
-       @Override
-       public String getType() {
-               return type;
-       }
-
-       protected Repository getRepository() {
-               return repository;
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-       public String toString() {
-               return "Entity Definition " + getType();
-       }
-
-}
diff --git a/org.argeo.entity.ui/.classpath b/org.argeo.entity.ui/.classpath
deleted file mode 100644 (file)
index e801ebf..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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>
diff --git a/org.argeo.entity.ui/.gitignore b/org.argeo.entity.ui/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.entity.ui/.project b/org.argeo.entity.ui/.project
deleted file mode 100644 (file)
index a1f7177..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.entity.ui</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>
diff --git a/org.argeo.entity.ui/META-INF/.gitignore b/org.argeo.entity.ui/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.entity.ui/bnd.bnd b/org.argeo.entity.ui/bnd.bnd
deleted file mode 100644 (file)
index e7cd4cb..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Import-Package:\
-org.eclipse.swt,\
-*
\ No newline at end of file
diff --git a/org.argeo.entity.ui/build.properties b/org.argeo.entity.ui/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/org.argeo.entity.ui/pom.xml b/org.argeo.entity.ui/pom.xml
deleted file mode 100644 (file)
index f2399cf..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <groupId>org.argeo.suite</groupId>
-               <artifactId>argeo-suite</artifactId>
-               <version>2.1.18-SNAPSHOT</version>
-               <relativePath>..</relativePath>
-       </parent>
-       <artifactId>org.argeo.entity.ui</artifactId>
-       <name>Entity UI</name>
-       <packaging>jar</packaging>
-       <dependencies>
-               <dependency>
-                       <groupId>org.argeo.suite</groupId>
-                       <artifactId>org.argeo.entity.core</artifactId>
-                       <version>2.1.18-SNAPSHOT</version>
-               </dependency>
-
-               <!-- Argeo Commons -->
-               <dependency>
-                       <groupId>org.argeo.commons</groupId>
-                       <artifactId>org.argeo.cms.ui</artifactId>
-                       <version>${version.argeo-commons}</version>
-               </dependency>
-
-               <!-- Specific -->
-               <dependency>
-                       <groupId>org.argeo.commons</groupId>
-                       <artifactId>org.argeo.eclipse.ui.rap</artifactId>
-                       <version>2.1.91-SNAPSHOT</version>
-                       <scope>provided</scope>
-               </dependency>
-
-               <!-- Eclipse E4 -->
-               <dependency>
-                       <groupId>org.argeo.tp</groupId>
-                       <artifactId>argeo-tp-rap-e4</artifactId>
-                       <version>${version.argeo-tp}</version>
-                       <type>pom</type>
-                       <scope>provided</scope>
-               </dependency>
-       </dependencies>
-</project>
diff --git a/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java b/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java
deleted file mode 100644 (file)
index a7f240f..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.argeo.entity.ui.forms;
-
-import javax.jcr.Item;
-
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.util.CmsIcon;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.widgets.ContextOverlay;
-import org.argeo.cms.ui.widgets.StyledControl;
-import org.argeo.entity.TermsManager;
-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.Label;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** Common logic between single and mutliple terms editable part. */
-public abstract class AbstractTermsPart extends StyledControl implements EditablePart {
-       private static final long serialVersionUID = -5497097995341927710L;
-       protected final TermsManager termsManager;
-       protected final String typology;
-
-       protected final boolean editable;
-
-       private CmsIcon deleteIcon;
-       private CmsIcon addIcon;
-       private CmsIcon cancelIcon;
-
-       private Color highlightColor;
-       private Composite highlight;
-
-       protected final CmsTheme theme;
-
-       public AbstractTermsPart(Composite parent, int style, Item item, TermsManager termsManager,
-                       String typology) {
-               super(parent, style, item);
-               this.termsManager = termsManager;
-               this.typology = typology;
-               this.theme = CmsTheme.getCmsTheme(parent);
-               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
-               highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
-       }
-
-       protected void createHighlight(Composite block) {
-               highlight = new Composite(block, SWT.NONE);
-               highlight.setBackground(highlightColor);
-               GridData highlightGd = new GridData(SWT.FILL, SWT.FILL, false, false);
-               highlightGd.widthHint = 5;
-               highlightGd.heightHint = 3;
-               highlight.setLayoutData(highlightGd);
-
-       }
-
-       protected String getTermLabel(String name) {
-               return name;
-       }
-
-       protected abstract void refresh(ContextOverlay contextArea, String filter, Text txt);
-
-       protected boolean isTermSelectable(String term) {
-               return true;
-       }
-
-       protected void processTermListLabel(String term, Label label) {
-
-       }
-
-       //
-       // STYLING
-       //
-       public void setDeleteIcon(CmsIcon deleteIcon) {
-               this.deleteIcon = deleteIcon;
-       }
-
-       public void setAddIcon(CmsIcon addIcon) {
-               this.addIcon = addIcon;
-       }
-
-       public void setCancelIcon(CmsIcon cancelIcon) {
-               this.cancelIcon = cancelIcon;
-       }
-
-       protected TermsManager getTermsManager() {
-               return termsManager;
-       }
-
-       protected void styleDelete(ToolItem deleteItem) {
-               if (deleteIcon != null)
-                       deleteItem.setImage(deleteIcon.getSmallIcon(theme));
-               else
-                       deleteItem.setText("-");
-       }
-
-       protected void styleCancel(ToolItem cancelItem) {
-               if (cancelIcon != null)
-                       cancelItem.setImage(cancelIcon.getSmallIcon(theme));
-               else
-                       cancelItem.setText("X");
-       }
-
-       protected void styleAdd(ToolItem addItem) {
-               if (addIcon != null)
-                       addItem.setImage(addIcon.getSmallIcon(theme));
-               else
-                       addItem.setText("+");
-       }
-}
diff --git a/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java b/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java
deleted file mode 100644 (file)
index 1a12e90..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.argeo.entity.ui.forms;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Item;
-
-import org.argeo.cms.ui.forms.FormStyle;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.widgets.ContextOverlay;
-import org.argeo.eclipse.ui.MouseDoubleClick;
-import org.argeo.eclipse.ui.MouseDown;
-import org.argeo.eclipse.ui.Selected;
-import org.argeo.entity.TermsManager;
-import org.argeo.jcr.Jcr;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** {@link EditablePart} for multiple terms. */
-public class MultiTermsPart extends AbstractTermsPart {
-       private static final long serialVersionUID = -4961135649177920808L;
-
-       public MultiTermsPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
-               super(parent, style, item, termsManager, typology);
-       }
-
-       @Override
-       protected Control createControl(Composite box, String style) {
-               Composite placeholder = new Composite(box, SWT.NONE);
-               RowLayout rl = new RowLayout(SWT.HORIZONTAL | SWT.WRAP);
-               placeholder.setLayout(rl);
-               List<String> currentValue = Jcr.getMultiple(getNode(), typology);
-               if (currentValue != null && !currentValue.isEmpty())
-                       for (String value : currentValue) {
-                               Composite block = new Composite(placeholder, SWT.NONE);
-                               block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
-                               Label lbl = new Label(block, SWT.SINGLE);
-                               String display = getTermLabel(value);
-                               lbl.setText(display);
-                               CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
-                               if (editable)
-                                       lbl.addMouseListener((MouseDoubleClick) (e) -> {
-                                               startEditing();
-                                       });
-                               if (isEditing()) {
-                                       ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
-                                       ToolItem deleteItem = new ToolItem(toolBar, SWT.FLAT);
-                                       styleDelete(deleteItem);
-                                       deleteItem.addSelectionListener((Selected) (e) -> {
-                                               // we retrieve them again here because they may have changed
-                                               List<String> curr = Jcr.getMultiple(getNode(), typology);
-                                               List<String> newValue = new ArrayList<>();
-                                               for (String v : curr) {
-                                                       if (!v.equals(value))
-                                                               newValue.add(v);
-                                               }
-                                               Jcr.set(getNode(), typology, newValue);
-                                               Jcr.save(getNode());
-                                               block.dispose();
-                                               layout(true, true);
-                                       });
-
-                               }
-                       }
-               else {// empty
-                       if (editable && !isEditing()) {
-                               ToolBar toolBar = new ToolBar(placeholder, SWT.HORIZONTAL);
-                               ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
-                               styleAdd(addItem);
-                               addItem.addSelectionListener((Selected) (e) -> {
-                                       startEditing();
-                               });
-                       }
-               }
-
-               if (isEditing()) {
-                       Composite block = new Composite(placeholder, SWT.NONE);
-                       block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
-
-                       createHighlight(block);
-
-                       Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
-                       txt.setLayoutData(CmsUiUtils.fillWidth());
-//                     txt.setMessage("[new]");
-
-                       CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
-
-                       ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
-                       ToolItem cancelItem = new ToolItem(toolBar, SWT.FLAT);
-                       styleCancel(cancelItem);
-                       cancelItem.addSelectionListener((Selected) (e) -> {
-                               stopEditing();
-                       });
-
-                       ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
-                               private static final long serialVersionUID = -7980078594405384874L;
-
-                               @Override
-                               protected void onHide() {
-                                       stopEditing();
-                               }
-                       };
-                       contextOverlay.setLayout(new GridLayout());
-                       // filter
-                       txt.addModifyListener((e) -> {
-                               String filter = txt.getText().toLowerCase();
-                               if ("".equals(filter.trim()))
-                                       filter = null;
-                               refresh(contextOverlay, filter, txt);
-                       });
-                       txt.addFocusListener(new FocusListener() {
-                               private static final long serialVersionUID = -6024501573409619949L;
-
-                               @Override
-                               public void focusLost(FocusEvent event) {
-//                                     if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
-//                                             getDisplay().asyncExec(() -> stopEditing());
-                               }
-
-                               @Override
-                               public void focusGained(FocusEvent event) {
-                                       // txt.setText("");
-                                       if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
-                                               refresh(contextOverlay, null, txt);
-                               }
-                       });
-                       layout(new Control[] { txt });
-                       // getDisplay().asyncExec(() -> txt.setFocus());
-               }
-               return placeholder;
-       }
-
-       @Override
-       protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
-               CmsUiUtils.clear(contextArea);
-               List<String> terms = termsManager.listAllTerms(typology);
-               List<String> currentValue = Jcr.getMultiple(getNode(), typology);
-               terms: for (String term : terms) {
-                       if (currentValue != null && currentValue.contains(term))
-                               continue terms;
-                       String display = getTermLabel(term);
-                       if (filter != null && !display.toLowerCase().contains(filter))
-                               continue terms;
-                       Label termL = new Label(contextArea, SWT.WRAP);
-                       termL.setText(display);
-                       processTermListLabel(term, termL);
-                       if (isTermSelectable(term))
-                               termL.addMouseListener((MouseDown) (e) -> {
-                                       List<String> newValue = new ArrayList<>();
-                                       List<String> curr = Jcr.getMultiple(getNode(), typology);
-                                       if (currentValue != null)
-                                               newValue.addAll(curr);
-                                       newValue.add(term);
-                                       Jcr.set(getNode(), typology, newValue);
-                                       Jcr.save(getNode());
-                                       contextArea.hide();
-                                       stopEditing();
-                               });
-               }
-               contextArea.show();
-       }
-
-}
diff --git a/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java b/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java
deleted file mode 100644 (file)
index e9fad04..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-package org.argeo.entity.ui.forms;
-
-import java.util.List;
-
-import javax.jcr.Item;
-
-import org.argeo.cms.ui.forms.FormStyle;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.widgets.ContextOverlay;
-import org.argeo.eclipse.ui.MouseDoubleClick;
-import org.argeo.eclipse.ui.MouseDown;
-import org.argeo.eclipse.ui.Selected;
-import org.argeo.entity.TermsManager;
-import org.argeo.jcr.Jcr;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-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;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** {@link EditablePart} for terms. */
-public class SingleTermPart extends AbstractTermsPart {
-       private static final long serialVersionUID = -4961135649177920808L;
-
-       public SingleTermPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
-               super(parent, style, item, termsManager, typology);
-       }
-
-       @Override
-       protected Control createControl(Composite box, String style) {
-               if (isEditing()) {
-                       Composite block = new Composite(box, SWT.NONE);
-                       block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
-
-                       createHighlight(block);
-
-                       Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
-                       CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
-
-                       ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
-                       ToolItem deleteItem = new ToolItem(toolBar, SWT.PUSH);
-                       styleDelete(deleteItem);
-                       deleteItem.addSelectionListener((Selected) (e) -> {
-                               Jcr.set(getNode(), typology, null);
-                               Jcr.save(getNode());
-                               stopEditing();
-                       });
-                       ToolItem cancelItem = new ToolItem(toolBar, SWT.PUSH);
-                       styleCancel(cancelItem);
-                       cancelItem.addSelectionListener((Selected) (e) -> {
-                               stopEditing();
-                       });
-
-                       ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
-                               private static final long serialVersionUID = -7980078594405384874L;
-
-                               @Override
-                               protected void onHide() {
-                                       stopEditing();
-                               }
-                       };
-                       contextOverlay.setLayout(new GridLayout());
-                       // filter
-                       txt.addModifyListener((e) -> {
-                               String filter = txt.getText().toLowerCase();
-                               if ("".equals(filter.trim()))
-                                       filter = null;
-                               refresh(contextOverlay, filter, txt);
-                       });
-                       txt.addFocusListener(new FocusListener() {
-                               private static final long serialVersionUID = -6024501573409619949L;
-
-                               @Override
-                               public void focusLost(FocusEvent event) {
-//                                     if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
-//                                             getDisplay().asyncExec(() -> stopEditing());
-                               }
-
-                               @Override
-                               public void focusGained(FocusEvent event) {
-                                       // txt.setText("");
-                                       if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
-                                               refresh(contextOverlay, null, txt);
-                               }
-                       });
-                       layout(new Control[] { block });
-                       getDisplay().asyncExec(() -> txt.setFocus());
-                       return block;
-               } else {
-                       Composite block = new Composite(box, SWT.NONE);
-                       block.setLayout(CmsUiUtils.noSpaceGridLayout(2));
-                       String currentValue = Jcr.get(getNode(), typology);
-                       if (currentValue != null) {
-                               Label lbl = new Label(block, SWT.SINGLE);
-                               String display = getTermLabel(currentValue);
-                               lbl.setText(display);
-                               CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
-
-                               lbl.addMouseListener((MouseDoubleClick) (e) -> {
-                                       startEditing();
-                               });
-                       } else {
-                               ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
-                               ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
-                               styleAdd(addItem);
-                               addItem.addSelectionListener((Selected) (e) -> {
-                                       startEditing();
-                               });
-                       }
-                       return block;
-               }
-       }
-
-       @Override
-       protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
-               CmsUiUtils.clear(contextArea);
-               List<String> terms = termsManager.listAllTerms(typology);
-               terms: for (String term : terms) {
-                       String display = getTermLabel(term);
-                       if (filter != null && !display.toLowerCase().contains(filter))
-                               continue terms;
-                       Label termL = new Label(contextArea, SWT.WRAP);
-                       termL.setText(display);
-                       processTermListLabel(term, termL);
-                       if (isTermSelectable(term))
-                               termL.addMouseListener((MouseDown) (e) -> {
-                                       Jcr.set(getNode(), typology, term);
-                                       Jcr.save(getNode());
-                                       contextArea.hide();
-                                       stopEditing();
-                               });
-               }
-               contextArea.show();
-               // txt.setFocus();
-       }
-
-}
diff --git a/org.argeo.suite.core/.classpath b/org.argeo.suite.core/.classpath
deleted file mode 100644 (file)
index e801ebf..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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>
diff --git a/org.argeo.suite.core/.gitignore b/org.argeo.suite.core/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.suite.core/.project b/org.argeo.suite.core/.project
deleted file mode 100644 (file)
index ab084af..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.suite.core</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>
diff --git a/org.argeo.suite.core/META-INF/.gitignore b/org.argeo.suite.core/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.suite.core/OSGI-INF/maintenanceService.xml b/org.argeo.suite.core/OSGI-INF/maintenanceService.xml
deleted file mode 100644 (file)
index 2d495c8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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="Suite Maintenance Service">
-   <implementation class="org.argeo.suite.core.SuiteMaintenanceService"/>
-   <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
-   <reference bind="setUserTransaction" cardinality="1..1" interface="javax.transaction.UserTransaction" name="UserTransaction" policy="static"/>
-   <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
-</scr:component>
diff --git a/org.argeo.suite.core/OSGI-INF/termsManager.xml b/org.argeo.suite.core/OSGI-INF/termsManager.xml
deleted file mode 100644 (file)
index 3e6d4c6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?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="Suite Terms Manager">
-   <implementation class="org.argeo.suite.core.SuiteTermsManager"/>
-   <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
-   <service>
-      <provide interface="org.argeo.entity.TermsManager"/>
-   </service>
-</scr:component>
diff --git a/org.argeo.suite.core/bnd.bnd b/org.argeo.suite.core/bnd.bnd
deleted file mode 100644 (file)
index 1b9efff..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Bundle-ActivationPolicy: lazy
-
-Service-Component:\
-OSGI-INF/termsManager.xml,\
-OSGI-INF/maintenanceService.xml
-
-Import-Package:\
-javax.transaction,\
-org.osgi.service.useradmin,\
-javax.jcr.nodetype,\
-javax.jcr.security,\
-org.argeo.api,\
-org.argeo.entity,\
-*
\ No newline at end of file
diff --git a/org.argeo.suite.core/build.properties b/org.argeo.suite.core/build.properties
deleted file mode 100644 (file)
index 6210e84..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-output.. = bin/
-bin.includes = META-INF/,\
-               .,\
-               OSGI-INF/
-source.. = src/
diff --git a/org.argeo.suite.core/pom.xml b/org.argeo.suite.core/pom.xml
deleted file mode 100644 (file)
index 2ed110f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <groupId>org.argeo.suite</groupId>
-               <artifactId>argeo-suite</artifactId>
-               <version>2.1.18-SNAPSHOT</version>
-               <relativePath>..</relativePath>
-       </parent>
-       <artifactId>org.argeo.suite.core</artifactId>
-       <name>Suite Core</name>
-       <packaging>jar</packaging>
-       <dependencies>
-               <dependency>
-                       <groupId>org.argeo.suite</groupId>
-                       <artifactId>org.argeo.entity.core</artifactId>
-                       <version>2.1.18-SNAPSHOT</version>
-               </dependency>
-
-               <!-- Argeo Commons -->
-               <dependency>
-                       <groupId>org.argeo.commons</groupId>
-                       <artifactId>org.argeo.cms</artifactId>
-                       <version>${version.argeo-commons}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.argeo.commons</groupId>
-                       <artifactId>org.argeo.maintenance</artifactId>
-                       <version>${version.argeo-commons}</version>
-               </dependency>
-       </dependencies>
-</project>
diff --git a/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java b/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java
deleted file mode 100644 (file)
index bfba46e..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.argeo.suite;
-
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A container for an object whose relevance can be ranked. Typically used in an
- * OSGi context with the service.ranking property.
- */
-public class RankedObject<T> {
-       private final static Log log = LogFactory.getLog(RankedObject.class);
-
-       private final static String SERVICE_RANKING = "service.ranking";
-//     private final static String SERVICE_ID = "service.id";
-
-       private T object;
-       private Map<String, Object> properties;
-       private final Long rank;
-
-       public RankedObject(T object, Map<String, Object> properties) {
-               this(object, properties, extractRanking(properties));
-       }
-
-       public RankedObject(T object, Map<String, Object> properties, Long rank) {
-               super();
-               this.object = object;
-               this.properties = properties;
-               this.rank = rank;
-       }
-
-       private static Long extractRanking(Map<String, Object> properties) {
-               if (properties == null)
-                       return 0l;
-               if (properties.containsKey(SERVICE_RANKING))
-                       return Long.valueOf(properties.get(SERVICE_RANKING).toString());
-//             else if (properties.containsKey(SERVICE_ID))
-//                     return (Long) properties.get(SERVICE_ID);
-               else
-                       return 0l;
-       }
-
-       public T get() {
-               return object;
-       }
-
-       public Map<String, Object> getProperties() {
-               return properties;
-       }
-
-       public Long getRank() {
-               return rank;
-       }
-
-       @Override
-       public int hashCode() {
-               return object.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (!(obj instanceof RankedObject))
-                       return false;
-               RankedObject<?> other = (RankedObject<?>) obj;
-               return rank.equals(other.rank) && object.equals(other.object);
-       }
-
-       @Override
-       public String toString() {
-               return object.getClass().getName() + " with rank " + rank;
-       }
-
-       public static <K, T> RankedObject<T> putIfHigherRank(Map<K, RankedObject<T>> map, K key, T object,
-                       Map<String, Object> properties) {
-               RankedObject<T> rankedObject = new RankedObject<>(object, properties);
-               if (!map.containsKey(key)) {
-                       map.put(key, rankedObject);
-                       if (log.isTraceEnabled())
-                               log.trace(
-                                               "Added " + key + " as " + object.getClass().getName() + " with rank " + rankedObject.getRank());
-                       return rankedObject;
-               } else {
-                       RankedObject<T> current = map.get(key);
-                       if (current.getRank() <= rankedObject.getRank()) {
-                               map.put(key, rankedObject);
-                               if (log.isTraceEnabled())
-                                       log.trace("Replaced " + key + " by " + object.getClass().getName() + " with rank "
-                                                       + rankedObject.getRank());
-                               return rankedObject;
-                       } else {
-                               return current;
-                       }
-               }
-
-       }
-
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/RankingKey.java b/org.argeo.suite.core/src/org/argeo/suite/RankingKey.java
deleted file mode 100644 (file)
index e099195..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.argeo.suite;
-
-import java.util.Map;
-
-/**
- * Key used to classify and filter available components (typically provided by
- * OSGi services).
- */
-@Deprecated
-public class RankingKey implements Comparable<RankingKey> {
-       public final static String SERVICE_PID = "service.pid";
-       public final static String SERVICE_ID = "service.id";
-       public final static String SERVICE_RANKING = "service.ranking";
-       public final static String DATA_TYPE = "data.type";
-
-       private String pid;
-       private Integer ranking = 0;
-       private Long id = 0l;
-       private String dataType;
-       private String dataPath;
-
-       public RankingKey(String pid, Integer ranking, Long id, String dataType, String dataPath) {
-               super();
-               this.pid = pid;
-               this.ranking = ranking;
-               this.id = id;
-               this.dataType = dataType;
-               this.dataPath = dataPath;
-       }
-
-       public RankingKey(Map<String, Object> properties) {
-               this.pid = properties.containsKey(SERVICE_PID) ? properties.get(SERVICE_PID).toString() : null;
-               this.ranking = properties.containsKey(SERVICE_RANKING)
-                               ? Integer.parseInt(properties.get(SERVICE_RANKING).toString())
-                               : 0;
-               this.id = properties.containsKey(SERVICE_ID) ? (Long) properties.get(SERVICE_ID) : null;
-
-               // Argeo specific
-               this.dataType = properties.containsKey(DATA_TYPE) ? properties.get(DATA_TYPE).toString() : null;
-       }
-
-       @Override
-       public int hashCode() {
-               Integer result = 0;
-               if (pid != null)
-                       result = +pid.hashCode();
-               if (ranking != null)
-                       result = +ranking;
-               if (dataType != null)
-                       result = +dataType.hashCode();
-               return result;
-       }
-
-       @Override
-       protected Object clone() throws CloneNotSupportedException {
-               return new RankingKey(pid, ranking, id, dataType, dataPath);
-       }
-
-       @Override
-       public String toString() {
-               StringBuilder sb = new StringBuilder("");
-               if (pid != null)
-                       sb.append(pid);
-               if (ranking != null && ranking != 0)
-                       sb.append(' ').append(ranking);
-               if (dataType != null)
-                       sb.append(' ').append(dataType);
-               return sb.toString();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (!(obj instanceof RankingKey))
-                       return false;
-               RankingKey other = (RankingKey) obj;
-               return equalsOrBothNull(pid, other.pid) && equalsOrBothNull(ranking, other.ranking)
-                               && equalsOrBothNull(id, other.id) && equalsOrBothNull(dataType, other.dataType)
-                               && equalsOrBothNull(dataPath, other.dataPath);
-       }
-
-       @Override
-       public int compareTo(RankingKey o) {
-               if (pid != null && o.pid != null) {
-                       if (pid.equals(o.pid)) {
-                               if (ranking.equals(o.ranking))
-                                       if (id != null && o.id != null)
-                                               return id.compareTo(o.id);
-                                       else
-                                               return 0;
-                               else
-                                       return ranking.compareTo(o.ranking);
-                       } else {
-                               return pid.compareTo(o.pid);
-                       }
-
-               } else {
-                       if (dataType != null && o.dataType != null) {
-                               if (dataType.equals(o.dataType)) {
-                                       // TODO factorise
-                                       if (ranking.equals(o.ranking))
-                                               if (id != null && o.id != null)
-                                                       return id.compareTo(o.id);
-                                               else
-                                                       return 0;
-                                       else
-                                               return ranking.compareTo(o.ranking);
-                               } else {
-                                       return dataPath.compareTo(o.dataType);
-                               }
-                       }
-               }
-               return -1;
-       }
-
-       public String getPid() {
-               return pid;
-       }
-
-       public Integer getRanking() {
-               return ranking;
-       }
-
-       public Long getId() {
-               return id;
-       }
-
-       public String getDataType() {
-               return dataType;
-       }
-
-       public String getDataPath() {
-               return dataPath;
-       }
-
-       public static RankingKey minPid(String pid) {
-               return new RankingKey(pid, Integer.MIN_VALUE, null, null, null);
-       }
-
-       public static RankingKey maxPid(String pid) {
-               return new RankingKey(pid, Integer.MAX_VALUE, null, null, null);
-       }
-
-       public static RankingKey minDataType(String dataType) {
-               return new RankingKey(null, Integer.MIN_VALUE, null, dataType, null);
-       }
-
-       public static RankingKey maxDataType(String dataType) {
-               return new RankingKey(null, Integer.MAX_VALUE, null, dataType, null);
-       }
-
-       private static boolean equalsOrBothNull(Object o1, Object o2) {
-               if (o1 == null && o2 == null)
-                       return true;
-               if (o1 == null && o2 != null)
-                       return false;
-               if (o1 != null && o2 == null)
-                       return false;
-               return o2.equals(o1);
-       }
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java b/org.argeo.suite.core/src/org/argeo/suite/SuiteRole.java
deleted file mode 100644 (file)
index 382f50c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.suite;
-
-import org.argeo.api.NodeConstants;
-import org.argeo.naming.Distinguished;
-import org.argeo.naming.LdapAttrs;
-
-/** Office specific roles used in the code */
-public enum SuiteRole implements Distinguished {
-       coworker, manager;
-
-       public String getRolePrefix() {
-               return "org.argeo.suite";
-       }
-
-       public String dn() {
-               return new StringBuilder(LdapAttrs.cn.name()).append("=").append(getRolePrefix()).append(".").append(name())
-                               .append(",").append(NodeConstants.ROLES_BASEDN).toString();
-       }
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java b/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java
deleted file mode 100644 (file)
index e63b515..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-package org.argeo.suite;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.security.Privilege;
-import javax.naming.ldap.LdapName;
-import javax.security.auth.x500.X500Principal;
-
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.auth.CmsSession;
-import org.argeo.entity.EntityType;
-import org.argeo.jackrabbit.security.JackrabbitSecurityUtils;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.naming.LdapAttrs;
-
-/** Utilities around the Argeo Suite APIs. */
-public class SuiteUtils {
-
-       public static String getUserNodePath(LdapName userDn) {
-               String uid = userDn.getRdn(userDn.size() - 1).getValue().toString();
-               return EntityType.user.basePath() + '/' + uid;
-       }
-
-       public static Node getOrCreateUserNode(Session adminSession, LdapName userDn) {
-               try {
-                       Node usersBase = adminSession.getNode(EntityType.user.basePath());
-                       String uid = userDn.getRdn(userDn.size() - 1).getValue().toString();
-                       Node userNode;
-                       if (!usersBase.hasNode(uid)) {
-                               userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
-                               userNode.addMixin(EntityType.user.get());
-                               userNode.addMixin(NodeType.MIX_CREATED);
-                               userNode.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString());
-                               userNode.setProperty(LdapAttrs.uid.property(), uid);
-                               adminSession.save();
-                               JackrabbitSecurityUtils.denyPrivilege(adminSession, userNode.getPath(), SuiteRole.coworker.dn(),
-                                               Privilege.JCR_READ);
-                               JcrUtils.addPrivilege(adminSession, userNode.getPath(), new X500Principal(userDn.toString()).getName(),
-                                               Privilege.JCR_READ);
-                               JcrUtils.addPrivilege(adminSession, userNode.getPath(), NodeConstants.ROLE_USER_ADMIN,
-                                               Privilege.JCR_ALL);
-                       } else {
-                               userNode = usersBase.getNode(uid);
-                       }
-                       return userNode;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot create user node for " + userDn, e);
-               }
-       }
-
-       public static Node getCmsSessionNode(Session session, CmsSession cmsSession) {
-               try {
-                       return session.getNode(getUserNodePath(cmsSession.getUserDn()) + '/' + cmsSession.getUuid().toString());
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get session dir for " + cmsSession, e);
-               }
-       }
-
-       public static Node getOrCreateCmsSessionNode(Session adminSession, CmsSession cmsSession) {
-               try {
-                       LdapName userDn = cmsSession.getUserDn();
-//                     String uid = userDn.get(userDn.size() - 1);
-                       Node userNode = getOrCreateUserNode(adminSession, userDn);
-//                     if (!usersBase.hasNode(uid)) {
-//                             userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
-//                             userNode.addMixin(EntityType.user.get());
-//                             userNode.addMixin(NodeType.MIX_CREATED);
-//                             usersBase.setProperty(LdapAttrs.uid.property(), uid);
-//                             usersBase.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString());
-//                             adminSession.save();
-//                     } else {
-//                             userNode = usersBase.getNode(uid);
-//                     }
-                       String cmsSessionUuid = cmsSession.getUuid().toString();
-                       Node cmsSessionNode;
-                       if (!userNode.hasNode(cmsSessionUuid)) {
-                               cmsSessionNode = userNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED);
-                               cmsSessionNode.addMixin(NodeType.MIX_CREATED);
-                               adminSession.save();
-                               JcrUtils.addPrivilege(adminSession, cmsSessionNode.getPath(), cmsSession.getUserRole(),
-                                               Privilege.JCR_ALL);
-                       } else {
-                               cmsSessionNode = userNode.getNode(cmsSessionUuid);
-                       }
-                       return cmsSessionNode;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot create session dir for " + cmsSession, e);
-               }
-       }
-
-       /** Singleton. */
-       private SuiteUtils() {
-
-       }
-
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/CustomMaintenanceService.java b/org.argeo.suite.core/src/org/argeo/suite/core/CustomMaintenanceService.java
deleted file mode 100644 (file)
index b6e997a..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.argeo.suite.core;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.ItemExistsException;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.maintenance.AbstractMaintenanceService;
-
-/** Base for custom initialisations. */
-public abstract class CustomMaintenanceService extends AbstractMaintenanceService {
-       private final static Log log = LogFactory.getLog(AbstractMaintenanceService.class);
-
-       protected List<String> getTypologies() {
-               return new ArrayList<>();
-       }
-
-       protected String getTypologiesLoadBase() {
-               return "/sys/terms";
-       }
-
-       protected void loadTypologies(Node customBaseNode) throws RepositoryException, IOException {
-               List<String> typologies = getTypologies();
-               if (!typologies.isEmpty()) {
-                       Node termsBase = JcrUtils.getOrAdd(customBaseNode, EntityType.terms.name(), EntityType.typologies.get());
-                       for (String terms : typologies) {
-                               loadTerms(termsBase, terms);
-                       }
-                       termsBase.getSession().save();
-               }
-       }
-
-       protected void loadTerms(Node termsBase, String name) throws IOException, RepositoryException {
-               try {
-                       if (termsBase.hasNode(name))
-                               return;
-
-                       String termsLoadPath = getTypologiesLoadBase() + '/' + name + ".xml";
-                       URL termsUrl = getClass().getClassLoader().getResource(termsLoadPath);
-                       if (termsUrl == null)
-                               throw new IllegalArgumentException("Terms '" + name + "' not found.");
-                       try (InputStream in = termsUrl.openStream()) {
-                               termsBase.getSession().importXML(termsBase.getPath(), in,
-                                               ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-                       } catch (ItemExistsException e) {
-                               log.warn("Terms " + name + " exists with another UUID, removing it...");
-                               termsBase.getNode(name).remove();
-                               try (InputStream in = termsUrl.openStream()) {
-                                       termsBase.getSession().importXML(termsBase.getPath(), in,
-                                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-                               }
-                       }
-                       if (log.isDebugEnabled())
-                               log.debug("Terms '" + name + "' loaded.");
-                       termsBase.getSession().save();
-               } catch (RepositoryException | IOException e) {
-                       log.error("Cannot load terms '" + name + "': " + e.getMessage());
-                       throw e;
-               }
-       }
-
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java
deleted file mode 100644 (file)
index b217373..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.argeo.suite.core;
-
-import java.io.IOException;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.security.Privilege;
-
-import org.argeo.api.NodeConstants;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.maintenance.AbstractMaintenanceService;
-
-/** Initialises an Argeo Suite backend. */
-public class SuiteMaintenanceService extends AbstractMaintenanceService {
-
-       @Override
-       public boolean prepareJcrTree(Session adminSession) throws RepositoryException, IOException {
-               boolean modified = false;
-               Node rootNode = adminSession.getRootNode();
-               if (!rootNode.hasNode(EntityType.user.name())) {
-                       rootNode.addNode(EntityType.user.name(), NodeType.NT_UNSTRUCTURED);
-                       modified = true;
-               }
-               if (modified)
-                       adminSession.save();
-               return modified;
-       }
-
-       @Override
-       public void configurePrivileges(Session adminSession) throws RepositoryException {
-               JcrUtils.addPrivilege(adminSession, EntityType.user.basePath(), NodeConstants.ROLE_USER_ADMIN,
-                               Privilege.JCR_ALL);
-               //JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), Privilege.JCR_READ);
-       }
-
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java
deleted file mode 100644 (file)
index 0c03dc5..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.argeo.suite.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
- */
-class SuiteTerm {
-       private final String name;
-       private final String relativePath;
-       private final SuiteTypology typology;
-       private final String id;
-
-       private final SuiteTerm parentTerm;
-       private final List<SuiteTerm> subTerms = new ArrayList<>();
-
-       SuiteTerm(SuiteTypology typology, String relativePath, SuiteTerm parentTerm) {
-               this.typology = typology;
-               this.parentTerm = parentTerm;
-               this.relativePath = relativePath;
-               int index = relativePath.lastIndexOf('/');
-               if (index > 0) {
-                       this.name = relativePath.substring(index);
-               } else {
-                       this.name = relativePath;
-               }
-               id = typology.getName() + '/' + relativePath;
-       }
-
-       public String getName() {
-               return name;
-       }
-
-       public String getRelativePath() {
-               return relativePath;
-       }
-
-       SuiteTypology getTypology() {
-               return typology;
-       }
-
-       public String getId() {
-               return id;
-       }
-
-       List<SuiteTerm> getSubTerms() {
-               return subTerms;
-       }
-
-       SuiteTerm getParentTerm() {
-               return parentTerm;
-       }
-
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java
deleted file mode 100644 (file)
index 1362f94..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.argeo.suite.core;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.NodeConstants;
-import org.argeo.api.NodeUtils;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.entity.TermsManager;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-
-/** Argeo Suite implementation of terms manager. */
-public class SuiteTermsManager implements TermsManager {
-       private final Map<String, SuiteTerm> terms = new HashMap<>();
-       private final Map<String, SuiteTypology> typologies = new HashMap<>();
-
-       // JCR
-       private Repository repository;
-       private Session adminSession;
-
-       public void init() {
-               adminSession = NodeUtils.openDataAdminSession(repository, NodeConstants.SYS_WORKSPACE);
-       }
-
-       @Override
-       public List<String> listAllTerms(String typology) {
-               List<String> res = new ArrayList<>();
-               SuiteTypology t = getTypology(typology);
-               for (SuiteTerm term : t.getAllTerms()) {
-                       res.add(term.getId());
-               }
-               return res;
-       }
-
-       SuiteTypology getTypology(String typology) {
-               SuiteTypology t = typologies.get(typology);
-               if (t == null) {
-                       Node termsNode = Jcr.getNode(adminSession, "SELECT * FROM [{0}] WHERE NAME()=\"{1}\"",
-                                       EntityType.terms.get(), typology);
-                       if (termsNode == null)
-                               throw new IllegalArgumentException("Typology " + typology + " not found.");
-                       t = loadTypology(termsNode);
-               }
-               return t;
-       }
-
-       SuiteTypology loadTypology(Node termsNode) {
-               try {
-                       SuiteTypology typology = new SuiteTypology(termsNode);
-                       for (Node termNode : Jcr.iterate(termsNode.getNodes())) {
-                               if (termNode.isNodeType(EntityType.term.get())) {
-                                       SuiteTerm term = loadTerm(typology, termNode, null);
-                                       if (!term.getSubTerms().isEmpty())
-                                               typology.markNotFlat();
-                                       typology.getSubTerms().add(term);
-                               }
-                       }
-                       typologies.put(typology.getName(), typology);
-                       return typology;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot load typology from " + termsNode, e);
-               }
-       }
-
-       SuiteTerm loadTerm(SuiteTypology typology, Node termNode, SuiteTerm parentTerm) throws RepositoryException {
-               String name = termNode.getProperty(EntityNames.NAME).getString();
-               String relativePath = parentTerm == null ? name : parentTerm.getRelativePath() + '/' + name;
-               SuiteTerm term = new SuiteTerm(typology, relativePath, parentTerm);
-               terms.put(term.getId(), term);
-               for (Node subTermNode : Jcr.iterate(termNode.getNodes())) {
-                       if (termNode.isNodeType(EntityType.term.get())) {
-                               SuiteTerm subTerm = loadTerm(typology, subTermNode, term);
-                               term.getSubTerms().add(subTerm);
-                       }
-               }
-               return term;
-       }
-
-       public void destroy() {
-               Jcr.logout(adminSession);
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java
deleted file mode 100644 (file)
index e84066c..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.argeo.suite.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-
-import org.argeo.jcr.Jcr;
-
-/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
-class SuiteTypology {
-       private final String name;
-       private final Node node;
-       private boolean isFlat = true;
-
-       private final List<SuiteTerm> subTerms = new ArrayList<>();
-
-       public SuiteTypology(Node node) {
-               this.node = node;
-               this.name = Jcr.getName(this.node);
-       }
-
-       public String getName() {
-               return name;
-       }
-
-       public Node getNode() {
-               return node;
-       }
-
-       void markNotFlat() {
-               if (isFlat)
-                       isFlat = false;
-       }
-
-       public boolean isFlat() {
-               return isFlat;
-       }
-
-       public List<SuiteTerm> getSubTerms() {
-               return subTerms;
-       }
-
-       public List<SuiteTerm> getAllTerms() {
-               if (isFlat)
-                       return subTerms;
-               else {
-                       List<SuiteTerm> terms = new ArrayList<>();
-                       for (SuiteTerm subTerm : subTerms) {
-                               terms.add(subTerm);
-                               collectSubTerms(terms, subTerm);
-                       }
-                       return terms;
-               }
-       }
-
-       private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
-               for (SuiteTerm subTerm : term.getSubTerms()) {
-                       terms.add(subTerm);
-                       collectSubTerms(terms, subTerm);
-               }
-       }
-
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java b/org.argeo.suite.core/src/org/argeo/suite/library/DocxExtractor.java
deleted file mode 100644 (file)
index 53e73f3..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-package org.argeo.suite.library;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.argeo.util.DigestUtils;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-
-/** Parses a .docx document, trying its best to extract text and table data. */
-public class DocxExtractor {
-       final static String T = "t";
-       final static String TC = "tc";
-       final static String TR = "tr";
-       final static String TBL = "tbl";
-       final static String P = "p";
-       static boolean debug = false;
-
-       final static String PROOF_ERR = "proofErr";
-       final static String TYPE = "type";
-       final static String SPELL_START = "spellStart";
-       final static String SPELL_END = "spellEnd";
-
-       protected List<Tbl> tables = new ArrayList<>();
-       protected List<String> text = new ArrayList<>();
-       protected Map<String, byte[]> media = new TreeMap<>();
-       private Set<String> mediaDigests = new HashSet<>();
-
-       protected void processTextItem(List<String> lines, String str) {
-               lines.add(str);
-       }
-
-       protected boolean skipMedia(String digest) {
-               return false;
-       }
-
-       class DocxHandler extends DefaultHandler {
-
-               private StringBuilder buffer = new StringBuilder();
-               private Tbl currentTbl = null;
-
-               boolean inSpellErr = false;
-               boolean inParagraph = false;
-
-               @Override
-               public void startElement(String uri, String name, String qName, Attributes attributes) throws SAXException {
-                       // System.out.println(localName + " " + qName + " " + uri.hashCode());
-                       if (P.equals(name)) {
-                               if (debug && currentTbl == null)
-                                       System.out.println("# START PARA");
-                               inParagraph = true;
-                       } else if (PROOF_ERR.equals(name)) {
-                               String type = attributes.getValue(uri, TYPE);
-                               if (SPELL_START.equals(type))
-                                       inSpellErr = true;
-                               else if (SPELL_END.equals(type))
-                                       inSpellErr = false;
-
-                       } else if (TBL.equals(name)) {
-                               if (currentTbl != null) {
-                                       Tbl childTbl = new Tbl();
-                                       childTbl.parentTbl = currentTbl;
-                                       currentTbl = childTbl;
-                                       // throw new IllegalStateException("Already an active table");
-                               } else {
-                                       currentTbl = new Tbl();
-                               }
-                       }
-               }
-
-               @Override
-               public void endElement(String uri, String name, String qName) throws SAXException {
-                       if (name.equals(T)) {
-//                             if (inSpellErr) {
-//                                     // do not reset the buffer
-//                                     return;
-//                             }
-
-                               if (currentTbl != null) {
-                                       currentTbl.appendText(buffer.toString());
-                               } else {
-                                       String str = buffer.toString();
-                                       // replace NO-BREAK SPACE by regular space.
-                                       str = str.replace('\u00A0', ' ');
-                                       str = str.strip();
-                                       if (!"".equals(str)) {
-                                               processTextItem(text, str);
-                                       }
-                               }
-                       } else if (name.equals(P)) {
-                               if (debug && currentTbl == null)
-                                       System.out.println("# END PARA");
-                               if (currentTbl != null) {
-                                       currentTbl.currentRow.current.text.append('\n');
-                               } else {
-
-                               }
-                               inParagraph = false;
-                       } else if (name.equals(TC)) {
-                               if (currentTbl != null)
-                                       currentTbl.closeColumn();
-                       } else if (name.equals(TR)) {
-                               if (currentTbl != null)
-                                       currentTbl.closeRow();
-                       } else if (name.equals(TBL)) {
-                               if (currentTbl != null) {
-                                       tables.add(currentTbl);
-                                       if (currentTbl.parentTbl != null)
-                                               currentTbl = currentTbl.parentTbl;
-                                       else
-                                               currentTbl = null;
-                               } else {
-                                       throw new IllegalStateException("Closing a table while none was open.");
-                               }
-                       }
-                       // reset the buffer
-                       buffer.setLength(0);
-               }
-
-               @Override
-               public void characters(char[] ch, int start, int length) throws SAXException {
-                       buffer.append(ch, start, length);
-               }
-
-       }
-
-       public static class Tbl {
-               Tbl parentTbl = null;
-               Tr currentRow = new Tr();
-               List<Tr> rows = new ArrayList<>();
-
-               void appendText(String str) {
-                       currentRow.current.text.append(str);
-               }
-
-               void closeColumn() {
-                       currentRow.columns.add(currentRow.current);
-                       currentRow.current = new Tc();
-               }
-
-               void closeRow() {
-                       rows.add(currentRow);
-                       currentRow = new Tr();
-               }
-
-               public List<Tr> getRows() {
-                       return rows;
-               }
-
-               @Override
-               public String toString() {
-                       StringBuilder sb = new StringBuilder();
-                       for (Tr tr : rows) {
-                               String txt = tr.toString();
-                               sb.append(txt).append('\n');
-                       }
-                       return sb.toString();
-               }
-       }
-
-       public static class Tr {
-               Tc current = new Tc();
-               List<Tc> columns = new ArrayList<>();
-
-               @Override
-               public String toString() {
-                       StringBuilder sb = new StringBuilder();
-                       for (Tc tc : columns) {
-                               sb.append("\"").append(tc.toString()).append("\"").append(',');
-                       }
-                       return sb.toString();
-               }
-
-               public List<Tc> getColumns() {
-                       return columns;
-               }
-
-       }
-
-       public static class Tc {
-               StringBuilder text = new StringBuilder();
-
-               @Override
-               public String toString() {
-                       return text.toString().trim();
-               }
-
-       }
-
-       protected void parse(Reader in) {
-               try {
-                       SAXParserFactory spf = SAXParserFactory.newInstance();
-                       spf.setNamespaceAware(true);
-                       SAXParser saxParser = spf.newSAXParser();
-                       XMLReader xmlReader = saxParser.getXMLReader();
-                       xmlReader.setContentHandler(new DocxHandler());
-                       xmlReader.parse(new InputSource(in));
-               } catch (ParserConfigurationException | SAXException | IOException e) {
-                       throw new RuntimeException("Cannot parse document", e);
-               }
-       }
-
-       public List<String> getText() {
-               return text;
-       }
-
-       public List<Tbl> getTables() {
-               return tables;
-       }
-
-       public Map<String, byte[]> getMedia() {
-               return media;
-       }
-
-       public void load(ZipInputStream zIn) {
-               try {
-                       ZipEntry entry = null;
-                       while ((entry = zIn.getNextEntry()) != null) {
-                               if ("word/document.xml".equals(entry.getName())) {
-                                       try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-                                               byte[] buffer = new byte[2048];
-                                               int len = 0;
-                                               while ((len = zIn.read(buffer)) > 0) {
-                                                       out.write(buffer, 0, len);
-                                               }
-                                               try (Reader reader = new InputStreamReader(new ByteArrayInputStream(out.toByteArray()),
-                                                               StandardCharsets.UTF_8)) {
-                                                       parse(reader);
-                                               }
-                                       }
-                               } else if (entry.getName().startsWith("word/media")) {
-                                       String fileName = entry.getName().substring(entry.getName().lastIndexOf('/') + 1);
-                                       int dotIndex = fileName.lastIndexOf('.');
-                                       String ext = fileName.substring(dotIndex + 1).toLowerCase();
-                                       // we ignore .jfif
-                                       if ("jpeg".equals(ext))
-                                               ext = "jpg";
-                                       fileName = fileName.substring(0, dotIndex) + "." + ext;
-                                       switch (ext) {
-                                       case "png":
-                                       case "jpg":
-                                       case "gif":
-                                       case "bmp":
-                                       case "tiff":
-                                               try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-                                                       byte[] buffer = new byte[2048];
-                                                       int len = 0;
-                                                       while ((len = zIn.read(buffer)) > 0) {
-                                                               out.write(buffer, 0, len);
-                                                       }
-                                                       byte[] bytes = out.toByteArray();
-                                                       String digest = DigestUtils.digest(DigestUtils.MD5, bytes);
-                                                       if (skipMedia(digest))
-                                                               break;
-                                                       if (!mediaDigests.contains(digest)) {
-                                                               media.put(fileName, bytes);
-                                                               mediaDigests.add(digest);
-                                                       }
-                                               }
-                                               break;
-                                       default:
-                                               break;
-                                       }
-                               } else {
-                                       // System.out.println(entry.getName());
-                               }
-                       }
-               } catch (IOException e) {
-                       // TODO Auto-generated catch block
-                       e.printStackTrace();
-               }
-               // throw new IllegalArgumentException("No document.xml found");
-
-       }
-
-//     public static Reader extractDocumentXml(ZipInputStream zIn) throws IOException {
-//             ZipEntry entry = null;
-//             while ((entry = zIn.getNextEntry()) != null) {
-//                     if ("word/document.xml".equals(entry.getName())) {
-//                             try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-//                                     byte[] buffer = new byte[2048];
-//                                     int len = 0;
-//                                     while ((len = zIn.read(buffer)) > 0) {
-//                                             out.write(buffer, 0, len);
-//                                     }
-//                                     return new InputStreamReader(new ByteArrayInputStream(out.toByteArray()), StandardCharsets.UTF_8);
-//                             }
-//                     } else {
-//                             System.out.println(entry.getName());
-//                     }
-//             }
-//             throw new IllegalArgumentException("No document.xml found");
-//     }
-
-//     protected static ZipInputStream openAsZip(String file) throws IOException {
-//             ZipInputStream zIn;
-//             Path path = Paths.get(file);
-//             zIn = new ZipInputStream(Files.newInputStream(path));
-//             return zIn;
-//     }
-
-       public static void main(String[] args) throws IOException {
-               if (args.length == 0)
-                       throw new IllegalArgumentException("Provide a file path");
-               Path p = Paths.get(args[0]);
-
-               DocxExtractor importer = new DocxExtractor();
-               try (ZipInputStream zIn = new ZipInputStream(Files.newInputStream(p))) {
-                       importer.load(zIn);
-               }
-               // display
-               System.out.println("## TEXT");
-               for (int i = 0; i < importer.text.size(); i++) {
-                       String str = importer.text.get(i);
-                       System.out.println(str);
-               }
-
-               System.out.println("\n");
-
-               for (int i = 0; i < importer.tables.size(); i++) {
-                       Tbl tbl = importer.tables.get(i);
-                       System.out.println("## TABLE " + i);
-                       System.out.println(tbl);
-               }
-
-               System.out.println("## MEDIA");
-               for (String fileName : importer.media.keySet()) {
-                       int sizeKb = importer.media.get(fileName).length / 1024;
-                       System.out.println(fileName + " " + sizeKb + " kB");
-               }
-       }
-
-}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/util/XPathUtils.java b/org.argeo.suite.core/src/org/argeo/suite/util/XPathUtils.java
deleted file mode 100644 (file)
index 66d9aa0..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-package org.argeo.suite.util;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.jackrabbit.util.ISO9075;
-
-/** Ease XPath generation for JCR requests */
-public class XPathUtils {
-       private final static Log log = LogFactory.getLog(XPathUtils.class);
-
-       private final static String QUERY_XPATH = "xpath";
-
-       public static String descendantFrom(String parentPath) {
-               if (notEmpty(parentPath)) {
-                       if ("/".equals(parentPath))
-                               parentPath = "";
-                       // Hardcoded dependency to Jackrabbit. Remove
-                       String result = "/jcr:root" + ISO9075.encodePath(parentPath);
-                       if (log.isTraceEnabled()) {
-                               String result2 = "/jcr:root" + parentPath;
-                               if (!result2.equals(result))
-                                       log.warn("Encoded Path " + result2 + " --> " + result);
-                       }
-                       return result;
-               } else
-                       return "";
-       }
-
-       public static String localAnd(String... conditions) {
-               StringBuilder builder = new StringBuilder();
-               for (String condition : conditions) {
-                       if (notEmpty(condition)) {
-                               builder.append(" ").append(condition).append(" and ");
-                       }
-               }
-               if (builder.length() > 3)
-                       return builder.substring(0, builder.length() - 4);
-               else
-                       return "";
-       }
-
-       public static String xPathNot(String condition) {
-               if (notEmpty(condition))
-                       return "not(" + condition + ")";
-               else
-                       return "";
-       }
-
-       public static String getFreeTextConstraint(String filter) throws RepositoryException {
-               StringBuilder builder = new StringBuilder();
-               if (notEmpty(filter)) {
-                       String[] strs = filter.trim().split(" ");
-                       for (String token : strs) {
-                               builder.append("jcr:contains(.,'*" + encodeXPathStringValue(token) + "*') and ");
-                       }
-                       return builder.substring(0, builder.length() - 4);
-               }
-               return "";
-       }
-
-       public static String getPropertyContains(String propertyName, String filter) throws RepositoryException {
-               if (notEmpty(filter))
-                       return "jcr:contains(@" + propertyName + ",'*" + encodeXPathStringValue(filter) + "*')";
-               return "";
-       }
-
-       private final static DateFormat jcrRefFormatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'+02:00'");
-
-       /**
-        * @param propertyName
-        * @param calendar       the reference date
-        * @param lowerOrGreater "&lt;", "&gt;" TODO validate "&gt;="
-        * @return
-        * @throws RepositoryException
-        */
-       public static String getPropertyDateComparaison(String propertyName, Calendar cal, String lowerOrGreater)
-                       throws RepositoryException {
-               if (cal != null) {
-                       String jcrDateStr = jcrRefFormatter.format(cal.getTime());
-
-                       // jcrDateStr = "2015-08-03T05:00:03:000Z";
-                       String result = "@" + propertyName + " " + lowerOrGreater + " xs:dateTime('" + jcrDateStr + "')";
-                       return result;
-               }
-               return "";
-       }
-
-       public static String getPropertyEquals(String propertyName, String value) {
-               if (notEmpty(value))
-                       return "@" + propertyName + "='" + encodeXPathStringValue(value) + "'";
-               return "";
-       }
-
-       public static String encodeXPathStringValue(String propertyValue) {
-               // TODO implement safer mechanism to escape invalid characters
-               // Also check why we have used this regex in ResourceSerrviceImpl l 474
-               // String cleanedKey = key.replaceAll("(?:')", "''");
-               String result = propertyValue.replaceAll("'", "''");
-               return result;
-       }
-
-       public static void andAppend(StringBuilder builder, String condition) {
-               if (notEmpty(condition)) {
-                       builder.append(condition);
-                       builder.append(" and ");
-               }
-       }
-
-       public static void appendOrderByProperties(StringBuilder builder, boolean ascending, String... propertyNames) {
-               if (propertyNames.length > 0) {
-                       builder.append(" order by ");
-                       for (String propName : propertyNames)
-                               builder.append("@").append(propName).append(", ");
-                       builder = builder.delete(builder.length() - 2, builder.length());
-                       if (ascending)
-                               builder.append(" ascending ");
-                       else
-                               builder.append(" descending ");
-               }
-       }
-
-       public static void appendAndPropStringCondition(StringBuilder builder, String propertyName, String filter)
-                       throws RepositoryException {
-               if (notEmpty(filter)) {
-                       andAppend(builder, getPropertyContains(propertyName, filter));
-               }
-       }
-
-       public static void appendAndNotPropStringCondition(StringBuilder builder, String propertyName, String filter)
-                       throws RepositoryException {
-               if (notEmpty(filter)) {
-                       String cond = getPropertyContains(propertyName, filter);
-                       builder.append(xPathNot(cond));
-                       builder.append(" and ");
-               }
-       }
-
-       public static Query createQuery(Session session, String queryString) throws RepositoryException {
-               QueryManager queryManager = session.getWorkspace().getQueryManager();
-               // Localise JCR properties for XPATH
-               queryString = localiseJcrItemNames(queryString);
-               return queryManager.createQuery(queryString, QUERY_XPATH);
-       }
-
-       private final static String NS_JCR = "\\{http://www.jcp.org/jcr/1.0\\}";
-       private final static String NS_NT = "\\{http://www.jcp.org/jcr/nt/1.0\\}";
-       private final static String NS_MIX = "\\{http://www.jcp.org/jcr/mix/1.0\\}";
-
-       /**
-        * Replace the generic namespace with the local "jcr:", "nt:", "mix:" values. It
-        * is a workaround that must be later cleaned
-        */
-       public static String localiseJcrItemNames(String name) {
-               name = name.replaceAll(NS_JCR, "jcr:");
-               name = name.replaceAll(NS_NT, "nt:");
-               name = name.replaceAll(NS_MIX, "mix:");
-               return name;
-       }
-
-       private static boolean notEmpty(String stringToTest) {
-               return !(stringToTest == null || "".equals(stringToTest.trim()));
-       }
-
-       /** Singleton. */
-       private XPathUtils() {
-
-       }
-}
diff --git a/org.argeo.suite.theme.default/.gitignore b/org.argeo.suite.theme.default/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.suite.theme.default/.project b/org.argeo.suite.theme.default/.project
deleted file mode 100644 (file)
index d157155..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.suite.theme.default</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <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>
-       </natures>
-</projectDescription>
diff --git a/org.argeo.suite.theme.default/META-INF/.gitignore b/org.argeo.suite.theme.default/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.suite.theme.default/OSGI-INF/cmsTheme.xml b/org.argeo.suite.theme.default/OSGI-INF/cmsTheme.xml
deleted file mode 100644 (file)
index 66b8c44..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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="Argeo Suite Default Theme">
-   <implementation class="org.argeo.cms.ui.util.BundleCmsTheme"/>
-   <service>
-      <provide interface="org.argeo.cms.ui.CmsTheme"/>
-   </service>
-</scr:component>
diff --git a/org.argeo.suite.theme.default/bnd.bnd b/org.argeo.suite.theme.default/bnd.bnd
deleted file mode 100644 (file)
index 6c4a97c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-Service-Component:\
-OSGI-INF/cmsTheme.xml
-
-Import-Package:\
-org.argeo.cms.ui.util,\
-*
\ No newline at end of file
diff --git a/org.argeo.suite.theme.default/build.properties b/org.argeo.suite.theme.default/build.properties
deleted file mode 100644 (file)
index 9cb37cd..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-bin.includes = META-INF/,\
-               icons/,\
-               OSGI-INF/
diff --git a/org.argeo.suite.theme.default/icons/types/16/add.png b/org.argeo.suite.theme.default/icons/types/16/add.png
deleted file mode 100644 (file)
index 5c06bf0..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/add.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/close.png b/org.argeo.suite.theme.default/icons/types/16/close.png
deleted file mode 100644 (file)
index af85e1a..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/close.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/dashboard.png b/org.argeo.suite.theme.default/icons/types/16/dashboard.png
deleted file mode 100644 (file)
index 1235592..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/dashboard.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/delete.png b/org.argeo.suite.theme.default/icons/types/16/delete.png
deleted file mode 100644 (file)
index dd2f428..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/delete.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/document.png b/org.argeo.suite.theme.default/icons/types/16/document.png
deleted file mode 100644 (file)
index b168263..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/document.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/documents.png b/org.argeo.suite.theme.default/icons/types/16/documents.png
deleted file mode 100644 (file)
index 56deec5..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/documents.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/folder.png b/org.argeo.suite.theme.default/icons/types/16/folder.png
deleted file mode 100644 (file)
index fefbb40..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/folder.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/inbox.png b/org.argeo.suite.theme.default/icons/types/16/inbox.png
deleted file mode 100644 (file)
index d1aa6af..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/inbox.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/location.png b/org.argeo.suite.theme.default/icons/types/16/location.png
deleted file mode 100644 (file)
index 17c7070..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/location.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/logout.png b/org.argeo.suite.theme.default/icons/types/16/logout.png
deleted file mode 100644 (file)
index f685ea9..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/logout.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/map.png b/org.argeo.suite.theme.default/icons/types/16/map.png
deleted file mode 100644 (file)
index 99690e6..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/map.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/organisation.png b/org.argeo.suite.theme.default/icons/types/16/organisation.png
deleted file mode 100644 (file)
index 2e81a6c..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/organisation.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/people.png b/org.argeo.suite.theme.default/icons/types/16/people.png
deleted file mode 100644 (file)
index 925d571..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/people.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/person.png b/org.argeo.suite.theme.default/icons/types/16/person.png
deleted file mode 100644 (file)
index 8f518e1..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/person.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/refresh.png b/org.argeo.suite.theme.default/icons/types/16/refresh.png
deleted file mode 100644 (file)
index 0d39107..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/refresh.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/save.png b/org.argeo.suite.theme.default/icons/types/16/save.png
deleted file mode 100644 (file)
index 1c58ada..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/save.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/search.png b/org.argeo.suite.theme.default/icons/types/16/search.png
deleted file mode 100644 (file)
index d32874b..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/search.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/settings.png b/org.argeo.suite.theme.default/icons/types/16/settings.png
deleted file mode 100644 (file)
index ac2d8c9..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/settings.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/tag.png b/org.argeo.suite.theme.default/icons/types/16/tag.png
deleted file mode 100644 (file)
index cefdbb9..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/tag.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/task.png b/org.argeo.suite.theme.default/icons/types/16/task.png
deleted file mode 100644 (file)
index eeb7e01..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/task.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/16/user.png b/org.argeo.suite.theme.default/icons/types/16/user.png
deleted file mode 100644 (file)
index 13a8f76..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/16/user.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/add.png b/org.argeo.suite.theme.default/icons/types/32/add.png
deleted file mode 100644 (file)
index 15feb20..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/add.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/close.png b/org.argeo.suite.theme.default/icons/types/32/close.png
deleted file mode 100644 (file)
index d0729a5..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/close.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/dashboard.png b/org.argeo.suite.theme.default/icons/types/32/dashboard.png
deleted file mode 100644 (file)
index 4c24f43..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/dashboard.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/delete.png b/org.argeo.suite.theme.default/icons/types/32/delete.png
deleted file mode 100644 (file)
index 2ee3d88..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/delete.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/document.png b/org.argeo.suite.theme.default/icons/types/32/document.png
deleted file mode 100644 (file)
index a4653fa..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/document.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/documents.png b/org.argeo.suite.theme.default/icons/types/32/documents.png
deleted file mode 100644 (file)
index 29db972..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/documents.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/folder.png b/org.argeo.suite.theme.default/icons/types/32/folder.png
deleted file mode 100644 (file)
index b98fc84..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/folder.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/inbox.png b/org.argeo.suite.theme.default/icons/types/32/inbox.png
deleted file mode 100644 (file)
index 7583c99..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/inbox.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/location.png b/org.argeo.suite.theme.default/icons/types/32/location.png
deleted file mode 100644 (file)
index d9207f1..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/location.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/logout.png b/org.argeo.suite.theme.default/icons/types/32/logout.png
deleted file mode 100644 (file)
index 2d8024f..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/logout.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/map.png b/org.argeo.suite.theme.default/icons/types/32/map.png
deleted file mode 100644 (file)
index 9a82a96..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/map.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/organisation.png b/org.argeo.suite.theme.default/icons/types/32/organisation.png
deleted file mode 100644 (file)
index 62890c2..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/organisation.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/people.png b/org.argeo.suite.theme.default/icons/types/32/people.png
deleted file mode 100644 (file)
index 5f53288..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/people.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/person.png b/org.argeo.suite.theme.default/icons/types/32/person.png
deleted file mode 100644 (file)
index a6c5f1d..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/person.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/save.png b/org.argeo.suite.theme.default/icons/types/32/save.png
deleted file mode 100644 (file)
index d7597d1..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/save.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/search.png b/org.argeo.suite.theme.default/icons/types/32/search.png
deleted file mode 100644 (file)
index 8d89a4a..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/search.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/settings.png b/org.argeo.suite.theme.default/icons/types/32/settings.png
deleted file mode 100644 (file)
index 4e3fa20..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/settings.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/tag.png b/org.argeo.suite.theme.default/icons/types/32/tag.png
deleted file mode 100644 (file)
index 907e216..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/tag.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/task.png b/org.argeo.suite.theme.default/icons/types/32/task.png
deleted file mode 100644 (file)
index b6bd243..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/task.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/icons/types/32/user.png b/org.argeo.suite.theme.default/icons/types/32/user.png
deleted file mode 100644 (file)
index 50fd404..0000000
Binary files a/org.argeo.suite.theme.default/icons/types/32/user.png and /dev/null differ
diff --git a/org.argeo.suite.theme.default/pom.xml b/org.argeo.suite.theme.default/pom.xml
deleted file mode 100644 (file)
index f48b083..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <groupId>org.argeo.suite</groupId>
-               <artifactId>argeo-suite</artifactId>
-               <version>2.1.18-SNAPSHOT</version>
-               <relativePath>..</relativePath>
-       </parent>
-       <artifactId>org.argeo.suite.theme.default</artifactId>
-       <name>Suite Default Theme</name>
-       <packaging>jar</packaging>
-       <dependencies>
-       </dependencies>
-</project>
diff --git a/org.argeo.suite.theme.default/rap/work.css b/org.argeo.suite.theme.default/rap/work.css
deleted file mode 100644 (file)
index c0aaeb1..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-.argeo-suite-header {
-       color: white;
-       background-color: #00294b;
-}
-
-.argeo-suite-headerTitle {
-       font: bold 18px sans-serif;
-       color: white;
-       background-color: #00294b;
-}
-
-.argeo-suite-leadPane {
-       background-color: #eee;
-}
-
-Label.argeo-suite-leadPane {
-       font: 14px sans-serif;
-       color: #888;
-       background-color: #eee;
-}
-
-Button.argeo-suite-leadPane:hover {
-       cursor:pointer;
-}
-
-.argeo-suite-recentItems {
-       font: bold 14px sans-serif;
-       color: white;
-       background-color: #00294b;
-       padding: 8px 16px;
-}
-
-.argeo-suite-titleContainer {
-       background-color: #00294b;
-       padding: 6px 8px 4px 8px;
-}
-
-.argeo-suite-titleLabel {
-       font: bold 14px sans-serif;
-       color: white;
-       background-color: #00294b;
-}
-
-.argeo-suite-subTitleLabel {
-       font: italic 14px sans-serif;
-       color: #777;
-       padding: 4px 8px;
-}
-
-.argeo-suite-simpleLabel {
-       font: bold 14px sans-serif;
-       padding: 0px;
-}
-
-.argeo-suite-simpleText {
-       font: 14px sans-serif;
-       padding: 0px;
-}
-
-.argeo-suite-titleCell {
-       font: bold 14px sans-serif;
-       background-color: #ddd;
-}
-
-.argeo-suite-inlineButton {
-       padding: 0px 4px;
-       font: 12px sans-serif;
-       border: 1px solid white;
-       color: white;
-       background-image: none;
-       background-color: #00294b;
-}
-
-.argeo-suite-inlineButton:hover {
-       color: #00294b;
-       background-color: white;
-}
-
-Composite.argeo-suite-mainTabBody {
-       background-color: #eee;
-       border: 1px solid #bbb;
-}
-
-.argeo-suite-mainTab {
-       background-color: #eee;
-       border: 1px solid #888;
-}
-
-ToolItem.argeo-suite-mainTab {
-       border: none;
-       background-color: #eee;
-}
-
-ToolItem.argeo-suite-mainTab:hover {
-       background-color: #eee;
-}
-
-
-Button.argeo-suite-mainTab {
-       border: 1px solid #eee;
-       background-color: #eee;
-}
-
-.argeo-suite-mainTab:hover {
-       background-color: #eee;
-}
-
-Button.argeo-suite-mainTab:hover {
-       cursor: pointer;
-       background-color: #eee;
-}
-
-.argeo-suite-mainTabSelected {
-       font: bold 14px sans-serif;
-       color: white;
-       /*background-color: #00294b;*/
-       background-color: #5882b5;
-       border:1px solid #888;
-}
-
-ToolItem.argeo-suite-mainTabSelected {
-       border: none;
-}
-
-ToolItem.argeo-suite-mainTabSelected:hover {
-       background-color: #5882b5;
-}
-
-Button.argeo-suite-mainTabSelected {
-       border: none;
-}
-
-Sash {
-  border: 1px solid white;
-  background-image: none;
-  background-color: white;
-}
-
-Sash:hover {
-  border: 1px solid #5882b5;
-  background-color: #5882b5;
-}
-
-TreeItem{
-       background-color:#fff;
-}
-
-Tree-RowOverlay:selected {
-       color:#fff;
-       background-color:#5882b5;
-}
-
-TableItem{
-       background-color:#fff;
-}
-
-Table-RowOverlay:selected {
-       color:#fff;
-       background-color:#5882b5;
-}
-
-.argeo-suite-navigationBar{
-       background-color:#ddd;
-}
-
-.argeo-suite-navigationTitle{
-       background-color:#ddd;
-       font:bold 14px sans-serif;
-}
-
-.argeo-suite-navigationButton{
-       color:#777;
-       background-color:#ddd;
-       font:bold 14px sans-serif;
-}
-
-.argeo-suite-navigationButton:hover{
-       cursor:pointer;
-       color:#ddd;
-       background-color:#777;
-}
diff --git a/org.argeo.suite.theme.default/swt/app.css b/org.argeo.suite.theme.default/swt/app.css
deleted file mode 100644 (file)
index 4ac745d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-.argeo-suite-header {
-       color: white;
-       background-color: #00294b;
-}
-
-.argeo-suite-headerTitle {
-       font: bold 14px sans-serif;
-       color: white;
-       background-color: #00294b;
-}
-
-.argeo-suite-leadPane {
-       background-color: #eee;
-}
-
-Label.argeo-suite-leadPane {
-       font: 11px sans-serif;
-       color: #888;
-       background-color: #eee;
-}
-
-Button.argeo-suite-leadPane:hover {
-       cursor: pointer;
-}
-
-.argeo-suite-recentItems {
-       font: bold 13px sans-serif;
-       color: white;
-       background-color: #00294b;
-       padding: 8px 16px;
-}
-
-.argeo-suite-titleContainer {
-       background-color: #00294b;
-}
-
-.argeo-suite-titleLabel {
-       font: bold 13px sans-serif;
-       margin: 6px 8px 4px 8px;
-       color: white;
-       background-color: #00294b;
-}
-
-.argeo-suite-subTitleLabel {
-       font: italic 14px sans-serif;
-       color: #777;
-       margin: 4px 8px;
-}
-
-.argeo-suite-formLine {
-       padding: 4px 8px 4px 16px;
-}
-
-.argeo-suite-simpleLabel {
-       font: normal 11px sans-serif;
-       border: 8px solid #eee;
-}
-
-.argeo-suite-simpleText {
-       
-}
-
-.argeo-suite-simpleInput {
-       padding: 4px 8px 4px 8px;
-}
-
-.argeo-suite-titleCell {
-       font: bold 11px sans-serif;
-       background-color: #ddd;
-}
-
-.argeo-suite-inlineButton {
-       padding: 0px 4px;
-       font: 12px sans-serif;
-       border: 1px solid white;
-       color: white;
-       background-image: none;
-       background-color: #00294b;
-}
-
-.argeo-suite-inlineButton:hover {
-       color: #00294b;
-       background-color: white;
-}
-
-Composite.argeo-suite-mainTabBody {
-       background-color: #eee;
-       border: 1px solid #bbb;
-}
-
-.argeo-suite-mainTab {
-       background-color: #eee;
-       border: 1px solid #bbb;
-}
-
-ToolItem.argeo-suite-mainTab {
-       border: none;
-       background-color: #eee;
-}
-
-Button.argeo-suite-mainTab {
-       border: none;
-       background-color: #eee;
-}
-
-.argeo-suite-mainTab:hover {
-       background-color: #eee;
-}
-
-Button.argeo-suite-mainTab:hover {
-       cursor: pointer;
-       background-color: #eee;
-}
-
-.argeo-suite-mainTabSelected {
-       font: bold 14px sans-serif;
-       color: white;
-       /*background-color: #00294b;*/
-       background-color: #5882b5;
-       border: 1px solid #00294b;
-}
-
-ToolItem.argeo-suite-mainTabSelected {
-       border: none;
-}
-
-Button.argeo-suite-mainTabSelected {
-       border: none;
-}
\ No newline at end of file
diff --git a/org.argeo.suite.ui.rap/.gitignore b/org.argeo.suite.ui.rap/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.suite.ui.rap/.project b/org.argeo.suite.ui.rap/.project
deleted file mode 100644 (file)
index eff6bb0..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.suite.ui.rap</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <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>
-       </natures>
-</projectDescription>
diff --git a/org.argeo.suite.ui.rap/META-INF/.gitignore b/org.argeo.suite.ui.rap/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.suite.ui.rap/OSGI-INF/cmsWebApp.xml b/org.argeo.suite.ui.rap/OSGI-INF/cmsWebApp.xml
deleted file mode 100644 (file)
index 4dfdcff..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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="Argeo Suite Web App">
-   <implementation class="org.argeo.cms.web.CmsWebApp"/>
-   <property name="contextName" type="String" value="argeo"/>
-   <reference bind="setCmsApp" cardinality="1..1" interface="org.argeo.cms.ui.CmsApp" name="CmsApp" policy="dynamic" target="(service.pid=argeo.suite.ui.app)" unbind="unsetCmsApp"/>
-   <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
-</scr:component>
diff --git a/org.argeo.suite.ui.rap/bnd.bnd b/org.argeo.suite.ui.rap/bnd.bnd
deleted file mode 100644 (file)
index 35b671b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-Service-Component: OSGI-INF/cmsWebApp.xml
-
-Import-Package:\
-org.argeo.cms.web,\
-org.eclipse.rap.rwt.application,\
-*
diff --git a/org.argeo.suite.ui.rap/build.properties b/org.argeo.suite.ui.rap/build.properties
deleted file mode 100644 (file)
index 6210e84..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-output.. = bin/
-bin.includes = META-INF/,\
-               .,\
-               OSGI-INF/
-source.. = src/
diff --git a/org.argeo.suite.ui.rap/pom.xml b/org.argeo.suite.ui.rap/pom.xml
deleted file mode 100644 (file)
index 1ffe19e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <groupId>org.argeo.suite</groupId>
-               <artifactId>argeo-suite</artifactId>
-               <version>2.1.18-SNAPSHOT</version>
-               <relativePath>..</relativePath>
-       </parent>
-       <artifactId>org.argeo.suite.ui.rap</artifactId>
-       <name>Suite UI RAP</name>
-       <packaging>jar</packaging>
-       <dependencies>
-               <dependency>
-                       <groupId>org.argeo.suite</groupId>
-                       <artifactId>org.argeo.suite.ui</artifactId>
-                       <version>2.1.18-SNAPSHOT</version>
-               </dependency>
-
-               <!-- Eclipse E4 -->
-               <dependency>
-                       <groupId>org.argeo.tp</groupId>
-                       <artifactId>argeo-tp-rap-e4</artifactId>
-                       <version>${version.argeo-tp}</version>
-                       <type>pom</type>
-                       <scope>provided</scope>
-               </dependency>
-       </dependencies>
-</project>
diff --git a/org.argeo.suite.ui/.classpath b/org.argeo.suite.ui/.classpath
deleted file mode 100644 (file)
index e801ebf..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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>
diff --git a/org.argeo.suite.ui/.gitignore b/org.argeo.suite.ui/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.suite.ui/.project b/org.argeo.suite.ui/.project
deleted file mode 100644 (file)
index 7146bab..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.suite.ui</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>
diff --git a/org.argeo.suite.ui/META-INF/.gitignore b/org.argeo.suite.ui/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.suite.ui/OSGI-INF/cmsApp.xml b/org.argeo.suite.ui/OSGI-INF/cmsApp.xml
deleted file mode 100644 (file)
index e42eeeb..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<?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="Argeo Suite App">
-   <implementation class="org.argeo.suite.ui.SuiteApp"/>
-   <service>
-      <provide interface="org.argeo.cms.ui.CmsApp"/>
-      <provide interface="org.osgi.service.event.EventHandler"/>
-   </service>
-   <properties entry="config/cmsApp.properties"/>
-   <reference bind="addUiProvider" cardinality="0..n" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" unbind="removeUiProvider"/>
-   <reference bind="addTheme" cardinality="1..n" interface="org.argeo.cms.ui.CmsTheme" name="CmsTheme" policy="dynamic" unbind="removeTheme"/>
-   <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="dynamic" target="(cn=ego)"/>
-   <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
-   <reference bind="setCmsUserManager" cardinality="1..1" interface="org.argeo.cms.CmsUserManager" name="CmsUserManager" policy="static"/>
-</scr:component>
diff --git a/org.argeo.suite.ui/OSGI-INF/dashboard.xml b/org.argeo.suite.ui/OSGI-INF/dashboard.xml
deleted file mode 100644 (file)
index f678b5b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default Dashboard">
-   <implementation class="org.argeo.suite.ui.DefaultDashboard"/>
-   <service>
-      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
-   </service>
-   <properties entry="config/dashboard.properties"/>
-</scr:component>
diff --git a/org.argeo.suite.ui/OSGI-INF/dashboardLayer.xml b/org.argeo.suite.ui/OSGI-INF/dashboardLayer.xml
deleted file mode 100644 (file)
index b60eafc..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Dashboard Layer">
-   <implementation class="org.argeo.suite.ui.DefaultEditionLayer"/>
-   <service>
-      <provide interface="org.argeo.suite.ui.SuiteLayer"/>
-   </service>
-   <properties entry="config/dashboardLayer.properties"/>
-   <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.suite.ui.recentItems)"/>
-</scr:component>
diff --git a/org.argeo.suite.ui/OSGI-INF/header.xml b/org.argeo.suite.ui/OSGI-INF/header.xml
deleted file mode 100644 (file)
index a8fc66d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Work Header">
-   <implementation class="org.argeo.suite.ui.DefaultHeader"/>
-   <service>
-      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
-      <provide interface="org.osgi.service.cm.ManagedService"/>
-   </service>
-   <properties entry="config/header.properties"/>
-</scr:component>
diff --git a/org.argeo.suite.ui/OSGI-INF/l10n/bundle.properties b/org.argeo.suite.ui/OSGI-INF/l10n/bundle.properties
deleted file mode 100644 (file)
index 3d08155..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-dashboard=dashboard
-people=contacts
-documents=documents
-locations=locations
-recentItems=recent items
-
-appTitle=Argeo Suite
-
-#
-# PEOPLE
-# org.argeo.people.ui.PeopleMsg
-#
-person=Person
-organisation=Organisation
-
-# NewPersonWizard
-firstName=First Name
-lastName=Last Name
-salutation=Salutation
-email=Email
-personWizardWindowTitle=New person
-personWizardPageTitle=Create a contact
-
-# NewOrgWizard
-legalName=Legal name
-legalForm=Legal form
-vatId=VAT ID
-orgWizardWindowTitle=New organisation
-orgWizardPageTitle=Create an organisation
-
-
-# ContextAddressComposite
-chooseAnOrganisation=Choose an organisation
-street=Street
-streetComplement=Street complement
-zipCode=Zip code
-city=City
-state=State
-country=Country
-geopoint=Geopoint
-
-# FilteredOrderableEntityTable
-filterHelp=Type filter criterion separated by a space
-
-# BankAccountComposite
-accountHolder=Account holder
-bankName=Bank name
-currency=Currency
-accountNumber=Account number
-bankNumber=Bank number
-BIC=BIC
-IBAN=IBAN
-
-# EditJobDialog
-position=Role
-chosenItem=Chose item
-department=Department
-isPrimary=Is primary
-searchAndChooseEntity=Search and choose a corresponding entity
-
-# ContactListCTab (e4)
-notes=Notes
-addAContact=Add a contact
-contactValue=Contact value
-linkedCompany=Linked company
-
-# OrgAdminInfoCTab (e4)
-paymentAccount=Payment account
-
-# OrgEditor (e4)
-orgDetails=Details
-orgActivityLog=Activity log
-team=Team
-orgAdmin=Admin.
-
-# PersonEditor (e4)
-personDetails=Contact details
-personActivityLog=Activity log
-personOrgs=Organisations
-personSecurity=Security
-
-# PersonSecurityCTab (e4)
-resetPassword=Reset password
-
-# Generic
-label=Label
-aCustomLabel=A custom label
-description=Description
-value=Value
-name=Name
-primary=Primary
-add=Add
-save=Save
-pickUp=Pick up
-
-# Tags
-confirmNewTag=Tag #{0} is not yet registered. Are you sure you want to create it?
-cannotCreateTag=Tag #{0} is not yet registered and you don't have enough rights to create it.
diff --git a/org.argeo.suite.ui/OSGI-INF/l10n/bundle_de.properties b/org.argeo.suite.ui/OSGI-INF/l10n/bundle_de.properties
deleted file mode 100644 (file)
index 0af19c2..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-dashboard=dashboard
-people=Kontakte
-documents=Dokumente
-locations=Orte
-recentItems=neulich
-
-appTitle=Argeo Suite
-
-#
-# PEOPLE
-# org.argeo.people.ui.PeopleMsg
-#
-person=Person
-organisation=Organisation
-
-# NewPersonWizard
-firstName=Vorname
-lastName=Nachname
-salutation=Salutation
-email=E-Mail
-personWizardWindowTitle=Neue Person
-personWizardPageTitle=Kontakt erstellen
-
-# NewOrgWizard
-legalName=Name
-legalForm=Geschäftsform
-vatId=Ust ID
-orgWizardWindowTitle=Neue Organisation
-orgWizardPageTitle=Organisation erstellen
-
-
-# ContextAddressComposite
-chooseAnOrganisation=Organisation wählen
-street=Strasse
-streetComplement=Strasse Zusatz
-zipCode=PLZ
-city=Stadt
-state=Bundesland
-country=Land
-geopoint=Geopoint
-
-# FilteredOrderableEntityTable
-filterHelp=Type filter criterion separated by a space
-
-# BankAccountComposite
-accountHolder=Kontoinhaber 
-bankName=Name der Bank
-currency=Währung
-accountNumber=Kontonummer
-bankNumber=BLZ
-BIC=BIC
-IBAN=IBAN
-
-# EditJobDialog
-position=Rolle
-chosenItem=Auswahl
-department=Abteilung
-isPrimary=Ist Primär
-searchAndChooseEntity=Suche und wähle ein zugehöriges Objekt
-
-# ContactListCTab (e4)
-notes=Bemerkungen
-addAContact=Kontakt hinzufügen
-contactValue=Kontakt value
-linkedCompany=zugehörige Firma
-
-# OrgAdminInfoCTab (e4)
-paymentAccount=Geschäftskonto
-
-# OrgEditor (e4)
-orgDetails=Details
-orgActivityLog=Aktivitäten Log
-team=Team
-orgAdmin=Admin.
-
-# PersonEditor (e4)
-personDetails=Kontakt Daten
-personActivityLog=Aktivitäten Log
-personOrgs=Organisationen
-personSecurity=Sicherheit
-
-# PersonSecurityCTab (e4)
-resetPassword=Passwort zurücksetzen
-
-# Generic
-label=Beschriftung
-aCustomLabel=Eine spezifische Beschriftung
-description=Beschreibung
-value=Wert
-name=Name
-primary=Haupt-
-add=Hinzufügen
-save=Speichern
-pickUp=Aussuchen
-
-# Tags
-confirmNewTag=Das Hashtag '{0}' existiert noch nicht. WollenSie es hinzufügen?
-cannotCreateTag=Das Hashtag '{0}' existiert nicht uns Sie haben nicht die Rechte, um es hinzufügen.
diff --git a/org.argeo.suite.ui/OSGI-INF/l10n/bundle_fr.properties b/org.argeo.suite.ui/OSGI-INF/l10n/bundle_fr.properties
deleted file mode 100644 (file)
index 225e5fd..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-dashboard=dashboard
-people=contacts
-documents=documents
-locations=lieux
-recentItems=récent
-
-appTitle=Argeo Suite
-
-#
-# GENERIC
-#
-
-#
-# PEOPLE
-# org.argeo.people.ui.PeopleMsg
-#
-person=Personne
-organisation=Organisation
-
-# NewPersonWizard
-firstName=Prénom
-lastName=Nom
-salutation=Salutation
-email=Email
-personWizardWindowTitle=Nouvelle personne
-personWizardPageTitle=Créer un contact
-
-# NewOrgWizard
-legalName=Nom
-legalForm=Forme légale
-vatId=ID TVA
-orgWizardWindowTitle=Nouvelle organisation
-orgWizardPageTitle=Créer une organisation
-
-
-# ContextAddressComposite
-chooseAnOrganisation=Choisir une organisation
-street=Rue
-streetComplement=Complément rue
-zipCode=Code postal
-city=Ville
-state=État
-country=Pays
-geopoint=Géocoordonnées
-
-# FilteredOrderableEntityTable
-filterHelp=Sasir les critères de filtrage séparés par des espaces 
-
-# BankAccountComposite
-accountHolder=Propriétaire du compte
-bankName=Nom de la banque
-currency=Devise
-accountNumber=Numéro de compte
-bankNumber=Numéro de banque
-BIC=BIC
-IBAN=IBAN
-
-# EditJobDialog
-position=Rôle
-chosenItem=Choisir une Ã©lément
-department=Service
-isPrimary=Principal
-searchAndChooseEntity=Cherhcer et choisir l'entitée correspondante
-
-# ContactListCTab (e4)
-notes=Notes
-addAContact=Ajouter un contact
-contactValue=Valeur
-linkedCompany=Entreprise liée
-
-# OrgAdminInfoCTab (e4)
-paymentAccount=Compte de paiement
-
-# OrgEditor (e4)
-orgDetails=Détails
-orgActivityLog=Activités
-team=Équipe
-orgAdmin=Admin.
-
-# PersonEditor (e4)
-personDetails=Détails du contact
-personActivityLog=Activités
-personOrgs=Organisations
-personSecurity=Accès
-
-# PersonSecurityCTab (e4)
-resetPassword=Force le mot de passe
-
-# Generic
-label=Étiquette
-aCustomLabel=Une Ã©tiquette spécifique
-description=Description
-value=Valeur
-name=Nom
-primary=Principal
-add=Ajouter
-save=Sauver
-pickUp=Choisir
-
-# Tags
-confirmNewTag=Le tag #{0} n'existe pas encore. Voulez-vous le créer?
-cannotCreateTag=Le tag #{0} n'existe pas encore et vous n'avez pas les droits pour le créer.
diff --git a/org.argeo.suite.ui/OSGI-INF/leadPane.xml b/org.argeo.suite.ui/OSGI-INF/leadPane.xml
deleted file mode 100644 (file)
index 9d3f2dd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Lead Pane">
-   <implementation class="org.argeo.suite.ui.DefaultLeadPane"/>
-   <service>
-      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
-   </service>
-   <properties entry="config/leadPane.properties"/>
-   <property name="defaultLayers" type="String">argeo.suite.ui.dashboardLayer
-argeo.documents.ui.documentsLayer
-   </property>
-   <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
-</scr:component>
diff --git a/org.argeo.suite.ui/OSGI-INF/loginScreen.xml b/org.argeo.suite.ui/OSGI-INF/loginScreen.xml
deleted file mode 100644 (file)
index 0c5377a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Default Login Screen">
-   <implementation class="org.argeo.suite.ui.DefaultLoginScreen"/>
-   <properties entry="config/loginScreen.properties"/>
-   <service>
-      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
-   </service>
-</scr:component>
diff --git a/org.argeo.suite.ui/OSGI-INF/recentItems.xml b/org.argeo.suite.ui/OSGI-INF/recentItems.xml
deleted file mode 100644 (file)
index 8aaee16..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" name="Default Recent Items">
-   <implementation class="org.argeo.suite.ui.RecentItems"/>
-   <service>
-      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
-   </service>
-   <properties entry="config/recentItems.properties"/>
-</scr:component>
diff --git a/org.argeo.suite.ui/bnd.bnd b/org.argeo.suite.ui/bnd.bnd
deleted file mode 100644 (file)
index b49d736..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-Service-Component:\
-OSGI-INF/cmsApp.xml,\
-OSGI-INF/header.xml,\
-OSGI-INF/leadPane.xml,\
-OSGI-INF/loginScreen.xml,\
-OSGI-INF/recentItems.xml,\
-OSGI-INF/dashboard.xml,\
-OSGI-INF/dashboardLayer.xml
-
-Import-Package:\
-org.argeo.api,\
-org.eclipse.swt,\
-org.osgi.framework,\
-org.argeo.entity,\
-org.eclipse.core.commands.common,\
-org.eclipse.jface.window,\
-org.eclipse.jface.dialogs,\
-*
diff --git a/org.argeo.suite.ui/build.properties b/org.argeo.suite.ui/build.properties
deleted file mode 100644 (file)
index d829967..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-output.. = bin/
-bin.includes = META-INF/,\
-               .,\
-               OSGI-INF/,\
-               config/,\
-               OSGI-INF/loginScreen.xml,\
-               OSGI-INF/dashboard.xml,\
-               OSGI-INF/recentItems.xml,\
-               OSGI-INF/dashboardLayer.xml
-source.. = src/
diff --git a/org.argeo.suite.ui/config/cmsApp.properties b/org.argeo.suite.ui/config/cmsApp.properties
deleted file mode 100644 (file)
index 1dec00e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-service.pid=argeo.suite.ui.app
-
-event.topics=argeo/suite/*
\ No newline at end of file
diff --git a/org.argeo.suite.ui/config/dashboard.properties b/org.argeo.suite.ui/config/dashboard.properties
deleted file mode 100644 (file)
index 1832543..0000000
+++ /dev/null
@@ -1 +0,0 @@
-service.pid=argeo.suite.ui.dashboard
diff --git a/org.argeo.suite.ui/config/dashboardLayer.properties b/org.argeo.suite.ui/config/dashboardLayer.properties
deleted file mode 100644 (file)
index 79abe4c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-service.pid=argeo.suite.ui.dashboardLayer
-
-title=Dashboard
-icon=dashboard
\ No newline at end of file
diff --git a/org.argeo.suite.ui/config/header.properties b/org.argeo.suite.ui/config/header.properties
deleted file mode 100644 (file)
index 034d5f5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-service.pid=argeo.suite.ui.header
-argeo.suite.ui=true
-
-argeo.suite.ui.header.title=%appTitle
\ No newline at end of file
diff --git a/org.argeo.suite.ui/config/leadPane.properties b/org.argeo.suite.ui/config/leadPane.properties
deleted file mode 100644 (file)
index 0d7b193..0000000
+++ /dev/null
@@ -1 +0,0 @@
-service.pid=argeo.suite.ui.leadPane
diff --git a/org.argeo.suite.ui/config/loginScreen.properties b/org.argeo.suite.ui/config/loginScreen.properties
deleted file mode 100644 (file)
index 332614d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-service.pid=argeo.suite.ui.loginScreen
diff --git a/org.argeo.suite.ui/config/recentItems.properties b/org.argeo.suite.ui/config/recentItems.properties
deleted file mode 100644 (file)
index 7321c55..0000000
+++ /dev/null
@@ -1 +0,0 @@
-service.pid=argeo.suite.ui.recentItems
diff --git a/org.argeo.suite.ui/pom.xml b/org.argeo.suite.ui/pom.xml
deleted file mode 100644 (file)
index 114ed7c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <groupId>org.argeo.suite</groupId>
-               <artifactId>argeo-suite</artifactId>
-               <version>2.1.18-SNAPSHOT</version>
-               <relativePath>..</relativePath>
-       </parent>
-       <artifactId>org.argeo.suite.ui</artifactId>
-       <name>Suite UI</name>
-       <packaging>jar</packaging>
-       <dependencies>
-               <dependency>
-                       <groupId>org.argeo.suite</groupId>
-                       <artifactId>org.argeo.suite.core</artifactId>
-                       <version>2.1.18-SNAPSHOT</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.argeo.suite</groupId>
-                       <artifactId>org.argeo.entity.ui</artifactId>
-                       <version>2.1.18-SNAPSHOT</version>
-               </dependency>
-
-               <!-- Argeo Commons -->
-               <dependency>
-                       <groupId>org.argeo.commons</groupId>
-                       <artifactId>org.argeo.eclipse.ui</artifactId>
-                       <version>${version.argeo-commons}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.argeo.commons</groupId>
-                       <artifactId>org.argeo.eclipse.ui.rap</artifactId>
-                       <version>${version.argeo-commons}</version>
-                       <scope>provided</scope>
-               </dependency>
-
-               <!-- Eclipse E4 -->
-               <dependency>
-                       <groupId>org.argeo.tp</groupId>
-                       <artifactId>argeo-tp-rap-e4</artifactId>
-                       <version>${version.argeo-tp}</version>
-                       <type>pom</type>
-                       <scope>provided</scope>
-               </dependency>
-       </dependencies>
-</project>
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/AdminEntryArea.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/AdminEntryArea.java
deleted file mode 100644 (file)
index 8c75f22..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.Set;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.dialogs.CmsWizardDialog;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.Selected;
-import org.argeo.naming.LdapAttrs;
-import org.argeo.suite.SuiteRole;
-import org.argeo.suite.ui.dialogs.NewUserWizard;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.window.Window;
-import org.eclipse.jface.wizard.Wizard;
-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.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-import org.osgi.service.useradmin.User;
-
-/** Entry to the admin area. */
-public class AdminEntryArea implements CmsUiProvider {
-
-       private CmsUserManager cmsUserManager;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsTheme theme = CmsTheme.getCmsTheme(parent);
-               parent.setLayout(new GridLayout());
-               TableViewer usersViewer = new TableViewer(parent);
-               usersViewer.setContentProvider(new UsersContentProvider());
-
-               TableViewerColumn idCol = new TableViewerColumn(usersViewer, SWT.NONE);
-               idCol.getColumn().setWidth(70);
-               idCol.setLabelProvider(new ColumnLabelProvider() {
-
-                       @Override
-                       public String getText(Object element) {
-
-                               return getUserProperty(element, LdapAttrs.uid.name());
-                       }
-               });
-
-               TableViewerColumn givenNameCol = new TableViewerColumn(usersViewer, SWT.NONE);
-               givenNameCol.getColumn().setWidth(150);
-               givenNameCol.setLabelProvider(new ColumnLabelProvider() {
-
-                       @Override
-                       public String getText(Object element) {
-
-                               return getUserProperty(element, LdapAttrs.givenName.name());
-                       }
-               });
-
-               TableViewerColumn snCol = new TableViewerColumn(usersViewer, SWT.NONE);
-               snCol.getColumn().setWidth(150);
-               snCol.setLabelProvider(new ColumnLabelProvider() {
-
-                       @Override
-                       public String getText(Object element) {
-
-                               return getUserProperty(element, LdapAttrs.sn.name());
-                       }
-               });
-
-               TableViewerColumn mailCol = new TableViewerColumn(usersViewer, SWT.NONE);
-               mailCol.getColumn().setWidth(400);
-               mailCol.setLabelProvider(new ColumnLabelProvider() {
-
-                       @Override
-                       public String getText(Object element) {
-
-                               return getUserProperty(element, LdapAttrs.mail.name());
-                       }
-               });
-
-               Composite bottom = new Composite(parent, SWT.NONE);
-               bottom.setLayoutData(CmsUiUtils.fillWidth());
-               bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
-               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
-               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
-               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               deleteItem.setEnabled(false);
-//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
-               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
-               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
-               usersViewer.addDoubleClickListener(new IDoubleClickListener() {
-
-                       @Override
-                       public void doubleClick(DoubleClickEvent event) {
-                               User user = (User) usersViewer.getStructuredSelection().getFirstElement();
-                               if (user != null) {
-//                                     Node userNode = getOrCreateUserNode(user, context);
-                                       CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
-                                                       SuiteEvent.eventProperties(user));
-                               }
-
-                       }
-               });
-               usersViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-                       public void selectionChanged(SelectionChangedEvent event) {
-                               User user = (User) usersViewer.getStructuredSelection().getFirstElement();
-                               if (user != null) {
-//                                     Node userNode = getOrCreateUserNode(user, context);
-                                       CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
-                                                       SuiteEvent.eventProperties(user));
-                                       deleteItem.setEnabled(true);
-                               } else {
-                                       deleteItem.setEnabled(false);
-                               }
-                       }
-               });
-
-               addItem.addSelectionListener((Selected) (e) -> {
-                       // SuiteUtils.getOrCreateUserNode(adminSession, userDn);
-                       Wizard wizard = new NewUserWizard(null);
-                       CmsWizardDialog dialog = new CmsWizardDialog(parent.getShell(), wizard);
-                       // WizardDialog dialog = new WizardDialog(shell, wizard);
-                       if (dialog.open() == Window.OK) {
-                               // TODO create
-                       }
-               });
-
-               usersViewer.getTable().setLayoutData(CmsUiUtils.fillAll());
-               usersViewer.setInput(cmsUserManager);
-
-               return usersViewer.getTable();
-       }
-
-//     private Node getOrCreateUserNode(User user, Node context) {
-//             return JcrUtils.mkdirs(Jcr.getSession(context),
-//                             "/" + EntityType.user.name() + "/" + getUserProperty(user, LdapAttrs.uid.name()),
-//                             EntityType.user.get());
-//     }
-
-       private String getUserProperty(Object element, String key) {
-               Object value = ((User) element).getProperties().get(key);
-               return value != null ? value.toString() : null;
-       }
-
-       class UsersContentProvider implements IStructuredContentProvider {
-
-               @Override
-               public Object[] getElements(Object inputElement) {
-                       CmsUserManager cum = (CmsUserManager) inputElement;
-                       Set<User> users = cum.listUsersInGroup(SuiteRole.coworker.dn(), null);
-                       return users.toArray();
-               }
-
-               @Override
-               public void dispose() {
-               }
-
-               @Override
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               }
-
-       }
-
-       public void setCmsUserManager(CmsUserManager cmsUserManager) {
-               this.cmsUserManager = cmsUserManager;
-       }
-
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultDashboard.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultDashboard.java
deleted file mode 100644 (file)
index 9835b67..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** Provides a dashboard. */
-public class DefaultDashboard implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               parent.setLayout(new GridLayout());
-               CmsView cmsView = CmsView.getCmsView(parent);
-               if (cmsView.isAnonymous())
-                       throw new IllegalStateException("No user is not logged in");
-
-               Label lbl = new Label(parent, SWT.NONE);
-               lbl.setText("Welcome " + CurrentUser.getDisplayName() + "!");
-
-               return lbl;
-       }
-
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java
deleted file mode 100644 (file)
index 7b8bb3e..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.widgets.TabbedArea;
-import org.argeo.util.LangUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** An app layer based on an entry area and an editor area. */
-public class DefaultEditionLayer implements SuiteLayer {
-       private CmsUiProvider entryArea;
-       private CmsUiProvider workArea;
-       private List<String> weights = new ArrayList<>();
-       private boolean startMaximized = false;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               if (entryArea != null) {
-                       SashFormEditionArea sashFormEditionArea = new SashFormEditionArea(parent, parent.getStyle());
-                       entryArea.createUi(sashFormEditionArea.getEntryArea(), context);
-                       if (this.workArea != null) {
-                               this.workArea.createUi(sashFormEditionArea.getEditorArea(), context);
-                       }
-                       return sashFormEditionArea;
-               } else {
-                       if (this.workArea != null) {
-                               Composite area = new Composite(parent, SWT.NONE);
-                               this.workArea.createUi(area, context);
-                               return area;
-                       }
-                       CmsTheme theme = CmsTheme.getCmsTheme(parent);
-                       TabbedArea tabbedArea = createTabbedArea(parent, theme);
-                       return tabbedArea;
-               }
-       }
-
-       @Override
-       public void view(CmsUiProvider uiProvider, Composite workArea, Node context) {
-               TabbedArea tabbedArea;
-               if (workArea instanceof SashFormEditionArea) {
-                       tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
-               } else if (workArea instanceof TabbedArea) {
-                       tabbedArea = (TabbedArea) workArea;
-               } else
-                       throw new IllegalArgumentException("Unsupported work area " + workArea.getClass().getName());
-               tabbedArea.view(uiProvider, context);
-       }
-
-       @Override
-       public void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
-               TabbedArea tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
-               tabbedArea.open(uiProvider, context);
-       }
-
-       public void init(Map<String, Object> properties) {
-               weights = LangUtils.toStringList(properties.get(Property.weights.name()));
-               startMaximized = properties.containsKey(Property.startMaximized.name())
-                               && "true".equals(properties.get(Property.startMaximized.name()));
-       }
-
-       public void setEntryArea(CmsUiProvider entryArea) {
-               this.entryArea = entryArea;
-       }
-
-       public void setWorkArea(CmsUiProvider workArea) {
-               this.workArea = workArea;
-       }
-
-       TabbedArea createTabbedArea(Composite parent, CmsTheme theme) {
-               TabbedArea tabbedArea = new TabbedArea(parent, SWT.NONE);
-               tabbedArea.setBodyStyle(SuiteStyle.mainTabBody.style());
-               tabbedArea.setTabStyle(SuiteStyle.mainTab.style());
-               tabbedArea.setTabSelectedStyle(SuiteStyle.mainTabSelected.style());
-               tabbedArea.setCloseIcon(SuiteIcon.close.getSmallIcon(theme));
-               tabbedArea.setLayoutData(CmsUiUtils.fillAll());
-               return tabbedArea;
-       }
-
-       /** A work area based on an entry area and and a tabbed area. */
-       class SashFormEditionArea extends SashForm {
-               private static final long serialVersionUID = 2219125778722702618L;
-               private CmsTheme theme;
-               private Composite entryArea;
-               private Composite editorArea;
-               private TabbedArea tabbedArea;
-
-               SashFormEditionArea(Composite parent, int style) {
-                       super(parent, SWT.HORIZONTAL);
-                       theme = CmsTheme.getCmsTheme(parent);
-
-                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
-                               editorArea = new Composite(this, SWT.BORDER);
-                               entryArea = new Composite(this, SWT.BORDER);
-                       } else {
-                               entryArea = new Composite(this, SWT.NONE);
-                               editorArea = new Composite(this, SWT.NONE);
-                       }
-
-                       if (weights.size() != 0) {
-                               int[] actualWeight = new int[weights.size()];
-                               for (int i = 0; i < weights.size(); i++) {
-                                       actualWeight[i] = Integer.parseInt(weights.get(i));
-                               }
-                               setWeights(actualWeight);
-                       } else {
-                               int[] actualWeights = new int[] { 3000, 7000 };
-                               setWeights(actualWeights);
-                       }
-                       if (startMaximized)
-                               setMaximizedControl(editorArea);
-                       editorArea.setLayout(new GridLayout());
-
-                       if (DefaultEditionLayer.this.workArea == null) {
-                               tabbedArea = createTabbedArea(editorArea, theme);
-                       }
-
-               }
-
-               Composite getEntryArea() {
-                       return entryArea;
-               }
-
-               TabbedArea getTabbedArea() {
-                       return tabbedArea;
-               }
-
-               Composite getEditorArea() {
-                       return editorArea;
-               }
-
-       }
-}
\ No newline at end of file
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java
deleted file mode 100644 (file)
index a251e14..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.Dictionary;
-import java.util.Map;
-import java.util.TreeMap;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.util.LangUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
-
-public class DefaultHeader implements CmsUiProvider, ManagedService {
-       public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title";
-       private Map<String, String> properties;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsView cmsView = CmsView.getCmsView(parent);
-               CmsTheme theme = CmsTheme.getCmsTheme(parent);
-
-               parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, true)));
-
-               // TODO right to left
-               Composite lead = new Composite(parent, SWT.NONE);
-               CmsUiUtils.style(lead, SuiteStyle.header);
-               lead.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false));
-               lead.setLayout(new GridLayout());
-               Label lbl = new Label(lead, SWT.NONE);
-               String title = properties.get(TITLE_PROPERTY);
-               lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString()
-                               : title);
-               CmsUiUtils.style(lbl, SuiteStyle.headerTitle);
-               lbl.setLayoutData(CmsUiUtils.fillWidth());
-
-               Composite middle = new Composite(parent, SWT.NONE);
-               CmsUiUtils.style(middle, SuiteStyle.header);
-               middle.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
-               middle.setLayout(new GridLayout());
-
-               Composite end = new Composite(parent, SWT.NONE);
-               CmsUiUtils.style(end, SuiteStyle.header);
-               end.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, false));
-
-               if (!cmsView.isAnonymous()) {
-                       end.setLayout(new GridLayout(2, false));
-                       Label userL = new Label(end, SWT.NONE);
-                       CmsUiUtils.style(userL, SuiteStyle.header);
-                       userL.setText(CurrentUser.getDisplayName());
-                       Button logoutB = new Button(end, SWT.FLAT);
-//                     CmsUiUtils.style(logoutB, SuiteStyle.header);
-                       logoutB.setImage(SuiteIcon.logout.getSmallIcon(theme));
-                       logoutB.addSelectionListener(new SelectionAdapter() {
-                               private static final long serialVersionUID = 7116760083964201233L;
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       cmsView.logout();
-                               }
-
-                       });
-               } else {
-                       end.setLayout(new GridLayout(1, false));
-                       // required in order to avoid wrong height after logout
-                       new Label(end, SWT.NONE).setText("");
-
-               }
-               return lbl;
-       }
-
-       public void init(Map<String, String> properties) {
-               this.properties = new TreeMap<>(properties);
-       }
-
-       @Override
-       public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
-               if (properties != null)
-                       this.properties.putAll(LangUtils.dictToStringMap(properties));
-       }
-
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java
deleted file mode 100644 (file)
index a207e7a..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-import java.util.TreeMap;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.Localized;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.suite.RankedObject;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.Constants;
-
-/** Side pane listing various perspectives. */
-public class DefaultLeadPane implements CmsUiProvider {
-       private final static Log log = LogFactory.getLog(DefaultLeadPane.class);
-
-       public static enum Property {
-               defaultLayers, adminLayers;
-       }
-
-       private Map<String, RankedObject<SuiteLayer>> layers = Collections.synchronizedSortedMap(new TreeMap<>());
-       private String[] defaultLayers;
-       private String[] adminLayers;
-
-       @Override
-       public Control createUi(Composite parent, Node node) throws RepositoryException {
-               CmsView cmsView = CmsView.getCmsView(parent);
-               GridLayout layout = new GridLayout();
-               layout.verticalSpacing = 10;
-               layout.marginTop = 10;
-               layout.marginLeft = 10;
-               layout.marginRight = 10;
-               parent.setLayout(layout);
-
-               Button first = null;
-               for (String layerId : defaultLayers) {
-                       if (layers.containsKey(layerId)) {
-                               RankedObject<SuiteLayer> layerObj = layers.get(layerId);
-
-                               // TODO deal with i10n
-                               String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
-                               Localized title = null;
-                               if (titleStr != null)
-                                       title = new Localized.Untranslated(titleStr);
-
-                               String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
-                               SuiteIcon icon = null;
-                               if (iconName != null)
-                                       icon = SuiteIcon.valueOf(iconName);
-
-                               Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon);
-                               if (first == null)
-                                       first = b;
-                       }
-               }
-
-               // TODO factorise
-               boolean isAdmin = cmsView.doAs(() -> CurrentUser.isInRole(NodeConstants.ROLE_USER_ADMIN));
-               if (isAdmin && adminLayers != null)
-                       for (String layerId : adminLayers) {
-                               if (layers.containsKey(layerId)) {
-                                       RankedObject<SuiteLayer> layerObj = layers.get(layerId);
-
-                                       // TODO deal with i10n
-                                       String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
-                                       Localized title = null;
-                                       if (titleStr != null)
-                                               title = new Localized.Untranslated(titleStr);
-
-                                       String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
-                                       SuiteIcon icon = null;
-                                       if (iconName != null)
-                                               icon = SuiteIcon.valueOf(iconName);
-
-                                       Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon);
-                                       if (first == null)
-                                               first = b;
-                               }
-                       }
-
-//             Button dashboardB = createButton(parent, SuiteMsg.dashboard.name(), SuiteMsg.dashboard, SuiteIcon.dashboard);
-               if (!cmsView.isAnonymous()) {
-//                     createButton(parent, SuiteMsg.documents.name(), SuiteMsg.documents, SuiteIcon.documents);
-//                     createButton(parent, SuiteMsg.people.name(), SuiteMsg.people, SuiteIcon.people);
-//                     createButton(parent, SuiteMsg.locations.name(), SuiteMsg.locations, SuiteIcon.location);
-               }
-               return first;
-       }
-
-       public void init(Map<String, Object> properties) {
-               defaultLayers = (String[]) properties.get(Property.defaultLayers.toString());
-               if (defaultLayers == null)
-                       throw new IllegalArgumentException("Default layers must be set.");
-               if (log.isDebugEnabled())
-                       log.debug("Default layers: " + Arrays.asList(defaultLayers));
-               adminLayers = (String[]) properties.get(Property.adminLayers.toString());
-               if (log.isDebugEnabled() && adminLayers != null)
-                       log.debug("Admin layers: " + Arrays.asList(adminLayers));
-       }
-
-       public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
-               if (properties.containsKey(Constants.SERVICE_PID)) {
-                       String pid = (String) properties.get(Constants.SERVICE_PID);
-                       RankedObject.putIfHigherRank(layers, pid, layer, properties);
-               }
-       }
-
-       public void removeLayer(SuiteLayer layer, Map<String, Object> properties) {
-               if (properties.containsKey(Constants.SERVICE_PID)) {
-                       String pid = (String) properties.get(Constants.SERVICE_PID);
-                       if (layers.containsKey(pid)) {
-                               if (layers.get(pid).equals(new RankedObject<SuiteLayer>(layer, properties))) {
-                                       layers.remove(pid);
-                               }
-                       }
-               }
-       }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java
deleted file mode 100644 (file)
index 3757a19..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.widgets.auth.CmsLogin;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Provides a login screen. */
-public class DefaultLoginScreen implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsView cmsView = CmsView.getCmsView(parent);
-               if (!cmsView.isAnonymous())
-                       throw new IllegalStateException(CurrentUser.getUsername() + " is already logged in");
-
-               parent.setLayout(new GridLayout());
-               Composite loginArea = new Composite(parent, SWT.NONE);
-               loginArea.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
-               
-               CmsLogin cmsLogin = new CmsLogin(cmsView);
-               cmsLogin.createUi(loginArea);
-               return cmsLogin.getCredentialsBlock();
-       }
-
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/RecentItems.java
deleted file mode 100644 (file)
index b9aa5b7..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-package org.argeo.suite.ui;
-
-import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.EventListener;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.suite.ui.widgets.DelayedText;
-import org.argeo.suite.util.XPathUtils;
-import org.eclipse.jface.layout.TableColumnLayout;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ColumnWeightData;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** List recent items. */
-public class RecentItems implements CmsUiProvider {
-       private final static int SEARCH_TEXT_DELAY = 800;
-       private final static int SEARCH_DEFAULT_LIMIT = 100;
-
-       private CmsTheme theme;
-
-       private String entityType;
-
-       static enum Property {
-               entityTypes;
-       }
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               theme = CmsTheme.getCmsTheme(parent);
-               parent.setLayout(new GridLayout());
-//             parent.setLayout(CmsUiUtils.noSpaceGridLayout());
-               parent.setLayout(new GridLayout());
-
-//             Composite top = new Composite(parent, SWT.BORDER);
-//             CmsUiUtils.style(top, SuiteStyle.recentItems);
-//             top.setLayoutData(CmsUiUtils.fillWidth());
-//             top.setLayout(CmsUiUtils.noSpaceGridLayout(2));
-//             Label lbl = new Label(top, SWT.FLAT);
-//             lbl.setLayoutData(CmsUiUtils.fillWidth());
-//             lbl.setText(SuiteMsg.recentItems.lead());
-//             CmsUiUtils.style(lbl, SuiteStyle.recentItems);
-//
-//             ToolBar topToolBar = new ToolBar(top, SWT.NONE);
-//             ToolItem addItem = new ToolItem(topToolBar, SWT.FLAT);
-////           CmsUiUtils.style(addItem, SuiteStyle.recentItems);
-//             addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
-
-               if (context == null)
-                       return null;
-               SingleEntityViewer entityViewer = new SingleEntityViewer(parent, SWT.NONE, context.getSession());
-               entityViewer.createUi();
-               entityViewer.getViewer().getTable().setLayoutData(CmsUiUtils.fillAll());
-
-               Composite bottom = new Composite(parent, SWT.NONE);
-               bottom.setLayoutData(CmsUiUtils.fillWidth());
-               bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
-               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
-               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
-               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               deleteItem.setEnabled(false);
-//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
-               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
-               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
-               entityViewer.getViewer().addDoubleClickListener(new IDoubleClickListener() {
-
-                       @Override
-                       public void doubleClick(DoubleClickEvent event) {
-                               Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
-                               if (node != null)
-                                       CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
-                                                       SuiteEvent.eventProperties(node));
-
-                       }
-               });
-               entityViewer.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
-                       public void selectionChanged(SelectionChangedEvent event) {
-                               Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
-                               if (node != null) {
-                                       CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
-                                                       SuiteEvent.eventProperties(node));
-                                       deleteItem.setEnabled(true);
-                               } else {
-                                       deleteItem.setEnabled(false);
-                               }
-                       }
-               });
-
-               return entityViewer.filterTxt;
-
-       }
-
-       public void init(Map<String, String> properties) {
-               // TODO manage multiple entities
-               entityType = properties.get(Property.entityTypes.name());
-       }
-
-       class SingleEntityViewer {
-               Composite parent;
-               Text filterTxt;
-               TableViewer viewer;
-               Session session;
-
-               public SingleEntityViewer(Composite parent, int style, Session session) {
-                       this.parent = parent;
-                       this.session = session;
-               }
-
-               public void createUi() {
-                       // MainLayout
-                       addFilterPanel(parent);
-                       viewer = createListPart(parent, new SingleEntityLabelProvider());
-                       refreshFilteredList();
-
-                       try {
-                               String[] nodeTypes = entityType != null && entityType.contains(":") ? new String[] { entityType }
-                                               : null;
-                               session.getWorkspace().getObservationManager().addEventListener(new EventListener() {
-
-                                       @Override
-                                       public void onEvent(EventIterator events) {
-                                               parent.getDisplay().asyncExec(() -> refreshFilteredList());
-                                       }
-                               }, Event.PROPERTY_CHANGED | Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED, "/", true,
-                                               null, nodeTypes, false);
-                       } catch (RepositoryException e) {
-                               throw new IllegalStateException("Cannot add JCR observer", e);
-                       }
-
-               }
-
-               private void addFilterPanel(Composite parent) {
-                       // Use a delayed text: the query won't be done until the user stop
-                       // typing for 800ms
-                       int style = SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL;
-                       DelayedText delayedText = new DelayedText(parent, style, SEARCH_TEXT_DELAY);
-                       filterTxt = delayedText.getText();
-                       filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
-
-                       // final ServerPushSession pushSession = new ServerPushSession();
-                       delayedText.addDelayedModifyListener(null, new ModifyListener() {
-                               private static final long serialVersionUID = 5003010530960334977L;
-
-                               public void modifyText(ModifyEvent event) {
-                                       delayedText.getText().getDisplay().asyncExec(new Runnable() {
-                                               @Override
-                                               public void run() {
-                                                       refreshFilteredList();
-                                               }
-                                       });
-                                       // pushSession.stop();
-                               }
-                       });
-
-                       // Jump to the first item of the list using the down arrow
-                       filterTxt.addKeyListener(new KeyListener() {
-                               private static final long serialVersionUID = -4523394262771183968L;
-
-                               @Override
-                               public void keyReleased(KeyEvent e) {
-                               }
-
-                               @Override
-                               public void keyPressed(KeyEvent e) {
-                                       // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
-                                       // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
-                                       if (e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.TAB) {
-//                                     Object first = entityViewer.getElementAt(0);
-//                                     if (first != null) {
-//                                             entityViewer.getTable().setFocus();
-//                                             entityViewer.setSelection(new StructuredSelection(first), true);
-//                                     }
-                                               e.doit = false;
-                                       }
-                               }
-                       });
-
-                       parent.addDisposeListener((e) -> {
-                               delayedText.close();
-                       });
-               }
-
-               protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) {
-//                     parent.setLayout(new GridLayout());
-//                     parent.setLayout(CmsUiUtils.noSpaceGridLayout());
-
-                       Composite tableComposite = new Composite(parent, SWT.NONE);
-                       GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL
-                                       | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
-                       tableComposite.setLayoutData(gd);
-
-                       TableViewer viewer = new TableViewer(tableComposite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
-                       viewer.setLabelProvider(labelProvider);
-
-                       TableColumn singleColumn = new TableColumn(viewer.getTable(), SWT.V_SCROLL);
-                       TableColumnLayout tableColumnLayout = new TableColumnLayout();
-                       tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(85));
-                       tableComposite.setLayout(tableColumnLayout);
-
-                       // Corresponding table & style
-                       Table table = viewer.getTable();
-//                     Listener[] mouseDownListeners = table.getListeners(SWT.MouseDown);
-//                     for (Listener listener :  table.getListeners(SWT.MouseDown))
-//                             table.removeListener(SWT.MouseDown, listener);
-//                     for (Listener listener :  table.getListeners(SWT.MouseUp))
-//                             table.removeListener(SWT.MouseUp, listener);
-//                     for (Listener listener :  table.getListeners(SWT.MouseDoubleClick))
-//                             table.removeListener(SWT.MouseDoubleClick, listener);
-//                     
-//                     table.addMouseListener(new MouseListener() {
-//
-//                             @Override
-//                             public void mouseUp(MouseEvent e) {
-//                                     System.out.println("Mouse up: "+e);
-//                             }
-//
-//                             @Override
-//                             public void mouseDown(MouseEvent e) {
-//                                     System.out.println("Mouse down: "+e);
-//                             }
-//
-//                             @Override
-//                             public void mouseDoubleClick(MouseEvent e) {
-//                                     System.out.println("Mouse double: "+e);
-//
-//                             }
-//                     });
-                       table.setLinesVisible(true);
-                       table.setHeaderVisible(false);
-                       // CmsUiUtils.markup(table);
-                       // CmsUiUtils.setItemHeight(table, 26);
-
-                       viewer.setContentProvider(new BasicNodeListContentProvider());
-                       return viewer;
-               }
-
-//             public boolean setFocus() {
-//                     refreshFilteredList();
-//                     return parent.setFocus();
-//             }
-
-               public void forceRefresh(Object object) {
-                       refreshFilteredList();
-               }
-
-               protected void refreshFilteredList() {
-                       try {
-                               String filter = filterTxt.getText();
-                               // Prevents the query on the full repository
-                               // if (isEmpty(filter)) {
-                               // entityViewer.setInput(null);
-                               // return;
-                               // }
-
-                               // XPATH Query
-                               String xpathQueryStr;
-                               if (entityType != null) {
-                                       int indexColumn = entityType.indexOf(':');
-                                       if (indexColumn > 0) {// JCR node type
-                                               xpathQueryStr = "//element(*, " + entityType + ") order by @jcr:created descending";
-                                       } else {
-                                               xpathQueryStr = entityType.contains(":") ? "//element(*, " + entityType + ")"
-                                                               : "//element(*, " + EntityType.entity.get() + ")[@entity:type='" + entityType + "']";
-                                       }
-                               } else {
-                                       xpathQueryStr = "//element(*, " + EntityType.entity.get() + ")";
-                               }
-//                     String xpathQueryStr = "//element(*, " + ConnectTypes.CONNECT_ENTITY + ")";
-                               String xpathFilter = XPathUtils.getFreeTextConstraint(filter);
-                               if (notEmpty(xpathFilter))
-                                       xpathQueryStr += "[" + xpathFilter + "]";
-
-//                             long begin = System.currentTimeMillis();
-                               // session.refresh(false);
-                               Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
-
-                               xpathQuery.setLimit(SEARCH_DEFAULT_LIMIT);
-                               QueryResult result = xpathQuery.execute();
-
-                               NodeIterator nit = result.getNodes();
-                               viewer.setInput(JcrUtils.nodeIteratorToList(nit));
-//                             if (log.isTraceEnabled()) {
-//                                     long end = System.currentTimeMillis();
-//                                     log.trace("Quick Search - Found: " + nit.getSize() + " in " + (end - begin)
-//                                                     + " ms by executing XPath query (" + xpathQueryStr + ").");
-//                             }
-                       } catch (RepositoryException e) {
-                               throw new IllegalStateException("Unable to list entities", e);
-                       }
-               }
-
-               public TableViewer getViewer() {
-                       return viewer;
-               }
-
-               class SingleEntityLabelProvider extends ColumnLabelProvider {
-                       private static final long serialVersionUID = -2209337675781795677L;
-
-                       @Override
-                       public String getText(Object element) {
-                               return Jcr.getTitle((Node) element);
-                       }
-
-               }
-
-               class BasicNodeListContentProvider implements IStructuredContentProvider {
-                       private static final long serialVersionUID = 1L;
-                       // keep a cache of the Nodes in the content provider to be able to
-                       // manage long request
-                       private List<Node> nodes;
-
-                       public void dispose() {
-                       }
-
-                       /** Expects a list of nodes as a new input */
-                       @SuppressWarnings("unchecked")
-                       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-                               nodes = (List<Node>) newInput;
-                       }
-
-                       public Object[] getElements(Object arg0) {
-                               return nodes.toArray();
-                       }
-               }
-       }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java
deleted file mode 100644 (file)
index dbed853..0000000
+++ /dev/null
@@ -1,517 +0,0 @@
-package org.argeo.suite.ui;
-
-import static org.argeo.cms.ui.CmsView.CMS_VIEW_UID_PROPERTY;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeUtils;
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.auth.CmsSession;
-import org.argeo.cms.ui.AbstractCmsApp;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.dialogs.CmsFeedback;
-import org.argeo.cms.ui.util.CmsEvent;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.entity.EntityConstants;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.suite.RankedObject;
-import org.argeo.suite.SuiteUtils;
-import org.argeo.util.LangUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Constants;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
-import org.osgi.service.useradmin.User;
-
-/** The Argeo Suite App. */
-public class SuiteApp extends AbstractCmsApp implements EventHandler {
-       private final static Log log = LogFactory.getLog(SuiteApp.class);
-
-       public final static String PUBLIC_BASE_PATH_PROPERTY = "publicBasePath";
-       public final static String DEFAULT_UI_NAME_PROPERTY = "defaultUiName";
-       public final static String DEFAULT_THEME_ID_PROPERTY = "defaultThemeId";
-
-       private String publicBasePath = null;
-
-       private String pidPrefix;
-       private String headerPid;
-       private String leadPanePid;
-       private String loginScreenPid;
-//     private String DASHBOARD_PID = pidPrefix + "dashboard";
-//     private String RECENT_ITEMS_PID = pidPrefix + "recentItems";
-
-       private String defaultUiName = "app";
-       private String defaultThemeId = "org.argeo.suite.theme.default";
-
-       private Map<String, RankedObject<CmsUiProvider>> uiProvidersByPid = Collections.synchronizedMap(new HashMap<>());
-       private Map<String, RankedObject<CmsUiProvider>> uiProvidersByType = Collections.synchronizedMap(new HashMap<>());
-       private Map<String, RankedObject<SuiteLayer>> layersByPid = Collections.synchronizedSortedMap(new TreeMap<>());
-       private Map<String, RankedObject<SuiteLayer>> layersByType = Collections.synchronizedSortedMap(new TreeMap<>());
-
-       private CmsUserManager cmsUserManager;
-
-       // TODO make more optimal or via CmsSession/CmsView
-       private Map<String, SuiteUi> managedUis = new HashMap<>();
-
-//     private CmsUiProvider headerPart = null;
-
-       public void init(Map<String, Object> properties) {
-               if (log.isDebugEnabled())
-                       log.info("Argeo Suite App started");
-
-               if (properties.containsKey(DEFAULT_UI_NAME_PROPERTY))
-                       defaultUiName = LangUtils.get(properties, DEFAULT_UI_NAME_PROPERTY);
-               if (properties.containsKey(DEFAULT_THEME_ID_PROPERTY))
-                       defaultThemeId = LangUtils.get(properties, DEFAULT_THEME_ID_PROPERTY);
-               publicBasePath = LangUtils.get(properties, PUBLIC_BASE_PATH_PROPERTY);
-
-               if (properties.containsKey(Constants.SERVICE_PID)) {
-                       String servicePid = properties.get(Constants.SERVICE_PID).toString();
-                       if (servicePid.endsWith(".app")) {
-                               pidPrefix = servicePid.substring(0, servicePid.length() - "app".length());
-                       }
-               }
-
-               if (pidPrefix == null)
-                       throw new IllegalArgumentException("PID prefix must be set.");
-
-               headerPid = pidPrefix + "header";
-               leadPanePid = pidPrefix + "leadPane";
-               loginScreenPid = pidPrefix + "loginScreen";
-       }
-
-       public void destroy(Map<String, Object> properties) {
-               for (SuiteUi ui : managedUis.values())
-                       if (!ui.isDisposed())
-                               ui.dispose();
-               if (log.isDebugEnabled())
-                       log.info("Argeo Suite App stopped");
-
-       }
-
-       @Override
-       public Set<String> getUiNames() {
-               HashSet<String> uiNames = new HashSet<>();
-               uiNames.add(defaultUiName);
-               return uiNames;
-       }
-
-       @Override
-       public Composite initUi(Composite parent) {
-               String uiName = parent.getData(UI_NAME_PROPERTY) != null ? parent.getData(UI_NAME_PROPERTY).toString() : null;
-               CmsView cmsView = CmsView.getCmsView(parent);
-               if (cmsView == null)
-                       throw new IllegalStateException("No CMS view is registered.");
-               CmsTheme theme = getTheme(uiName);
-               if (theme != null)
-                       CmsTheme.registerCmsTheme(parent.getShell(), theme);
-               SuiteUi argeoSuiteUi = new SuiteUi(parent, SWT.INHERIT_DEFAULT);
-               String uid = cmsView.getUid();
-               managedUis.put(uid, argeoSuiteUi);
-               argeoSuiteUi.addDisposeListener((e) -> {
-                       managedUis.remove(uid);
-                       if (log.isDebugEnabled())
-                               log.debug("Suite UI " + uid + " has been disposed.");
-               });
-               refreshUi(argeoSuiteUi, null);
-               return argeoSuiteUi;
-       }
-
-       @Override
-       public String getThemeId(String uiName) {
-               return defaultThemeId;
-       }
-
-       @Override
-       public void refreshUi(Composite parent, String state) {
-               try {
-                       Node context = null;
-                       SuiteUi ui = (SuiteUi) parent;
-                       CmsView cmsView = CmsView.getCmsView(parent);
-                       if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login
-                               ui.logout();
-                               refreshPart(findUiProvider(headerPid), ui.getHeader(), context);
-                               ui.refreshBelowHeader(false);
-                               refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context);
-                               ui.layout(true, true);
-                       } else {
-                               CmsSession cmsSession = cmsView.getCmsSession();
-                               if (ui.getUserDir() == null) {
-                                       if (cmsView.isAnonymous()) {
-                                               assert publicBasePath != null;
-                                               ui.initSessions(getRepository(), publicBasePath);
-                                       } else {
-                                               Session adminSession = null;
-                                               try {
-                                                       adminSession = NodeUtils.openDataAdminSession(getRepository(), null);
-                                                       Node userDir = SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
-                                                       ui.initSessions(getRepository(), userDir.getPath());
-                                               } finally {
-                                                       Jcr.logout(adminSession);
-                                               }
-                                       }
-                               }
-                               initLocale(cmsSession);
-                               context = stateToNode(ui, state);
-                               if (context == null)
-                                       context = ui.getUserDir();
-
-                               refreshPart(findUiProvider(headerPid), ui.getHeader(), context);
-                               ui.refreshBelowHeader(true);
-                               for (String key : layersByPid.keySet()) {
-                                       SuiteLayer layer = layersByPid.get(key).get();
-                                       ui.addLayer(key, layer);
-                               }
-                               refreshPart(findUiProvider(leadPanePid), ui.getLeadPane(), context);
-                               ui.layout(true, true);
-                               setState(parent, state);
-                       }
-               } catch (Exception e) {
-                       CmsFeedback.show("Unexpected exception", e);
-               }
-       }
-
-       private void initLocale(CmsSession cmsSession) {
-               if (cmsSession == null)
-                       return;
-               Locale locale = cmsSession.getLocale();
-               UiContext.setLocale(locale);
-               LocaleUtils.setThreadLocale(locale);
-
-       }
-
-       private void refreshPart(CmsUiProvider uiProvider, Composite part, Node context) {
-               CmsUiUtils.clear(part);
-               uiProvider.createUiPart(part, context);
-       }
-
-       private CmsUiProvider findUiProvider(String pid) {
-               if (!uiProvidersByPid.containsKey(pid))
-                       throw new IllegalArgumentException("No UI provider registered as " + pid);
-               return uiProvidersByPid.get(pid).get();
-       }
-
-       private <T> T findByType(Map<String, RankedObject<T>> byType, Node context) {
-               if (context == null)
-                       throw new IllegalArgumentException("A node should be provided");
-               try {
-                       // mixins
-                       Set<String> types = new TreeSet<>();
-                       for (NodeType nodeType : context.getMixinNodeTypes()) {
-                               String typeName = nodeType.getName();
-                               if (byType.containsKey(typeName)) {
-                                       types.add(typeName);
-                               }
-                       }
-                       // primary node type
-                       {
-                               NodeType nodeType = context.getPrimaryNodeType();
-                               String typeName = nodeType.getName();
-                               if (byType.containsKey(typeName)) {
-                                       types.add(typeName);
-                               }
-                               for (NodeType mixin : nodeType.getDeclaredSupertypes()) {
-                                       if (byType.containsKey(mixin.getName())) {
-                                               types.add(mixin.getName());
-                                       }
-                               }
-                       }
-                       // entity type
-                       if (context.isNodeType(EntityType.entity.get())) {
-                               if (context.hasProperty(EntityNames.ENTITY_TYPE)) {
-                                       String typeName = context.getProperty(EntityNames.ENTITY_TYPE).getString();
-                                       if (byType.containsKey(typeName)) {
-                                               types.add(typeName);
-                                       }
-                               }
-                       }
-
-//                     if (context.getPath().equals("/")) {// root node
-//                             types.add("nt:folder");
-//                     }
-                       if (NodeUtils.isUserHome(context) && byType.containsKey("nt:folder")) {// home node
-                               types.add("nt:folder");
-                       }
-
-                       if (types.size() == 0)
-                               throw new IllegalArgumentException("No type found for " + context);
-                       String type = types.iterator().next();
-                       if (!byType.containsKey(type))
-                               throw new IllegalArgumentException("No component found for " + context + " with type " + type);
-                       return byType.get(type).get();
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException(e);
-               }
-       }
-
-       @Override
-       public void setState(Composite parent, String state) {
-               if (state == null || state.equals("~"))
-                       return;
-               if (!state.startsWith("/") && !state.equals("~")) {
-                       if (parent instanceof SuiteUi) {
-                               SuiteUi ui = (SuiteUi) parent;
-                               String currentLayerId = ui.getCurrentLayerId();
-                               if (state.equals(currentLayerId))
-                                       return; // does nothing
-                               else {
-                                       Map<String, Object> properties = new HashMap<>();
-                                       properties.put(SuiteEvent.LAYER, state);
-                                       ui.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), properties);
-                               }
-                       }
-                       return;
-               }
-               SuiteUi suiteUi = (SuiteUi) parent;
-               Node node = stateToNode(suiteUi, state);
-               if (node == null) {
-                       suiteUi.getCmsView().navigateTo("~");
-               } else {
-                       suiteUi.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), SuiteEvent.eventProperties(node));
-                       suiteUi.getCmsView().sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(node));
-               }
-       }
-
-       private String nodeToState(Node node) {
-               return '/' + Jcr.getWorkspaceName(node) + Jcr.getPath(node);
-       }
-
-       private Node stateToNode(SuiteUi suiteUi, String state) {
-               if (suiteUi == null)
-                       return null;
-               if (state == null || !state.startsWith("/"))
-                       return null;
-
-               String path = state.substring(1);
-               String workspace;
-               if (path.equals("")) {
-                       workspace = null;
-                       path = "/";
-               } else {
-                       int index = path.indexOf('/');
-                       if (index == 0) {
-                               log.error("Cannot interpret " + state);
-//                             cmsView.navigateTo("~");
-                               return null;
-                       } else if (index > 0) {
-                               workspace = path.substring(0, index);
-                               path = path.substring(index);
-                       } else {// index<0, assuming root node
-                               workspace = path;
-                               path = "/";
-                       }
-               }
-               Session session = suiteUi.getSession(workspace);
-               if (session == null)
-                       return null;
-               Node node = Jcr.getNode(session, path);
-               return node;
-       }
-
-       /*
-        * Events management
-        */
-
-       @Override
-       public void handleEvent(Event event) {
-
-               // Specific UI related events
-               SuiteUi ui = getRelatedUi(event);
-               if (ui == null)
-                       return;
-               try {
-//                     String currentLayerId = ui.getCurrentLayerId();
-//                     SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null;
-                       if (isTopic(event, SuiteEvent.refreshPart)) {
-                               Node node = getNode(ui, event);
-                               if (node == null)
-                                       return;
-                               CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
-                               SuiteLayer layer = findByType(layersByType, node);
-                               ui.switchToLayer(layer, node);
-                               ui.getCmsView().runAs(() -> layer.view(uiProvider, ui.getCurrentWorkArea(), node));
-                               ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node));
-                       } else if (isTopic(event, SuiteEvent.openNewPart)) {
-                               Node node = getNode(ui, event);
-                               if (node == null)
-                                       return;
-                               CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
-                               SuiteLayer layer = findByType(layersByType, node);
-                               ui.switchToLayer(layer, node);
-                               ui.getCmsView().runAs(() -> layer.open(uiProvider, ui.getCurrentWorkArea(), node));
-                               ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node));
-                       } else if (isTopic(event, SuiteEvent.switchLayer)) {
-                               String layerId = get(event, SuiteEvent.LAYER);
-                               if (layerId != null) {
-//                                     ui.switchToLayer(layerId, ui.getUserDir());
-                                       ui.getCmsView().runAs(() -> ui.switchToLayer(layerId, ui.getUserDir()));
-                                       ui.getCmsView().navigateTo(layerId);
-                               } else {
-                                       Node node = getNode(ui, event);
-                                       if (node != null) {
-                                               SuiteLayer layer = findByType(layersByType, node);
-                                               ui.getCmsView().runAs(() -> ui.switchToLayer(layer, node));
-                                       }
-                               }
-                       }
-               } catch (Exception e) {
-                       log.error("Cannot handle event " + event, e);
-//                     CmsView.getCmsView(ui).exception(e);
-               }
-
-       }
-
-       private Node getNode(SuiteUi ui, Event event) {
-               String nodePath = get(event, SuiteEvent.NODE_PATH);
-               String workspaceName = get(event, SuiteEvent.WORKSPACE);
-               Session session = ui.getSession(workspaceName);
-               Node node;
-               if (nodePath == null) {
-                       // look for a user
-                       String username = get(event, SuiteEvent.USERNAME);
-                       if (username == null)
-                               return null;
-                       User user = cmsUserManager.getUser(username);
-                       if (user == null)
-                               return null;
-                       LdapName userDn;
-                       try {
-                               userDn = new LdapName(user.getName());
-                       } catch (InvalidNameException e) {
-                               throw new IllegalArgumentException("Badly formatted username", e);
-                       }
-                       String userNodePath = SuiteUtils.getUserNodePath(userDn);
-                       if (Jcr.itemExists(session, userNodePath))
-                               node = Jcr.getNode(session, userNodePath);
-                       else {
-                               Session adminSession = null;
-                               try {
-                                       adminSession = NodeUtils.openDataAdminSession(getRepository(), workspaceName);
-                                       SuiteUtils.getOrCreateUserNode(adminSession, userDn);
-                               } finally {
-                                       Jcr.logout(adminSession);
-                               }
-                               node = Jcr.getNode(session, userNodePath);
-                       }
-               } else {
-                       node = Jcr.getNode(session, nodePath);
-               }
-               return node;
-       }
-
-       private SuiteUi getRelatedUi(Event event) {
-               return managedUis.get(get(event, CMS_VIEW_UID_PROPERTY));
-       }
-
-       private static boolean isTopic(Event event, CmsEvent cmsEvent) {
-               return event.getTopic().equals(cmsEvent.topic());
-       }
-
-       private static String get(Event event, String key) {
-               Object value = event.getProperty(key);
-               if (value == null)
-                       return null;
-//                     throw new IllegalArgumentException("Property " + key + " must be set");
-               return value.toString();
-
-       }
-
-       /*
-        * Dependency injection.
-        */
-
-       public void addUiProvider(CmsUiProvider uiProvider, Map<String, Object> properties) {
-               if (properties.containsKey(Constants.SERVICE_PID)) {
-                       String pid = (String) properties.get(Constants.SERVICE_PID);
-                       RankedObject.putIfHigherRank(uiProvidersByPid, pid, uiProvider, properties);
-               }
-               if (properties.containsKey(EntityConstants.TYPE)) {
-                       List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
-                       for (String type : types)
-                               RankedObject.putIfHigherRank(uiProvidersByType, type, uiProvider, properties);
-               }
-       }
-
-       public void removeUiProvider(CmsUiProvider uiProvider, Map<String, Object> properties) {
-               if (properties.containsKey(Constants.SERVICE_PID)) {
-                       String pid = (String) properties.get(Constants.SERVICE_PID);
-                       if (uiProvidersByPid.containsKey(pid)) {
-                               if (uiProvidersByPid.get(pid).equals(new RankedObject<CmsUiProvider>(uiProvider, properties))) {
-                                       uiProvidersByPid.remove(pid);
-                               }
-                       }
-               }
-               if (properties.containsKey(EntityConstants.TYPE)) {
-                       List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
-                       for (String type : types) {
-                               if (uiProvidersByType.containsKey(type)) {
-                                       if (uiProvidersByType.get(type).equals(new RankedObject<CmsUiProvider>(uiProvider, properties))) {
-                                               uiProvidersByType.remove(type);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
-               if (properties.containsKey(Constants.SERVICE_PID)) {
-                       String pid = (String) properties.get(Constants.SERVICE_PID);
-                       RankedObject.putIfHigherRank(layersByPid, pid, layer, properties);
-               }
-               if (properties.containsKey(EntityConstants.TYPE)) {
-                       List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
-                       for (String type : types)
-                               RankedObject.putIfHigherRank(layersByType, type, layer, properties);
-               }
-       }
-
-       public void removeLayer(SuiteLayer layer, Map<String, Object> properties) {
-               if (properties.containsKey(Constants.SERVICE_PID)) {
-                       String pid = (String) properties.get(Constants.SERVICE_PID);
-                       if (layersByPid.containsKey(pid)) {
-                               if (layersByPid.get(pid).equals(new RankedObject<SuiteLayer>(layer, properties))) {
-                                       layersByPid.remove(pid);
-                               }
-                       }
-               }
-               if (properties.containsKey(EntityConstants.TYPE)) {
-                       List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
-                       for (String type : types) {
-                               if (layersByType.containsKey(type)) {
-                                       if (layersByType.get(type).equals(new RankedObject<CmsUiProvider>(layer, properties))) {
-                                               layersByType.remove(type);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       public void setCmsUserManager(CmsUserManager cmsUserManager) {
-               this.cmsUserManager = cmsUserManager;
-       }
-
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteEvent.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteEvent.java
deleted file mode 100644 (file)
index 563cd21..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.ui.util.CmsEvent;
-import org.argeo.jcr.Jcr;
-import org.osgi.service.useradmin.User;
-
-/** Events specific to Argeo Suite. */
-public enum SuiteEvent implements CmsEvent {
-       openNewPart, refreshPart, switchLayer;
-
-       public final static String LAYER = "layer";
-//     public final static String NODE_ID = "nodeId";
-       public final static String NODE_PATH = "path";
-       public final static String USERNAME = "username";
-       public final static String WORKSPACE = "workspace";
-
-       public String getTopicBase() {
-               return "argeo/suite/ui";
-       }
-
-       public static Map<String, Object> eventProperties(Node node) {
-               Map<String, Object> properties = new HashMap<>();
-               properties.put(NODE_PATH, Jcr.getPath(node));
-               properties.put(WORKSPACE, Jcr.getWorkspaceName(node));
-               return properties;
-       }
-
-       public static Map<String, Object> eventProperties(User user) {
-               Map<String, Object> properties = new HashMap<>();
-               properties.put(USERNAME, user.getName());
-               return properties;
-       }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteIcon.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteIcon.java
deleted file mode 100644 (file)
index e40ba5a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.argeo.suite.ui;
-
-import org.argeo.cms.ui.util.CmsIcon;
-
-/** Icon names used by Argeo Suite. */
-public enum SuiteIcon implements CmsIcon {
-       add, save, close, search, delete, logout, dashboard,
-       // people
-       people, person, organisation,
-       // library
-       documents, document, folder,
-       // admin and settings
-       settings, user,
-       // misc
-       task, tag, location, inbox, map;
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java
deleted file mode 100644 (file)
index 8af7611..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.widgets.Composite;
-
-/** An UI layer for the main work area. */
-public interface SuiteLayer extends CmsUiProvider {
-       static enum Property {
-               title, icon, weights, startMaximized;
-       }
-
-       void view(CmsUiProvider uiProvider, Composite workArea, Node context);
-
-       default void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
-               view(uiProvider, workArea, context);
-       }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteMsg.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteMsg.java
deleted file mode 100644 (file)
index 3b376db..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.argeo.suite.ui;
-
-import org.argeo.cms.Localized;
-
-/** Localized messages. */
-public enum SuiteMsg implements Localized {
-       dashboard, people, documents, locations, recentItems,
-       // NewPersonWizard
-       firstName, lastName, salutation, email, personWizardWindowTitle, personWizardPageTitle,
-       // NewOrgWizard
-       orgWizardWindowTitle, orgWizardPageTitle, legalName, legalForm, vatId,
-       // ContextAddressComposite
-       chooseAnOrganisation, street, streetComplement, zipCode, city, state, country, geopoint,
-       // FilteredOrderableEntityTable
-       filterHelp,
-       // BankAccountComposite
-       accountHolder, bankName, currency, accountNumber, bankNumber, BIC, IBAN,
-       // EditJobDialog
-       position, chosenItem, department, isPrimary, searchAndChooseEntity,
-       // ContactListCTab (e4)
-       notes, addAContact, contactValue, linkedCompany,
-       // OrgAdminInfoCTab (e4)
-       paymentAccount,
-       // OrgEditor (e4)
-       orgDetails, orgActivityLog, team, orgAdmin,
-       // PersonEditor (e4)
-       personDetails, personActivityLog, personOrgs, personSecurity,
-       // PersonSecurityCTab (e4)
-       resetPassword,
-       // Generic
-       label, aCustomLabel, description, value, name, primary, add, save, pickup,
-       // Tag
-       confirmNewTag, cannotCreateTag;
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteStyle.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteStyle.java
deleted file mode 100644 (file)
index 5183fa4..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.argeo.suite.ui;
-
-import org.argeo.cms.ui.util.CmsStyle;
-
-/** Styles used by Argeo Suite work UI. */
-public enum SuiteStyle implements CmsStyle {
-       // Header
-       header, headerTitle, headerMenu, headerMenuItem,
-       // Recent items
-       recentItems,
-       // Lead pane
-       leadPane, leadPaneItem, leadPaneSectionTitle, leadPaneSubSectionTitle,
-       // Group composite
-       titleContainer, titleLabel, subTitleLabel, formLine, formColumn, navigationBar, navigationTitle, navigationButton,
-       // Forms elements
-       simpleLabel, simpleText, simpleInput,
-       // table
-       titleCell,
-       // layers
-       workArea,
-       // tabbed area
-       mainTabBody, mainTabSelected, mainTab,
-       // Buttons
-       inlineButton;
-
-       @Override
-       public String getClassPrefix() {
-               return "argeo-suite";
-       }
-
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java
deleted file mode 100644 (file)
index b245762..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.jcr.Jcr;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FormLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** The view for the default ergonomics of Argeo Suite. */
-class SuiteUi extends Composite {
-       private static final long serialVersionUID = 6207018859086689108L;
-       private final static Log log = LogFactory.getLog(SuiteUi.class);
-       private Composite header;
-       private Composite belowHeader;
-       private Composite leadPane;
-       private Composite dynamicArea;
-
-       private Session sysSession;
-//     private Session homeSession;
-       private Node userDir;
-
-       private Map<String, SuiteLayer> layers = new HashMap<>();
-       private Map<String, Composite> workAreas = new HashMap<>();
-       private String currentLayerId = null;
-
-       private CmsView cmsView;
-
-       public SuiteUi(Composite parent, int style) {
-               super(parent, style);
-               cmsView = CmsView.getCmsView(parent);
-               this.setLayout(CmsUiUtils.noSpaceGridLayout());
-
-               header = new Composite(this, SWT.NONE);
-               header.setLayout(CmsUiUtils.noSpaceGridLayout());
-               CmsUiUtils.style(header, SuiteStyle.header);
-               header.setLayoutData(CmsUiUtils.fillWidth());
-
-               belowHeader = new Composite(this, SWT.NONE);
-               belowHeader.setLayoutData(CmsUiUtils.fillAll());
-       }
-
-       public void refreshBelowHeader(boolean initApp) {
-               CmsUiUtils.clear(belowHeader);
-               int style = getStyle();
-               if (initApp) {
-                       belowHeader.setLayout(CmsUiUtils.noSpaceGridLayout(2));
-
-                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
-                               dynamicArea = new Composite(belowHeader, SWT.NONE);
-                               leadPane = new Composite(belowHeader, SWT.NONE);
-                       } else {
-                               leadPane = new Composite(belowHeader, SWT.NONE);
-                               dynamicArea = new Composite(belowHeader, SWT.NONE);
-                       }
-                       leadPane.setLayoutData(CmsUiUtils.fillHeight());
-                       leadPane.setLayout(CmsUiUtils.noSpaceGridLayout());
-                       CmsUiUtils.style(leadPane, SuiteStyle.leadPane);
-
-                       dynamicArea.setLayoutData(CmsUiUtils.fillAll());
-                       dynamicArea.setLayout(new FormLayout());
-
-               } else {
-                       belowHeader.setLayout(CmsUiUtils.noSpaceGridLayout());
-               }
-       }
-
-       /*
-        * LAYERS
-        */
-
-       Composite getCurrentWorkArea() {
-               if (currentLayerId == null)
-                       throw new IllegalStateException("No current layer");
-               return workAreas.get(currentLayerId);
-       }
-
-       String getCurrentLayerId() {
-               return currentLayerId;
-       }
-
-       private Composite getLayer(String id, Node context) {
-               if (!layers.containsKey(id))
-                       return null;
-               if (!workAreas.containsKey(id))
-                       initLayer(id, layers.get(id), context);
-               return workAreas.get(id);
-       }
-
-       Composite switchToLayer(String layerId, Node context) {
-               Composite current = null;
-               if (currentLayerId != null) {
-                       current = getCurrentWorkArea();
-                       if (currentLayerId.equals(layerId))
-                               return current;
-               }
-               if (context == null) {
-                       if (!cmsView.isAnonymous())
-                               context = userDir;
-               }
-               Composite toShow = getLayer(layerId, context);
-               if (toShow != null) {
-                       currentLayerId = layerId;
-                       if (!isDisposed()) {
-//                             getDisplay().syncExec(() -> {
-                               if (!toShow.isDisposed()) {
-                                       toShow.moveAbove(null);
-                               } else {
-                                       log.warn("Cannot show work area because it is disposed.");
-                                       toShow = initLayer(layerId, layers.get(layerId), context);
-                                       toShow.moveAbove(null);
-                               }
-                               dynamicArea.layout(true, true);
-//                             });
-                       }
-                       return toShow;
-               } else {
-                       return current;
-               }
-       }
-
-       Composite switchToLayer(SuiteLayer layer, Node context) {
-               // TODO make it more robust
-               for (String layerId : layers.keySet()) {
-                       SuiteLayer l = layers.get(layerId);
-                       if (layer == l) {
-                               return switchToLayer(layerId, context);
-                       }
-               }
-               throw new IllegalArgumentException("Layer is not registered.");
-       }
-
-       void addLayer(String id, SuiteLayer layer) {
-               layers.put(id, layer);
-       }
-
-       void removeLayer(String id) {
-               layers.remove(id);
-               if (workAreas.containsKey(id)) {
-                       Composite workArea = workAreas.remove(id);
-                       if (!workArea.isDisposed())
-                               workArea.dispose();
-               }
-       }
-
-       protected Composite initLayer(String id, SuiteLayer layer, Node context) {
-               Composite workArea = cmsView.doAs(() -> (Composite) layer.createUiPart(dynamicArea, context));
-               CmsUiUtils.style(workArea, SuiteStyle.workArea);
-               workArea.setLayoutData(CmsUiUtils.coverAll());
-               workAreas.put(id, workArea);
-               return workArea;
-       }
-
-       synchronized void logout() {
-               userDir = null;
-               Jcr.logout(sysSession);
-//             Jcr.logout(homeSession);
-               currentLayerId = null;
-               workAreas.clear();
-       }
-
-       /*
-        * GETTERS / SETTERS
-        */
-
-       Composite getHeader() {
-               return header;
-       }
-
-       Composite getLeadPane() {
-               return leadPane;
-       }
-
-       Composite getBelowHeader() {
-               return belowHeader;
-       }
-
-//     Session getSysSession() {
-//             return sysSession;
-//     }
-//
-       synchronized void initSessions(Repository repository, String userDirPath) throws RepositoryException {
-               this.sysSession = repository.login();
-//             this.homeSession = repository.login(NodeConstants.HOME_WORKSPACE);
-               userDir = sysSession.getNode(userDirPath);
-               addDisposeListener((e) -> {
-                       Jcr.logout(sysSession);
-//                     Jcr.logout(homeSession);
-               });
-       }
-
-       Node getUserDir() {
-               return userDir;
-       }
-
-       Session getSysSession() {
-               return sysSession;
-       }
-
-       Session getSession(String workspaceName) {
-               if (workspaceName == null)
-                       return sysSession;
-               if (NodeConstants.SYS_WORKSPACE.equals(workspaceName))
-                       return sysSession;
-//             else if (NodeConstants.HOME_WORKSPACE.equals(workspaceName))
-//                     return homeSession;
-               else
-                       throw new IllegalArgumentException("Unknown workspace " + workspaceName);
-       }
-
-       public CmsView getCmsView() {
-               return cmsView;
-       }
-
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java
deleted file mode 100644 (file)
index 8e9a9d5..0000000
+++ /dev/null
@@ -1,368 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.cms.Localized;
-import org.argeo.cms.ui.CmsEditable;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.cms.ui.dialogs.LightweightDialog;
-import org.argeo.cms.ui.util.CmsIcon;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** UI utilities related to the APAF project. */
-public class SuiteUiUtils {
-
-       /** Singleton. */
-       private SuiteUiUtils() {
-       }
-
-       /** creates a title bar composite with label and optional button */
-       public static void addTitleBar(Composite parent, String title, Boolean isEditable) {
-               Composite titleBar = new Composite(parent, SWT.NONE);
-               titleBar.setLayoutData(CmsUiUtils.fillWidth());
-               CmsUiUtils.style(titleBar, SuiteStyle.titleContainer);
-
-               titleBar.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(2, false)));
-               Label titleLbl = new Label(titleBar, SWT.NONE);
-               titleLbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
-               CmsUiUtils.style(titleLbl, SuiteStyle.titleLabel);
-               titleLbl.setText(title);
-
-               if (isEditable) {
-                       Button editBtn = new Button(titleBar, SWT.PUSH);
-                       editBtn.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
-                       CmsUiUtils.style(editBtn, SuiteStyle.inlineButton);
-                       editBtn.setText("Edit");
-               }
-       }
-
-       public static Label addFormLabel(Composite parent, String label) {
-               Label lbl = new Label(parent, SWT.WRAP);
-               lbl.setText(label);
-               // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
-               CmsUiUtils.style(lbl, SuiteStyle.simpleLabel);
-               return lbl;
-       }
-
-       public static Text addFormTextField(Composite parent, String text, String message) {
-               return addFormTextField(parent, text, message, SWT.NONE);
-       }
-
-       public static Text addFormTextField(Composite parent, String text, String message, int style) {
-               Text txt = new Text(parent, style);
-               if (text != null)
-                       txt.setText(text);
-               if (message != null)
-                       txt.setMessage(message);
-               txt.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
-               CmsUiUtils.style(txt, SuiteStyle.simpleText);
-               return txt;
-       }
-
-       public static Text addFormInputField(Composite parent, String placeholder) {
-               Text txt = new Text(parent, SWT.BORDER);
-
-               GridData gridData = CmsUiUtils.fillWidth();
-               txt.setLayoutData(gridData);
-
-               if (placeholder != null)
-                       txt.setText(placeholder);
-
-               CmsUiUtils.style(txt, SuiteStyle.simpleInput);
-               return txt;
-       }
-
-       /** creates a single horizontal-block composite for key:value display */
-       public static Text addFormLine(Composite parent, String label, String text) {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(2, false));
-               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
-               addFormLabel(lineComposite, label);
-               Text txt = addFormTextField(lineComposite, text, null);
-               txt.setEditable(false);
-               txt.setLayoutData(CmsUiUtils.fillWidth());
-               return txt;
-       }
-
-       public static Text addFormLine(Composite parent, String label, Node node, String property,
-                       CmsEditable cmsEditable) {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(2, false));
-               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
-               addFormLabel(lineComposite, label);
-               String text = Jcr.get(node, property);
-//             int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
-               Text txt = addFormTextField(lineComposite, text, null, SWT.WRAP);
-               if (cmsEditable != null && cmsEditable.isEditing()) {
-                       txt.addModifyListener((e) -> {
-                               Jcr.set(node, property, txt.getText());
-                               Jcr.save(node);
-                       });
-               } else {
-                       txt.setEditable(false);
-               }
-               txt.setLayoutData(CmsUiUtils.fillWidth());
-               return txt;
-       }
-
-       public static Text addFormInput(Composite parent, String label, String placeholder) {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(2, false));
-               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
-               addFormLabel(lineComposite, label);
-               Text txt = addFormInputField(lineComposite, placeholder);
-               txt.setLayoutData(CmsUiUtils.fillWidth());
-               return txt;
-       }
-
-       /**
-        * creates a single horizontal-block composite for key:value display, with
-        * offset value
-        */
-       public static Text addFormLine(Composite parent, String label, String text, Integer offset) {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(3, false));
-               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
-               Label offsetLbl = new Label(lineComposite, SWT.NONE);
-               GridData gridData = new GridData();
-               gridData.widthHint = offset;
-               offsetLbl.setLayoutData(gridData);
-               addFormLabel(lineComposite, label);
-               Text txt = addFormTextField(lineComposite, text, null);
-               txt.setLayoutData(CmsUiUtils.fillWidth());
-               return txt;
-       }
-
-       /** creates a single vertical-block composite for key:value display */
-       public static Text addFormColumn(Composite parent, String label, String text) {
-//             Composite columnComposite = new Composite(parent, SWT.NONE);
-//             columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-//             columnComposite.setLayout(new GridLayout(1, false));
-               addFormLabel(parent, label);
-               Text txt = addFormTextField(parent, text, null);
-               txt.setEditable(false);
-               txt.setLayoutData(CmsUiUtils.fillWidth());
-               return txt;
-       }
-
-       public static Text addFormColumn(Composite parent, String label, Node node, String property,
-                       CmsEditable cmsEditable) {
-//             Composite columnComposite = new Composite(parent, SWT.NONE);
-//             columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-//             columnComposite.setLayout(new GridLayout(1, false));
-               addFormLabel(parent, label);
-               String text = Jcr.get(node, property);
-//             int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
-               Text txt = addFormTextField(parent, text, null, SWT.WRAP);
-               if (cmsEditable != null && cmsEditable.isEditing()) {
-                       txt.addModifyListener((e) -> {
-                               Jcr.set(node, property, txt.getText());
-                               Jcr.save(node);
-                       });
-               } else {
-                       txt.setEditable(false);
-               }
-               txt.setLayoutData(CmsUiUtils.fillWidth());
-               return txt;
-       }
-
-       public static Label createBoldLabel(Composite parent, Localized localized) {
-               Label label = new Label(parent, SWT.LEAD);
-               label.setText(localized.lead());
-               label.setFont(EclipseUiUtils.getBoldFont(parent));
-               label.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
-               return label;
-       }
-
-       public static Label addFormPicture(Composite parent, String label, Node fileNode) throws RepositoryException {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(2, true));
-               CmsUiUtils.style(lineComposite, SuiteStyle.formLine);
-               addFormLabel(lineComposite, label);
-
-               return addPicture(lineComposite, fileNode);
-       }
-
-       public static Label addPicture(Composite parent, Node fileNode) throws RepositoryException {
-               return addPicture(parent, fileNode, null);
-       }
-
-       public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth) throws RepositoryException {
-               Node content = fileNode.getNode(Node.JCR_CONTENT);
-               // TODO move it deeper in the middleware.
-               if (!content.isNodeType(EntityType.box.get())) {
-                       if (content.getSession().hasPermission(content.getPath(), Session.ACTION_SET_PROPERTY)) {
-                               try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
-                                       ImageData imageData = new ImageData(in);
-                                       content.addMixin(EntityType.box.get());
-                                       content.setProperty(EntityNames.SVG_WIDTH, imageData.width);
-                                       content.setProperty(EntityNames.SVG_HEIGHT, imageData.height);
-                                       content.getSession().save();
-                               } catch (IOException e) {
-                                       throw new RuntimeException(e);
-                               }
-                       }
-               }
-
-               // TODO optimise
-               Long width;
-               Long height;
-               if (content.isNodeType(EntityType.box.get())) {
-                       width = content.getProperty(EntityNames.SVG_WIDTH).getLong();
-                       height = content.getProperty(EntityNames.SVG_HEIGHT).getLong();
-               } else {
-                       try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
-                               ImageData imageData = new ImageData(in);
-                               width = Long.valueOf(imageData.width);
-                               height = Long.valueOf(imageData.height);
-                       } catch (IOException e) {
-                               throw new RuntimeException(e);
-                       }
-               }
-
-               if (maxWidth != null && width > maxWidth) {
-                       Double ratio = maxWidth.doubleValue() / width.doubleValue();
-                       width = maxWidth.longValue();
-                       height = Math.round(ratio * height);
-               }
-               Label img = new Label(parent, SWT.NONE);
-               CmsUiUtils.markup(img);
-               img.setText(CmsUiUtils.img(fileNode, width.toString(), height.toString()));
-               if (parent.getLayout() instanceof GridLayout) {
-                       GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
-                       gd.widthHint = width.intValue();
-                       gd.heightHint = height.intValue();
-                       img.setLayoutData(gd);
-               }
-               img.addMouseListener(new MouseListener() {
-                       private static final long serialVersionUID = -1362242049325206168L;
-
-                       @Override
-                       public void mouseUp(MouseEvent e) {
-                       }
-
-                       @Override
-                       public void mouseDown(MouseEvent e) {
-                       }
-
-                       @Override
-                       public void mouseDoubleClick(MouseEvent e) {
-                               LightweightDialog dialog = new LightweightDialog(img.getShell()) {
-
-                                       @Override
-                                       protected Control createDialogArea(Composite parent) {
-                                               parent.setLayout(new GridLayout());
-                                               ScrolledComposite scroll = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
-                                               scroll.setLayoutData(CmsUiUtils.fillAll());
-                                               scroll.setLayout(CmsUiUtils.noSpaceGridLayout());
-                                               scroll.setExpandHorizontal(true);
-                                               scroll.setExpandVertical(true);
-                                               // scroll.setAlwaysShowScrollBars(true);
-
-                                               Composite c = new Composite(scroll, SWT.NONE);
-                                               scroll.setContent(c);
-                                               c.setLayout(new GridLayout());
-                                               c.setLayoutData(CmsUiUtils.fillAll());
-                                               Label bigImg = new Label(c, SWT.NONE);
-                                               CmsUiUtils.markup(bigImg);
-                                               bigImg.setText(CmsUiUtils.img(fileNode, Jcr.get(content, EntityNames.SVG_WIDTH),
-                                                               Jcr.get(content, EntityNames.SVG_HEIGHT)));
-                                               bigImg.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
-                                               return bigImg;
-                                       }
-
-                                       @Override
-                                       protected Point getInitialSize() {
-                                               Point shellSize = img.getShell().getSize();
-                                               return new Point(shellSize.x - 100, shellSize.y - 100);
-                                       }
-
-                               };
-                               dialog.open();
-                       }
-               });
-               return img;
-       }
-
-       public static Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon) {
-               CmsTheme theme = CmsTheme.getCmsTheme(parent);
-               Button button = new Button(parent, SWT.PUSH);
-               CmsUiUtils.style(button, SuiteStyle.leadPane);
-               if (icon != null)
-                       button.setImage(icon.getBigIcon(theme));
-               button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false));
-               // button.setToolTipText(msg.lead());
-               if (msg != null) {
-                       Label lbl = new Label(parent, SWT.NONE);
-                       CmsUiUtils.style(lbl, SuiteStyle.leadPane);
-                       lbl.setText(msg.lead());
-                       lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
-               }
-               CmsUiUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer);
-               return button;
-       }
-
-//     public static String createAndConfigureEntity(Shell shell, Session referenceSession, String mainMixin,
-//                     String... additionnalProps) {
-//
-//             Session tmpSession = null;
-//             Session mainSession = null;
-//             try {
-//                     // FIXME would not work if home is another physical workspace
-//                     tmpSession = referenceSession.getRepository().login(NodeConstants.HOME_WORKSPACE);
-//                     Node draftNode = null;
-//                     for (int i = 0; i < additionnalProps.length - 1; i += 2) {
-//                             draftNode.setProperty(additionnalProps[i], additionnalProps[i + 1]);
-//                     }
-//                     Wizard wizard = null;
-//                     CmsWizardDialog dialog = new CmsWizardDialog(shell, wizard);
-//                     // WizardDialog dialog = new WizardDialog(shell, wizard);
-//                     if (dialog.open() == Window.OK) {
-//                             String parentPath = null;// "/" + appService.getBaseRelPath(mainMixin);
-//                             // FIXME it should be possible to specify the workspace
-//                             mainSession = referenceSession.getRepository().login();
-//                             Node parent = mainSession.getNode(parentPath);
-//                             Node task = null;// appService.publishEntity(parent, mainMixin, draftNode);
-////                           task = appService.saveEntity(task, false);
-//                             referenceSession.refresh(true);
-//                             return task.getPath();
-//                     }
-//                     return null;
-//             } catch (RepositoryException e1) {
-//                     throw new JcrException(
-//                                     "Unable to create " + mainMixin + " entity with session " + referenceSession.toString(), e1);
-//             } finally {
-//                     JcrUtils.logoutQuietly(tmpSession);
-//                     JcrUtils.logoutQuietly(mainSession);
-//             }
-//     }
-
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUserUiProvider.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUserUiProvider.java
deleted file mode 100644 (file)
index 04d7a7b..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.naming.LdapAttrs;
-import org.eclipse.swt.SWT;
-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.Group;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.useradmin.User;
-
-/** Edit a suite user. */
-public class SuiteUserUiProvider implements CmsUiProvider {
-       private String[] availableRoles;
-       private CmsUserManager cmsUserManager;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               Section main = new Section(parent, SWT.NONE, context);
-               main.setLayoutData(CmsUiUtils.fillAll());
-
-               String uid = context.getName();
-               User user = cmsUserManager.getUserFromLocalId(uid);
-
-//             Text givenName = new Text(main, SWT.SINGLE);
-//             givenName.setText(getUserProperty(user, LdapAttrs.givenName.name()));
-               Text givenName = SuiteUiUtils.addFormInput(main, SuiteMsg.firstName.lead(),
-                               getUserProperty(user, LdapAttrs.givenName.name()));
-
-               Text sn = SuiteUiUtils.addFormInput(main, SuiteMsg.lastName.lead(), getUserProperty(user, LdapAttrs.sn.name()));
-               // sn.setText(getUserProperty(user, LdapAttrs.sn.name()));
-
-               Text email = SuiteUiUtils.addFormInput(main, SuiteMsg.email.lead(),
-                               getUserProperty(user, LdapAttrs.mail.name()));
-               // email.setText(getUserProperty(user, LdapAttrs.mail.name()));
-
-               Text uidT = SuiteUiUtils.addFormLine(main, "uid", getUserProperty(user, LdapAttrs.uid.name()));
-               uidT.setText(uid);
-
-//             Label dnL = new Label(main, SWT.NONE);
-//             dnL.setText(user.getName());
-
-               // roles
-               // Section rolesSection = new Section(main, SWT.NONE, context);
-               Group rolesSection = new Group(main, SWT.NONE);
-               rolesSection.setText("Roles");
-               rolesSection.setLayoutData(CmsUiUtils.fillWidth());
-               rolesSection.setLayout(new GridLayout());
-               // new Label(rolesSection, SWT.NONE).setText("Roles:");
-               List<String> roles = Arrays.asList(cmsUserManager.getUserRoles(user.getName()));
-               for (String role : availableRoles) {
-                       // new Label(rolesSection, SWT.NONE).setText(role);
-                       Button radio = new Button(rolesSection, SWT.CHECK);
-                       radio.setText(role);
-                       if (roles.contains(role))
-                               radio.setSelection(true);
-               }
-
-               return main;
-       }
-
-       public void setCmsUserManager(CmsUserManager cmsUserManager) {
-               this.cmsUserManager = cmsUserManager;
-       }
-
-       private String getUserProperty(Object element, String key) {
-               Object value = ((User) element).getProperties().get(key);
-               return value != null ? value.toString() : null;
-       }
-
-       public void init(Map<String, Object> properties) {
-               availableRoles = (String[]) properties.get("availableRoles");
-       }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonPage.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonPage.java
deleted file mode 100644 (file)
index ddd4488..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.argeo.suite.ui.dialogs;
-
-import org.argeo.suite.ui.SuiteMsg;
-import org.argeo.suite.ui.SuiteUiUtils;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-public class NewPersonPage extends WizardPage {
-       private static final long serialVersionUID = -944349994177526468L;
-       protected Text lastNameTxt;
-       protected Text firstNameTxt;
-       protected Text emailTxt;
-
-       protected NewPersonPage(String pageName) {
-               super(pageName);
-               setTitle(SuiteMsg.personWizardPageTitle.lead());
-       }
-
-       @Override
-       public void createControl(Composite parent) {
-               parent.setLayout(new GridLayout(2, false));
-
-               // FirstName
-               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
-               firstNameTxt = new Text(parent, SWT.BORDER);
-               firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
-               // LastName
-               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
-               lastNameTxt = new Text(parent, SWT.BORDER);
-               lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
-               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.email);
-               emailTxt = new Text(parent, SWT.BORDER);
-               emailTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
-               ModifyListener ml = new ModifyListener() {
-                       private static final long serialVersionUID = -1628130380128946886L;
-
-                       @Override
-                       public void modifyText(ModifyEvent event) {
-                               getContainer().updateButtons();
-                       }
-               };
-
-               firstNameTxt.addModifyListener(ml);
-               lastNameTxt.addModifyListener(ml);
-               emailTxt.addModifyListener(ml);
-
-               // Don't forget this.
-               setControl(firstNameTxt);
-               firstNameTxt.setFocus();
-
-       }
-
-//     public void updateNode(Node node, PeopleService peopleService, ResourcesService resourcesService) {
-//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_LAST_NAME, PropertyType.STRING, lastNameTxt.getText());
-//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_FIRST_NAME, PropertyType.STRING,
-//                             firstNameTxt.getText());
-//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_DISPLAY_NAME, PropertyType.STRING,
-//                             firstNameTxt.getText() + " " + lastNameTxt.getText());
-//             String email = emailTxt.getText();
-//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_PRIMARY_EMAIL, PropertyType.STRING, email);
-//             PeopleJcrUtils.createEmail(resourcesService, peopleService, node, email, true, null, null);
-//     }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonWizard.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewPersonWizard.java
deleted file mode 100644 (file)
index 9db5e04..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-package org.argeo.suite.ui.dialogs;
-
-import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
-
-import javax.jcr.Node;
-
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.suite.ui.SuiteMsg;
-import org.argeo.suite.ui.SuiteUiUtils;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-/** Ask first & last name. Update the passed node on finish */
-public class NewPersonWizard extends Wizard {
-       // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
-
-       // Context
-       private Node person;
-
-       // This page widgets
-       protected Text lastNameTxt;
-       protected Text firstNameTxt;
-       // private Button useDistinctDisplayNameBtn;
-       // private Text displayNameTxt;
-
-       public NewPersonWizard(Node person) {
-               this.person = person;
-       }
-
-       @Override
-       public void addPages() {
-               try {
-                       MainInfoPage page = new MainInfoPage("Main page");
-                       addPage(page);
-               } catch (Exception e) {
-                       throw new RuntimeException("Cannot add page to wizard", e);
-               }
-               setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
-       }
-
-       /**
-        * Called when the user click on 'Finish' in the wizard. The task is then
-        * created and the corresponding session saved.
-        */
-       @Override
-       public boolean performFinish() {
-               String lastName = lastNameTxt.getText();
-               String firstName = firstNameTxt.getText();
-               // String displayName = displayNameTxt.getText();
-               // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
-               if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
-                       MessageDialog.openError(getShell(), "Non-valid information",
-                                       "Please enter at least a name that is not empty.");
-                       return false;
-               } else {
-//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
-//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
-//                     String fullName = firstName + " " + lastName;
-//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
-                       return true;
-               }
-       }
-
-       @Override
-       public boolean performCancel() {
-               return true;
-       }
-
-       @Override
-       public boolean canFinish() {
-               String lastName = lastNameTxt.getText();
-               String firstName = firstNameTxt.getText();
-               if (isEmpty(lastName) && isEmpty(firstName)) {
-                       return false;
-               } else
-                       return true;
-       }
-
-       protected class MainInfoPage extends WizardPage {
-               private static final long serialVersionUID = 1L;
-
-               public MainInfoPage(String pageName) {
-                       super(pageName);
-                       setTitle(SuiteMsg.personWizardPageTitle.lead());
-                       // setMessage("Please enter a last name and/or a first name.");
-               }
-
-               public void createControl(Composite parent) {
-                       parent.setLayout(new GridLayout(2, false));
-
-                       // FirstName
-                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
-                       firstNameTxt = new Text(parent, SWT.BORDER);
-                       // firstNameTxt.setMessage("a first name");
-                       firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
-                       // LastName
-                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
-                       lastNameTxt = new Text(parent, SWT.BORDER);
-                       // lastNameTxt.setMessage("a last name");
-                       lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
-                       // Display Name
-                       // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
-                       // useDistinctDisplayNameBtn.setText("Define a disting display name");
-                       // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
-                       // true, false, 2, 1));
-                       //
-                       // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
-                       // displayNameTxt = new Text(parent, SWT.BORDER);
-                       // displayNameTxt.setMessage("an optional display name");
-                       // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
-                       // false));
-                       // displayNameTxt.setEnabled(false);
-                       //
-                       // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
-                       // private static final long serialVersionUID = 1L;
-                       //
-                       // @Override
-                       // public void widgetSelected(SelectionEvent e) {
-                       // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
-                       // }
-                       // });
-
-                       ModifyListener ml = new ModifyListener() {
-                               private static final long serialVersionUID = -1628130380128946886L;
-
-                               @Override
-                               public void modifyText(ModifyEvent event) {
-                                       getContainer().updateButtons();
-                               }
-                       };
-
-                       firstNameTxt.addModifyListener(ml);
-                       lastNameTxt.addModifyListener(ml);
-                       // displayNameTxt.addModifyListener(ml);
-
-                       // Don't forget this.
-                       setControl(firstNameTxt);
-                       firstNameTxt.setFocus();
-               }
-       }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewUserWizard.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/dialogs/NewUserWizard.java
deleted file mode 100644 (file)
index 5b4575d..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-package org.argeo.suite.ui.dialogs;
-
-import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
-
-import javax.jcr.Node;
-
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.suite.ui.SuiteMsg;
-import org.argeo.suite.ui.SuiteUiUtils;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-/** Ask first & last name. Update the passed node on finish */
-public class NewUserWizard extends Wizard {
-       // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
-
-       // Context
-       private Node person;
-
-       // This page widgets
-       protected Text lastNameTxt;
-       protected Text firstNameTxt;
-       // private Button useDistinctDisplayNameBtn;
-       // private Text displayNameTxt;
-
-       public NewUserWizard(Node person) {
-               this.person = person;
-       }
-
-       @Override
-       public void addPages() {
-               try {
-                       MainInfoPage page = new MainInfoPage("Main page");
-                       addPage(page);
-               } catch (Exception e) {
-                       throw new RuntimeException("Cannot add page to wizard", e);
-               }
-               setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
-       }
-
-       /**
-        * Called when the user click on 'Finish' in the wizard. The task is then
-        * created and the corresponding session saved.
-        */
-       @Override
-       public boolean performFinish() {
-               String lastName = lastNameTxt.getText();
-               String firstName = firstNameTxt.getText();
-               // String displayName = displayNameTxt.getText();
-               // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
-               if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
-                       MessageDialog.openError(getShell(), "Non-valid information",
-                                       "Please enter at least a name that is not empty.");
-                       return false;
-               } else {
-//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
-//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
-//                     String fullName = firstName + " " + lastName;
-//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
-                       return true;
-               }
-       }
-
-       @Override
-       public boolean performCancel() {
-               return true;
-       }
-
-       @Override
-       public boolean canFinish() {
-               String lastName = lastNameTxt.getText();
-               String firstName = firstNameTxt.getText();
-               if (isEmpty(lastName) && isEmpty(firstName)) {
-                       return false;
-               } else
-                       return true;
-       }
-
-       protected class MainInfoPage extends WizardPage {
-               private static final long serialVersionUID = 1L;
-
-               public MainInfoPage(String pageName) {
-                       super(pageName);
-                       setTitle(SuiteMsg.personWizardPageTitle.lead());
-                       // setMessage("Please enter a last name and/or a first name.");
-               }
-
-               public void createControl(Composite parent) {
-                       parent.setLayout(new GridLayout(2, false));
-
-                       // FirstName
-                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
-                       firstNameTxt = new Text(parent, SWT.BORDER);
-                       // firstNameTxt.setMessage("a first name");
-                       firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
-                       // LastName
-                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
-                       lastNameTxt = new Text(parent, SWT.BORDER);
-                       // lastNameTxt.setMessage("a last name");
-                       lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
-                       // Display Name
-                       // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
-                       // useDistinctDisplayNameBtn.setText("Define a disting display name");
-                       // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
-                       // true, false, 2, 1));
-                       //
-                       // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
-                       // displayNameTxt = new Text(parent, SWT.BORDER);
-                       // displayNameTxt.setMessage("an optional display name");
-                       // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
-                       // false));
-                       // displayNameTxt.setEnabled(false);
-                       //
-                       // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
-                       // private static final long serialVersionUID = 1L;
-                       //
-                       // @Override
-                       // public void widgetSelected(SelectionEvent e) {
-                       // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
-                       // }
-                       // });
-
-                       ModifyListener ml = new ModifyListener() {
-                               private static final long serialVersionUID = -1628130380128946886L;
-
-                               @Override
-                               public void modifyText(ModifyEvent event) {
-                                       getContainer().updateButtons();
-                               }
-                       };
-
-                       firstNameTxt.addModifyListener(ml);
-                       lastNameTxt.addModifyListener(ml);
-                       // displayNameTxt.addModifyListener(ml);
-
-                       // Don't forget this.
-                       setControl(firstNameTxt);
-                       firstNameTxt.setFocus();
-               }
-       }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java
deleted file mode 100644 (file)
index 07f9cee..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-package org.argeo.suite.ui.widgets;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-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;
-
-/**
- * Generic popup context menu for TableViewer to enable single sourcing between
- * CMS and Workbench
- */
-public abstract class AbstractConnectContextMenu {
-
-       private Shell parentShell;
-       private Shell shell;
-       // Local context
-
-       private final static String KEY_ACTION_ID = "actionId";
-       private final String[] defaultActions;
-       private Map<String, Button> actionButtons = new HashMap<String, Button>();
-
-       public AbstractConnectContextMenu(Display display, String[] defaultActions) {
-               parentShell = display.getActiveShell();
-               shell = new Shell(parentShell, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-               this.defaultActions = defaultActions;
-       }
-
-       protected void createControl() {
-               shell.setLayout(EclipseUiUtils.noSpaceGridLayout());
-               Composite boxCmp = new Composite(shell, SWT.NO_FOCUS | SWT.BORDER);
-               boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
-//             CmsUiUtils.style(boxCmp, ConnectUiStyles.CONTEXT_MENU_BOX);
-               createContextMenu(boxCmp);
-               shell.addShellListener(new ActionsShellListener());
-       }
-
-       protected void createContextMenu(Composite boxCmp) {
-               ActionsSelListener asl = new ActionsSelListener();
-               for (String actionId : defaultActions) {
-                       Button btn = new Button(boxCmp, SWT.FLAT | SWT.LEAD);
-                       btn.setText(getLabel(actionId));
-                       btn.setLayoutData(EclipseUiUtils.fillWidth());
-                       CmsUiUtils.markup(btn);
-//                     CmsUiUtils.style(btn, actionId + ConnectUiStyles.BUTTON_SUFFIX);
-                       btn.setData(KEY_ACTION_ID, actionId);
-                       btn.addSelectionListener(asl);
-                       actionButtons.put(actionId, btn);
-               }
-       }
-
-       protected void setVisible(boolean visible, String... buttonIds) {
-               for (String id : buttonIds) {
-                       Button button = actionButtons.get(id);
-                       button.setVisible(visible);
-                       GridData gd = (GridData) button.getLayoutData();
-                       gd.heightHint = visible ? SWT.DEFAULT : 0;
-               }
-       }
-
-       public void show(Control source, Point location, IStructuredSelection selection) {
-               if (shell.isDisposed()) {
-                       shell = new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-                       createControl();
-               }
-               if (shell.isVisible())
-                       shell.setVisible(false);
-
-               if (aboutToShow(source, location, selection)) {
-                       shell.pack();
-                       shell.layout();
-                       if (source instanceof Control)
-                               shell.setLocation(((Control) source).toDisplay(location.x, location.y));
-                       shell.open();
-               }
-       }
-
-       protected Shell getParentShell() {
-               return parentShell;
-       }
-
-       class StyleButton extends Label {
-               private static final long serialVersionUID = 7731102609123946115L;
-
-               public StyleButton(Composite parent, int swtStyle) {
-                       super(parent, swtStyle);
-               }
-       }
-
-       class ActionsSelListener extends SelectionAdapter {
-               private static final long serialVersionUID = -1041871937815812149L;
-
-               @Override
-               public void widgetSelected(SelectionEvent e) {
-                       Object eventSource = e.getSource();
-                       if (eventSource instanceof Button) {
-                               Button pressedBtn = (Button) eventSource;
-                               performAction((String) pressedBtn.getData(KEY_ACTION_ID));
-                               shell.close();
-                       }
-               }
-       }
-
-       class ActionsShellListener extends org.eclipse.swt.events.ShellAdapter {
-               private static final long serialVersionUID = -5092341449523150827L;
-
-               @Override
-               public void shellDeactivated(ShellEvent e) {
-                       setVisible(false);
-                       shell.setVisible(false);
-                       //shell.close();
-               }
-       }
-
-       protected abstract boolean performAction(String actionId);
-
-       protected abstract boolean aboutToShow(Control source, Point location, IStructuredSelection selection);
-
-       protected abstract String getLabel(String actionId);
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java
deleted file mode 100644 (file)
index ffe733e..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-package org.argeo.suite.ui.widgets;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.rap.rwt.widgets.DropDown;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.Widget;
-
-/**
- * Enable easy addition of a {@code DropDown} widget to a text with listeners
- * configured
- */
-public abstract class ConnectAbstractDropDown {
-
-       private final Text text;
-       private final DropDown dropDown;
-       private boolean modifyFromList = false;
-
-       // Current displayed text
-       private String userText = "";
-       // Current displayed list items
-       private String[] values;
-
-       // Fine tuning
-       boolean readOnly;
-       boolean refreshOnFocus;
-
-       /** Implementing classes should call refreshValues() after initialisation */
-       public ConnectAbstractDropDown(Text text) {
-               this(text, SWT.NONE, false);
-       }
-
-       /**
-        * Implementing classes should call refreshValues() after initialisation
-        * 
-        * @param text
-        * @param style
-        *            only SWT.READ_ONLY is understood, check if the entered text is
-        *            part of the legal choices.
-        */
-       public ConnectAbstractDropDown(Text text, int style) {
-               this(text, style, false);
-       }
-
-       /**
-        * Implementers should call refreshValues() once init has been done.
-        * 
-        * @param text
-        * @param style
-        *            only SWT.READ_ONLY is understood, check if the entered text is
-        *            part of the legal choices.
-        * @param refreshOnFocus
-        *            if true, the possible values are computed each time the focus is
-        *            gained. It enables, among other to fine tune the getFilteredValues
-        *            method depending on the current context
-        */
-       public ConnectAbstractDropDown(Text text, int style, boolean refreshOnFocus) {
-               this.text = text;
-               dropDown = new DropDown(text);
-               Object obj = dropDown;
-               if (obj instanceof Widget)
-                       CmsUiUtils.markup((Widget) obj);
-               readOnly = (style & SWT.READ_ONLY) != 0;
-               this.refreshOnFocus = refreshOnFocus;
-               addListeners();
-       }
-
-       /**
-        * Overwrite to force the refresh of the possible values on focus gained event
-        */
-       protected boolean refreshOnFocus() {
-               return refreshOnFocus;
-       }
-
-       public String getText() {
-               return text.getText();
-       }
-
-       public void init() {
-               refreshValues();
-       }
-
-       public void reset(String value) {
-               modifyFromList = true;
-               if (EclipseUiUtils.notEmpty(value))
-                       text.setText(value);
-               else
-                       text.setText("");
-               refreshValues();
-               modifyFromList = false;
-       }
-
-       /** Overwrite to provide specific filtering */
-       protected abstract List<String> getFilteredValues(String filter);
-
-       protected void refreshValues() {
-               List<String> filteredValues = getFilteredValues(text.getText());
-               values = filteredValues.toArray(new String[filteredValues.size()]);
-               dropDown.setItems(values);
-       }
-
-       protected void addListeners() {
-               addModifyListener();
-               addSelectionListener();
-               addDefaultSelectionListener();
-               addFocusListener();
-       }
-
-       protected void addFocusListener() {
-               text.addFocusListener(new FocusListener() {
-                       private static final long serialVersionUID = -7179112097626535946L;
-
-                       public void focusGained(FocusEvent event) {
-                               if (refreshOnFocus) {
-                                       modifyFromList = true;
-                                       refreshValues();
-                                       modifyFromList = false;
-                               }
-                               dropDown.setVisible(true);
-                       }
-
-                       public void focusLost(FocusEvent event) {
-                               dropDown.setVisible(false);
-                               if (readOnly && values != null && !Arrays.asList(values).contains(userText)) {
-                                       modifyFromList = true;
-                                       text.setText("");
-                                       refreshValues();
-                                       modifyFromList = false;
-                               }
-                       }
-               });
-       }
-
-       private void addSelectionListener() {
-               Object obj = dropDown;
-               if (obj instanceof Widget)
-                       ((Widget) obj).addListener(SWT.Selection, new Listener() {
-                               private static final long serialVersionUID = -2357157809365135142L;
-
-                               public void handleEvent(Event event) {
-                                       if (event.index != -1) {
-                                               modifyFromList = true;
-                                               text.setText(values[event.index]);
-                                               modifyFromList = false;
-                                               text.selectAll();
-                                       } else {
-                                               text.setText(userText);
-                                               text.setSelection(userText.length(), userText.length());
-                                               text.setFocus();
-                                       }
-                               }
-                       });
-       }
-
-       private void addDefaultSelectionListener() {
-               Object obj = dropDown;
-               if (obj instanceof Widget)
-                       ((Widget) obj).addListener(SWT.DefaultSelection, new Listener() {
-                               private static final long serialVersionUID = -5958008322630466068L;
-
-                               public void handleEvent(Event event) {
-                                       if (event.index != -1) {
-                                               text.setText(values[event.index]);
-                                               text.setSelection(event.text.length());
-                                               dropDown.setVisible(false);
-                                       }
-                               }
-                       });
-       }
-
-       private void addModifyListener() {
-               text.addListener(SWT.Modify, new Listener() {
-                       private static final long serialVersionUID = -4373972835244263346L;
-
-                       public void handleEvent(Event event) {
-                               if (!modifyFromList) {
-                                       userText = text.getText();
-                                       refreshValues();
-                                       if (values.length == 1)
-                                               dropDown.setSelectionIndex(0);
-                                       dropDown.setVisible(true);
-                               }
-                       }
-               });
-       }
-}
diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/DelayedText.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/DelayedText.java
deleted file mode 100644 (file)
index a03c250..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-package org.argeo.suite.ui.widgets;
-
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.eclipse.rap.rwt.service.ServerPushSession;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Text that introduce a timer in the attached ModifyListener.
- * 
- * Note that corresponding ModifyEvent will *NOT* be sent in the UI thread.
- * Calling ModifierInstance must be implemented in consequence. Note also that
- * this delayed text only manages one listener at a time.
- *
- */
-public class DelayedText {
-       final int delay;
-       private Object lock = new Object();
-       private MyTimer timer = new MyTimer(DelayedText.this.toString());
-       private ModifyListener delayedModifyListener;
-       private ServerPushSession pushSession;
-
-       private Text text;
-
-       private ModifyListener modifyListener = new ModifyListener() {
-               private static final long serialVersionUID = 1117506414462641980L;
-
-               public void modifyText(ModifyEvent e) {
-                       ModifyEvent delayedEvent = null;
-                       synchronized (lock) {
-                               if (delayedModifyListener != null) {
-                                       Event tmpEvent = new Event();
-                                       tmpEvent.widget = text;
-                                       tmpEvent.display = e.display;
-                                       tmpEvent.data = e.data;
-                                       tmpEvent.time = e.time;
-                                       delayedEvent = new ModifyEvent(tmpEvent);
-                               }
-                       }
-                       final ModifyEvent timerModifyEvent = delayedEvent;
-
-                       synchronized (timer) {
-                               if (timer.timerTask != null) {
-                                       timer.timerTask.cancel();
-                                       timer.timerTask = null;
-                               }
-
-                               if (delayedEvent != null) {
-                                       timer.timerTask = new TimerTask() {
-                                               public void run() {
-                                                       synchronized (lock) {
-                                                               delayedModifyListener.modifyText(timerModifyEvent);
-                                                               // Bad approach: it is not a good idea to put a
-                                                               // display.asyncExec in a lock...
-                                                               // DelayedText.this.getDisplay().asyncExec(new
-                                                               // Runnable() {
-                                                               // @Override
-                                                               // public void run() {
-                                                               // delayedModifyListener.modifyText(timerModifyEvent);
-                                                               // }
-                                                               // }
-                                                               // );
-                                                       }
-                                                       synchronized (timer) {
-                                                               timer.timerTask = null;
-                                                       }
-                                               }
-                                       };
-                                       timer.schedule(timer.timerTask, delay);
-                                       if (pushSession != null)
-                                               pushSession.start();
-                               }
-                       }
-               };
-       };
-
-       public DelayedText(Composite parent, int style, int delayInMs) {
-               // super(parent, style);
-               text = new Text(parent, style);
-               this.delay = delayInMs;
-               text.addModifyListener(modifyListener);
-       }
-
-       /**
-        * Adds a modify text listener that will be delayed. If another Modify event
-        * happens during the waiting delay, the older event will be canceled an a new
-        * one will be scheduled after another new delay.
-        */
-       public void addDelayedModifyListener(ServerPushSession pushSession, ModifyListener listener) {
-               synchronized (lock) {
-                       delayedModifyListener = listener;
-                       this.pushSession = pushSession;
-               }
-       }
-
-       public void removeDelayedModifyListener(ModifyListener listener) {
-               synchronized (lock) {
-                       delayedModifyListener = null;
-                       pushSession = null;
-               }
-       }
-
-       private class MyTimer extends Timer {
-               private TimerTask timerTask = null;
-
-               public MyTimer(String name) {
-                       super(name);
-               }
-       }
-
-       public Text getText() {
-               return text;
-       }
-
-       public void close() {
-               if (pushSession != null)
-                       pushSession.stop();
-               if (timer != null)
-                       timer.cancel();
-       };
-
-}
diff --git a/pom.xml b/pom.xml
index 2d4ef3ff3ce9b12017886b9b0855f646dd567766..36bd192644f29f7ca0bc8ca6b03dab2d27b9fbcb 100644 (file)
--- a/pom.xml
+++ b/pom.xml
                <git.rw />
        </properties>
        <modules>
-               <!-- Entity Framework -->
-               <module>org.argeo.entity.api</module>
-               <module>org.argeo.entity.core</module>
-               <module>org.argeo.entity.ui</module>
-
-               <!-- Argeo Suite -->
-               <module>org.argeo.suite.core</module>
-               <module>org.argeo.suite.ui</module>
-               <module>org.argeo.suite.ui.rap</module>
-               <module>org.argeo.suite.theme.default</module>
-
+               <module>core</module>
                <!-- Functional areas -->
                <module>library</module>
                <module>publishing</module>