Rename packages
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 13 Jan 2022 14:20:49 +0000 (15:20 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 13 Jan 2022 14:20:49 +0000 (15:20 +0100)
255 files changed:
org.argeo.app.api/pom.xml
org.argeo.app.api/src/org/argeo/app/api/EntityConstants.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/EntityDefinition.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/EntityMimeType.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/EntityNames.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/EntityType.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/EntityTypes.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/JcrName.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/RankedObject.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/RankingKey.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/SuiteRole.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/Term.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/TermsManager.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/Typology.java [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/app/api/entity.cnd [new file with mode: 0644]
org.argeo.app.api/src/org/argeo/entity/EntityConstants.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/EntityDefinition.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/EntityMimeType.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/EntityNames.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/EntityType.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/EntityTypes.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/JcrName.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/Term.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/TermsManager.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/Typology.java [deleted file]
org.argeo.app.api/src/org/argeo/entity/entity.cnd [deleted file]
org.argeo.app.core/OSGI-INF/maintenanceService.xml
org.argeo.app.core/OSGI-INF/termsManager.xml
org.argeo.app.core/bnd.bnd
org.argeo.app.core/src/org/argeo/app/core/CustomMaintenanceService.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/core/JcrEntityDefinition.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/core/SuiteMaintenanceService.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/core/SuiteTerm.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/core/SuiteTermsManager.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/core/SuiteTypology.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/core/SuiteUtils.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/core/XPathUtils.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/docbook/Dbk4Converter.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/docbook/DbkAttr.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/docbook/DbkMsg.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/docbook/DbkType.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/docbook/db4-upgrade.xsl [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/docbook/docbook-full.cnd [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/docbook/docbook.cnd [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/geo/GeoJsonUtils.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/geo/GeoToSvg.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/geo/geonames/GeonamesAdm.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/library/DocxExtractor.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/odk/BundleResourceOdkForm.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/odk/OdkForm.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/odk/OdkNames.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/odk/OdkUtils.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/odk/OrxListName.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/odk/OrxManifestName.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/odk/OrxType.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/odk/odk.cnd [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/app/xforms/xforms.cnd [new file with mode: 0644]
org.argeo.app.core/src/org/argeo/docbook/Dbk4Converter.java [deleted file]
org.argeo.app.core/src/org/argeo/docbook/DbkAttr.java [deleted file]
org.argeo.app.core/src/org/argeo/docbook/DbkMsg.java [deleted file]
org.argeo.app.core/src/org/argeo/docbook/DbkType.java [deleted file]
org.argeo.app.core/src/org/argeo/docbook/DbkUtils.java [deleted file]
org.argeo.app.core/src/org/argeo/docbook/db4-upgrade.xsl [deleted file]
org.argeo.app.core/src/org/argeo/docbook/docbook-full.cnd [deleted file]
org.argeo.app.core/src/org/argeo/docbook/docbook.cnd [deleted file]
org.argeo.app.core/src/org/argeo/entity/core/JcrEntityDefinition.java [deleted file]
org.argeo.app.core/src/org/argeo/geo/GeoJsonUtils.java [deleted file]
org.argeo.app.core/src/org/argeo/geo/GeoToSvg.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/RankedObject.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/RankingKey.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/SuiteRole.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/SuiteUtils.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/core/CustomMaintenanceService.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/core/SuiteMaintenanceService.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/core/SuiteTerm.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/core/SuiteTermsManager.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/core/SuiteTypology.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/library/DocxExtractor.java [deleted file]
org.argeo.app.core/src/org/argeo/suite/util/XPathUtils.java [deleted file]
org.argeo.app.core/src/org/argeo/support/geonames/GeonamesAdm.java [deleted file]
org.argeo.app.core/src/org/argeo/support/geonames/ImportGeonamesAdmin.java [deleted file]
org.argeo.app.core/src/org/argeo/support/odk/BundleResourceOdkForm.java [deleted file]
org.argeo.app.core/src/org/argeo/support/odk/OdkForm.java [deleted file]
org.argeo.app.core/src/org/argeo/support/odk/OdkNames.java [deleted file]
org.argeo.app.core/src/org/argeo/support/odk/OdkUtils.java [deleted file]
org.argeo.app.core/src/org/argeo/support/odk/OrxListName.java [deleted file]
org.argeo.app.core/src/org/argeo/support/odk/OrxManifestName.java [deleted file]
org.argeo.app.core/src/org/argeo/support/odk/OrxType.java [deleted file]
org.argeo.app.core/src/org/argeo/support/odk/odk.cnd [deleted file]
org.argeo.app.core/src/org/argeo/support/xforms/FormSubmissionListener.java [deleted file]
org.argeo.app.core/src/org/argeo/support/xforms/xforms.cnd [deleted file]
org.argeo.app.servlet.odk/OSGI-INF/odkFormListServlet.xml
org.argeo.app.servlet.odk/OSGI-INF/odkFormServlet.xml
org.argeo.app.servlet.odk/OSGI-INF/odkManifestServlet.xml
org.argeo.app.servlet.odk/OSGI-INF/odkServletContext.xml
org.argeo.app.servlet.odk/OSGI-INF/odkSubmissionServlet.xml
org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormListServlet.java [new file with mode: 0644]
org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormServlet.java [new file with mode: 0644]
org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java [new file with mode: 0644]
org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkServletContext.java [new file with mode: 0644]
org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java [new file with mode: 0644]
org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkFormListServlet.java [deleted file]
org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkFormServlet.java [deleted file]
org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkManifestServlet.java [deleted file]
org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkServletContext.java [deleted file]
org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java [deleted file]
org.argeo.app.servlet.publish/OSGI-INF/dbk4Converter.xml
org.argeo.app.servlet.publish/OSGI-INF/dbkServlet.xml
org.argeo.app.servlet.publish/OSGI-INF/documentUiProvider.xml
org.argeo.app.servlet.publish/OSGI-INF/fontsServlet.xml
org.argeo.app.servlet.publish/OSGI-INF/wwwLayer.xml
org.argeo.app.servlet.publish/bnd.bnd
org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/DbkServlet.java [new file with mode: 0644]
org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FontsServlet.java [new file with mode: 0644]
org.argeo.app.servlet.publish/src/org/argeo/publishing/servlet/DbkServlet.java [deleted file]
org.argeo.app.servlet.publish/src/org/argeo/publishing/servlet/FontsServlet.java [deleted file]
org.argeo.app.ui/OSGI-INF/adminLeadPane.xml
org.argeo.app.ui/OSGI-INF/cmsApp.xml
org.argeo.app.ui/OSGI-INF/dashboard.xml
org.argeo.app.ui/OSGI-INF/dashboardLayer.xml
org.argeo.app.ui/OSGI-INF/eventRecorder.xml
org.argeo.app.ui/OSGI-INF/footer.xml
org.argeo.app.ui/OSGI-INF/header.xml
org.argeo.app.ui/OSGI-INF/leadPane.xml
org.argeo.app.ui/OSGI-INF/loginScreen.xml
org.argeo.app.ui/OSGI-INF/recentItems.xml
org.argeo.app.ui/OSGI-INF/termsEntryArea.xml
org.argeo.app.ui/OSGI-INF/termsLayer.xml
org.argeo.app.ui/bnd.bnd
org.argeo.app.ui/pom.xml
org.argeo.app.ui/src/org/argeo/app/ui/DefaultDashboard.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/DefaultEditionLayer.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/DefaultFooter.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/DefaultHeader.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/DefaultLeadPane.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/DefaultLoginScreen.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/EventRecorder.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/RecentItems.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/SuiteApp.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/SuiteEvent.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/SuiteIcon.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/SuiteLayer.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/SuiteMsg.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/SuiteStyle.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/SuiteUi.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/TermsEntryArea.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonPage.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonWizard.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewUserWizard.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/AbstractDbkViewer.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/CustomDbkEditor.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkContextMenu.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImageManager.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImg.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkSectionTitle.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkTextInterpreter.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkVideo.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/DocumentPage.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/DocumentTextEditor.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/Paragraph.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextEditorHeader.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextInterpreter.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextSection.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/forms/AbstractTermsPart.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/forms/MultiTermsPart.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/forms/SingleTermPart.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/library/ContentEntryArea.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsContextMenu.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFileComposite.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFolderComposite.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFolderUiProvider.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsTreeUiProvider.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsUiService.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OLMap.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OpenLayersMap.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OverviewMap.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/openlayers/map-osm.html [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/openlayers/map.js [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/people/PeopleEntryArea.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/people/PersonUiProvider.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/people/SuiteUserUiProvider.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/people/SuiteUsersEntryArea.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/publish/DocumentUiProvider.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/publish/PublishingApp.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/publish/PublishingStyle.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/widgets/AbstractConnectContextMenu.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/widgets/ConnectAbstractDropDown.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/widgets/DelayedText.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/widgets/TabbedArea.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/app/ui/widgets/TreeOrSearchArea.java [new file with mode: 0644]
org.argeo.app.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/CustomDbkEditor.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/DbkContextMenu.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/DbkImageManager.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/DbkImg.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/DbkSectionTitle.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/DbkTextInterpreter.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/DbkVideo.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/DocumentPage.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/DocumentTextEditor.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/Paragraph.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/TextEditorHeader.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/TextInterpreter.java [deleted file]
org.argeo.app.ui/src/org/argeo/docbook/ui/TextSection.java [deleted file]
org.argeo.app.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java [deleted file]
org.argeo.app.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java [deleted file]
org.argeo.app.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java [deleted file]
org.argeo.app.ui/src/org/argeo/library/ui/ContentEntryArea.java [deleted file]
org.argeo.app.ui/src/org/argeo/library/ui/DocumentsContextMenu.java [deleted file]
org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFileComposite.java [deleted file]
org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFolderComposite.java [deleted file]
org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFolderUiProvider.java [deleted file]
org.argeo.app.ui/src/org/argeo/library/ui/DocumentsTreeUiProvider.java [deleted file]
org.argeo.app.ui/src/org/argeo/library/ui/DocumentsUiService.java [deleted file]
org.argeo.app.ui/src/org/argeo/people/ui/PeopleEntryArea.java [deleted file]
org.argeo.app.ui/src/org/argeo/people/ui/PersonUiProvider.java [deleted file]
org.argeo.app.ui/src/org/argeo/people/ui/SuiteUserUiProvider.java [deleted file]
org.argeo.app.ui/src/org/argeo/people/ui/SuiteUsersEntryArea.java [deleted file]
org.argeo.app.ui/src/org/argeo/publishing/ui/DocumentUiProvider.java [deleted file]
org.argeo.app.ui/src/org/argeo/publishing/ui/PublishingApp.java [deleted file]
org.argeo.app.ui/src/org/argeo/publishing/ui/PublishingStyle.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/DefaultDashboard.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/DefaultFooter.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/DefaultHeader.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/DefaultLeadPane.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/EventRecorder.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/RecentItems.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/SuiteApp.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/SuiteEvent.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/SuiteIcon.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/SuiteLayer.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/SuiteMsg.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/SuiteStyle.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/SuiteUi.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/SuiteUiUtils.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/TermsEntryArea.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/dialogs/NewPersonPage.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/dialogs/NewPersonWizard.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/dialogs/NewUserWizard.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/widgets/DelayedText.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/widgets/TabbedArea.java [deleted file]
org.argeo.app.ui/src/org/argeo/suite/ui/widgets/TreeOrSearchArea.java [deleted file]
org.argeo.app.ui/src/org/argeo/support/openlayers/OLMap.java [deleted file]
org.argeo.app.ui/src/org/argeo/support/openlayers/OpenLayersMap.java [deleted file]
org.argeo.app.ui/src/org/argeo/support/openlayers/OverviewMap.java [deleted file]
org.argeo.app.ui/src/org/argeo/support/openlayers/map-osm.html [deleted file]
org.argeo.app.ui/src/org/argeo/support/openlayers/map.js [deleted file]

index 4bd6bcf613de0a7fb68e340d845c4d50d8bea846..7c7f588ddeecb2bb2fec174fccf0358a1098e530 100644 (file)
        <packaging>jar</packaging>
        <dependencies>
                <!-- Argeo Commons -->
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.api</artifactId>
+                       <version>${version.argeo-commons}</version>
+               </dependency>
                <dependency>
                        <groupId>org.argeo.commons</groupId>
                        <artifactId>org.argeo.util</artifactId>
diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityConstants.java b/org.argeo.app.api/src/org/argeo/app/api/EntityConstants.java
new file mode 100644 (file)
index 0000000..c7885be
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.app.api;
+
+/** Constant related to entities, typically used in an OSGi context. */
+public interface EntityConstants {
+       final static String TYPE = "entity.type";
+       final static String DEFAULT_EDITOR_ID = "entity.defaultEditorId";
+
+}
diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityDefinition.java b/org.argeo.app.api/src/org/argeo/app/api/EntityDefinition.java
new file mode 100644 (file)
index 0000000..e1280cf
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.app.api;
+
+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.app.api/src/org/argeo/app/api/EntityMimeType.java b/org.argeo.app.api/src/org/argeo/app/api/EntityMimeType.java
new file mode 100644 (file)
index 0000000..eaefcd0
--- /dev/null
@@ -0,0 +1,60 @@
+package org.argeo.app.api;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+/** Supported mime types. */
+public enum EntityMimeType {
+       XML("text/xml", "xml"), CSV("text/csv", "csv");
+
+       private final String mimeType;
+       private final String[] extensions;
+
+       EntityMimeType(String mimeType, String... extensions) {
+               this.mimeType = mimeType;
+               this.extensions = extensions;
+       }
+
+       public String getMimeType() {
+               return mimeType;
+       }
+
+       public String[] getExtensions() {
+               return extensions;
+       }
+
+       public String getDefaultExtension() {
+               if (extensions.length > 0)
+                       return extensions[0];
+               else
+                       return null;
+       }
+
+       public String toHttpContentType(Charset charset) {
+               if (charset == null)
+                       return mimeType;
+               return mimeType + "; charset=" + charset.name();
+       }
+
+       public String toHttpContentType() {
+               if (mimeType.startsWith("text/")) {
+                       return toHttpContentType(StandardCharsets.UTF_8);
+               } else {
+                       return mimeType;
+               }
+       }
+
+       public static EntityMimeType find(String mimeType) {
+               for (EntityMimeType entityMimeType : values()) {
+                       if (entityMimeType.mimeType.equals(mimeType))
+                               return entityMimeType;
+               }
+               return null;
+       }
+
+       @Override
+       public String toString() {
+               return mimeType;
+       }
+
+}
diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java b/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java
new file mode 100644 (file)
index 0000000..7776056
--- /dev/null
@@ -0,0 +1,61 @@
+package org.argeo.app.api;
+
+import org.argeo.util.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.app.api/src/org/argeo/app/api/EntityType.java b/org.argeo.app.api/src/org/argeo/app/api/EntityType.java
new file mode 100644 (file)
index 0000000..48b1266
--- /dev/null
@@ -0,0 +1,42 @@
+package org.argeo.app.api;
+
+/** Types related to entities. */
+public enum EntityType implements JcrName {
+       // entity
+       entity, local, relatedTo,
+       // structure
+       space, document,
+       // 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.app.api/src/org/argeo/app/api/EntityTypes.java b/org.argeo.app.api/src/org/argeo/app/api/EntityTypes.java
new file mode 100644 (file)
index 0000000..f320794
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.app.api;
+
+/** Types related to entities. */
+@Deprecated
+public interface EntityTypes {
+       final static String ENTITY_ENTITY = "entity:entity";
+       final static String ENTITY_DEFINITION = "entity:definition";
+
+       final static String ENTITY_PERSON = "entity:person";
+}
diff --git a/org.argeo.app.api/src/org/argeo/app/api/JcrName.java b/org.argeo.app.api/src/org/argeo/app/api/JcrName.java
new file mode 100644 (file)
index 0000000..182494a
--- /dev/null
@@ -0,0 +1,30 @@
+package org.argeo.app.api;
+
+import java.util.function.Supplier;
+
+/** Can be applied to {@link Enum}s in order to generate prefixed names. */
+@FunctionalInterface
+public interface JcrName extends Supplier<String> {
+       String name();
+
+       default String getPrefix() {
+               return null;
+       }
+
+       default String getNamespace() {
+               return null;
+       }
+
+       @Override
+       default String get() {
+               String prefix = getPrefix();
+               return prefix != null ? prefix + ":" + name() : name();
+       }
+
+       default String withNamespace() {
+               String namespace = getNamespace();
+               if (namespace == null)
+                       throw new UnsupportedOperationException("No namespace is specified for " + getClass());
+               return "{" + namespace + "}" + name();
+       }
+}
diff --git a/org.argeo.app.api/src/org/argeo/app/api/RankedObject.java b/org.argeo.app.api/src/org/argeo/app/api/RankedObject.java
new file mode 100644 (file)
index 0000000..31c43a7
--- /dev/null
@@ -0,0 +1,97 @@
+package org.argeo.app.api;
+
+import java.util.Map;
+
+import org.argeo.api.cms.CmsLog;
+
+/**
+ * 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 CmsLog log = CmsLog.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.app.api/src/org/argeo/app/api/RankingKey.java b/org.argeo.app.api/src/org/argeo/app/api/RankingKey.java
new file mode 100644 (file)
index 0000000..691570c
--- /dev/null
@@ -0,0 +1,160 @@
+package org.argeo.app.api;
+
+import java.util.Map;
+
+/**
+ * Key used to classify and filter available components (typically provided by
+ * OSGi services).
+ */
+@Deprecated
+public class RankingKey implements Comparable<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.app.api/src/org/argeo/app/api/SuiteRole.java b/org.argeo.app.api/src/org/argeo/app/api/SuiteRole.java
new file mode 100644 (file)
index 0000000..38ce11f
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.app.api;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.util.naming.Distinguished;
+import org.argeo.util.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(CmsConstants.ROLES_BASEDN).toString();
+       }
+}
diff --git a/org.argeo.app.api/src/org/argeo/app/api/Term.java b/org.argeo.app.api/src/org/argeo/app/api/Term.java
new file mode 100644 (file)
index 0000000..5a7f09e
--- /dev/null
@@ -0,0 +1,22 @@
+package org.argeo.app.api;
+
+import java.util.List;
+
+/**
+ * A name within a {@link Typology}, used to qualify an entity (categories,
+ * keywords, etc.).
+ */
+public interface Term {
+       String getId();
+
+       String getName();
+
+//     String getRelativePath();
+
+       Typology getTypology();
+
+       List<? extends Term> getSubTerms();
+
+       Term getParentTerm();
+
+}
diff --git a/org.argeo.app.api/src/org/argeo/app/api/TermsManager.java b/org.argeo.app.api/src/org/argeo/app/api/TermsManager.java
new file mode 100644 (file)
index 0000000..decddd9
--- /dev/null
@@ -0,0 +1,13 @@
+package org.argeo.app.api;
+
+import java.util.List;
+
+/** Provides optimised access and utilities around terms typologies. */
+public interface TermsManager {
+       Typology getTypology(String typology);
+       
+       Term getTerm(String id);
+
+       List<Term> listAllTerms(String typology);
+
+}
diff --git a/org.argeo.app.api/src/org/argeo/app/api/Typology.java b/org.argeo.app.api/src/org/argeo/app/api/Typology.java
new file mode 100644 (file)
index 0000000..f57e692
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.app.api;
+
+import java.util.List;
+
+/** A structured and exhaustive set of {@link Term}s. */
+public interface Typology {
+
+       String getId();
+
+       boolean isFlat();
+
+       List<? extends Term> getSubTerms();
+
+       Term findTermByName(String name);
+}
diff --git a/org.argeo.app.api/src/org/argeo/app/api/entity.cnd b/org.argeo.app.api/src/org/argeo/app/api/entity.cnd
new file mode 100644 (file)
index 0000000..2ea89f9
--- /dev/null
@@ -0,0 +1,114 @@
+// 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)
+
+[entity:query] > nt:query, mix:referenceable
+
+[entity:querySet]
++ * (entity:query) = entity:query *
+
+//
+// STRUCTURE
+//
+[entity:space]
+mixin
+
+[entity:document]
+mixin
+
+//
+// TYPOLOGY
+//
+[entity:typologies]
++ * (entity:terms) = entity:terms
+
+[entity:term]
+orderable
+- name (NAME)
+- * (*)
++ term (entity:term) = entity:term *
+
+[entity:terms] > mix:referenceable
+orderable
++ term (entity:term) = entity:term *
+
+//
+// FORM
+//
+[entity:form]
+mixin
++ queries (entity:querySet) = entity:querySet
+
+[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.app.api/src/org/argeo/entity/EntityConstants.java b/org.argeo.app.api/src/org/argeo/entity/EntityConstants.java
deleted file mode 100644 (file)
index 93021e0..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_EDITOR_ID = "entity.defaultEditorId";
-
-}
diff --git a/org.argeo.app.api/src/org/argeo/entity/EntityDefinition.java b/org.argeo.app.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.app.api/src/org/argeo/entity/EntityMimeType.java b/org.argeo.app.api/src/org/argeo/entity/EntityMimeType.java
deleted file mode 100644 (file)
index 997f1be..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.argeo.entity;
-
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-/** Supported mime types. */
-public enum EntityMimeType {
-       XML("text/xml", "xml"), CSV("text/csv", "csv");
-
-       private final String mimeType;
-       private final String[] extensions;
-
-       EntityMimeType(String mimeType, String... extensions) {
-               this.mimeType = mimeType;
-               this.extensions = extensions;
-       }
-
-       public String getMimeType() {
-               return mimeType;
-       }
-
-       public String[] getExtensions() {
-               return extensions;
-       }
-
-       public String getDefaultExtension() {
-               if (extensions.length > 0)
-                       return extensions[0];
-               else
-                       return null;
-       }
-
-       public String toHttpContentType(Charset charset) {
-               if (charset == null)
-                       return mimeType;
-               return mimeType + "; charset=" + charset.name();
-       }
-
-       public String toHttpContentType() {
-               if (mimeType.startsWith("text/")) {
-                       return toHttpContentType(StandardCharsets.UTF_8);
-               } else {
-                       return mimeType;
-               }
-       }
-
-       public static EntityMimeType find(String mimeType) {
-               for (EntityMimeType entityMimeType : values()) {
-                       if (entityMimeType.mimeType.equals(mimeType))
-                               return entityMimeType;
-               }
-               return null;
-       }
-
-       @Override
-       public String toString() {
-               return mimeType;
-       }
-
-}
diff --git a/org.argeo.app.api/src/org/argeo/entity/EntityNames.java b/org.argeo.app.api/src/org/argeo/entity/EntityNames.java
deleted file mode 100644 (file)
index 57901c4..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.argeo.entity;
-
-import org.argeo.util.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.app.api/src/org/argeo/entity/EntityType.java b/org.argeo.app.api/src/org/argeo/entity/EntityType.java
deleted file mode 100644 (file)
index 089cdcf..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.argeo.entity;
-
-/** Types related to entities. */
-public enum EntityType implements JcrName {
-       // entity
-       entity, local, relatedTo,
-       // structure
-       space, document,
-       // 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.app.api/src/org/argeo/entity/EntityTypes.java b/org.argeo.app.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.app.api/src/org/argeo/entity/JcrName.java b/org.argeo.app.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.app.api/src/org/argeo/entity/Term.java b/org.argeo.app.api/src/org/argeo/entity/Term.java
deleted file mode 100644 (file)
index 3bf075a..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.argeo.entity;
-
-import java.util.List;
-
-/**
- * A name within a {@link Typology}, used to qualify an entity (categories,
- * keywords, etc.).
- */
-public interface Term {
-       String getId();
-
-       String getName();
-
-//     String getRelativePath();
-
-       Typology getTypology();
-
-       List<? extends Term> getSubTerms();
-
-       Term getParentTerm();
-
-}
diff --git a/org.argeo.app.api/src/org/argeo/entity/TermsManager.java b/org.argeo.app.api/src/org/argeo/entity/TermsManager.java
deleted file mode 100644 (file)
index 7564ff9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.argeo.entity;
-
-import java.util.List;
-
-/** Provides optimised access and utilities around terms typologies. */
-public interface TermsManager {
-       Typology getTypology(String typology);
-       
-       Term getTerm(String id);
-
-       List<Term> listAllTerms(String typology);
-
-}
diff --git a/org.argeo.app.api/src/org/argeo/entity/Typology.java b/org.argeo.app.api/src/org/argeo/entity/Typology.java
deleted file mode 100644 (file)
index 5be27e3..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.entity;
-
-import java.util.List;
-
-/** A structured and exhaustive set of {@link Term}s. */
-public interface Typology {
-
-       String getId();
-
-       boolean isFlat();
-
-       List<? extends Term> getSubTerms();
-
-       Term findTermByName(String name);
-}
diff --git a/org.argeo.app.api/src/org/argeo/entity/entity.cnd b/org.argeo.app.api/src/org/argeo/entity/entity.cnd
deleted file mode 100644 (file)
index 2ea89f9..0000000
+++ /dev/null
@@ -1,114 +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)
-
-[entity:query] > nt:query, mix:referenceable
-
-[entity:querySet]
-+ * (entity:query) = entity:query *
-
-//
-// STRUCTURE
-//
-[entity:space]
-mixin
-
-[entity:document]
-mixin
-
-//
-// TYPOLOGY
-//
-[entity:typologies]
-+ * (entity:terms) = entity:terms
-
-[entity:term]
-orderable
-- name (NAME)
-- * (*)
-+ term (entity:term) = entity:term *
-
-[entity:terms] > mix:referenceable
-orderable
-+ term (entity:term) = entity:term *
-
-//
-// FORM
-//
-[entity:form]
-mixin
-+ queries (entity:querySet) = entity:querySet
-
-[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)
index 2d495c805e1497e9b1c9db1587094f7cc869a925..48a982fdf2fed411214fb3ea0309314bac368f44 100644 (file)
@@ -1,6 +1,6 @@
 <?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"/>
+   <implementation class="org.argeo.app.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"/>
index 3e6d4c6783cda7fd4069555f573d49bcbc5e9aee..92f84c6a92e1512d6f0eadd9e4f9cbf894be15d7 100644 (file)
@@ -1,8 +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"/>
+   <implementation class="org.argeo.app.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"/>
+      <provide interface="org.argeo.app.api.TermsManager"/>
    </service>
 </scr:component>
index fc27132b13a01fc5afdb0c2f6402e828b17988fa..f7a9e0d89e33bdd92f2c553263cf0ccae381b7ce 100644 (file)
@@ -10,5 +10,4 @@ org.osgi.service.useradmin,\
 javax.jcr.nodetype,\
 javax.jcr.security,\
 com.fasterxml.jackson.core,\
-org.argeo.entity,\
 *
\ No newline at end of file
diff --git a/org.argeo.app.core/src/org/argeo/app/core/CustomMaintenanceService.java b/org.argeo.app.core/src/org/argeo/app/core/CustomMaintenanceService.java
new file mode 100644 (file)
index 0000000..4b69883
--- /dev/null
@@ -0,0 +1,73 @@
+package org.argeo.app.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.argeo.api.cms.CmsLog;
+import org.argeo.app.api.EntityType;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.maintenance.AbstractMaintenanceService;
+
+/** Base for custom initialisations. */
+public abstract class CustomMaintenanceService extends AbstractMaintenanceService {
+       private final static CmsLog log = CmsLog.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);
+                       }
+                       // TODO do not save here, so that upper layers can decide when to save
+                       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.");
+                       // TODO do not save here, so that upper layers can decide when to save
+                       termsBase.getSession().save();
+               } catch (RepositoryException | IOException e) {
+                       log.error("Cannot load terms '" + name + "': " + e.getMessage());
+                       throw e;
+               }
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/core/JcrEntityDefinition.java b/org.argeo.app.core/src/org/argeo/app/core/JcrEntityDefinition.java
new file mode 100644 (file)
index 0000000..10c27a8
--- /dev/null
@@ -0,0 +1,73 @@
+package org.argeo.app.core;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.app.api.EntityConstants;
+import org.argeo.app.api.EntityDefinition;
+import org.argeo.cms.jcr.CmsJcrUtils;
+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 defaultEditorId;
+
+       public void init(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
+               Session adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
+               try {
+                       type = properties.get(EntityConstants.TYPE);
+                       if (type == null)
+                               throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set.");
+                       defaultEditorId = properties.get(EntityConstants.DEFAULT_EDITOR_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 defaultEditorId;
+       }
+
+       @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.app.core/src/org/argeo/app/core/SuiteMaintenanceService.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteMaintenanceService.java
new file mode 100644 (file)
index 0000000..532b7dd
--- /dev/null
@@ -0,0 +1,39 @@
+package org.argeo.app.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.cms.CmsConstants;
+import org.argeo.app.api.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(), CmsConstants.ROLE_USER_ADMIN,
+                               Privilege.JCR_ALL);
+               //JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), Privilege.JCR_READ);
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/core/SuiteTerm.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteTerm.java
new file mode 100644 (file)
index 0000000..aef23b5
--- /dev/null
@@ -0,0 +1,62 @@
+package org.argeo.app.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.app.api.Term;
+
+/**
+ * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
+ */
+class SuiteTerm implements Term {
+       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 + 1);
+               } else {
+                       this.name = relativePath;
+               }
+               id = typology.getName() + '/' + relativePath;
+       }
+
+       @Override
+       public String getId() {
+               return id;
+       }
+
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       public String getRelativePath() {
+               return relativePath;
+       }
+
+       @Override
+       public SuiteTypology getTypology() {
+               return typology;
+       }
+
+       @Override
+       public List<SuiteTerm> getSubTerms() {
+               return subTerms;
+       }
+
+       @Override
+       public SuiteTerm getParentTerm() {
+               return parentTerm;
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/core/SuiteTermsManager.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteTermsManager.java
new file mode 100644 (file)
index 0000000..c14f871
--- /dev/null
@@ -0,0 +1,103 @@
+package org.argeo.app.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.cms.CmsConstants;
+import org.argeo.app.api.EntityNames;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.api.Term;
+import org.argeo.app.api.TermsManager;
+import org.argeo.cms.jcr.CmsJcrUtils;
+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 = CmsJcrUtils.openDataAdminSession(repository, CmsConstants.SYS_WORKSPACE);
+       }
+
+       @Override
+       public List<Term> listAllTerms(String typology) {
+               List<Term> res = new ArrayList<>();
+               SuiteTypology t = getTypology(typology);
+               for (SuiteTerm term : t.getAllTerms()) {
+                       res.add(term);
+               }
+               return res;
+       }
+
+       @Override
+       public SuiteTerm getTerm(String termId) {
+               return terms.get(termId);
+       }
+
+       @Override
+       public 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.app.core/src/org/argeo/app/core/SuiteTypology.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteTypology.java
new file mode 100644 (file)
index 0000000..7838274
--- /dev/null
@@ -0,0 +1,95 @@
+package org.argeo.app.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.app.api.Term;
+import org.argeo.app.api.Typology;
+import org.argeo.jcr.Jcr;
+
+/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
+class SuiteTypology implements Typology {
+       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);
+       }
+
+       @Override
+       public String getId() {
+               return name;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public Node getNode() {
+               return node;
+       }
+
+       void markNotFlat() {
+               if (isFlat)
+                       isFlat = false;
+       }
+
+       @Override
+       public boolean isFlat() {
+               return isFlat;
+       }
+
+       @Override
+       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;
+               }
+       }
+
+       public Term findTermByName(String name) {
+               List<SuiteTerm> collected = new ArrayList<>();
+               for (SuiteTerm subTerm : subTerms) {
+                       collectTermsByName(subTerm, name, collected);
+               }
+               if (collected.isEmpty())
+                       return null;
+               if (collected.size() == 1)
+                       return collected.get(0);
+               throw new IllegalArgumentException(
+                               "There are " + collected.size() + " terms with name " + name + " in typology " + getId());
+       }
+
+       private void collectTermsByName(SuiteTerm term, String name, List<SuiteTerm> collected) {
+               if (term.getName().equals(name)) {
+                       collected.add(term);
+               }
+               for (SuiteTerm subTerm : term.getSubTerms()) {
+                       collectTermsByName(subTerm, name, collected);
+               }
+       }
+
+       private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
+               for (SuiteTerm subTerm : term.getSubTerms()) {
+                       terms.add(subTerm);
+                       collectSubTerms(terms, subTerm);
+               }
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/core/SuiteUtils.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteUtils.java
new file mode 100644 (file)
index 0000000..0a31b14
--- /dev/null
@@ -0,0 +1,123 @@
+package org.argeo.app.core;
+
+import java.util.HashSet;
+import java.util.Set;
+
+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.cms.CmsConstants;
+import org.argeo.api.cms.CmsSession;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.api.SuiteRole;
+import org.argeo.jackrabbit.security.JackrabbitSecurityUtils;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.util.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(), CmsConstants.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() {
+
+       }
+
+       public static Set<String> extractRoles(String[] semiColArr) {
+               Set<String> res = new HashSet<>();
+               // TODO factorize and make it more robust
+               final String rolesPrefix = "roles:=\"";
+               // first one is layer id
+               for (int i = 1; i < semiColArr.length; i++) {
+                       if (semiColArr[i].startsWith(rolesPrefix)) {
+                               String rolesStr = semiColArr[i].substring(rolesPrefix.length());
+                               // remove last "
+                               rolesStr = rolesStr.substring(0, rolesStr.lastIndexOf('\"'));
+                               // TODO support AND (&) as well
+                               String[] roles = rolesStr.split("\\|");// OR (|)
+                               for (String role : roles) {
+                                       res.add(role.trim());
+                               }
+                       }
+               }
+               return res;
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/core/XPathUtils.java b/org.argeo.app.core/src/org/argeo/app/core/XPathUtils.java
new file mode 100644 (file)
index 0000000..f86445c
--- /dev/null
@@ -0,0 +1,176 @@
+package org.argeo.app.core;
+
+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.jackrabbit.util.ISO9075;
+import org.argeo.api.cms.CmsLog;
+
+/** Ease XPath generation for JCR requests */
+public class XPathUtils {
+       private final static CmsLog log = CmsLog.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.app.core/src/org/argeo/app/docbook/Dbk4Converter.java b/org.argeo.app.core/src/org/argeo/app/docbook/Dbk4Converter.java
new file mode 100644 (file)
index 0000000..d3957d9
--- /dev/null
@@ -0,0 +1,100 @@
+package org.argeo.app.docbook;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.xalan.processor.TransformerFactoryImpl;
+import org.argeo.jcr.JcrException;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/** Convert from DocBook v4 to DocBook v5, using the official XSL. */
+public class Dbk4Converter {
+       private final Templates templates;
+
+       public Dbk4Converter() {
+               try (InputStream in = getClass().getResourceAsStream("db4-upgrade.xsl")) {
+                       Source xsl = new StreamSource(in);
+                       TransformerFactory transformerFactory = new TransformerFactoryImpl();
+                       templates = transformerFactory.newTemplates(xsl);
+               } catch (IOException | TransformerConfigurationException e) {
+                       throw new RuntimeException("Cannot initialise DocBook v4 converter", e);
+               }
+       }
+
+       public void importXml(Node baseNode, InputStream in) throws IOException {
+               try (ByteArrayOutputStream out = new ByteArrayOutputStream();) {
+                       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+                       factory.setXIncludeAware(true);
+                       factory.setNamespaceAware(true);
+                       DocumentBuilder docBuilder = factory.newDocumentBuilder();
+                       Document doc = docBuilder.parse(new InputSource(in));
+                       Source xmlInput = new DOMSource(doc);
+
+//                     ContentHandler contentHandler = baseNode.getSession().getImportContentHandler(baseNode.getPath(),
+//                                     ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+
+                       Transformer transformer = templates.newTransformer();
+                       Result xmlOutput = new StreamResult(out);
+                       transformer.transform(xmlInput, xmlOutput);
+                       try (InputStream dbk5in = new ByteArrayInputStream(out.toByteArray())) {
+                               baseNode.getSession().importXML(baseNode.getPath(), dbk5in,
+                                               ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot import XML to " + baseNode, e);
+               } catch (TransformerException | SAXException | ParserConfigurationException e) {
+                       throw new RuntimeException("Cannot import DocBook v4 to " + baseNode, e);
+               }
+
+       }
+
+       public static void main(String[] args) {
+               try {
+
+                       Source xsl = new StreamSource(new File("/usr/share/xml/docbook5/stylesheet/upgrade/db4-upgrade.xsl"));
+                       TransformerFactory transformerFactory = new TransformerFactoryImpl();
+                       Templates templates = transformerFactory.newTemplates(xsl);
+
+                       File inputDir = new File(args[0]);
+                       File outputDir = new File(args[1]);
+
+                       for (File inputFile : inputDir.listFiles()) {
+                               Result xmlOutput = new StreamResult(new File(outputDir, inputFile.getName()));
+
+                               DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+                               factory.setXIncludeAware(true);
+                               factory.setNamespaceAware(true);
+                               DocumentBuilder docBuilder = factory.newDocumentBuilder();
+                               Document doc = docBuilder.parse(inputFile);
+                               Source xmlInput = new DOMSource(doc);
+                               Transformer transformer = templates.newTransformer();
+                               transformer.transform(xmlInput, xmlOutput);
+                       }
+               } catch (Throwable e) {
+                       e.printStackTrace();
+               }
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkAttr.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkAttr.java
new file mode 100644 (file)
index 0000000..f6cf839
--- /dev/null
@@ -0,0 +1,13 @@
+package org.argeo.app.docbook;
+
+/** Supported DocBook attributes. */
+public enum DbkAttr {
+       role,
+       //
+       fileref, contentwidth, contentdepth
+       //
+       ;
+
+       public final static String XLINK_HREF = "xlink:href";
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkMsg.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkMsg.java
new file mode 100644 (file)
index 0000000..2f34988
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.app.docbook;
+
+import org.argeo.cms.Localized;
+
+/** DocBook related messages. */
+public enum DbkMsg implements Localized {
+       paragraph, deleteParagraph,
+       //
+       section, deleteSection,
+       //
+       media, deleteMedia, insertPicture, insertVideo, insertParagraph,
+       //
+       ;
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkType.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkType.java
new file mode 100644 (file)
index 0000000..3e3585f
--- /dev/null
@@ -0,0 +1,35 @@
+package org.argeo.app.docbook;
+
+import org.argeo.app.api.JcrName;
+
+/** Supported DocBook elements */
+public enum DbkType implements JcrName {
+       book, article, section,
+       //
+       info, title, para,
+       //
+       mediaobject, imageobject, imagedata, videoobject, videodata, caption,
+       //
+       link,
+       //
+       ;
+
+       @Override
+       public String getPrefix() {
+               return prefix();
+       }
+
+       public static String prefix() {
+               return "dbk";
+       }
+
+       @Override
+       public String getNamespace() {
+               return namespace();
+       }
+
+       public static String namespace() {
+               return "http://docbook.org/ns/docbook";
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java
new file mode 100644 (file)
index 0000000..6c959f4
--- /dev/null
@@ -0,0 +1,253 @@
+package org.argeo.app.docbook;
+
+import static org.argeo.app.docbook.DbkType.para;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.app.api.EntityType;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.JcrxApi;
+
+/** Utilities around DocBook. */
+public class DbkUtils {
+       private final static CmsLog log = CmsLog.getLog(DbkUtils.class);
+
+       /** Get or add a DocBook element. */
+       public static Node getOrAddDbk(Node parent, DbkType child) {
+               try {
+                       if (!parent.hasNode(child.get())) {
+                               return addDbk(parent, child);
+                       } else {
+                               return parent.getNode(child.get());
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get or add element " + child.get() + " to " + parent, e);
+               }
+       }
+
+       /** Add a DocBook element to this node. */
+       public static Node addDbk(Node parent, DbkType child) {
+               try {
+                       Node node = parent.addNode(child.get(), child.get());
+                       return node;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot add element " + child.get() + " to " + parent, e);
+               }
+       }
+
+       /** Whether this DocBook element is of this type. */
+       public static boolean isDbk(Node node, DbkType type) {
+               return Jcr.getName(node).equals(type.get());
+       }
+
+       /** Whether this node is a DocBook type. */
+       public static boolean isDbk(Node node) {
+               String name = Jcr.getName(node);
+               for (DbkType type : DbkType.values()) {
+                       if (name.equals(type.get()))
+                               return true;
+               }
+               return false;
+       }
+
+       public static String getTitle(Node node) {
+               return JcrxApi.getXmlValue(node, DbkType.title.get());
+       }
+
+       public static void setTitle(Node node, String txt) {
+               Node titleNode = getOrAddDbk(node, DbkType.title);
+               JcrxApi.setXmlValue(node, titleNode, txt);
+       }
+
+       public static Node getMetadata(Node infoContainer) {
+               try {
+                       if (!infoContainer.hasNode(DbkType.info.get()))
+                               return null;
+                       Node info = infoContainer.getNode(DbkType.info.get());
+                       if (!info.hasNode(EntityType.local.get()))
+                               return null;
+                       return info.getNode(EntityType.local.get());
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot retrieve metadata from " + infoContainer, e);
+               }
+       }
+
+       public static Node getChildByRole(Node parent, String role) {
+               try {
+                       NodeIterator baseSections = parent.getNodes();
+                       while (baseSections.hasNext()) {
+                               Node n = baseSections.nextNode();
+                               String r = Jcr.get(n, DbkAttr.role.name());
+                               if (r != null && r.equals(role))
+                                       return n;
+                       }
+                       return null;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get child from " + parent + " with role " + role, e);
+               }
+       }
+
+       public static Node addParagraph(Node node, String txt) {
+               Node p = addDbk(node, para);
+               JcrxApi.setXmlValue(node, p, txt);
+               return p;
+       }
+
+       /**
+        * Removes a paragraph if it empty. The sesison is not saved.
+        * 
+        * @return true if the paragraph was empty and it was removed
+        */
+       public static boolean removeIfEmptyParagraph(Node node) {
+               try {
+                       if (isDbk(node, DbkType.para)) {
+                               NodeIterator nit = node.getNodes();
+                               if (!nit.hasNext()) {
+                                       node.remove();
+                                       return true;
+                               }
+                               Node first = nit.nextNode();
+                               if (nit.hasNext())
+                                       return false;
+                               if (first.getName().equals(Jcr.JCR_XMLTEXT)) {
+                                       String str = Jcr.get(first, Jcr.JCR_XMLCHARACTERS);
+                                       if (str != null && str.trim().equals("")) {
+                                               node.remove();
+                                               return true;
+                                       }
+                               } else {
+                                       return false;
+                               }
+                       }
+                       return false;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot remove possibly empty paragraph", e);
+               }
+       }
+
+       public static Node insertImageAfter(Node sibling) {
+               try {
+
+                       Node parent = sibling.getParent();
+                       Node mediaNode = addDbk(parent, DbkType.mediaobject);
+                       // TODO optimise?
+                       parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
+                                       sibling.getName() + "[" + sibling.getIndex() + "]");
+                       parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
+                                       mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
+
+                       Node imageNode = addDbk(mediaNode, DbkType.imageobject);
+                       Node imageDataNode = addDbk(imageNode, DbkType.imagedata);
+//                     Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
+//                     Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]);
+//                     fileNode.addMixin(EntityType.box.get());
+//                     fileNode.setProperty(EntityNames.SVG_WIDTH, 0);
+//                     fileNode.setProperty(EntityNames.SVG_LENGTH, 0);
+//                     fileNode.addMixin(NodeType.MIX_MIMETYPE);
+//
+//                     // we assume this is a folder next to the main DocBook document
+//                     // TODO make it more robust and generic
+//                     String fileRef = mediaNode.getName();
+//                     imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef);
+                       return mediaNode;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot insert empty image after " + sibling, e);
+               }
+       }
+
+       public static Node insertVideoAfter(Node sibling) {
+               try {
+
+                       Node parent = sibling.getParent();
+                       Node mediaNode = addDbk(parent, DbkType.mediaobject);
+                       // TODO optimise?
+                       parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
+                                       sibling.getName() + "[" + sibling.getIndex() + "]");
+                       parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
+                                       mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
+
+                       Node videoNode = addDbk(mediaNode, DbkType.videoobject);
+                       Node videoDataNode = addDbk(videoNode, DbkType.videodata);
+                       return mediaNode;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot insert empty image after " + sibling, e);
+               }
+       }
+
+       public static String getMediaFileref(Node node) {
+               try {
+                       Node mediadata;
+                       if (node.hasNode(DbkType.imageobject.get())) {
+                               mediadata = node.getNode(DbkType.imageobject.get()).getNode(DbkType.imagedata.get());
+                       } else if (node.hasNode(DbkType.videoobject.get())) {
+                               mediadata = node.getNode(DbkType.videoobject.get()).getNode(DbkType.videodata.get());
+                       } else {
+                               throw new IllegalArgumentException("Fileref not found in " + node);
+                       }
+
+                       if (mediadata.hasProperty(DbkAttr.fileref.name())) {
+                               return mediadata.getProperty(DbkAttr.fileref.name()).getString();
+                       } else {
+                               return null;
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot retrieve file ref from " + node, e);
+               }
+       }
+
+       public static void exportXml(Node node, OutputStream out) throws IOException {
+               try {
+                       node.getSession().exportDocumentView(node.getPath(), out, false, false);
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot export " + node + " to XML", e);
+               }
+       }
+
+       public static void exportToFs(Node baseNode, DbkType type, Path directory) {
+               String fileName = Jcr.getName(baseNode) + ".dbk.xml";
+               Path filePath = directory.resolve(fileName);
+               Node docBookNode = Jcr.getNode(baseNode, type.get());
+               if (docBookNode == null)
+                       throw new IllegalArgumentException("No " + type.get() + " under " + baseNode);
+               try {
+                       Files.createDirectories(directory);
+                       try (OutputStream out = Files.newOutputStream(filePath)) {
+                               exportXml(docBookNode, out);
+                       }
+                       JcrUtils.copyFilesToFs(baseNode, directory, true);
+                       if (log.isDebugEnabled())
+                               log.debug("DocBook " + baseNode + " exported to " + filePath.toAbsolutePath());
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       public static void importXml(Node baseNode, InputStream in) throws IOException {
+               try {
+                       baseNode.getSession().importXML(baseNode.getPath(), in,
+                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot import XML to " + baseNode, e);
+               }
+
+       }
+
+       /** Singleton. */
+       private DbkUtils() {
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/db4-upgrade.xsl b/org.argeo.app.core/src/org/argeo/app/docbook/db4-upgrade.xsl
new file mode 100644 (file)
index 0000000..00096be
--- /dev/null
@@ -0,0 +1,1398 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:exsl="http://exslt.org/common"
+               xmlns:db = "http://docbook.org/ns/docbook"
+               xmlns:xlink="http://www.w3.org/1999/xlink"
+                exclude-result-prefixes="exsl db"
+                version="1.0">
+
+<!--
+# ======================================================================
+# This file is part of DocBook V5.0CR5
+#
+# Copyright 2005 Norman Walsh, Sun Microsystems, Inc., and the
+# Organization for the Advancement of Structured Information
+# Standards (OASIS).
+#
+# Release: $Id: db4-upgrade.xsl 7660 2008-02-06 13:48:36Z nwalsh $
+#
+# Permission to use, copy, modify and distribute this stylesheet
+# and its accompanying documentation for any purpose and without fee
+# is hereby granted in perpetuity, provided that the above copyright
+# notice and this paragraph appear in all copies. The copyright
+# holders make no representation about the suitability of the schema
+# for any purpose. It is provided "as is" without expressed or implied
+# warranty.
+#
+# Please direct all questions, bug reports, or suggestions for changes
+# to the docbook@lists.oasis-open.org mailing list. For more
+# information, see http://www.oasis-open.org/docbook/.
+#
+# ======================================================================
+-->
+
+<xsl:variable name="version" select="'1.0'"/>
+
+<xsl:output method="xml" encoding="utf-8" indent="no" omit-xml-declaration="yes"/>
+
+<xsl:preserve-space elements="*"/>
+<xsl:param name="rootid">
+  <xsl:choose>
+  <xsl:when test="/*/@id">
+    <xsl:value-of select="/*/@id"/>
+  </xsl:when>
+  <xsl:otherwise>
+    <xsl:text>UNKNOWN</xsl:text>
+  </xsl:otherwise>
+  </xsl:choose>
+</xsl:param>
+
+<xsl:param name="defaultDate" select="''"/>
+
+<xsl:template match="/">
+  <xsl:variable name="converted">
+    <xsl:apply-templates/>
+  </xsl:variable>
+  <xsl:comment>
+    <xsl:text> Converted by db4-upgrade version </xsl:text>
+    <xsl:value-of select="$version"/>
+    <xsl:text> </xsl:text>
+  </xsl:comment>
+  <xsl:text>&#10;</xsl:text>
+  <xsl:apply-templates select="exsl:node-set($converted)/*" mode="addNS"/>
+</xsl:template>
+
+<xsl:template match="bookinfo|chapterinfo|articleinfo|artheader|appendixinfo
+                    |blockinfo
+                     |bibliographyinfo|glossaryinfo|indexinfo|setinfo
+                    |setindexinfo
+                     |sect1info|sect2info|sect3info|sect4info|sect5info
+                     |sectioninfo
+                     |refsect1info|refsect2info|refsect3info|refsectioninfo
+                    |referenceinfo|partinfo"
+              priority="200">
+  <info>
+    <xsl:call-template name="copy.attributes"/>
+
+    <!-- titles can be inside or outside or both. fix that -->
+    <xsl:choose>
+      <xsl:when test="title and following-sibling::title">
+        <xsl:if test="title != following-sibling::title">
+          <xsl:call-template name="emit-message">
+            <xsl:with-param name="message">
+              <xsl:text>Check </xsl:text>
+              <xsl:value-of select="name(..)"/>
+              <xsl:text> title.</xsl:text>
+            </xsl:with-param>
+          </xsl:call-template>
+        </xsl:if>
+        <xsl:apply-templates select="title" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="title">
+        <xsl:apply-templates select="title" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="following-sibling::title">
+        <xsl:apply-templates select="following-sibling::title" mode="copy"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="emit-message">
+          <xsl:with-param name="message">
+            <xsl:text>Check </xsl:text>
+            <xsl:value-of select="name(..)"/>
+            <xsl:text>: no title.</xsl:text>
+          </xsl:with-param>
+        </xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:choose>
+      <xsl:when test="titleabbrev and following-sibling::titleabbrev">
+        <xsl:if test="titleabbrev != following-sibling::titleabbrev">
+          <xsl:call-template name="emit-message">
+            <xsl:with-param name="message">
+              <xsl:text>Check </xsl:text>
+              <xsl:value-of select="name(..)"/>
+              <xsl:text> titleabbrev.</xsl:text>
+            </xsl:with-param>
+          </xsl:call-template>
+        </xsl:if>
+        <xsl:apply-templates select="titleabbrev" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="titleabbrev">
+        <xsl:apply-templates select="titleabbrev" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="following-sibling::titleabbrev">
+        <xsl:apply-templates select="following-sibling::titleabbrev" mode="copy"/>
+      </xsl:when>
+    </xsl:choose>
+
+    <xsl:choose>
+      <xsl:when test="subtitle and following-sibling::subtitle">
+        <xsl:if test="subtitle != following-sibling::subtitle">
+          <xsl:call-template name="emit-message">
+            <xsl:with-param name="message">
+              <xsl:text>Check </xsl:text>
+              <xsl:value-of select="name(..)"/>
+              <xsl:text> subtitle.</xsl:text>
+            </xsl:with-param>
+          </xsl:call-template>
+        </xsl:if>
+        <xsl:apply-templates select="subtitle" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="subtitle">
+        <xsl:apply-templates select="subtitle" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="following-sibling::subtitle">
+        <xsl:apply-templates select="following-sibling::subtitle" mode="copy"/>
+      </xsl:when>
+    </xsl:choose>
+
+    <xsl:apply-templates/>
+  </info>
+</xsl:template>
+
+<xsl:template match="objectinfo|prefaceinfo|refsynopsisdivinfo
+                    |screeninfo|sidebarinfo"
+             priority="200">
+  <info>
+    <xsl:call-template name="copy.attributes"/>
+
+    <!-- titles can be inside or outside or both. fix that -->
+    <xsl:choose>
+      <xsl:when test="title and following-sibling::title">
+        <xsl:if test="title != following-sibling::title">
+          <xsl:call-template name="emit-message">
+            <xsl:with-param name="message">
+              <xsl:text>Check </xsl:text>
+              <xsl:value-of select="name(..)"/>
+              <xsl:text> title.</xsl:text>
+            </xsl:with-param>
+          </xsl:call-template>
+        </xsl:if>
+        <xsl:apply-templates select="title" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="title">
+        <xsl:apply-templates select="title" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="following-sibling::title">
+        <xsl:apply-templates select="following-sibling::title" mode="copy"/>
+      </xsl:when>
+      <xsl:otherwise>
+       <!-- it's ok if there's no title on these -->
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:choose>
+      <xsl:when test="titleabbrev and following-sibling::titleabbrev">
+        <xsl:if test="titleabbrev != following-sibling::titleabbrev">
+          <xsl:call-template name="emit-message">
+          <xsl:with-param name="message">
+            <xsl:text>Check </xsl:text>
+            <xsl:value-of select="name(..)"/>
+            <xsl:text> titleabbrev.</xsl:text>
+          </xsl:with-param>
+        </xsl:call-template>
+        </xsl:if>
+        <xsl:apply-templates select="titleabbrev" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="titleabbrev">
+        <xsl:apply-templates select="titleabbrev" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="following-sibling::titleabbrev">
+        <xsl:apply-templates select="following-sibling::titleabbrev" mode="copy"/>
+      </xsl:when>
+    </xsl:choose>
+
+    <xsl:choose>
+      <xsl:when test="subtitle and following-sibling::subtitle">
+        <xsl:if test="subtitle != following-sibling::subtitle">
+          <xsl:call-template name="emit-message">
+            <xsl:with-param name="message">
+              <xsl:text>Check </xsl:text>
+              <xsl:value-of select="name(..)"/>
+              <xsl:text> subtitle.</xsl:text>
+            </xsl:with-param>
+          </xsl:call-template>
+        </xsl:if>
+        <xsl:apply-templates select="subtitle" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="subtitle">
+        <xsl:apply-templates select="subtitle" mode="copy"/>
+      </xsl:when>
+      <xsl:when test="following-sibling::subtitle">
+        <xsl:apply-templates select="following-sibling::subtitle" mode="copy"/>
+      </xsl:when>
+    </xsl:choose>
+
+    <xsl:apply-templates/>
+  </info>
+</xsl:template>
+
+<xsl:template match="refentryinfo"
+              priority="200">
+  <info>
+    <xsl:call-template name="copy.attributes"/>
+
+    <!-- titles can be inside or outside or both. fix that -->
+    <xsl:if test="title">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Discarding title from refentryinfo!</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+    </xsl:if>
+
+    <xsl:if test="titleabbrev">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Discarding titleabbrev from refentryinfo!</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+    </xsl:if>
+
+    <xsl:if test="subtitle">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Discarding subtitle from refentryinfo!</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+    </xsl:if>
+
+    <xsl:apply-templates/>
+  </info>
+</xsl:template>
+
+<xsl:template match="refmiscinfo"
+              priority="200">
+  <refmiscinfo>
+    <xsl:call-template name="copy.attributes">
+      <xsl:with-param name="suppress" select="'class'"/>
+    </xsl:call-template>
+    <xsl:if test="@class">
+      <xsl:choose>
+       <xsl:when test="@class = 'source'
+                       or @class = 'version'
+                       or @class = 'manual'
+                       or @class = 'sectdesc'
+                       or @class = 'software'">
+         <xsl:attribute name="class">
+           <xsl:value-of select="@class"/>
+         </xsl:attribute>
+       </xsl:when>
+       <xsl:otherwise>
+         <xsl:attribute name="class">
+           <xsl:value-of select="'other'"/>
+         </xsl:attribute>
+         <xsl:attribute name="otherclass">
+           <xsl:value-of select="@class"/>
+         </xsl:attribute>
+       </xsl:otherwise>
+      </xsl:choose>
+    </xsl:if>
+    <xsl:apply-templates/>
+  </refmiscinfo>
+</xsl:template>
+
+<xsl:template match="corpauthor" priority="200">
+  <author>
+    <xsl:call-template name="copy.attributes"/>
+    <orgname>
+      <xsl:apply-templates/>
+    </orgname>
+  </author>
+</xsl:template>
+
+<xsl:template match="corpname" priority="200">
+  <orgname>
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </orgname>
+</xsl:template>
+
+<xsl:template match="author[not(personname)]|editor[not(personname)]|othercredit[not(personname)]" priority="200">
+  <xsl:copy>
+    <xsl:call-template name="copy.attributes"/>
+    <personname>
+      <xsl:apply-templates select="honorific|firstname|surname|othername|lineage"/>
+    </personname>
+    <xsl:apply-templates select="*[not(self::honorific|self::firstname|self::surname
+                                   |self::othername|self::lineage)]"/>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="address|programlisting|screen|funcsynopsisinfo
+                     |classsynopsisinfo|literallayout" priority="200">
+  <xsl:copy>
+    <xsl:call-template name="copy.attributes">
+      <xsl:with-param name="suppress" select="'format'"/>
+    </xsl:call-template>
+    <xsl:apply-templates/>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="productname[@class]" priority="200">
+  <xsl:call-template name="emit-message">
+    <xsl:with-param name="message">
+      <xsl:text>Dropping class attribute from productname</xsl:text>
+    </xsl:with-param>
+  </xsl:call-template>
+  <xsl:copy>
+    <xsl:call-template name="copy.attributes">
+      <xsl:with-param name="suppress" select="'class'"/>
+    </xsl:call-template>
+    <xsl:apply-templates/>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="dedication|preface|chapter|appendix|part|partintro
+                     |article|bibliography|glossary|glossdiv|index
+                    |reference[not(referenceinfo)]
+                     |book" priority="200">
+  <xsl:choose>
+    <xsl:when test="not(dedicationinfo|prefaceinfo|chapterinfo
+                       |appendixinfo|partinfo
+                        |articleinfo|artheader|bibliographyinfo
+                       |glossaryinfo|indexinfo
+                        |bookinfo)">
+      <xsl:copy>
+        <xsl:call-template name="copy.attributes"/>
+        <xsl:if test="title|subtitle|titleabbrev">
+          <info>
+            <xsl:apply-templates select="title" mode="copy"/>
+            <xsl:apply-templates select="titleabbrev" mode="copy"/>
+            <xsl:apply-templates select="subtitle" mode="copy"/>
+            <xsl:apply-templates select="abstract" mode="copy"/>
+          </info>
+        </xsl:if>
+        <xsl:apply-templates/>
+      </xsl:copy>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:copy>
+        <xsl:call-template name="copy.attributes"/>
+        <xsl:apply-templates/>
+      </xsl:copy>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="formalpara|figure|table[tgroup]|example|blockquote
+                     |caution|important|note|warning|tip
+                     |bibliodiv|glossarydiv|indexdiv
+                    |orderedlist|itemizedlist|variablelist|procedure
+                    |task|tasksummary|taskprerequisites|taskrelated
+                    |sidebar"
+             priority="200">
+  <xsl:choose>
+    <xsl:when test="blockinfo">
+      <xsl:copy>
+        <xsl:call-template name="copy.attributes"/>
+        <xsl:apply-templates/>
+      </xsl:copy>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:copy>
+        <xsl:call-template name="copy.attributes"/>
+
+       <xsl:if test="title|titleabbrev|subtitle">
+         <info>
+           <xsl:apply-templates select="title" mode="copy"/>
+           <xsl:apply-templates select="titleabbrev" mode="copy"/>
+           <xsl:apply-templates select="subtitle" mode="copy"/>
+         </info>
+       </xsl:if>
+
+        <xsl:apply-templates/>
+      </xsl:copy>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="equation" priority="200">
+  <xsl:choose>
+    <xsl:when test="not(title)">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param
+            name="message"
+            >Convert equation without title to informal equation.</xsl:with-param>
+      </xsl:call-template>
+      <informalequation>
+        <xsl:call-template name="copy.attributes"/>
+        <xsl:apply-templates/>
+      </informalequation>
+    </xsl:when>
+    <xsl:when test="blockinfo">
+      <xsl:copy>
+        <xsl:call-template name="copy.attributes"/>
+        <xsl:apply-templates/>
+      </xsl:copy>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:copy>
+        <xsl:call-template name="copy.attributes"/>
+        <info>
+          <xsl:apply-templates select="title" mode="copy"/>
+          <xsl:apply-templates select="titleabbrev" mode="copy"/>
+          <xsl:apply-templates select="subtitle" mode="copy"/>
+        </info>
+        <xsl:apply-templates/>
+      </xsl:copy>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="sect1|sect2|sect3|sect4|sect5|section"
+             priority="200">
+  <section>
+    <xsl:call-template name="copy.attributes"/>
+
+    <xsl:if test="not(sect1info|sect2info|sect3info|sect4info|sect5info|sectioninfo)">
+      <info>
+        <xsl:apply-templates select="title" mode="copy"/>
+        <xsl:apply-templates select="titleabbrev" mode="copy"/>
+        <xsl:apply-templates select="subtitle" mode="copy"/>
+        <xsl:apply-templates select="abstract" mode="copy"/>
+      </info>
+    </xsl:if>
+    <xsl:apply-templates/>
+  </section>
+</xsl:template>
+
+<xsl:template match="simplesect"
+             priority="200">
+  <simplesect>
+    <xsl:call-template name="copy.attributes"/>
+    <info>
+      <xsl:apply-templates select="title" mode="copy"/>
+      <xsl:apply-templates select="titleabbrev" mode="copy"/>
+      <xsl:apply-templates select="subtitle" mode="copy"/>
+      <xsl:apply-templates select="abstract" mode="copy"/>
+    </info>
+    <xsl:apply-templates/>
+  </simplesect>
+</xsl:template>
+
+<xsl:template match="refsect1|refsect2|refsect3|refsection" priority="200">
+  <refsection>
+    <xsl:call-template name="copy.attributes"/>
+
+    <xsl:if test="not(refsect1info|refsect2info|refsect3info|refsectioninfo)">
+      <info>
+        <xsl:apply-templates select="title" mode="copy"/>
+        <xsl:apply-templates select="titleabbrev" mode="copy"/>
+        <xsl:apply-templates select="subtitle" mode="copy"/>
+        <xsl:apply-templates select="abstract" mode="copy"/>
+      </info>
+    </xsl:if>
+    <xsl:apply-templates/>
+  </refsection>
+</xsl:template>
+
+<xsl:template match="imagedata|videodata|audiodata|textdata" priority="200">
+  <xsl:copy>
+    <xsl:call-template name="copy.attributes">
+      <xsl:with-param name="suppress" select="'srccredit'"/>
+    </xsl:call-template>
+    <xsl:if test="@srccredit">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Check conversion of srccredit </xsl:text>
+          <xsl:text>(othercredit="srccredit").</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+      <info>
+        <othercredit class="other" otherclass="srccredit">
+          <orgname>???</orgname>
+          <contrib>
+            <xsl:value-of select="@srccredit"/>
+          </contrib>
+        </othercredit>
+      </info>
+    </xsl:if>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="sgmltag" priority="200">
+  <tag>
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:if test="@class = 'sgmlcomment'">
+      <xsl:attribute name="class">comment</xsl:attribute>
+    </xsl:if>
+    <xsl:apply-templates/>
+  </tag>
+</xsl:template>
+
+<xsl:template match="inlinegraphic[@format='linespecific']" priority="210">
+  <textobject>
+    <textdata>
+      <xsl:call-template name="copy.attributes"/>
+    </textdata>
+  </textobject>
+</xsl:template>
+
+<xsl:template match="inlinegraphic" priority="200">
+  <inlinemediaobject>
+    <imageobject>
+      <imagedata>
+       <xsl:call-template name="copy.attributes"/>
+      </imagedata>
+    </imageobject>
+  </inlinemediaobject>
+</xsl:template>
+
+<xsl:template match="graphic[@format='linespecific']" priority="210">
+  <mediaobject>
+    <textobject>
+      <textdata>
+       <xsl:call-template name="copy.attributes"/>
+      </textdata>
+    </textobject>
+  </mediaobject>
+</xsl:template>
+
+<xsl:template match="graphic" priority="200">
+  <mediaobject>
+    <imageobject>
+      <imagedata>
+       <xsl:call-template name="copy.attributes"/>
+      </imagedata>
+    </imageobject>
+  </mediaobject>
+</xsl:template>
+
+<xsl:template match="pubsnumber" priority="200">
+  <biblioid class="pubsnumber">
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </biblioid>
+</xsl:template>
+
+<xsl:template match="invpartnumber" priority="200">
+  <xsl:call-template name="emit-message">
+    <xsl:with-param name="message">
+      <xsl:text>Converting invpartnumber to biblioid otherclass="invpartnumber".</xsl:text>
+    </xsl:with-param>
+  </xsl:call-template>
+  <biblioid class="other" otherclass="invpartnumber">
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </biblioid>
+</xsl:template>
+
+<xsl:template match="contractsponsor" priority="200">
+  <xsl:variable name="contractnum"
+                select="preceding-sibling::contractnum|following-sibling::contractnum"/>
+
+  <xsl:call-template name="emit-message">
+    <xsl:with-param name="message">
+      <xsl:text>Converting contractsponsor to othercredit="contractsponsor".</xsl:text>
+    </xsl:with-param>
+  </xsl:call-template>
+
+  <othercredit class="other" otherclass="contractsponsor">
+    <orgname>
+      <xsl:call-template name="copy.attributes"/>
+      <xsl:apply-templates/>
+    </orgname>
+    <xsl:for-each select="$contractnum">
+      <contrib role="contractnum">
+        <xsl:apply-templates select="node()"/>
+      </contrib>
+    </xsl:for-each>
+  </othercredit>
+</xsl:template>
+
+<xsl:template match="contractnum" priority="200">
+  <xsl:if test="not(preceding-sibling::contractsponsor
+                    |following-sibling::contractsponsor)
+                and not(preceding-sibling::contractnum)">
+    <xsl:call-template name="emit-message">
+      <xsl:with-param name="message">
+        <xsl:text>Converting contractnum to othercredit="contractnum".</xsl:text>
+      </xsl:with-param>
+    </xsl:call-template>
+
+    <othercredit class="other" otherclass="contractnum">
+      <orgname>???</orgname>
+      <xsl:for-each select="self::contractnum
+                            |preceding-sibling::contractnum
+                            |following-sibling::contractnum">
+        <contrib>
+          <xsl:apply-templates select="node()"/>
+        </contrib>
+      </xsl:for-each>
+    </othercredit>
+  </xsl:if>
+</xsl:template>
+
+<xsl:template match="isbn|issn" priority="200">
+  <biblioid class="{local-name(.)}">
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </biblioid>
+</xsl:template>
+
+<xsl:template match="biblioid[count(*) = 1
+                             and ulink
+                             and normalize-space(text()) = '']" priority="200">
+  <biblioid xlink:href="{ulink/@url}">
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates select="ulink/node()"/>
+  </biblioid>
+</xsl:template>
+
+<xsl:template match="authorblurb" priority="200">
+  <personblurb>
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </personblurb>
+</xsl:template>
+
+<xsl:template match="collabname" priority="200">
+  <xsl:call-template name="emit-message">
+    <xsl:with-param name="message">
+      <xsl:text>Check conversion of collabname </xsl:text>
+      <xsl:text>(orgname role="collabname").</xsl:text>
+    </xsl:with-param>
+  </xsl:call-template>
+  <orgname role="collabname">
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </orgname>
+</xsl:template>
+
+<xsl:template match="modespec" priority="200">
+  <xsl:call-template name="emit-message">
+    <xsl:with-param name="message">
+      <xsl:text>Discarding modespec (</xsl:text>
+      <xsl:value-of select="."/>
+      <xsl:text>).</xsl:text>
+    </xsl:with-param>
+  </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="mediaobjectco" priority="200">
+  <mediaobject>
+    <xsl:copy-of select="@*"/>
+    <xsl:apply-templates/>
+  </mediaobject>
+</xsl:template>
+
+<xsl:template match="remark" priority="200">
+  <!-- get rid of any embedded markup -->
+  <remark>
+    <xsl:copy-of select="@*"/>
+    <xsl:value-of select="."/>
+  </remark>
+</xsl:template>
+
+<xsl:template match="biblioentry/title
+                     |bibliomset/title
+                     |biblioset/title
+                     |bibliomixed/title" priority="400">
+  <citetitle>
+    <xsl:copy-of select="@*"/>
+    <xsl:apply-templates/>
+  </citetitle>
+</xsl:template>
+
+<xsl:template match="biblioentry/titleabbrev|biblioentry/subtitle
+                     |bibliomset/titleabbrev|bibliomset/subtitle
+                     |biblioset/titleabbrev|biblioset/subtitle
+                     |bibliomixed/titleabbrev|bibliomixed/subtitle"
+             priority="400">
+  <xsl:copy>
+    <xsl:copy-of select="@*"/>
+    <xsl:apply-templates/>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="biblioentry/contrib
+                     |bibliomset/contrib
+                     |bibliomixed/contrib" priority="200">
+  <xsl:call-template name="emit-message">
+    <xsl:with-param name="message">
+      <xsl:text>Check conversion of contrib </xsl:text>
+      <xsl:text>(othercontrib="contrib").</xsl:text>
+    </xsl:with-param>
+  </xsl:call-template>
+  <othercredit class="other" otherclass="contrib">
+    <orgname>???</orgname>
+    <contrib>
+      <xsl:call-template name="copy.attributes"/>
+      <xsl:apply-templates/>
+    </contrib>
+  </othercredit>
+</xsl:template>
+
+<xsl:template match="link" priority="200">
+  <xsl:copy>
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="ulink" priority="200">
+  <xsl:choose>
+    <xsl:when test="node()">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Converting ulink to link.</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+
+      <link xlink:href="{@url}">
+       <xsl:call-template name="copy.attributes">
+         <xsl:with-param name="suppress" select="'url'"/>
+       </xsl:call-template>
+       <xsl:apply-templates/>
+      </link>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Converting ulink to uri.</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+
+      <uri xlink:href="{@url}">
+       <xsl:call-template name="copy.attributes">
+         <xsl:with-param name="suppress" select="'url'"/>
+       </xsl:call-template>
+       <xsl:value-of select="@url"/>
+      </uri>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="olink" priority="200">
+  <xsl:if test="@linkmode">
+    <xsl:call-template name="emit-message">
+      <xsl:with-param name="message">
+        <xsl:text>Discarding linkmode on olink.</xsl:text>
+      </xsl:with-param>
+    </xsl:call-template>
+  </xsl:if>
+
+  <xsl:choose>
+    <xsl:when test="@targetdocent">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Converting olink targetdocent to targetdoc.</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+
+      <olink targetdoc="{unparsed-entity-uri(@targetdocent)}">
+       <xsl:for-each select="@*">
+         <xsl:if test="name(.) != 'targetdocent'
+                       and name(.) != 'linkmode'">
+           <xsl:copy/>
+         </xsl:if>
+       </xsl:for-each>
+       <xsl:apply-templates/>
+      </olink>
+    </xsl:when>
+    <xsl:otherwise>
+      <olink>
+       <xsl:for-each select="@*">
+         <xsl:if test="name(.) != 'linkmode'">
+           <xsl:copy/>
+         </xsl:if>
+       </xsl:for-each>
+       <xsl:apply-templates/>
+      </olink>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="biblioentry/firstname
+                     |biblioentry/surname
+                     |biblioentry/othername
+                     |biblioentry/lineage
+                     |biblioentry/honorific
+                     |bibliomset/firstname
+                     |bibliomset/surname
+                     |bibliomset/othername
+                     |bibliomset/lineage
+                     |bibliomset/honorific" priority="200">
+  <xsl:choose>
+    <xsl:when test="preceding-sibling::firstname
+                    |preceding-sibling::surname
+                    |preceding-sibling::othername
+                    |preceding-sibling::lineage
+                    |preceding-sibling::honorific">
+      <!-- nop -->
+    </xsl:when>
+    <xsl:otherwise>
+      <personname>
+        <xsl:apply-templates select="../firstname
+                                     |../surname
+                                     |../othername
+                                     |../lineage
+                                     |../honorific" mode="copy"/>
+      </personname>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="areaset" priority="200">
+  <xsl:copy>
+    <xsl:call-template name="copy.attributes">
+      <xsl:with-param name="suppress" select="'coords'"/>
+    </xsl:call-template>
+    <xsl:apply-templates/>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="date|pubdate" priority="200">
+  <xsl:variable name="rp1" select="substring-before(normalize-space(.), ' ')"/>
+  <xsl:variable name="rp2"
+               select="substring-before(substring-after(normalize-space(.), ' '),
+                                        ' ')"/>
+  <xsl:variable name="rp3"
+               select="substring-after(substring-after(normalize-space(.), ' '), ' ')"/>
+
+  <xsl:variable name="p1">
+    <xsl:choose>
+      <xsl:when test="contains($rp1, ',')">
+       <xsl:value-of select="substring-before($rp1, ',')"/>
+      </xsl:when>
+      <xsl:otherwise>
+       <xsl:value-of select="$rp1"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="p2">
+    <xsl:choose>
+      <xsl:when test="contains($rp2, ',')">
+       <xsl:value-of select="substring-before($rp2, ',')"/>
+      </xsl:when>
+      <xsl:otherwise>
+       <xsl:value-of select="$rp2"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="p3">
+    <xsl:choose>
+      <xsl:when test="contains($rp3, ',')">
+       <xsl:value-of select="substring-before($rp3, ',')"/>
+      </xsl:when>
+      <xsl:otherwise>
+       <xsl:value-of select="$rp3"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="date">
+    <xsl:choose>
+      <xsl:when test="string($p1+1) != 'NaN' and string($p3+1) != 'NaN'">
+       <xsl:choose>
+         <xsl:when test="$p2 = 'Jan' or $p2 = 'January'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-01-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Feb' or $p2 = 'February'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-02-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Mar' or $p2 = 'March'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-03-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Apr' or $p2 = 'April'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-04-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'May'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-05-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Jun' or $p2 = 'June'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-06-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Jul' or $p2 = 'July'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-07-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Aug' or $p2 = 'August'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-08-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Sep' or $p2 = 'September'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-09-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Oct' or $p2 = 'October'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-10-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Nov' or $p2 = 'November'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-11-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p2 = 'Dec' or $p2 = 'December'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-12-</xsl:text>
+           <xsl:number value="$p1" format="01"/>
+         </xsl:when>
+         <xsl:otherwise>
+           <xsl:apply-templates/>
+         </xsl:otherwise>
+       </xsl:choose>
+      </xsl:when>
+      <xsl:when test="string($p2+1) != 'NaN' and string($p3+1) != 'NaN'">
+       <xsl:choose>
+         <xsl:when test="$p1 = 'Jan' or $p1 = 'January'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-01-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Feb' or $p1 = 'February'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-02-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Mar' or $p1 = 'March'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-03-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Apr' or $p1 = 'April'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-04-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'May'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-05-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Jun' or $p1 = 'June'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-06-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Jul' or $p1 = 'July'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-07-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Aug' or $p1 = 'August'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-08-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Sep' or $p1 = 'September'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-09-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Oct' or $p1 = 'October'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-10-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Nov' or $p1 = 'November'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-11-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:when test="$p1 = 'Dec' or $p1 = 'December'">
+           <xsl:number value="$p3" format="0001"/>
+           <xsl:text>-12-</xsl:text>
+           <xsl:number value="$p2" format="01"/>
+         </xsl:when>
+         <xsl:otherwise>
+           <xsl:apply-templates/>
+         </xsl:otherwise>
+       </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+       <xsl:apply-templates/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:choose>
+    <xsl:when test="normalize-space($date) != normalize-space(.)">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Converted </xsl:text>
+          <xsl:value-of select="normalize-space(.)"/>
+          <xsl:text> into </xsl:text>
+          <xsl:value-of select="$date"/>
+          <xsl:text> for </xsl:text>
+          <xsl:value-of select="name(.)"/>
+        </xsl:with-param>
+      </xsl:call-template>
+
+      <xsl:copy>
+       <xsl:copy-of select="@*"/>
+       <xsl:value-of select="$date"/>
+      </xsl:copy>
+    </xsl:when>
+
+    <xsl:when test="$defaultDate != ''">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Unparseable date: </xsl:text>
+          <xsl:value-of select="normalize-space(.)"/>
+          <xsl:text> in </xsl:text>
+          <xsl:value-of select="name(.)"/>
+          <xsl:text> (Using default: </xsl:text>
+          <xsl:value-of select="$defaultDate"/>
+          <xsl:text>)</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+
+      <xsl:copy>
+       <xsl:copy-of select="@*"/>
+       <xsl:copy-of select="$defaultDate"/>
+       <xsl:comment>
+         <xsl:value-of select="."/>
+       </xsl:comment>
+      </xsl:copy>
+    </xsl:when>
+
+    <xsl:otherwise>
+      <!-- these don't really matter anymore
+           <xsl:call-template name="emit-message">
+           <xsl:with-param name="message">
+           <xsl:text>Unparseable date: </xsl:text>
+           <xsl:value-of select="normalize-space(.)"/>
+           <xsl:text> in </xsl:text>
+           <xsl:value-of select="name(.)"/>
+           </xsl:with-param>
+           </xsl:call-template>
+      -->
+      <xsl:copy>
+       <xsl:copy-of select="@*"/>
+       <xsl:apply-templates/>
+      </xsl:copy>
+    </xsl:otherwise>
+  </xsl:choose>      
+</xsl:template>
+
+<xsl:template match="title|subtitle|titleabbrev" priority="300">
+  <!-- nop -->
+</xsl:template>
+
+<xsl:template match="abstract" priority="300">
+  <xsl:if test="not(contains(name(parent::*),'info'))">
+    <xsl:call-template name="emit-message">
+      <xsl:with-param name="message">
+       <xsl:text>Check abstract; moved into info correctly?</xsl:text>
+      </xsl:with-param>
+    </xsl:call-template>
+  </xsl:if>
+</xsl:template>
+
+<xsl:template match="indexterm">
+  <!-- don't copy the defaulted significance='normal' attribute -->
+  <indexterm>
+    <xsl:call-template name="copy.attributes">
+      <xsl:with-param name="suppress">
+       <xsl:if test="@significance = 'normal'">significance</xsl:if>
+      </xsl:with-param>
+    </xsl:call-template>
+    <xsl:apply-templates/>
+  </indexterm>
+</xsl:template>
+
+<xsl:template match="ackno" priority="200">
+  <acknowledgements>
+    <xsl:copy-of select="@*"/>
+    <para>
+      <xsl:apply-templates/>
+    </para>
+  </acknowledgements>
+</xsl:template>
+
+<xsl:template match="lot|lotentry|tocback|tocchap|tocfront|toclevel1|
+                    toclevel2|toclevel3|toclevel4|toclevel5|tocpart" priority="200">
+  <tocdiv>
+    <xsl:copy-of select="@*"/>
+    <xsl:apply-templates/>
+  </tocdiv>
+</xsl:template>
+
+<xsl:template match="action" priority="200">
+  <phrase remap="action">
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </phrase>
+</xsl:template>
+
+<xsl:template match="beginpage" priority="200">
+  <xsl:comment> beginpage pagenum=<xsl:value-of select="@pagenum"/> </xsl:comment>
+  <xsl:call-template name="emit-message">
+    <xsl:with-param name="message">
+      <xsl:text>Replacing beginpage with comment</xsl:text>
+    </xsl:with-param>
+  </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="structname|structfield" priority="200">
+  <varname remap="{local-name(.)}">
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </varname>
+</xsl:template>
+
+<!-- ====================================================================== -->
+
+<!-- 6 Feb 2008, ndw changed mode=copy so that it only copies the first level,
+     then it switches back to "normal" mode so that other rewriting templates
+     catch embedded fixes -->
+
+<!--
+<xsl:template match="ulink" priority="200" mode="copy">
+  <xsl:choose>
+    <xsl:when test="node()">
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Converting ulink to phrase.</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+
+      <phrase xlink:href="{@url}">
+       <xsl:call-template name="copy.attributes">
+         <xsl:with-param name="suppress" select="'url'"/>
+       </xsl:call-template>
+       <xsl:apply-templates/>
+      </phrase>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:call-template name="emit-message">
+        <xsl:with-param name="message">
+          <xsl:text>Converting ulink to uri.</xsl:text>
+        </xsl:with-param>
+      </xsl:call-template>
+
+      <uri xlink:href="{@url}">
+       <xsl:call-template name="copy.attributes">
+         <xsl:with-param name="suppress" select="'url'"/>
+       </xsl:call-template>
+       <xsl:value-of select="@url"/>
+      </uri>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="sgmltag" priority="200" mode="copy">
+  <tag>
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </tag>
+</xsl:template>
+-->
+
+<xsl:template match="*" mode="copy">
+  <xsl:copy>
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </xsl:copy>
+</xsl:template>
+
+<!--
+<xsl:template match="comment()|processing-instruction()|text()" mode="copy">
+  <xsl:copy/>
+</xsl:template>
+-->
+
+<!-- ====================================================================== -->
+
+<xsl:template match="*">
+  <xsl:copy>
+    <xsl:call-template name="copy.attributes"/>
+    <xsl:apply-templates/>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="comment()|processing-instruction()|text()">
+  <xsl:copy/>
+</xsl:template>
+
+<!-- ====================================================================== -->
+
+<xsl:template name="copy.attributes">
+  <xsl:param name="src" select="."/>
+  <xsl:param name="suppress" select="''"/>
+
+  <xsl:for-each select="$src/@*">
+    <xsl:choose>
+      <xsl:when test="local-name(.) = 'moreinfo'">
+        <xsl:call-template name="emit-message">
+          <xsl:with-param name="message">
+            <xsl:text>Discarding moreinfo on </xsl:text>
+            <xsl:value-of select="local-name($src)"/>
+          </xsl:with-param>
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:when test="local-name(.) = 'lang'">
+        <xsl:attribute name="xml:lang">
+          <xsl:value-of select="."/>
+        </xsl:attribute>
+      </xsl:when>
+      <xsl:when test="local-name(.) = 'id'">
+        <xsl:attribute name="xml:id">
+          <xsl:value-of select="."/>
+        </xsl:attribute>
+      </xsl:when>
+      <xsl:when test="$suppress = local-name(.)"/>
+      <xsl:when test="local-name(.) = 'float'">
+       <xsl:choose>
+         <xsl:when test=". = '1'">
+            <xsl:call-template name="emit-message">
+              <xsl:with-param name="message">
+                <xsl:text>Discarding float on </xsl:text>
+                <xsl:value-of select="local-name($src)"/>
+              </xsl:with-param>
+            </xsl:call-template>
+            <xsl:if test="not($src/@floatstyle)">
+             <xsl:call-template name="emit-message">
+                <xsl:with-param name="message">
+                  <xsl:text>Adding floatstyle='normal' on </xsl:text>
+                  <xsl:value-of select="local-name($src)"/>
+                </xsl:with-param>
+              </xsl:call-template>
+              <xsl:attribute name="floatstyle">
+                <xsl:text>normal</xsl:text>
+             </xsl:attribute>
+           </xsl:if>
+         </xsl:when>
+         <xsl:when test=". = '0'">
+           <xsl:call-template name="emit-message">
+              <xsl:with-param name="message">
+                <xsl:text>Discarding float on </xsl:text>
+                <xsl:value-of select="local-name($src)"/>
+              </xsl:with-param>
+            </xsl:call-template>
+          </xsl:when>
+         <xsl:otherwise>
+           <xsl:call-template name="emit-message">
+          <xsl:with-param name="message">
+            <xsl:text>Discarding float on </xsl:text>
+            <xsl:value-of select="local-name($src)"/>
+          </xsl:with-param>
+            </xsl:call-template>
+            <xsl:if test="not($src/@floatstyle)">
+              <xsl:call-template name="emit-message">
+                <xsl:with-param name="message">
+                  <xsl:text>Adding floatstyle='</xsl:text>
+                  <xsl:value-of select="."/>
+                  <xsl:text>' on </xsl:text>
+                  <xsl:value-of select="local-name($src)"/>
+                </xsl:with-param>
+              </xsl:call-template>
+              <xsl:attribute name="floatstyle">
+               <xsl:value-of select="."/>
+             </xsl:attribute>
+           </xsl:if>
+         </xsl:otherwise>
+       </xsl:choose>
+      </xsl:when>
+      <xsl:when test="local-name(.) = 'entityref'">
+       <xsl:attribute name="fileref">
+         <xsl:value-of select="unparsed-entity-uri(@entityref)"/>
+       </xsl:attribute>
+      </xsl:when>
+
+      <xsl:when test="local-name($src) = 'simplemsgentry'
+                     and local-name(.) = 'audience'">
+        <xsl:attribute name="msgaud">
+          <xsl:value-of select="."/>
+        </xsl:attribute>
+      </xsl:when>
+      <xsl:when test="local-name($src) = 'simplemsgentry'
+                     and local-name(.) = 'origin'">
+        <xsl:attribute name="msgorig">
+          <xsl:value-of select="."/>
+        </xsl:attribute>
+      </xsl:when>
+      <xsl:when test="local-name($src) = 'simplemsgentry'
+                     and local-name(.) = 'level'">
+        <xsl:attribute name="msglevel">
+          <xsl:value-of select="."/>
+        </xsl:attribute>
+      </xsl:when>
+
+      <!-- * for upgrading XSL litprog params documentation -->
+      <xsl:when test="local-name($src) = 'refmiscinfo'
+                      and local-name(.) = 'role'
+                      and . = 'type'
+                      ">
+        <xsl:call-template name="emit-message">
+          <xsl:with-param name="message">
+            <xsl:text>Converting refmiscinfo@role=type to </xsl:text>
+            <xsl:text>@class=other,otherclass=type</xsl:text>
+          </xsl:with-param>
+        </xsl:call-template>
+        <xsl:attribute name="class">other</xsl:attribute>
+        <xsl:attribute name="otherclass">type</xsl:attribute>
+      </xsl:when>
+
+      <xsl:otherwise>
+        <xsl:copy/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:for-each>
+</xsl:template>
+
+<!-- ====================================================================== -->
+
+<xsl:template match="*" mode="addNS">
+  <xsl:choose>
+    <xsl:when test="namespace-uri(.) = ''">
+      <xsl:element name="{local-name(.)}"
+                  namespace="http://docbook.org/ns/docbook">
+       <xsl:if test="not(parent::*)">
+         <xsl:attribute name="version">5.0</xsl:attribute>
+       </xsl:if>
+       <xsl:copy-of select="@*"/>
+       <xsl:apply-templates mode="addNS"/>
+      </xsl:element>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:copy>
+       <xsl:if test="not(parent::*)">
+         <xsl:attribute name="version">5.0</xsl:attribute>
+       </xsl:if>
+       <xsl:copy-of select="@*"/>
+       <xsl:apply-templates mode="addNS"/>
+      </xsl:copy>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="comment()|processing-instruction()|text()" mode="addNS">
+  <xsl:copy/>
+</xsl:template>
+
+<!-- ====================================================================== -->
+
+<xsl:template name="emit-message">
+  <xsl:param name="message"/>
+  <xsl:message>
+    <xsl:value-of select="$message"/>
+    <xsl:text> (</xsl:text>
+    <xsl:value-of select="$rootid"/>
+    <xsl:text>)</xsl:text>
+  </xsl:message>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/docbook-full.cnd b/org.argeo.app.core/src/org/argeo/app/docbook/docbook-full.cnd
new file mode 100644 (file)
index 0000000..79c3882
--- /dev/null
@@ -0,0 +1,2998 @@
+<dbk = 'http://docbook.org/ns/docbook'>
+<argeodbk = 'http://www.argeo.org/ns/argeodbk'>
+<xlink = 'http://www.w3.org/1999/xlink'>
+//<xs = 'http://www.w3.org/2001/XMLSchema'>
+
+[argeodbk:titled]
+mixin
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:title (dbk:title) = dbk:title *
+ + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
+
+[argeodbk:linkingAttributes]
+mixin
+ - linkend (String)
+ - xlink:actuate (String)
+ - xlink:arcrole (String)
+ - xlink:href (String)
+ - xlink:role (String)
+ - xlink:show (String)
+ - xlink:title (String)
+ - xlink:type (String)
+
+[argeodbk:freeText]
+mixin
+ + dbk:phrase (dbk:phrase) = dbk:phrase *
+ + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[argeodbk:markupInlines]
+mixin
+ + dbk:code (dbk:code) = dbk:code *
+ + dbk:constant (dbk:constant) = dbk:constant *
+ + dbk:email (dbk:email) = dbk:email *
+ + dbk:literal (dbk:literal) = dbk:literal *
+ + dbk:markup (dbk:markup) = dbk:markup *
+ + dbk:symbol (dbk:symbol) = dbk:symbol *
+ + dbk:tag (dbk:tag) = dbk:tag *
+ + dbk:token (dbk:token) = dbk:token *
+ + dbk:uri (dbk:uri) = dbk:uri *
+
+[argeodbk:listElements]
+mixin
+ + dbk:bibliolist (dbk:bibliolist) = dbk:bibliolist *
+ + dbk:calloutlist (dbk:calloutlist) = dbk:calloutlist *
+ + dbk:glosslist (dbk:glosslist) = dbk:glosslist *
+ + dbk:itemizedlist (dbk:itemizedlist) = dbk:itemizedlist *
+ + dbk:orderedlist (dbk:orderedlist) = dbk:orderedlist *
+ + dbk:procedure (dbk:procedure) = dbk:procedure *
+ + dbk:qandaset (dbk:qandaset) = dbk:qandaset *
+ + dbk:segmentedlist (dbk:segmentedlist) = dbk:segmentedlist *
+ + dbk:simplelist (dbk:simplelist) = dbk:simplelist *
+ + dbk:variablelist (dbk:variablelist) = dbk:variablelist *
+
+[argeodbk:paragraphElements]
+mixin
+ + dbk:formalpara (dbk:formalpara) = dbk:formalpara *
+ + dbk:para (dbk:para) = dbk:para *
+ + dbk:simpara (dbk:simpara) = dbk:simpara *
+
+[argeodbk:indexingInlines]
+mixin
+ + dbk:indexterm (dbk:indexterm) = dbk:indexterm *
+
+[argeodbk:techDocElements]
+mixin
+ + dbk:caution (dbk:caution) = dbk:caution *
+ + dbk:classsynopsis (dbk:classsynopsis) = dbk:classsynopsis *
+ + dbk:cmdsynopsis (dbk:cmdsynopsis) = dbk:cmdsynopsis *
+ + dbk:constraintdef (dbk:constraintdef) = dbk:constraintdef *
+ + dbk:constructorsynopsis (dbk:constructorsynopsis) = dbk:constructorsynopsis *
+ + dbk:destructorsynopsis (dbk:destructorsynopsis) = dbk:destructorsynopsis *
+ + dbk:equation (dbk:equation) = dbk:equation *
+ + dbk:example (dbk:example) = dbk:example *
+ + dbk:fieldsynopsis (dbk:fieldsynopsis) = dbk:fieldsynopsis *
+ + dbk:figure (dbk:figure) = dbk:figure *
+ + dbk:funcsynopsis (dbk:funcsynopsis) = dbk:funcsynopsis *
+ + dbk:important (dbk:important) = dbk:important *
+ + dbk:informalequation (dbk:informalequation) = dbk:informalequation *
+ + dbk:informalexample (dbk:informalexample) = dbk:informalexample *
+ + dbk:informalfigure (dbk:informalfigure) = dbk:informalfigure *
+ + dbk:informaltable (dbk:informaltable) = dbk:informaltable *
+ + dbk:literallayout (dbk:literallayout) = dbk:literallayout *
+ + dbk:methodsynopsis (dbk:methodsynopsis) = dbk:methodsynopsis *
+ + dbk:msgset (dbk:msgset) = dbk:msgset *
+ + dbk:note (dbk:note) = dbk:note *
+ + dbk:productionset (dbk:productionset) = dbk:productionset *
+ + dbk:programlisting (dbk:programlisting) = dbk:programlisting *
+ + dbk:programlistingco (dbk:programlistingco) = dbk:programlistingco *
+ + dbk:screen (dbk:screen) = dbk:screen *
+ + dbk:screenco (dbk:screenco) = dbk:screenco *
+ + dbk:synopsis (dbk:synopsis) = dbk:synopsis *
+ + dbk:table (dbk:table) = dbk:table *
+ + dbk:task (dbk:task) = dbk:task *
+ + dbk:tip (dbk:tip) = dbk:tip *
+ + dbk:warning (dbk:warning) = dbk:warning *
+
+[argeodbk:techDocInlines]
+mixin
+ + dbk:accel (dbk:accel) = dbk:accel *
+ + dbk:application (dbk:application) = dbk:application *
+ + dbk:classname (dbk:classname) = dbk:classname *
+ + dbk:command (dbk:command) = dbk:command *
+ + dbk:computeroutput (dbk:computeroutput) = dbk:computeroutput *
+ + dbk:database (dbk:database) = dbk:database *
+ + dbk:envar (dbk:envar) = dbk:envar *
+ + dbk:errorcode (dbk:errorcode) = dbk:errorcode *
+ + dbk:errorname (dbk:errorname) = dbk:errorname *
+ + dbk:errortext (dbk:errortext) = dbk:errortext *
+ + dbk:errortype (dbk:errortype) = dbk:errortype *
+ + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
+ + dbk:filename (dbk:filename) = dbk:filename *
+ + dbk:function (dbk:function) = dbk:function *
+ + dbk:guibutton (dbk:guibutton) = dbk:guibutton *
+ + dbk:guiicon (dbk:guiicon) = dbk:guiicon *
+ + dbk:guilabel (dbk:guilabel) = dbk:guilabel *
+ + dbk:guimenu (dbk:guimenu) = dbk:guimenu *
+ + dbk:guimenuitem (dbk:guimenuitem) = dbk:guimenuitem *
+ + dbk:guisubmenu (dbk:guisubmenu) = dbk:guisubmenu *
+ + dbk:hardware (dbk:hardware) = dbk:hardware *
+ + dbk:initializer (dbk:initializer) = dbk:initializer *
+ + dbk:inlineequation (dbk:inlineequation) = dbk:inlineequation *
+ + dbk:interfacename (dbk:interfacename) = dbk:interfacename *
+ + dbk:keycap (dbk:keycap) = dbk:keycap *
+ + dbk:keycode (dbk:keycode) = dbk:keycode *
+ + dbk:keycombo (dbk:keycombo) = dbk:keycombo *
+ + dbk:keysym (dbk:keysym) = dbk:keysym *
+ + dbk:menuchoice (dbk:menuchoice) = dbk:menuchoice *
+ + dbk:methodname (dbk:methodname) = dbk:methodname *
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:mousebutton (dbk:mousebutton) = dbk:mousebutton *
+ + dbk:nonterminal (dbk:nonterminal) = dbk:nonterminal *
+ + dbk:ooclass (dbk:ooclass) = dbk:ooclass *
+ + dbk:ooexception (dbk:ooexception) = dbk:ooexception *
+ + dbk:oointerface (dbk:oointerface) = dbk:oointerface *
+ + dbk:option (dbk:option) = dbk:option *
+ + dbk:optional (dbk:optional) = dbk:optional *
+ + dbk:package (dbk:package) = dbk:package *
+ + dbk:parameter (dbk:parameter) = dbk:parameter *
+ + dbk:productname (dbk:productname) = dbk:productname *
+ + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
+ + dbk:prompt (dbk:prompt) = dbk:prompt *
+ + dbk:property (dbk:property) = dbk:property *
+ + dbk:returnvalue (dbk:returnvalue) = dbk:returnvalue *
+ + dbk:shortcut (dbk:shortcut) = dbk:shortcut *
+ + dbk:systemitem (dbk:systemitem) = dbk:systemitem *
+ + dbk:termdef (dbk:termdef) = dbk:termdef *
+ + dbk:trademark (dbk:trademark) = dbk:trademark *
+ + dbk:type (dbk:type) = dbk:type *
+ + dbk:userinput (dbk:userinput) = dbk:userinput *
+ + dbk:varname (dbk:varname) = dbk:varname *
+
+[argeodbk:publishingElements]
+mixin
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:blockquote (dbk:blockquote) = dbk:blockquote *
+ + dbk:epigraph (dbk:epigraph) = dbk:epigraph *
+ + dbk:sidebar (dbk:sidebar) = dbk:sidebar *
+
+[argeodbk:ubiquitousInlines]
+mixin
+ + dbk:alt (dbk:alt) = dbk:alt *
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:biblioref (dbk:biblioref) = dbk:biblioref *
+ + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
+ + dbk:link (dbk:link) = dbk:link *
+ + dbk:olink (dbk:olink) = dbk:olink *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:subscript (dbk:subscript) = dbk:subscript *
+ + dbk:superscript (dbk:superscript) = dbk:superscript *
+ + dbk:xref (dbk:xref) = dbk:xref *
+
+[argeodbk:abstractSection]
+mixin
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bibliography (dbk:bibliography) = dbk:bibliography *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:glossary (dbk:glossary) = dbk:glossary *
+ + dbk:index (dbk:index) = dbk:index *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:toc (dbk:toc) = dbk:toc *
+ - label (String)
+ - status (String)
+
+[argeodbk:bibliographyInlines]
+mixin
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:citation (dbk:citation) = dbk:citation *
+ + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
+ + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
+ + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:jobtitle (dbk:jobtitle) = dbk:jobtitle *
+ + dbk:org (dbk:org) = dbk:org *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:person (dbk:person) = dbk:person *
+ + dbk:personname (dbk:personname) = dbk:personname *
+
+[argeodbk:publishingInlines]
+mixin
+ + dbk:abbrev (dbk:abbrev) = dbk:abbrev *
+ + dbk:acronym (dbk:acronym) = dbk:acronym *
+ + dbk:coref (dbk:coref) = dbk:coref *
+ + dbk:date (dbk:date) = dbk:date *
+ + dbk:emphasis (dbk:emphasis) = dbk:emphasis *
+ + dbk:firstterm (dbk:firstterm) = dbk:firstterm *
+ + dbk:footnote (dbk:footnote) = dbk:footnote *
+ + dbk:footnoteref (dbk:footnoteref) = dbk:footnoteref *
+ + dbk:foreignphrase (dbk:foreignphrase) = dbk:foreignphrase *
+ + dbk:glossterm (dbk:glossterm) = dbk:glossterm *
+ + dbk:quote (dbk:quote) = dbk:quote *
+ + dbk:wordasword (dbk:wordasword) = dbk:wordasword *
+
+[argeodbk:base]
+abstract
+orderable
+ - annotations (String)
+ - arch (String)
+ - audience (String)
+ - condition (String)
+ - conformance (String)
+ - dir (String)
+ - os (String)
+ - remap (String)
+ - revision (String)
+ - revisionflag (String)
+ - role (String)
+ - security (String)
+ - userlevel (String)
+ - vendor (String)
+ - version (String)
+ - wordsize (String)
+ - xreflabel (String)
+
+[dbk:abbrev] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:trademark (dbk:trademark) = dbk:trademark *
+
+[dbk:abstract] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+
+[dbk:accel] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:acknowledgements] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:acronym] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:trademark (dbk:trademark) = dbk:trademark *
+
+[dbk:address] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:city (dbk:city) = dbk:city *
+ + dbk:country (dbk:country) = dbk:country *
+ + dbk:email (dbk:email) = dbk:email *
+ + dbk:fax (dbk:fax) = dbk:fax *
+ + dbk:otheraddr (dbk:otheraddr) = dbk:otheraddr *
+ + dbk:personname (dbk:personname) = dbk:personname *
+ + dbk:phone (dbk:phone) = dbk:phone *
+ + dbk:pob (dbk:pob) = dbk:pob *
+ + dbk:postcode (dbk:postcode) = dbk:postcode *
+ + dbk:state (dbk:state) = dbk:state *
+ + dbk:street (dbk:street) = dbk:street *
+ + dbk:uri (dbk:uri) = dbk:uri *
+ - continuation (String) 
+ - language (String) 
+ - linenumbering (String) 
+ - startinglinenumber (String) 
+ - xml:space (String) 
+
+[dbk:affiliation] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:jobtitle (dbk:jobtitle) = dbk:jobtitle *
+ + dbk:org (dbk:org) = dbk:org
+ + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
+ + dbk:orgname (dbk:orgname) = dbk:orgname
+ + dbk:shortaffil (dbk:shortaffil) = dbk:shortaffil
+
+[dbk:alt] > argeodbk:base
+ + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:anchor] > argeodbk:base
+
+[dbk:annotation] > argeodbk:base, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - annotates (String) 
+
+[dbk:answer] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:label (dbk:label) = dbk:label
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:appendix] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refentry (dbk:refentry) = dbk:refentry *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect1 (dbk:sect1) = dbk:sect1 *
+ + dbk:section (dbk:section) = dbk:section *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:application] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+
+[dbk:arc] > argeodbk:base
+ - xlink:from (String) 
+ - xlink:to (String) 
+
+[dbk:area] > argeodbk:base
+ + dbk:alt (dbk:alt) = dbk:alt
+ - coords (String) 
+ - label (String) 
+ - linkends (String) 
+ - otherunits (String) 
+ - units (String) 
+
+[dbk:areaset] > argeodbk:base
+ + dbk:area (dbk:area) = dbk:area *
+ - label (String) 
+ - linkends (String) 
+ - otherunits (String) 
+ - units (String) 
+
+[dbk:areaspec] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:area (dbk:area) = dbk:area *
+ + dbk:areaset (dbk:areaset) = dbk:areaset *
+ - otherunits (String) 
+ - units (String) 
+
+[dbk:arg] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:arg (dbk:arg) = dbk:arg *
+ + dbk:group (dbk:group) = dbk:group *
+ + dbk:option (dbk:option) = dbk:option *
+ + dbk:sbr (dbk:sbr) = dbk:sbr *
+ + dbk:synopfragmentref (dbk:synopfragmentref) = dbk:synopfragmentref *
+ - choice (String) 
+ - rep (String) 
+
+[dbk:article] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:acknowledgements (dbk:acknowledgements) = dbk:acknowledgements *
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:appendix (dbk:appendix) = dbk:appendix *
+ + dbk:colophon (dbk:colophon) = dbk:colophon *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refentry (dbk:refentry) = dbk:refentry *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect1 (dbk:sect1) = dbk:sect1 *
+ + dbk:section (dbk:section) = dbk:section *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ - class (String) 
+
+[dbk:artpagenums] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:attribution] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:citation (dbk:citation) = dbk:citation *
+ + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
+ + dbk:person (dbk:person) = dbk:person *
+ + dbk:personname (dbk:personname) = dbk:personname *
+
+[dbk:audiodata] > argeodbk:base
+ + dbk:info (dbk:info) = dbk:info
+ - entityref (String) 
+ - fileref (String) 
+ - format (String) 
+
+[dbk:audioobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:audiodata (dbk:audiodata) = dbk:audiodata
+ + dbk:info (dbk:info) = dbk:info
+
+[dbk:author] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
+ + dbk:contrib (dbk:contrib) = dbk:contrib *
+ + dbk:email (dbk:email) = dbk:email *
+ + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
+ + dbk:orgname (dbk:orgname) = dbk:orgname
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname
+ + dbk:uri (dbk:uri) = dbk:uri *
+
+[dbk:authorgroup] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
+
+[dbk:authorinitials] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:bibliocoverage] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - otherspatial (String) 
+ - othertemporal (String) 
+ - spatial (String) 
+ - temporal (String) 
+
+[dbk:bibliodiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:biblioentry (dbk:biblioentry) = dbk:biblioentry *
+ + dbk:bibliomixed (dbk:bibliomixed) = dbk:bibliomixed *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:biblioentry] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:publishingInlines
+ + dbk:abstract (dbk:abstract) = dbk:abstract *
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
+ + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
+ + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
+ + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
+ + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
+ + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
+ + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
+ + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
+ + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
+ + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
+ + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
+ + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
+ + dbk:collab (dbk:collab) = dbk:collab *
+ + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
+ + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
+ + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
+ + dbk:copyright (dbk:copyright) = dbk:copyright *
+ + dbk:cover (dbk:cover) = dbk:cover *
+ + dbk:edition (dbk:edition) = dbk:edition *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
+ + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
+ + dbk:itermset (dbk:itermset) = dbk:itermset *
+ + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
+ + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:org (dbk:org) = dbk:org *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
+ + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
+ + dbk:person (dbk:person) = dbk:person *
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname *
+ + dbk:phrase (dbk:phrase) = dbk:phrase *
+ + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
+ + dbk:productname (dbk:productname) = dbk:productname *
+ + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
+ + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
+ + dbk:publisher (dbk:publisher) = dbk:publisher *
+ + dbk:publishername (dbk:publishername) = dbk:publishername *
+ + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
+ + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
+ + dbk:subscript (dbk:subscript) = dbk:subscript *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:superscript (dbk:superscript) = dbk:superscript *
+ + dbk:title (dbk:title) = dbk:title *
+ + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
+ + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
+
+[dbk:bibliography] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bibliodiv (dbk:bibliodiv) = dbk:bibliodiv *
+ + dbk:biblioentry (dbk:biblioentry) = dbk:biblioentry *
+ + dbk:bibliomixed (dbk:bibliomixed) = dbk:bibliomixed *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:biblioid] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - otherclass (String) 
+
+[dbk:bibliolist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:biblioentry (dbk:biblioentry) = dbk:biblioentry *
+ + dbk:bibliomixed (dbk:bibliomixed) = dbk:bibliomixed *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:bibliomisc] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:bibliomixed] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:publishingInlines
+ + dbk:abstract (dbk:abstract) = dbk:abstract *
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
+ + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
+ + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
+ + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
+ + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
+ + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
+ + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
+ + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
+ + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
+ + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
+ + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
+ + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
+ + dbk:collab (dbk:collab) = dbk:collab *
+ + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
+ + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
+ + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
+ + dbk:copyright (dbk:copyright) = dbk:copyright *
+ + dbk:cover (dbk:cover) = dbk:cover *
+ + dbk:edition (dbk:edition) = dbk:edition *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
+ + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
+ + dbk:itermset (dbk:itermset) = dbk:itermset *
+ + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
+ + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:org (dbk:org) = dbk:org *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
+ + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
+ + dbk:person (dbk:person) = dbk:person *
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname *
+ + dbk:phrase (dbk:phrase) = dbk:phrase *
+ + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
+ + dbk:productname (dbk:productname) = dbk:productname *
+ + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
+ + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
+ + dbk:publisher (dbk:publisher) = dbk:publisher *
+ + dbk:publishername (dbk:publishername) = dbk:publishername *
+ + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
+ + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
+ + dbk:subscript (dbk:subscript) = dbk:subscript *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:superscript (dbk:superscript) = dbk:superscript *
+ + dbk:title (dbk:title) = dbk:title *
+ + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
+ + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:bibliomset] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:publishingInlines, argeodbk:ubiquitousInlines
+ + dbk:abstract (dbk:abstract) = dbk:abstract *
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
+ + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
+ + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
+ + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
+ + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
+ + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
+ + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
+ + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
+ + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
+ + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
+ + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
+ + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
+ + dbk:collab (dbk:collab) = dbk:collab *
+ + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
+ + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
+ + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
+ + dbk:copyright (dbk:copyright) = dbk:copyright *
+ + dbk:cover (dbk:cover) = dbk:cover *
+ + dbk:edition (dbk:edition) = dbk:edition *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
+ + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
+ + dbk:itermset (dbk:itermset) = dbk:itermset *
+ + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
+ + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:org (dbk:org) = dbk:org *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
+ + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
+ + dbk:person (dbk:person) = dbk:person *
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname *
+ + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
+ + dbk:productname (dbk:productname) = dbk:productname *
+ + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
+ + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
+ + dbk:publisher (dbk:publisher) = dbk:publisher *
+ + dbk:publishername (dbk:publishername) = dbk:publishername *
+ + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
+ + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:title (dbk:title) = dbk:title *
+ + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
+ + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
+ - relation (String) 
+
+[dbk:biblioref] > argeodbk:base, argeodbk:linkingAttributes
+ - begin (String) 
+ - end (String) 
+ - endterm (Reference) 
+ - units (String) 
+ - xrefstyle (String) 
+
+[dbk:bibliorelation] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - otherclass (String) 
+ - othertype (String) 
+ - type (String) 
+
+[dbk:biblioset] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:publishingInlines
+ + dbk:abstract (dbk:abstract) = dbk:abstract *
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
+ + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
+ + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
+ + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
+ + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
+ + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
+ + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
+ + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
+ + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
+ + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
+ + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
+ + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
+ + dbk:collab (dbk:collab) = dbk:collab *
+ + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
+ + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
+ + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
+ + dbk:copyright (dbk:copyright) = dbk:copyright *
+ + dbk:cover (dbk:cover) = dbk:cover *
+ + dbk:edition (dbk:edition) = dbk:edition *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
+ + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
+ + dbk:itermset (dbk:itermset) = dbk:itermset *
+ + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
+ + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:org (dbk:org) = dbk:org *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
+ + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
+ + dbk:person (dbk:person) = dbk:person *
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname *
+ + dbk:phrase (dbk:phrase) = dbk:phrase *
+ + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
+ + dbk:productname (dbk:productname) = dbk:productname *
+ + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
+ + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
+ + dbk:publisher (dbk:publisher) = dbk:publisher *
+ + dbk:publishername (dbk:publishername) = dbk:publishername *
+ + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
+ + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
+ + dbk:subscript (dbk:subscript) = dbk:subscript *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:superscript (dbk:superscript) = dbk:superscript *
+ + dbk:title (dbk:title) = dbk:title *
+ + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
+ + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
+ - relation (String) 
+
+[dbk:bibliosource] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - otherclass (String) 
+
+[dbk:blockquote] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:attribution (dbk:attribution) = dbk:attribution
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:book] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:acknowledgements (dbk:acknowledgements) = dbk:acknowledgements *
+ + dbk:appendix (dbk:appendix) = dbk:appendix *
+ + dbk:article (dbk:article) = dbk:article *
+ + dbk:bibliography (dbk:bibliography) = dbk:bibliography *
+ + dbk:chapter (dbk:chapter) = dbk:chapter *
+ + dbk:colophon (dbk:colophon) = dbk:colophon *
+ + dbk:dedication (dbk:dedication) = dbk:dedication *
+ + dbk:glossary (dbk:glossary) = dbk:glossary *
+ + dbk:index (dbk:index) = dbk:index *
+ + dbk:part (dbk:part) = dbk:part *
+ + dbk:preface (dbk:preface) = dbk:preface *
+ + dbk:reference (dbk:reference) = dbk:reference *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:toc (dbk:toc) = dbk:toc *
+ - label (String) 
+ - status (String) 
+
+[dbk:bridgehead] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - otherrenderas (String) 
+ - renderas (String) 
+
+[dbk:callout] > argeodbk:base, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - arearefs (String) 
+
+[dbk:calloutlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:callout (dbk:callout) = dbk:callout *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:caption] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+ - class (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - style (String) 
+ - title (String) 
+
+[dbk:caution] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:chapter] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refentry (dbk:refentry) = dbk:refentry *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect1 (dbk:sect1) = dbk:sect1 *
+ + dbk:section (dbk:section) = dbk:section *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:citation] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:citebiblioid] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - otherclass (String) 
+
+[dbk:citerefentry] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:manvolnum (dbk:manvolnum) = dbk:manvolnum
+ + dbk:refentrytitle (dbk:refentrytitle) = dbk:refentrytitle
+
+[dbk:citetitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - pubwork (String) 
+
+[dbk:city] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:classname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:classsynopsis] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:classsynopsisinfo (dbk:classsynopsisinfo) = dbk:classsynopsisinfo *
+ + dbk:constructorsynopsis (dbk:constructorsynopsis) = dbk:constructorsynopsis *
+ + dbk:destructorsynopsis (dbk:destructorsynopsis) = dbk:destructorsynopsis *
+ + dbk:fieldsynopsis (dbk:fieldsynopsis) = dbk:fieldsynopsis *
+ + dbk:methodsynopsis (dbk:methodsynopsis) = dbk:methodsynopsis *
+ + dbk:ooclass (dbk:ooclass) = dbk:ooclass *
+ + dbk:ooexception (dbk:ooexception) = dbk:ooexception *
+ + dbk:oointerface (dbk:oointerface) = dbk:oointerface *
+ - class (String) 
+ - language (String) 
+
+[dbk:classsynopsisinfo] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ - continuation (String) 
+ - language (String) 
+ - linenumbering (String) 
+ - startinglinenumber (String) 
+ - xml:space (String) 
+
+[dbk:cmdsynopsis] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:arg (dbk:arg) = dbk:arg *
+ + dbk:command (dbk:command) = dbk:command *
+ + dbk:group (dbk:group) = dbk:group *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:sbr (dbk:sbr) = dbk:sbr *
+ + dbk:synopfragment (dbk:synopfragment) = dbk:synopfragment *
+ - cmdlength (String) 
+ - label (String) 
+ - sepchar (String) 
+
+[dbk:co] > argeodbk:base
+ - label (String) 
+ - linkends (String) 
+
+[dbk:code] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:classname (dbk:classname) = dbk:classname *
+ + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
+ + dbk:function (dbk:function) = dbk:function *
+ + dbk:initializer (dbk:initializer) = dbk:initializer *
+ + dbk:interfacename (dbk:interfacename) = dbk:interfacename *
+ + dbk:methodname (dbk:methodname) = dbk:methodname *
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:ooclass (dbk:ooclass) = dbk:ooclass *
+ + dbk:ooexception (dbk:ooexception) = dbk:ooexception *
+ + dbk:oointerface (dbk:oointerface) = dbk:oointerface *
+ + dbk:parameter (dbk:parameter) = dbk:parameter *
+ + dbk:returnvalue (dbk:returnvalue) = dbk:returnvalue *
+ + dbk:type (dbk:type) = dbk:type *
+ + dbk:varname (dbk:varname) = dbk:varname *
+ - language (String) 
+
+[dbk:col] > nt:base
+ - align (String) 
+ - annotations (String) 
+ - arch (String) 
+ - audience (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - condition (String) 
+ - conformance (String) 
+ - dir (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - os (String) 
+ - remap (String) 
+ - revision (String) 
+ - revisionflag (String) 
+ - security (String) 
+ - span (String) 
+ - style (String) 
+ - title (String) 
+ - userlevel (String) 
+ - valign (String) 
+ - vendor (String) 
+ - version (String) 
+ - width (String) 
+ - wordsize (String) 
+ - xreflabel (String) 
+ - xml:base (String) 
+ - xml:id (String) 
+ - xml:lang (String) 
+
+[dbk:colgroup] > nt:base
+ + dbk:col (dbk:col) = dbk:col *
+ - align (String) 
+ - annotations (String) 
+ - arch (String) 
+ - audience (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - condition (String) 
+ - conformance (String) 
+ - dir (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - os (String) 
+ - remap (String) 
+ - revision (String) 
+ - revisionflag (String) 
+ - security (String) 
+ - span (String) 
+ - style (String) 
+ - title (String) 
+ - userlevel (String) 
+ - valign (String) 
+ - vendor (String) 
+ - version (String) 
+ - width (String) 
+ - wordsize (String) 
+ - xreflabel (String) 
+ - xml:base (String) 
+ - xml:id (String) 
+ - xml:lang (String) 
+
+[dbk:collab] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
+ + dbk:org (dbk:org) = dbk:org *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:person (dbk:person) = dbk:person *
+ + dbk:personname (dbk:personname) = dbk:personname *
+
+[dbk:colophon] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:colspec] > argeodbk:base, argeodbk:linkingAttributes
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - colname (String) 
+ - colnum (String) 
+ - colsep (String) 
+ - colwidth (String) 
+ - rowsep (String) 
+
+[dbk:command] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:computeroutput] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ + dbk:command (dbk:command) = dbk:command *
+ + dbk:computeroutput (dbk:computeroutput) = dbk:computeroutput *
+ + dbk:envar (dbk:envar) = dbk:envar *
+ + dbk:filename (dbk:filename) = dbk:filename *
+ + dbk:nonterminal (dbk:nonterminal) = dbk:nonterminal *
+ + dbk:option (dbk:option) = dbk:option *
+ + dbk:optional (dbk:optional) = dbk:optional *
+ + dbk:package (dbk:package) = dbk:package *
+ + dbk:parameter (dbk:parameter) = dbk:parameter *
+ + dbk:prompt (dbk:prompt) = dbk:prompt *
+ + dbk:property (dbk:property) = dbk:property *
+ + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
+ + dbk:systemitem (dbk:systemitem) = dbk:systemitem *
+ + dbk:termdef (dbk:termdef) = dbk:termdef *
+ + dbk:userinput (dbk:userinput) = dbk:userinput *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:confdates] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:confgroup] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:confdates (dbk:confdates) = dbk:confdates *
+ + dbk:confnum (dbk:confnum) = dbk:confnum *
+ + dbk:confsponsor (dbk:confsponsor) = dbk:confsponsor *
+ + dbk:conftitle (dbk:conftitle) = dbk:conftitle *
+
+[dbk:confnum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:confsponsor] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:conftitle] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:constant] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+
+[dbk:constraint] > argeodbk:base, argeodbk:linkingAttributes
+
+[dbk:constraintdef] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:constructorsynopsis] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
+ + dbk:methodname (dbk:methodname) = dbk:methodname
+ + dbk:methodparam (dbk:methodparam) = dbk:methodparam *
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:void (dbk:void) = dbk:void
+ - language (String) 
+
+[dbk:contractnum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:contractsponsor] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:contrib] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:copyright] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:holder (dbk:holder) = dbk:holder *
+ + dbk:year (dbk:year) = dbk:year *
+
+[dbk:coref] > argeodbk:base, argeodbk:linkingAttributes
+ - label (String) 
+
+[dbk:country] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:cover] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:classsynopsis (dbk:classsynopsis) = dbk:classsynopsis *
+ + dbk:cmdsynopsis (dbk:cmdsynopsis) = dbk:cmdsynopsis *
+ + dbk:constraintdef (dbk:constraintdef) = dbk:constraintdef *
+ + dbk:constructorsynopsis (dbk:constructorsynopsis) = dbk:constructorsynopsis *
+ + dbk:destructorsynopsis (dbk:destructorsynopsis) = dbk:destructorsynopsis *
+ + dbk:fieldsynopsis (dbk:fieldsynopsis) = dbk:fieldsynopsis *
+ + dbk:funcsynopsis (dbk:funcsynopsis) = dbk:funcsynopsis *
+ + dbk:informalequation (dbk:informalequation) = dbk:informalequation *
+ + dbk:informalexample (dbk:informalexample) = dbk:informalexample *
+ + dbk:informalfigure (dbk:informalfigure) = dbk:informalfigure *
+ + dbk:informaltable (dbk:informaltable) = dbk:informaltable *
+ + dbk:literallayout (dbk:literallayout) = dbk:literallayout *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:methodsynopsis (dbk:methodsynopsis) = dbk:methodsynopsis *
+ + dbk:msgset (dbk:msgset) = dbk:msgset *
+ + dbk:productionset (dbk:productionset) = dbk:productionset *
+ + dbk:programlisting (dbk:programlisting) = dbk:programlisting *
+ + dbk:programlistingco (dbk:programlistingco) = dbk:programlistingco *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screen (dbk:screen) = dbk:screen *
+ + dbk:screenco (dbk:screenco) = dbk:screenco *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:synopsis (dbk:synopsis) = dbk:synopsis *
+ + dbk:task (dbk:task) = dbk:task *
+
+[dbk:database] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+
+[dbk:date] > argeodbk:base, argeodbk:linkingAttributes
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:dedication] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:destructorsynopsis] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
+ + dbk:methodname (dbk:methodname) = dbk:methodname
+ + dbk:methodparam (dbk:methodparam) = dbk:methodparam *
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:void (dbk:void) = dbk:void
+ - language (String) 
+
+[dbk:edition] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:editor] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
+ + dbk:contrib (dbk:contrib) = dbk:contrib *
+ + dbk:email (dbk:email) = dbk:email *
+ + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
+ + dbk:orgname (dbk:orgname) = dbk:orgname
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname
+ + dbk:uri (dbk:uri) = dbk:uri *
+
+[dbk:email] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:emphasis] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:entry] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:markupInlines, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - colname (String) 
+ - colsep (String) 
+ - morerows (String) 
+ - nameend (String) 
+ - namest (String) 
+ - rotate (String) 
+ - rowsep (String) 
+ - spanname (String) 
+ - valign (String) 
+
+[dbk:entrytbl] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:colspec (dbk:colspec) = dbk:colspec *
+ + dbk:spanspec (dbk:spanspec) = dbk:spanspec *
+ + dbk:tbody (dbk:tbody) = dbk:tbody
+ + dbk:thead (dbk:thead) = dbk:thead
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - colname (String) 
+ - cols (String) 
+ - colsep (String) 
+ - nameend (String) 
+ - namest (String) 
+ - rowsep (String) 
+ - spanname (String) 
+ - tgroupstyle (String) 
+
+[dbk:envar] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:epigraph] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:attribution (dbk:attribution) = dbk:attribution
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:literallayout (dbk:literallayout) = dbk:literallayout *
+
+[dbk:equation] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:alt (dbk:alt) = dbk:alt
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:mathphrase (dbk:mathphrase) = dbk:mathphrase *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ - floatstyle (String) 
+ - label (String) 
+ - pgwide (String) 
+
+[dbk:errorcode] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:errorname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:errortext] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:errortype] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:example] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - floatstyle (String) 
+ - label (String) 
+ - pgwide (String) 
+ - width (String) 
+
+[dbk:exceptionname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:extendedlink] > argeodbk:base
+ + dbk:arc (dbk:arc) = dbk:arc *
+ + dbk:locator (dbk:locator) = dbk:locator *
+
+[dbk:fax] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:fieldsynopsis] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:initializer (dbk:initializer) = dbk:initializer
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:type (dbk:type) = dbk:type
+ + dbk:varname (dbk:varname) = dbk:varname
+ - language (String) 
+
+[dbk:figure] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - floatstyle (String) 
+ - label (String) 
+ - pgwide (String) 
+
+[dbk:filename] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - path (String) 
+
+[dbk:firstname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:firstterm] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - baseform (String) 
+
+[dbk:footnote] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - label (String) 
+
+[dbk:footnoteref] > argeodbk:base, argeodbk:linkingAttributes
+ - label (String) 
+
+[dbk:foreignphrase] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:publishingInlines
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:application (dbk:application) = dbk:application *
+ + dbk:biblioref (dbk:biblioref) = dbk:biblioref *
+ + dbk:database (dbk:database) = dbk:database *
+ + dbk:hardware (dbk:hardware) = dbk:hardware *
+ + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
+ + dbk:link (dbk:link) = dbk:link *
+ + dbk:olink (dbk:olink) = dbk:olink *
+ + dbk:phrase (dbk:phrase) = dbk:phrase *
+ + dbk:productname (dbk:productname) = dbk:productname *
+ + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
+ + dbk:subscript (dbk:subscript) = dbk:subscript *
+ + dbk:superscript (dbk:superscript) = dbk:superscript *
+ + dbk:trademark (dbk:trademark) = dbk:trademark *
+ + dbk:xref (dbk:xref) = dbk:xref *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:formalpara] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:para (dbk:para) = dbk:para
+
+[dbk:funcdef] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:function (dbk:function) = dbk:function *
+ + dbk:type (dbk:type) = dbk:type *
+
+[dbk:funcparams] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:funcprototype] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:funcdef (dbk:funcdef) = dbk:funcdef
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:paramdef (dbk:paramdef) = dbk:paramdef *
+ + dbk:varargs (dbk:varargs) = dbk:varargs
+ + dbk:varargs (dbk:varargs) = dbk:varargs
+ + dbk:void (dbk:void) = dbk:void
+
+[dbk:funcsynopsis] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:funcprototype (dbk:funcprototype) = dbk:funcprototype *
+ + dbk:funcsynopsisinfo (dbk:funcsynopsisinfo) = dbk:funcsynopsisinfo *
+ + dbk:info (dbk:info) = dbk:info
+ - language (String) 
+
+[dbk:funcsynopsisinfo] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ - continuation (String) 
+ - language (String) 
+ - linenumbering (String) 
+ - startinglinenumber (String) 
+ - xml:space (String) 
+
+[dbk:function] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:glossary] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bibliography (dbk:bibliography) = dbk:bibliography
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:glossdiv (dbk:glossdiv) = dbk:glossdiv *
+ + dbk:glossentry (dbk:glossentry) = dbk:glossentry *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:glossdef] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:glossseealso (dbk:glossseealso) = dbk:glossseealso *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - subject (String) 
+
+[dbk:glossdiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:glossentry (dbk:glossentry) = dbk:glossentry *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:glossentry] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes
+ + dbk:abbrev (dbk:abbrev) = dbk:abbrev
+ + dbk:acronym (dbk:acronym) = dbk:acronym
+ + dbk:glossdef (dbk:glossdef) = dbk:glossdef *
+ + dbk:glosssee (dbk:glosssee) = dbk:glosssee
+ + dbk:glossterm (dbk:glossterm) = dbk:glossterm
+ - sortas (String) 
+
+[dbk:glosslist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:glossentry (dbk:glossentry) = dbk:glossentry *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:glosssee] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - otherterm (Reference) 
+
+[dbk:glossseealso] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - otherterm (Reference) 
+
+[dbk:glossterm] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - baseform (String) 
+
+[dbk:group] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:arg (dbk:arg) = dbk:arg *
+ + dbk:group (dbk:group) = dbk:group *
+ + dbk:option (dbk:option) = dbk:option *
+ + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
+ + dbk:sbr (dbk:sbr) = dbk:sbr *
+ + dbk:synopfragmentref (dbk:synopfragmentref) = dbk:synopfragmentref *
+ - choice (String) 
+ - rep (String) 
+
+[dbk:guibutton] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:accel (dbk:accel) = dbk:accel *
+
+[dbk:guiicon] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:accel (dbk:accel) = dbk:accel *
+
+[dbk:guilabel] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:accel (dbk:accel) = dbk:accel *
+
+[dbk:guimenu] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:accel (dbk:accel) = dbk:accel *
+
+[dbk:guimenuitem] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:accel (dbk:accel) = dbk:accel *
+
+[dbk:guisubmenu] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:accel (dbk:accel) = dbk:accel *
+
+[dbk:hardware] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:holder] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:honorific] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:imagedata] > argeodbk:base
+ + dbk:info (dbk:info) = dbk:info
+ - align (String) 
+ - contentdepth (String) 
+ - contentwidth (String) 
+ - depth (String) 
+ - entityref (String) 
+ - fileref (String) 
+ - format (String) 
+ - scale (String) 
+ - scalefit (String) 
+ - valign (String) 
+ - width (String) 
+
+[dbk:imageobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:imagedata (dbk:imagedata) = dbk:imagedata
+ + dbk:info (dbk:info) = dbk:info
+
+[dbk:imageobjectco] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:areaspec (dbk:areaspec) = dbk:areaspec
+ + dbk:calloutlist (dbk:calloutlist) = dbk:calloutlist *
+ + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
+ + dbk:info (dbk:info) = dbk:info
+
+[dbk:important] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:index] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:indexdiv (dbk:indexdiv) = dbk:indexdiv *
+ + dbk:indexentry (dbk:indexentry) = dbk:indexentry *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+ - type (String) 
+
+[dbk:indexdiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:indexentry (dbk:indexentry) = dbk:indexentry *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:indexentry] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:primaryie (dbk:primaryie) = dbk:primaryie
+ + dbk:secondaryie (dbk:secondaryie) = dbk:secondaryie *
+ + dbk:seealsoie (dbk:seealsoie) = dbk:seealsoie *
+ + dbk:seeie (dbk:seeie) = dbk:seeie *
+ + dbk:tertiaryie (dbk:tertiaryie) = dbk:tertiaryie *
+
+[dbk:indexterm] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:primary (dbk:primary) = dbk:primary
+ + dbk:secondary (dbk:secondary) = dbk:secondary
+ + dbk:see (dbk:see) = dbk:see
+ + dbk:seealso (dbk:seealso) = dbk:seealso *
+ + dbk:tertiary (dbk:tertiary) = dbk:tertiary
+ - class (String) 
+ - pagenum (String) 
+ - scope (String) 
+ - significance (String) 
+ - startref (Reference) 
+ - type (String) 
+ - zone (String) 
+
+[dbk:info] > argeodbk:base
+ + dbk:abstract (dbk:abstract) = dbk:abstract *
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
+ + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
+ + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
+ + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
+ + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
+ + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
+ + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
+ + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
+ + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
+ + dbk:collab (dbk:collab) = dbk:collab *
+ + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
+ + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
+ + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
+ + dbk:copyright (dbk:copyright) = dbk:copyright *
+ + dbk:cover (dbk:cover) = dbk:cover *
+ + dbk:date (dbk:date) = dbk:date *
+ + dbk:edition (dbk:edition) = dbk:edition *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
+ + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
+ + dbk:itermset (dbk:itermset) = dbk:itermset *
+ + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
+ + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:org (dbk:org) = dbk:org *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
+ + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
+ + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
+ + dbk:productname (dbk:productname) = dbk:productname *
+ + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
+ + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
+ + dbk:publisher (dbk:publisher) = dbk:publisher *
+ + dbk:publishername (dbk:publishername) = dbk:publishername *
+ + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
+ + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:title (dbk:title) = dbk:title *
+ + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
+ + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
+ + * (nt:base) = nt:unstructured *
+
+[dbk:informalequation] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:alt (dbk:alt) = dbk:alt
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:mathphrase (dbk:mathphrase) = dbk:mathphrase *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+
+[dbk:informalexample] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - floatstyle (String) 
+ - width (String) 
+
+[dbk:informalfigure] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - floatstyle (String) 
+ - label (String) 
+ - pgwide (String) 
+
+[dbk:informaltable] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:col (dbk:col) = dbk:col *
+ + dbk:colgroup (dbk:colgroup) = dbk:colgroup *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:tbody (dbk:tbody) = dbk:tbody *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ + dbk:tfoot (dbk:tfoot) = dbk:tfoot
+ + dbk:tgroup (dbk:tgroup) = dbk:tgroup *
+ + dbk:thead (dbk:thead) = dbk:thead
+ + dbk:tr (dbk:tr) = dbk:tr *
+ - border (String) 
+ - cellpadding (String) 
+ - cellspacing (String) 
+ - class (String) 
+ - colsep (String) 
+ - floatstyle (String) 
+ - frame (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - orient (String) 
+ - pgwide (String) 
+ - rowheader (String) 
+ - rowsep (String) 
+ - rules (String) 
+ - style (String) 
+ - summary (String) 
+ - tabstyle (String) 
+ - title (String) 
+ - width (String) 
+
+[dbk:initializer] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:inlineequation] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:alt (dbk:alt) = dbk:alt
+ + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
+ + dbk:mathphrase (dbk:mathphrase) = dbk:mathphrase *
+
+[dbk:inlinemediaobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:alt (dbk:alt) = dbk:alt
+ + dbk:audioobject (dbk:audioobject) = dbk:audioobject *
+ + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
+ + dbk:imageobjectco (dbk:imageobjectco) = dbk:imageobjectco *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ + dbk:videoobject (dbk:videoobject) = dbk:videoobject *
+
+[dbk:interfacename] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:issuenum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:itemizedlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:listitem (dbk:listitem) = dbk:listitem *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - mark (String) 
+ - spacing (String) 
+
+[dbk:itermset] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes
+
+[dbk:jobtitle] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:keycap] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - function (String) 
+ - otherfunction (String) 
+
+[dbk:keycode] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:keycombo] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:keycap (dbk:keycap) = dbk:keycap *
+ + dbk:keycombo (dbk:keycombo) = dbk:keycombo *
+ + dbk:keysym (dbk:keysym) = dbk:keysym *
+ + dbk:mousebutton (dbk:mousebutton) = dbk:mousebutton *
+ - action (String) 
+ - otheraction (String) 
+
+[dbk:keysym] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:keyword] > argeodbk:base, argeodbk:linkingAttributes
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:keywordset] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:keyword (dbk:keyword) = dbk:keyword *
+
+[dbk:label] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:legalnotice] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:lhs] > argeodbk:base, argeodbk:linkingAttributes
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:lineage] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:lineannotation] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:link] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - endterm (Reference) 
+ - xrefstyle (String) 
+
+[dbk:listitem] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - override (String) 
+
+[dbk:literal] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:literallayout] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ - class (String) 
+ - continuation (String) 
+ - language (String) 
+ - linenumbering (String) 
+ - startinglinenumber (String) 
+ - xml:space (String) 
+
+[dbk:locator] > argeodbk:base
+ - xlink:label (String) 
+
+[dbk:manvolnum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:markup] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:mathphrase] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:emphasis (dbk:emphasis) = dbk:emphasis *
+
+[dbk:mediaobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:alt (dbk:alt) = dbk:alt
+ + dbk:audioobject (dbk:audioobject) = dbk:audioobject *
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
+ + dbk:imageobjectco (dbk:imageobjectco) = dbk:imageobjectco *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ + dbk:videoobject (dbk:videoobject) = dbk:videoobject *
+
+[dbk:member] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:menuchoice] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:guibutton (dbk:guibutton) = dbk:guibutton *
+ + dbk:guiicon (dbk:guiicon) = dbk:guiicon *
+ + dbk:guilabel (dbk:guilabel) = dbk:guilabel *
+ + dbk:guimenu (dbk:guimenu) = dbk:guimenu *
+ + dbk:guimenuitem (dbk:guimenuitem) = dbk:guimenuitem *
+ + dbk:guisubmenu (dbk:guisubmenu) = dbk:guisubmenu *
+ + dbk:shortcut (dbk:shortcut) = dbk:shortcut
+
+[dbk:methodname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:methodparam] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:funcparams (dbk:funcparams) = dbk:funcparams
+ + dbk:initializer (dbk:initializer) = dbk:initializer
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:parameter (dbk:parameter) = dbk:parameter
+ + dbk:type (dbk:type) = dbk:type *
+ - choice (String) 
+ - rep (String) 
+
+[dbk:methodsynopsis] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
+ + dbk:methodname (dbk:methodname) = dbk:methodname
+ + dbk:methodparam (dbk:methodparam) = dbk:methodparam *
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:type (dbk:type) = dbk:type
+ + dbk:void (dbk:void) = dbk:void
+ - language (String) 
+
+[dbk:modifier] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - xml:space (String) 
+
+[dbk:mousebutton] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:msg] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:msgmain (dbk:msgmain) = dbk:msgmain
+ + dbk:msgrel (dbk:msgrel) = dbk:msgrel *
+ + dbk:msgsub (dbk:msgsub) = dbk:msgsub *
+
+[dbk:msgaud] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:msgentry] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:msg (dbk:msg) = dbk:msg *
+ + dbk:msgexplan (dbk:msgexplan) = dbk:msgexplan *
+ + dbk:msginfo (dbk:msginfo) = dbk:msginfo
+
+[dbk:msgexplan] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:msginfo] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:msgaud (dbk:msgaud) = dbk:msgaud *
+ + dbk:msglevel (dbk:msglevel) = dbk:msglevel *
+ + dbk:msgorig (dbk:msgorig) = dbk:msgorig *
+
+[dbk:msglevel] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:msgmain] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:msgtext (dbk:msgtext) = dbk:msgtext
+
+[dbk:msgorig] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:msgrel] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:msgtext (dbk:msgtext) = dbk:msgtext
+
+[dbk:msgset] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:msgentry (dbk:msgentry) = dbk:msgentry *
+ + dbk:simplemsgentry (dbk:simplemsgentry) = dbk:simplemsgentry *
+
+[dbk:msgsub] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:msgtext (dbk:msgtext) = dbk:msgtext
+
+[dbk:msgtext] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:nonterminal] > argeodbk:base, argeodbk:linkingAttributes
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+ - def (String) 
+
+[dbk:note] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:olink] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - localinfo (String) 
+ - targetdoc (String) 
+ - targetptr (String) 
+ - type (String) 
+ - xrefstyle (String) 
+
+[dbk:ooclass] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:classname (dbk:classname) = dbk:classname
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:package (dbk:package) = dbk:package *
+
+[dbk:ooexception] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:package (dbk:package) = dbk:package *
+
+[dbk:oointerface] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:interfacename (dbk:interfacename) = dbk:interfacename
+ + dbk:modifier (dbk:modifier) = dbk:modifier *
+ + dbk:package (dbk:package) = dbk:package *
+
+[dbk:option] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:optional] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:orderedlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:listitem (dbk:listitem) = dbk:listitem *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - continuation (String) 
+ - inheritnum (String) 
+ - numeration (String) 
+ - spacing (String) 
+ - startingnumber (String) 
+
+[dbk:org] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
+ + dbk:email (dbk:email) = dbk:email *
+ + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
+ + dbk:orgname (dbk:orgname) = dbk:orgname
+ + dbk:uri (dbk:uri) = dbk:uri *
+
+[dbk:orgdiv] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:orgname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - otherclass (String) 
+
+[dbk:otheraddr] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:othercredit] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
+ + dbk:contrib (dbk:contrib) = dbk:contrib *
+ + dbk:email (dbk:email) = dbk:email *
+ + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
+ + dbk:orgname (dbk:orgname) = dbk:orgname
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname
+ + dbk:uri (dbk:uri) = dbk:uri *
+ - class (String) 
+ - otherclass (String) 
+
+[dbk:othername] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:package] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:pagenums] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:para] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:markupInlines, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:paramdef] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:funcparams (dbk:funcparams) = dbk:funcparams *
+ + dbk:initializer (dbk:initializer) = dbk:initializer *
+ + dbk:parameter (dbk:parameter) = dbk:parameter *
+ + dbk:type (dbk:type) = dbk:type *
+ - choice (String) 
+
+[dbk:parameter] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+
+[dbk:part] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:acknowledgements (dbk:acknowledgements) = dbk:acknowledgements *
+ + dbk:appendix (dbk:appendix) = dbk:appendix *
+ + dbk:article (dbk:article) = dbk:article *
+ + dbk:bibliography (dbk:bibliography) = dbk:bibliography *
+ + dbk:chapter (dbk:chapter) = dbk:chapter *
+ + dbk:colophon (dbk:colophon) = dbk:colophon *
+ + dbk:dedication (dbk:dedication) = dbk:dedication *
+ + dbk:glossary (dbk:glossary) = dbk:glossary *
+ + dbk:index (dbk:index) = dbk:index *
+ + dbk:partintro (dbk:partintro) = dbk:partintro
+ + dbk:preface (dbk:preface) = dbk:preface *
+ + dbk:refentry (dbk:refentry) = dbk:refentry *
+ + dbk:reference (dbk:reference) = dbk:reference *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:toc (dbk:toc) = dbk:toc *
+ - label (String) 
+ - status (String) 
+
+[dbk:partintro] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refentry (dbk:refentry) = dbk:refentry *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect1 (dbk:sect1) = dbk:sect1 *
+ + dbk:section (dbk:section) = dbk:section *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:person] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
+ + dbk:email (dbk:email) = dbk:email *
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname
+ + dbk:uri (dbk:uri) = dbk:uri *
+
+[dbk:personblurb] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+
+[dbk:personname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:firstname (dbk:firstname) = dbk:firstname *
+ + dbk:honorific (dbk:honorific) = dbk:honorific *
+ + dbk:lineage (dbk:lineage) = dbk:lineage *
+ + dbk:othername (dbk:othername) = dbk:othername *
+ + dbk:surname (dbk:surname) = dbk:surname *
+
+[dbk:phone] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:phrase] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:pob] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:postcode] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:preface] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refentry (dbk:refentry) = dbk:refentry *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect1 (dbk:sect1) = dbk:sect1 *
+ + dbk:section (dbk:section) = dbk:section *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:primary] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - sortas (String) 
+
+[dbk:primaryie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - linkends (String) 
+
+[dbk:printhistory] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+
+[dbk:procedure] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:step (dbk:step) = dbk:step *
+
+[dbk:production] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:constraint (dbk:constraint) = dbk:constraint *
+ + dbk:lhs (dbk:lhs) = dbk:lhs
+ + dbk:rhs (dbk:rhs) = dbk:rhs
+
+[dbk:productionrecap] > argeodbk:base, argeodbk:linkingAttributes
+
+[dbk:productionset] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:production (dbk:production) = dbk:production *
+ + dbk:productionrecap (dbk:productionrecap) = dbk:productionrecap *
+
+[dbk:productname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+
+[dbk:productnumber] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:programlisting] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ - continuation (String) 
+ - language (String) 
+ - linenumbering (String) 
+ - startinglinenumber (String) 
+ - width (String) 
+ - xml:space (String) 
+
+[dbk:programlistingco] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:areaspec (dbk:areaspec) = dbk:areaspec
+ + dbk:calloutlist (dbk:calloutlist) = dbk:calloutlist *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:programlisting (dbk:programlisting) = dbk:programlisting
+
+[dbk:prompt] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+
+[dbk:property] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:pubdate] > argeodbk:base, argeodbk:linkingAttributes
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:publisher] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:address (dbk:address) = dbk:address *
+ + dbk:publishername (dbk:publishername) = dbk:publishername
+
+[dbk:publishername] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:qandadiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:qandadiv (dbk:qandadiv) = dbk:qandadiv *
+ + dbk:qandaentry (dbk:qandaentry) = dbk:qandaentry *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:qandaentry] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:answer (dbk:answer) = dbk:answer *
+ + dbk:question (dbk:question) = dbk:question
+
+[dbk:qandaset] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:qandadiv (dbk:qandadiv) = dbk:qandadiv *
+ + dbk:qandaentry (dbk:qandaentry) = dbk:qandaentry *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - defaultlabel (String) 
+
+[dbk:question] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:label (dbk:label) = dbk:label
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:quote] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:refclass] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:application (dbk:application) = dbk:application *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:refdescriptor] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:refentry] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:refmeta (dbk:refmeta) = dbk:refmeta
+ + dbk:refnamediv (dbk:refnamediv) = dbk:refnamediv *
+ + dbk:refsect1 (dbk:refsect1) = dbk:refsect1 *
+ + dbk:refsection (dbk:refsection) = dbk:refsection *
+ + dbk:refsynopsisdiv (dbk:refsynopsisdiv) = dbk:refsynopsisdiv
+ - label (String) 
+ - status (String) 
+
+[dbk:refentrytitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:reference] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:partintro (dbk:partintro) = dbk:partintro
+ + dbk:refentry (dbk:refentry) = dbk:refentry *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:refmeta] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes
+ + dbk:manvolnum (dbk:manvolnum) = dbk:manvolnum
+ + dbk:refentrytitle (dbk:refentrytitle) = dbk:refentrytitle
+ + dbk:refmiscinfo (dbk:refmiscinfo) = dbk:refmiscinfo *
+
+[dbk:refmiscinfo] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - otherclass (String) 
+
+[dbk:refname] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:refnamediv] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:refclass (dbk:refclass) = dbk:refclass *
+ + dbk:refdescriptor (dbk:refdescriptor) = dbk:refdescriptor
+ + dbk:refname (dbk:refname) = dbk:refname *
+ + dbk:refpurpose (dbk:refpurpose) = dbk:refpurpose
+
+[dbk:refpurpose] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:refsect1] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refsect2 (dbk:refsect2) = dbk:refsect2 *
+ + dbk:refsect2 (dbk:refsect2) = dbk:refsect2 *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:refsect2] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refsect3 (dbk:refsect3) = dbk:refsect3 *
+ + dbk:refsect3 (dbk:refsect3) = dbk:refsect3 *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:refsect3] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:refsection] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refsection (dbk:refsection) = dbk:refsection *
+ + dbk:refsection (dbk:refsection) = dbk:refsection *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:refsynopsisdiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refsect2 (dbk:refsect2) = dbk:refsect2 *
+ + dbk:refsection (dbk:refsection) = dbk:refsection *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+
+[dbk:releaseinfo] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:remark] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:replaceable] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ - class (String) 
+
+[dbk:returnvalue] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:revdescription] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:revhistory] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:revision (dbk:revision) = dbk:revision *
+
+[dbk:revision] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
+ + dbk:date (dbk:date) = dbk:date
+ + dbk:revdescription (dbk:revdescription) = dbk:revdescription
+ + dbk:revnumber (dbk:revnumber) = dbk:revnumber
+ + dbk:revremark (dbk:revremark) = dbk:revremark
+
+[dbk:revnumber] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:revremark] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:rhs] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
+ + dbk:nonterminal (dbk:nonterminal) = dbk:nonterminal *
+ + dbk:sbr (dbk:sbr) = dbk:sbr *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:row] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:entry (dbk:entry) = dbk:entry *
+ + dbk:entrytbl (dbk:entrytbl) = dbk:entrytbl *
+ - rowsep (String) 
+ - valign (String) 
+
+[dbk:sbr] > argeodbk:base
+
+[dbk:screen] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ - continuation (String) 
+ - language (String) 
+ - linenumbering (String) 
+ - startinglinenumber (String) 
+ - width (String) 
+ - xml:space (String) 
+
+[dbk:screenco] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:areaspec (dbk:areaspec) = dbk:areaspec
+ + dbk:calloutlist (dbk:calloutlist) = dbk:calloutlist *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:screen (dbk:screen) = dbk:screen
+
+[dbk:screenshot] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+
+[dbk:secondary] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - sortas (String) 
+
+[dbk:secondaryie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - linkends (String) 
+
+[dbk:sect1] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect2 (dbk:sect2) = dbk:sect2 *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:sect2] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect3 (dbk:sect3) = dbk:sect3 *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:sect3] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect4 (dbk:sect4) = dbk:sect4 *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:sect4] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:sect5 (dbk:sect5) = dbk:sect5 *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:sect5] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:section] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:refentry (dbk:refentry) = dbk:refentry *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:section (dbk:section) = dbk:section *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+ + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
+
+[dbk:see] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:seealso] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:seealsoie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - linkends (String) 
+
+[dbk:seeie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:seg] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:seglistitem] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:seg (dbk:seg) = dbk:seg *
+
+[dbk:segmentedlist] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:seglistitem (dbk:seglistitem) = dbk:seglistitem *
+ + dbk:segtitle (dbk:segtitle) = dbk:segtitle *
+
+[dbk:segtitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:seriesvolnums] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:set] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:book (dbk:book) = dbk:book *
+ + dbk:set (dbk:set) = dbk:set *
+ + dbk:setindex (dbk:setindex) = dbk:setindex
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:toc (dbk:toc) = dbk:toc
+ - label (String) 
+ - status (String) 
+
+[dbk:setindex] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:indexdiv (dbk:indexdiv) = dbk:indexdiv *
+ + dbk:indexentry (dbk:indexentry) = dbk:indexentry *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+ - type (String) 
+
+[dbk:shortaffil] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:shortcut] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:keycap (dbk:keycap) = dbk:keycap *
+ + dbk:keycombo (dbk:keycombo) = dbk:keycombo *
+ + dbk:keysym (dbk:keysym) = dbk:keysym *
+ + dbk:mousebutton (dbk:mousebutton) = dbk:mousebutton *
+ - action (String) 
+ - otheraction (String) 
+
+[dbk:sidebar] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:simpara] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:info (dbk:info) = dbk:info *
+
+[dbk:simplelist] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:member (dbk:member) = dbk:member *
+ - columns (String) 
+ - type (String) 
+
+[dbk:simplemsgentry] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:msgexplan (dbk:msgexplan) = dbk:msgexplan *
+ + dbk:msgtext (dbk:msgtext) = dbk:msgtext
+ - msgaud (String) 
+ - msglevel (String) 
+ - msgorig (String) 
+
+[dbk:simplesect] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:spanspec] > argeodbk:base, argeodbk:linkingAttributes
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - colsep (String) 
+ - nameend (String) 
+ - namest (String) 
+ - rowsep (String) 
+ - spanname (String) 
+
+[dbk:state] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:step] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:stepalternatives (dbk:stepalternatives) = dbk:stepalternatives
+ + dbk:substeps (dbk:substeps) = dbk:substeps
+ - performance (String) 
+
+[dbk:stepalternatives] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:step (dbk:step) = dbk:step *
+ - performance (String) 
+
+[dbk:street] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:subject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:subjectterm (dbk:subjectterm) = dbk:subjectterm *
+ - weight (String) 
+
+[dbk:subjectset] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:subject (dbk:subject) = dbk:subject *
+ - scheme (String) 
+
+[dbk:subjectterm] > argeodbk:base, argeodbk:linkingAttributes
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:subscript] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:substeps] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:step (dbk:step) = dbk:step *
+ - performance (String) 
+
+[dbk:subtitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:superscript] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:surname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:symbol] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+
+[dbk:synopfragment] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:arg (dbk:arg) = dbk:arg *
+ + dbk:group (dbk:group) = dbk:group *
+
+[dbk:synopfragmentref] > argeodbk:base, argeodbk:linkingAttributes
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:synopsis] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ - continuation (String) 
+ - label (String) 
+ - language (String) 
+ - linenumbering (String) 
+ - startinglinenumber (String) 
+ - xml:space (String) 
+
+[dbk:systemitem] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ + dbk:co (dbk:co) = dbk:co *
+ - class (String) 
+
+[dbk:table] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:col (dbk:col) = dbk:col *
+ + dbk:colgroup (dbk:colgroup) = dbk:colgroup *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:tbody (dbk:tbody) = dbk:tbody *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ + dbk:tfoot (dbk:tfoot) = dbk:tfoot
+ + dbk:tgroup (dbk:tgroup) = dbk:tgroup *
+ + dbk:thead (dbk:thead) = dbk:thead
+ + dbk:tr (dbk:tr) = dbk:tr *
+ - border (String) 
+ - cellpadding (String) 
+ - cellspacing (String) 
+ - class (String) 
+ - colsep (String) 
+ - floatstyle (String) 
+ - frame (String) 
+ - label (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - orient (String) 
+ - pgwide (String) 
+ - rowheader (String) 
+ - rowsep (String) 
+ - rules (String) 
+ - shortentry (String) 
+ - style (String) 
+ - summary (String) 
+ - tabstyle (String) 
+ - title (String) 
+ - tocentry (String) 
+ - width (String) 
+
+[dbk:tag] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - namespace (String) 
+
+[dbk:task] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:example (dbk:example) = dbk:example *
+ + dbk:procedure (dbk:procedure) = dbk:procedure
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:taskprerequisites (dbk:taskprerequisites) = dbk:taskprerequisites
+ + dbk:taskrelated (dbk:taskrelated) = dbk:taskrelated
+ + dbk:tasksummary (dbk:tasksummary) = dbk:tasksummary
+
+[dbk:taskprerequisites] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:taskrelated] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:tasksummary] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:tbody] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:row (dbk:row) = dbk:row *
+ + dbk:tr (dbk:tr) = dbk:tr *
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - style (String) 
+ - title (String) 
+ - valign (String) 
+
+[dbk:td] > argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:markupInlines, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - abbr (String) 
+ - align (String) 
+ - annotations (String) 
+ - arch (String) 
+ - audience (String) 
+ - axis (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - colspan (String) 
+ - condition (String) 
+ - conformance (String) 
+ - dir (String) 
+ - headers (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - os (String) 
+ - remap (String) 
+ - revision (String) 
+ - revisionflag (String) 
+ - rowspan (String) 
+ - scope (String) 
+ - security (String) 
+ - style (String) 
+ - title (String) 
+ - userlevel (String) 
+ - valign (String) 
+ - vendor (String) 
+ - version (String) 
+ - wordsize (String) 
+ - xreflabel (String) 
+ - xml:base (String) 
+ - xml:id (String) 
+ - xml:lang (String) 
+
+[dbk:term] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:termdef] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - baseform (String) 
+ - sortas (String) 
+
+[dbk:tertiary] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - sortas (String) 
+
+[dbk:tertiaryie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - linkends (String) 
+
+[dbk:textdata] > argeodbk:base
+ + dbk:info (dbk:info) = dbk:info
+ - encoding (String) 
+ - entityref (String) 
+ - fileref (String) 
+ - format (String) 
+
+[dbk:textobject] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:phrase (dbk:phrase) = dbk:phrase
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:textdata (dbk:textdata) = dbk:textdata
+
+[dbk:tfoot] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:colspec (dbk:colspec) = dbk:colspec *
+ + dbk:row (dbk:row) = dbk:row *
+ + dbk:tr (dbk:tr) = dbk:tr *
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - style (String) 
+ - title (String) 
+ - valign (String) 
+
+[dbk:tgroup] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:colspec (dbk:colspec) = dbk:colspec *
+ + dbk:spanspec (dbk:spanspec) = dbk:spanspec *
+ + dbk:tbody (dbk:tbody) = dbk:tbody
+ + dbk:tfoot (dbk:tfoot) = dbk:tfoot
+ + dbk:thead (dbk:thead) = dbk:thead
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - cols (String) 
+ - colsep (String) 
+ - rowsep (String) 
+ - tgroupstyle (String) 
+
+[dbk:th] > argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:markupInlines, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ - abbr (String) 
+ - align (String) 
+ - annotations (String) 
+ - arch (String) 
+ - audience (String) 
+ - axis (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - colspan (String) 
+ - condition (String) 
+ - conformance (String) 
+ - dir (String) 
+ - headers (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - os (String) 
+ - remap (String) 
+ - revision (String) 
+ - revisionflag (String) 
+ - rowspan (String) 
+ - scope (String) 
+ - security (String) 
+ - style (String) 
+ - title (String) 
+ - userlevel (String) 
+ - valign (String) 
+ - vendor (String) 
+ - version (String) 
+ - wordsize (String) 
+ - xreflabel (String) 
+ - xml:base (String) 
+ - xml:id (String) 
+ - xml:lang (String) 
+
+[dbk:thead] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:colspec (dbk:colspec) = dbk:colspec *
+ + dbk:row (dbk:row) = dbk:row *
+ + dbk:tr (dbk:tr) = dbk:tr *
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - style (String) 
+ - title (String) 
+ - valign (String) 
+
+[dbk:tip] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:title] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:titleabbrev] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:toc] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:tocdiv (dbk:tocdiv) = dbk:tocdiv *
+ + dbk:tocentry (dbk:tocentry) = dbk:tocentry *
+
+[dbk:tocdiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:tocdiv (dbk:tocdiv) = dbk:tocdiv *
+ + dbk:tocentry (dbk:tocentry) = dbk:tocentry *
+ - pagenum (String) 
+
+[dbk:tocentry] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - pagenum (String) 
+
+[dbk:token] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:tr] > nt:base
+ + dbk:td (dbk:td) = dbk:td *
+ + dbk:th (dbk:th) = dbk:th *
+ - align (String) 
+ - annotations (String) 
+ - arch (String) 
+ - audience (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - condition (String) 
+ - conformance (String) 
+ - dir (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - os (String) 
+ - remap (String) 
+ - revision (String) 
+ - revisionflag (String) 
+ - security (String) 
+ - style (String) 
+ - title (String) 
+ - userlevel (String) 
+ - valign (String) 
+ - vendor (String) 
+ - version (String) 
+ - wordsize (String) 
+ - xreflabel (String) 
+ - xml:base (String) 
+ - xml:id (String) 
+ - xml:lang (String) 
+
+[dbk:trademark] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+
+[dbk:type] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:uri] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - type (String) 
+
+[dbk:userinput] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:ubiquitousInlines
+ + dbk:accel (dbk:accel) = dbk:accel *
+ + dbk:co (dbk:co) = dbk:co *
+ + dbk:command (dbk:command) = dbk:command *
+ + dbk:computeroutput (dbk:computeroutput) = dbk:computeroutput *
+ + dbk:envar (dbk:envar) = dbk:envar *
+ + dbk:filename (dbk:filename) = dbk:filename *
+ + dbk:guibutton (dbk:guibutton) = dbk:guibutton *
+ + dbk:guiicon (dbk:guiicon) = dbk:guiicon *
+ + dbk:guilabel (dbk:guilabel) = dbk:guilabel *
+ + dbk:guimenu (dbk:guimenu) = dbk:guimenu *
+ + dbk:guimenuitem (dbk:guimenuitem) = dbk:guimenuitem *
+ + dbk:guisubmenu (dbk:guisubmenu) = dbk:guisubmenu *
+ + dbk:keycap (dbk:keycap) = dbk:keycap *
+ + dbk:keycode (dbk:keycode) = dbk:keycode *
+ + dbk:keycombo (dbk:keycombo) = dbk:keycombo *
+ + dbk:keysym (dbk:keysym) = dbk:keysym *
+ + dbk:menuchoice (dbk:menuchoice) = dbk:menuchoice *
+ + dbk:mousebutton (dbk:mousebutton) = dbk:mousebutton *
+ + dbk:nonterminal (dbk:nonterminal) = dbk:nonterminal *
+ + dbk:option (dbk:option) = dbk:option *
+ + dbk:optional (dbk:optional) = dbk:optional *
+ + dbk:package (dbk:package) = dbk:package *
+ + dbk:parameter (dbk:parameter) = dbk:parameter *
+ + dbk:prompt (dbk:prompt) = dbk:prompt *
+ + dbk:property (dbk:property) = dbk:property *
+ + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
+ + dbk:shortcut (dbk:shortcut) = dbk:shortcut *
+ + dbk:systemitem (dbk:systemitem) = dbk:systemitem *
+ + dbk:termdef (dbk:termdef) = dbk:termdef *
+ + dbk:userinput (dbk:userinput) = dbk:userinput *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:varargs] > argeodbk:base, argeodbk:linkingAttributes
+
+[dbk:variablelist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+ + dbk:varlistentry (dbk:varlistentry) = dbk:varlistentry *
+ - spacing (String) 
+ - termlength (String) 
+
+[dbk:varlistentry] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:listitem (dbk:listitem) = dbk:listitem
+ + dbk:term (dbk:term) = dbk:term *
+
+[dbk:varname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:videodata] > argeodbk:base
+ + dbk:info (dbk:info) = dbk:info
+ - align (String) 
+ - contentdepth (String) 
+ - contentwidth (String) 
+ - depth (String) 
+ - entityref (String) 
+ - fileref (String) 
+ - format (String) 
+ - scale (String) 
+ - scalefit (String) 
+ - valign (String) 
+ - width (String) 
+
+[dbk:videoobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:videodata (dbk:videodata) = dbk:videodata
+
+[dbk:void] > argeodbk:base, argeodbk:linkingAttributes
+
+[dbk:volumenum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:warning] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
+ + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
+
+[dbk:wordasword] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:xref] > argeodbk:base, argeodbk:linkingAttributes
+ - endterm (Reference) 
+ - xrefstyle (String) 
+
+[dbk:year] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+//[xs:anyType] > nt:base
+// + * (nt:base) 
+// + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+// - * (undefined) 
+
+
diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/docbook.cnd b/org.argeo.app.core/src/org/argeo/app/docbook/docbook.cnd
new file mode 100644 (file)
index 0000000..5514e64
--- /dev/null
@@ -0,0 +1,527 @@
+<dbk = 'http://docbook.org/ns/docbook'>
+<argeodbk = 'http://www.argeo.org/ns/argeodbk'>
+<xlink = 'http://www.w3.org/1999/xlink'>
+
+[argeodbk:titled]
+mixin
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:title (dbk:title) = dbk:title *
+
+[argeodbk:linkingAttributes]
+mixin
+ - linkend (String)
+ - xlink:actuate (String)
+ - xlink:arcrole (String)
+ - xlink:href (String)
+ - xlink:role (String)
+ - xlink:show (String)
+ - xlink:title (String)
+ - xlink:type (String)
+
+[argeodbk:freeText]
+mixin
+ + dbk:phrase (dbk:phrase) = dbk:phrase *
+ + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[argeodbk:markupInlines]
+mixin
+
+[argeodbk:listElements]
+mixin
+ + dbk:itemizedlist (dbk:itemizedlist) = dbk:itemizedlist *
+ + dbk:orderedlist (dbk:orderedlist) = dbk:orderedlist *
+ + dbk:simplelist (dbk:simplelist) = dbk:simplelist *
+
+[argeodbk:paragraphElements]
+mixin
+ + dbk:para (dbk:para) = dbk:para *
+
+[argeodbk:indexingInlines]
+mixin
+
+[argeodbk:techDocElements]
+mixin
+ + dbk:table (dbk:table) = dbk:table *
+
+[argeodbk:techDocInlines]
+mixin
+
+[argeodbk:publishingElements]
+mixin
+
+[argeodbk:ubiquitousInlines]
+mixin
+ + dbk:alt (dbk:alt) = dbk:alt *
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:biblioref (dbk:biblioref) = dbk:biblioref *
+ + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
+ + dbk:link (dbk:link) = dbk:link *
+ + dbk:olink (dbk:olink) = dbk:olink *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:subscript (dbk:subscript) = dbk:subscript *
+ + dbk:superscript (dbk:superscript) = dbk:superscript *
+ + dbk:xref (dbk:xref) = dbk:xref *
+
+[argeodbk:abstractSection]
+mixin
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String)
+ - status (String)
+
+[argeodbk:bibliographyInlines]
+mixin
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:personname (dbk:personname) = dbk:personname *
+
+[argeodbk:publishingInlines]
+mixin
+ + dbk:emphasis (dbk:emphasis) = dbk:emphasis *
+
+[argeodbk:base]
+abstract
+orderable
+ - annotations (String)
+ - arch (String)
+ - audience (String)
+ - condition (String)
+ - conformance (String)
+ - dir (String)
+ - os (String)
+ - remap (String)
+ - revision (String)
+ - revisionflag (String)
+ - role (String)
+ - security (String)
+ - userlevel (String)
+ - vendor (String)
+ - version (String)
+ - wordsize (String)
+ - xreflabel (String)
+
+[dbk:alt] > argeodbk:base
+ + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+
+[dbk:anchor] > argeodbk:base
+
+[dbk:annotation] > argeodbk:base, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ - annotates (String) 
+
+[dbk:article] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:section (dbk:section) = dbk:section *
+ - class (String) 
+
+[dbk:audiodata] > argeodbk:base
+ + dbk:info (dbk:info) = dbk:info
+ - entityref (String) 
+ - fileref (String) 
+ - format (String) 
+
+[dbk:audioobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:audiodata (dbk:audiodata) = dbk:audiodata
+ + dbk:info (dbk:info) = dbk:info
+
+[dbk:author] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
+ + dbk:orgname (dbk:orgname) = dbk:orgname
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname
+
+[dbk:biblioref] > argeodbk:base, argeodbk:linkingAttributes
+ - begin (String) 
+ - end (String) 
+ - endterm (Reference) 
+ - units (String) 
+ - xrefstyle (String) 
+
+[dbk:book] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:article (dbk:article) = dbk:article *
+ + dbk:chapter (dbk:chapter) = dbk:chapter *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:caption] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
+ - class (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - style (String) 
+ - title (String) 
+
+[dbk:chapter] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:section (dbk:section) = dbk:section *
+
+[dbk:colspec] > argeodbk:base, argeodbk:linkingAttributes
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - colname (String) 
+ - colnum (String) 
+ - colsep (String) 
+ - colwidth (String) 
+ - rowsep (String) 
+
+[dbk:editor] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
+ + dbk:orgname (dbk:orgname) = dbk:orgname
+ + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
+ + dbk:personname (dbk:personname) = dbk:personname
+
+[dbk:emphasis] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:entry] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:markupInlines, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - colname (String) 
+ - colsep (String) 
+ - morerows (String) 
+ - nameend (String) 
+ - namest (String) 
+ - rotate (String) 
+ - rowsep (String) 
+ - spanname (String) 
+ - valign (String) 
+
+[dbk:entrytbl] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:colspec (dbk:colspec) = dbk:colspec *
+ + dbk:spanspec (dbk:spanspec) = dbk:spanspec *
+ + dbk:tbody (dbk:tbody) = dbk:tbody
+ + dbk:thead (dbk:thead) = dbk:thead
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - colname (String) 
+ - cols (String) 
+ - colsep (String) 
+ - nameend (String) 
+ - namest (String) 
+ - rowsep (String) 
+ - spanname (String) 
+ - tgroupstyle (String) 
+
+[dbk:imagedata] > argeodbk:base
+ + dbk:info (dbk:info) = dbk:info
+ - align (String) 
+ - contentdepth (String) 
+ - contentwidth (String) 
+ - depth (String) 
+ - entityref (String) 
+ - fileref (String) 
+ - format (String) 
+ - scale (String) 
+ - scalefit (String) 
+ - valign (String) 
+ - width (String) 
+
+[dbk:imageobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:imagedata (dbk:imagedata) = dbk:imagedata
+ + dbk:info (dbk:info) = dbk:info
+
+[dbk:info] > argeodbk:base
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:author (dbk:author) = dbk:author *
+ + dbk:editor (dbk:editor) = dbk:editor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:orgname (dbk:orgname) = dbk:orgname *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ + dbk:title (dbk:title) = dbk:title *
+ + * (nt:base) = nt:unstructured *
+
+[dbk:inlinemediaobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:alt (dbk:alt) = dbk:alt
+ + dbk:audioobject (dbk:audioobject) = dbk:audioobject *
+ + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ + dbk:videoobject (dbk:videoobject) = dbk:videoobject *
+
+[dbk:itemizedlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:listitem (dbk:listitem) = dbk:listitem *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ - mark (String) 
+ - spacing (String) 
+
+[dbk:link] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - endterm (Reference) 
+ - xrefstyle (String) 
+
+[dbk:listitem] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ - override (String) 
+
+[dbk:mediaobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:alt (dbk:alt) = dbk:alt
+ + dbk:audioobject (dbk:audioobject) = dbk:audioobject *
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ + dbk:videoobject (dbk:videoobject) = dbk:videoobject *
+
+[dbk:olink] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ - localinfo (String) 
+ - targetdoc (String) 
+ - targetptr (String) 
+ - type (String) 
+ - xrefstyle (String) 
+
+[dbk:orderedlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:listitem (dbk:listitem) = dbk:listitem *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:remark (dbk:remark) = dbk:remark *
+ - continuation (String) 
+ - inheritnum (String) 
+ - numeration (String) 
+ - spacing (String) 
+ - startingnumber (String) 
+
+[dbk:orgdiv] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:orgname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+ - otherclass (String) 
+
+[dbk:para] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:markupInlines, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+ + dbk:info (dbk:info) = dbk:info *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+
+[dbk:personblurb] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+
+[dbk:personname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:phrase] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:remark] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:replaceable] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+ - class (String) 
+
+[dbk:row] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:entry (dbk:entry) = dbk:entry *
+ + dbk:entrytbl (dbk:entrytbl) = dbk:entrytbl *
+ - rowsep (String) 
+ - valign (String) 
+
+[dbk:section] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:section (dbk:section) = dbk:section *
+
+[dbk:set] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:book (dbk:book) = dbk:book *
+ + dbk:set (dbk:set) = dbk:set *
+ + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
+ - label (String) 
+ - status (String) 
+
+[dbk:simplelist] > argeodbk:base, argeodbk:linkingAttributes
+ - columns (String) 
+ - type (String) 
+
+[dbk:spanspec] > argeodbk:base, argeodbk:linkingAttributes
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - colsep (String) 
+ - nameend (String) 
+ - namest (String) 
+ - rowsep (String) 
+ - spanname (String) 
+
+[dbk:subscript] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:subtitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:superscript] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
+
+[dbk:table] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:titled
+ + dbk:caption (dbk:caption) = dbk:caption
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:tbody (dbk:tbody) = dbk:tbody *
+ + dbk:textobject (dbk:textobject) = dbk:textobject *
+ + dbk:tfoot (dbk:tfoot) = dbk:tfoot
+ + dbk:tgroup (dbk:tgroup) = dbk:tgroup *
+ + dbk:thead (dbk:thead) = dbk:thead
+ - border (String) 
+ - cellpadding (String) 
+ - cellspacing (String) 
+ - class (String) 
+ - colsep (String) 
+ - floatstyle (String) 
+ - frame (String) 
+ - label (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - orient (String) 
+ - pgwide (String) 
+ - rowheader (String) 
+ - rowsep (String) 
+ - rules (String) 
+ - shortentry (String) 
+ - style (String) 
+ - summary (String) 
+ - tabstyle (String) 
+ - title (String) 
+ - tocentry (String) 
+ - width (String) 
+
+[dbk:tbody] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:row (dbk:row) = dbk:row *
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - style (String) 
+ - title (String) 
+ - valign (String) 
+
+[dbk:textobject] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
+ + dbk:anchor (dbk:anchor) = dbk:anchor *
+ + dbk:annotation (dbk:annotation) = dbk:annotation *
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
+ + dbk:phrase (dbk:phrase) = dbk:phrase
+ + dbk:remark (dbk:remark) = dbk:remark *
+
+[dbk:tfoot] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:colspec (dbk:colspec) = dbk:colspec *
+ + dbk:row (dbk:row) = dbk:row *
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - style (String) 
+ - title (String) 
+ - valign (String) 
+
+[dbk:tgroup] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:colspec (dbk:colspec) = dbk:colspec *
+ + dbk:spanspec (dbk:spanspec) = dbk:spanspec *
+ + dbk:tbody (dbk:tbody) = dbk:tbody
+ + dbk:tfoot (dbk:tfoot) = dbk:tfoot
+ + dbk:thead (dbk:thead) = dbk:thead
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - cols (String) 
+ - colsep (String) 
+ - rowsep (String) 
+ - tgroupstyle (String) 
+
+[dbk:thead] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:colspec (dbk:colspec) = dbk:colspec *
+ + dbk:row (dbk:row) = dbk:row *
+ - align (String) 
+ - char (String) 
+ - charoff (String) 
+ - class (String) 
+ - lang (String) 
+ - onclick (String) 
+ - ondblclick (String) 
+ - onkeydown (String) 
+ - onkeypress (String) 
+ - onkeyup (String) 
+ - onmousedown (String) 
+ - onmousemove (String) 
+ - onmouseout (String) 
+ - onmouseover (String) 
+ - onmouseup (String) 
+ - style (String) 
+ - title (String) 
+ - valign (String) 
+
+[dbk:title] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
+
+[dbk:videodata] > argeodbk:base
+ + dbk:info (dbk:info) = dbk:info
+ - align (String) 
+ - contentdepth (String) 
+ - contentwidth (String) 
+ - depth (String) 
+ - entityref (String) 
+ - fileref (String) 
+ - format (String) 
+ - scale (String) 
+ - scalefit (String) 
+ - valign (String) 
+ - width (String) 
+
+[dbk:videoobject] > argeodbk:base, argeodbk:linkingAttributes
+ + dbk:info (dbk:info) = dbk:info
+ + dbk:videodata (dbk:videodata) = dbk:videodata
+
+[dbk:xref] > argeodbk:base, argeodbk:linkingAttributes
+ - endterm (Reference) 
+ - xrefstyle (String) 
+
+
diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GeoJsonUtils.java b/org.argeo.app.core/src/org/argeo/app/geo/GeoJsonUtils.java
new file mode 100644 (file)
index 0000000..84610c8
--- /dev/null
@@ -0,0 +1,24 @@
+package org.argeo.app.geo;
+
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/** Geo data utilities. */
+public class GeoJsonUtils {
+
+       /** Add these properties to all features. */
+       public static void addProperties(JsonNode tree, Map<String, String> map) {
+               for (JsonNode feature : tree.get("features")) {
+                       ObjectNode properties = (ObjectNode) feature.get("properties");
+                       for (String key : map.keySet()) {
+                               properties.put(key, map.get(key));
+                       }
+               }
+       }
+
+       /** Singleton. */
+       private GeoJsonUtils() {
+       }
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GeoToSvg.java b/org.argeo.app.core/src/org/argeo/app/geo/GeoToSvg.java
new file mode 100644 (file)
index 0000000..abb5b39
--- /dev/null
@@ -0,0 +1,69 @@
+package org.argeo.app.geo;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/** Converts a geographical feature to an SVG. */
+public class GeoToSvg {
+       public void convertGeoJsonToSvg(Path source, Path target) {
+               ObjectMapper objectMapper = new ObjectMapper();
+               try (InputStream in = Files.newInputStream(source);
+                               Writer out = Files.newBufferedWriter(target, StandardCharsets.UTF_8)) {
+                       JsonNode tree = objectMapper.readTree(in);
+                       JsonNode coord = tree.get("features").get(0).get("geometry").get("coordinates");
+                       double ratio = 100;
+                       double minX = Double.POSITIVE_INFINITY;
+                       double maxX = Double.NEGATIVE_INFINITY;
+                       double minY = Double.POSITIVE_INFINITY;
+                       double maxY = Double.NEGATIVE_INFINITY;
+                       List<String> shapes = new ArrayList<>();
+                       for (JsonNode shape : coord) {
+                               StringBuffer sb = new StringBuffer();
+                               sb.append("<polyline style=\"stroke-width:0.00000003;stroke:#000000;\" points=\"");
+                               for (JsonNode latlng : shape) {
+                                       double lat = latlng.get(0).asDouble();
+                                       double y = lat * ratio;
+                                       if (y < minY)
+                                               minY = y;
+                                       if (y > maxY)
+                                               maxY = y;
+                                       double lng = latlng.get(1).asDouble();
+                                       double x = lng * ratio;
+                                       if (x < minX)
+                                               minX = x;
+                                       if (x > maxX)
+                                               maxX = x;
+                                       sb.append(y + "," + x + " ");
+                               }
+                               sb.append("\">");
+                               sb.append("</polyline>\n");
+                               shapes.add(sb.toString());
+                       }
+
+                       double width = maxX - minX;
+                       double height = maxY - minY;
+                       out.write("<svg xmlns=\"http://www.w3.org/2000/svg\"\n");
+                       out.write(" width=\"" + (int) (width * 1000) + "\"\n");
+                       out.write(" height=\"" + (int) (height * 1000) + "\"\n");
+                       out.write(" viewBox=\"" + minX + "," + minY + "," + width + "," + height + "\"\n");
+                       out.write(">\n");
+                       for (String shape : shapes) {
+                               out.write(shape);
+                               out.write("\n");
+                       }
+                       out.write("</svg>");
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot convert " + source + " to " + target, e);
+               }
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/geo/geonames/GeonamesAdm.java b/org.argeo.app.core/src/org/argeo/app/geo/geonames/GeonamesAdm.java
new file mode 100644 (file)
index 0000000..45febd2
--- /dev/null
@@ -0,0 +1,157 @@
+package org.argeo.app.geo.geonames;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/** A Geonames administrative subdivision. */
+public class GeonamesAdm {
+       private final Long geonameId;
+       private final String countryCode;
+       private final String adminCode1;
+       private final String admLevel;
+       private final Integer level;
+       private final String name;
+       private final String asciiName;
+       private final List<String> alternateNames;
+       private final Double lat;
+       private final Double lng;
+       private final LocalDate lastUpdated;
+       private final ZoneId timeZone;
+
+       private final Long[] upperLevelIds = new Long[5];
+       private final List<GeonamesAdm> upperLevels = new ArrayList<>();
+
+       private List<String> row;
+
+       /** Initialise from a row in the main Geonames table. */
+       public GeonamesAdm(List<String> row) {
+               geonameId = Long.parseLong(row.get(0));
+               admLevel = row.get(7);
+               countryCode = row.get(8);
+               adminCode1 = row.get(10);
+               if (admLevel.startsWith("ADM")) {
+                       if (admLevel.endsWith("H"))
+                               level = Integer.parseInt(admLevel.substring(3, admLevel.length() - 1));
+                       else
+                               level = Integer.parseInt(admLevel.substring(3));
+               } else if (admLevel.equals("PCLI")) {
+                       level = 0;
+               } else {
+                       throw new IllegalArgumentException("Unsupported admin level " + admLevel);
+               }
+               name = row.get(1);
+               asciiName = row.get(2);
+               alternateNames = Arrays.asList(row.get(3).split(","));
+               lat = Double.parseDouble(row.get(4));
+               lng = Double.parseDouble(row.get(5));
+               lastUpdated = LocalDate.parse(row.get(18));
+               timeZone = ZoneId.of(row.get(17));
+               // upper levels
+               if (row.get(11) != null && !row.get(11).trim().equals(""))
+                       upperLevelIds[2] = Long.parseLong(row.get(11));
+               if (row.get(12) != null && !row.get(12).trim().equals(""))
+                       upperLevelIds[3] = Long.parseLong(row.get(12));
+               if (row.get(13) != null && !row.get(13).trim().equals(""))
+                       upperLevelIds[4] = Long.parseLong(row.get(13));
+               this.row = row;
+       }
+
+       public void mapUpperLevels(Map<Long, GeonamesAdm> index) {
+               for (int i = 0; i < level; i++) {
+                       Long geonameId = upperLevelIds[i];
+                       upperLevels.add(i, index.get(geonameId));
+               }
+       }
+
+       public Long getGeonameId() {
+               return geonameId;
+       }
+
+       public Integer getLevel() {
+               return level;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public String getName(Function<String, String> transform) {
+               if (transform != null)
+                       return transform.apply(name);
+               else
+                       return name;
+
+       }
+
+       public String getAsciiName() {
+               return asciiName;
+       }
+
+       public List<String> getAlternateNames() {
+               return alternateNames;
+       }
+
+       public Double getLat() {
+               return lat;
+       }
+
+       public Double getLng() {
+               return lng;
+       }
+
+       public String getCountryCode() {
+               return countryCode;
+       }
+
+       public String getAdmLevel() {
+               return admLevel;
+       }
+
+       public List<String> getRow() {
+               return row;
+       }
+
+       public LocalDate getLastUpdated() {
+               return lastUpdated;
+       }
+
+       public ZoneId getTimeZone() {
+               return timeZone;
+       }
+
+       public String getAdminCode1() {
+               return adminCode1;
+       }
+
+       public Long[] getUpperLevelIds() {
+               return upperLevelIds;
+       }
+
+       public List<GeonamesAdm> getUpperLevels() {
+               return upperLevels;
+       }
+
+       @Override
+       public int hashCode() {
+               return geonameId.intValue();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (!(obj instanceof GeonamesAdm))
+                       return false;
+               GeonamesAdm other = (GeonamesAdm) obj;
+               return geonameId.equals(other.geonameId);
+       }
+
+       @Override
+       public String toString() {
+               return name + " (ADM" + level + " " + geonameId + ")";
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java b/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java
new file mode 100644 (file)
index 0000000..52456bb
--- /dev/null
@@ -0,0 +1,93 @@
+package org.argeo.app.geo.geonames;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.argeo.util.CsvParser;
+import org.argeo.util.CsvWriter;
+
+/** Import GeoNames administrative division from the main table. */
+public class ImportGeonamesAdmin {
+       // private Log log = LogFactory.getLog(ImportGeonamesAdmin.class);
+       private Map<Long, GeonamesAdm> geonamesAdms = new HashMap<>();
+
+       /** Loads the data. */
+       public void parse(InputStream in) {
+               Map<String, Long> countryGeonameIds = new HashMap<>();
+               Map<String, Long> admin1GeonameIds = new HashMap<>();
+               CsvParser csvParser = new CsvParser() {
+
+                       @Override
+                       protected void processLine(Integer lineNumber, List<String> header, List<String> tokens) {
+                               if (!"A".equals(tokens.get(6)))
+                                       return;
+                               GeonamesAdm geonamesAdm = new GeonamesAdm(tokens);
+                               geonamesAdms.put(geonamesAdm.getGeonameId(), geonamesAdm);
+                               if (geonamesAdm.getAdmLevel().equals("PCLI"))
+                                       countryGeonameIds.put(geonamesAdm.getCountryCode(), geonamesAdm.getGeonameId());
+                               if (geonamesAdm.getAdmLevel().equals("ADM1"))
+                                       admin1GeonameIds.put(geonamesAdm.getAdminCode1(), geonamesAdm.getGeonameId());
+                       }
+               };
+               csvParser.setSeparator('\t');
+               csvParser.setNoHeader(true);
+               csvParser.parse(in, StandardCharsets.UTF_8);
+
+               // fill upper levels
+               for (GeonamesAdm adm : geonamesAdms.values()) {
+                       adm.getUpperLevelIds()[0] = countryGeonameIds.get(adm.getCountryCode());
+                       if (adm.getLevel() > 0)
+                               adm.getUpperLevelIds()[1] = admin1GeonameIds.get(adm.getAdminCode1());
+                       adm.mapUpperLevels(geonamesAdms);
+               }
+
+       }
+
+       public Map<Long, GeonamesAdm> getGeonamesAdms() {
+               return geonamesAdms;
+       }
+
+       /**
+        * Copies only the Geonames of feature class 'A' (administrative subdivisions).
+        */
+       public static void filterGeonamesAdm(InputStream in, OutputStream out) {
+               CsvWriter csvWriter = new CsvWriter(out, StandardCharsets.UTF_8);
+               csvWriter.setSeparator('\t');
+               CsvParser csvParser = new CsvParser() {
+
+                       @Override
+                       protected void processLine(Integer lineNumber, List<String> header, List<String> tokens) {
+                               if (tokens.size() < 7 || !"A".equals(tokens.get(6)))
+                                       return;
+                               csvWriter.writeLine(tokens);
+                       }
+               };
+               csvParser.setSeparator('\t');
+               csvParser.setNoHeader(true);
+               csvParser.parse(in, StandardCharsets.UTF_8);
+       }
+
+       public static void main(String[] args) throws IOException {
+//             String country = "allCountries";
+               String country = "CI";
+//             try (InputStream in = Files
+//                             .newInputStream(Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + ".txt"));
+//                             OutputStream out = Files.newOutputStream(
+//                                             Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) {
+//                     ImportGeonamesAdmin.filterGeonamesAdm(in, out);
+//             }
+               try (InputStream in = Files.newInputStream(
+                               Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) {
+                       ImportGeonamesAdmin importGeonamesAdmin = new ImportGeonamesAdmin();
+                       importGeonamesAdmin.parse(in);
+               }
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/library/DocxExtractor.java b/org.argeo.app.core/src/org/argeo/app/library/DocxExtractor.java
new file mode 100644 (file)
index 0000000..17c6cf2
--- /dev/null
@@ -0,0 +1,355 @@
+package org.argeo.app.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.app.core/src/org/argeo/app/odk/BundleResourceOdkForm.java b/org.argeo.app.core/src/org/argeo/app/odk/BundleResourceOdkForm.java
new file mode 100644 (file)
index 0000000..97f978b
--- /dev/null
@@ -0,0 +1,101 @@
+package org.argeo.app.odk;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.argeo.util.DigestUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/** {@link OdkForm} implementation based on an OSGi {@link Bundle} resource. */
+public class BundleResourceOdkForm implements OdkForm {
+       private String formId;
+       private String name;
+       private String version;
+       private String description;
+       private String hash;
+       private String fileName;
+
+       private byte[] data;
+
+       public void init(Map<String, String> properties, BundleContext bundleContext) throws IOException {
+               String location = properties.get("location");
+               fileName = FilenameUtils.getName(location);
+               URL url = bundleContext.getBundle().getResource(location);
+               data = IOUtils.toByteArray(url.openStream());
+               hash = "md5:" + DigestUtils.digest(DigestUtils.MD5, data);
+
+               // TODO get it from the XML
+               formId = properties.get("formId");
+               version = properties.get("version");
+
+               name = properties.get("name");
+               description = properties.get("description");
+       }
+
+       @Override
+       public String getFormId() {
+               return formId;
+       }
+
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       @Override
+       public String getVersion() {
+               return version;
+       }
+
+       @Override
+       public String getDescription() {
+               return description;
+       }
+
+       @Override
+       public String getHash(String hashType) {
+               return hash;
+       }
+
+       @Override
+       public String getFileName() {
+               return fileName;
+       }
+
+       @Override
+       public InputStream openStream() {
+               return new ByteArrayInputStream(data);
+       }
+
+       @Override
+       public int hashCode() {
+               assert formId != null;
+               assert version != null;
+               return formId.hashCode() + version.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               assert formId != null;
+               assert version != null;
+               if (!(obj instanceof OdkForm))
+                       return false;
+               OdkForm other = (OdkForm) obj;
+               assert other.getFormId() != null;
+               assert other.getVersion() != null;
+
+               return other.getFormId().equals(formId) && other.getVersion().equals(version);
+       }
+
+       @Override
+       public String toString() {
+               return "ODK Form " + formId + ", v" + version;
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OdkForm.java b/org.argeo.app.core/src/org/argeo/app/odk/OdkForm.java
new file mode 100644 (file)
index 0000000..ec37a6f
--- /dev/null
@@ -0,0 +1,20 @@
+package org.argeo.app.odk;
+
+import java.io.InputStream;
+
+/** Abstraction of a single ODK form. */
+public interface OdkForm {
+       String getFormId();
+
+       String getName();
+
+       String getVersion();
+
+       String getDescription();
+
+       String getHash(String hashType);
+
+       String getFileName();
+
+       InputStream openStream();
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OdkNames.java b/org.argeo.app.core/src/org/argeo/app/odk/OdkNames.java
new file mode 100644 (file)
index 0000000..7702f83
--- /dev/null
@@ -0,0 +1,7 @@
+package org.argeo.app.odk;
+
+/** Names related to ODK. */
+public interface OdkNames {
+
+       public final static String H_HTML = "h:html";
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OdkUtils.java b/org.argeo.app.core/src/org/argeo/app/odk/OdkUtils.java
new file mode 100644 (file)
index 0000000..ff77738
--- /dev/null
@@ -0,0 +1,198 @@
+package org.argeo.app.odk;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.Row;
+import javax.jcr.query.RowIterator;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.app.api.EntityMimeType;
+import org.argeo.app.api.EntityType;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.JcrxApi;
+import org.argeo.util.DigestUtils;
+
+/** Utilities around ODK. */
+public class OdkUtils {
+       private final static CmsLog log = CmsLog.getLog(OdkUtils.class);
+
+       public static Node loadOdkForm(Node formBase, String name, InputStream in, InputStream... additionalNodes)
+                       throws RepositoryException, IOException {
+               if (!formBase.isNodeType(EntityType.formSet.get()))
+                       throw new IllegalArgumentException(
+                                       "Parent path " + formBase + " must be of type " + EntityType.formSet.get());
+               Node form = JcrUtils.getOrAdd(formBase, name, OrxListName.xform.get(), NodeType.MIX_VERSIONABLE);
+
+               String previousCsum = JcrxApi.getChecksum(form, JcrxApi.MD5);
+               String previousFormId = Jcr.get(form, OrxListName.formID.get());
+               String previousFormVersion = Jcr.get(form, OrxListName.version.get());
+
+               Session s = formBase.getSession();
+               s.importXML(form.getPath(), in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+
+               for (InputStream additionalIn : additionalNodes) {
+                       s.importXML(form.getPath(), additionalIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+               }
+               s.save();
+
+               // manage instances
+               // NodeIterator instances =
+               // form.getNodes("h:html/h:head/xforms:model/xforms:instance");
+               NodeIterator instances = form.getNode("h:html/h:head/xforms:model").getNodes("xforms:instance");
+               Node primaryInstance = null;
+               while (instances.hasNext()) {
+                       Node instance = instances.nextNode();
+                       if (primaryInstance == null) {
+                               primaryInstance = instance;
+                       } else {// secondary instances
+                               String instanceId = instance.getProperty("id").getString();
+                               URI instanceUri = null;
+                               if (instance.hasProperty("src"))
+                                       try {
+                                               instanceUri = new URI(instance.getProperty("src").getString());
+                                       } catch (URISyntaxException e) {
+                                               throw new IllegalArgumentException("Instance " + instanceId + " has a badly formatted URI", e);
+                                       }
+                               if (instanceUri != null) {
+                                       if ("jr".equals(instanceUri.getScheme())) {
+                                               String uuid;
+                                               String mimeType;
+                                               String encoding = StandardCharsets.UTF_8.name();
+                                               String type = instanceUri.getHost();
+                                               String path = instanceUri.getPath();
+                                               if ("file".equals(type)) {
+                                                       if (!path.endsWith(".xml"))
+                                                               throw new IllegalArgumentException("File uri " + instanceUri + " must end with .xml");
+                                                       // Work around bug in ODK Collect not supporting paths
+                                                       // path = path.substring(0, path.length() - ".xml".length());
+                                                       // Node target = file.getSession().getNode(path);
+                                                       uuid = path.substring(1, path.length() - ".xml".length());
+                                                       mimeType = EntityMimeType.XML.getMimeType();
+                                               } else if ("file-csv".equals(type)) {
+                                                       if (!path.endsWith(".csv"))
+                                                               throw new IllegalArgumentException("File uri " + instanceUri + " must end with .csv");
+                                                       // Work around bug in ODK Collect not supporting paths
+                                                       // path = path.substring(0, path.length() - ".csv".length());
+                                                       // Node target = file.getSession().getNode(path);
+                                                       uuid = path.substring(1, path.length() - ".csv".length());
+                                                       mimeType = EntityMimeType.CSV.getMimeType();
+                                               } else {
+                                                       throw new IllegalArgumentException("Unsupported instance type " + type);
+                                               }
+                                               Node manifest = JcrUtils.getOrAdd(form, OrxManifestName.manifest.name(),
+                                                               OrxManifestName.manifest.get());
+                                               Node file = JcrUtils.getOrAdd(manifest, instanceId);
+                                               file.addMixin(NodeType.MIX_MIMETYPE);
+                                               file.setProperty(Property.JCR_MIMETYPE, mimeType);
+                                               file.setProperty(Property.JCR_ENCODING, encoding);
+                                               Node target = file.getSession().getNodeByIdentifier(uuid);
+
+                                               if (target.isNodeType(NodeType.NT_QUERY)) {
+                                                       Query query = target.getSession().getWorkspace().getQueryManager().getQuery(target);
+                                                       query.setLimit(10);
+                                                       QueryResult queryResult = query.execute();
+                                                       RowIterator rit = queryResult.getRows();
+                                                       while (rit.hasNext()) {
+                                                               Row row = rit.nextRow();
+                                                               for (Value value : row.getValues()) {
+                                                                       System.out.print(value.getString());
+                                                                       System.out.print(',');
+                                                               }
+                                                               System.out.print('\n');
+                                                       }
+
+                                               }
+
+                                               if (target.isNodeType(NodeType.MIX_REFERENCEABLE)) {
+                                                       file.setProperty(Property.JCR_ID, target);
+                                                       if (file.hasProperty(Property.JCR_PATH))
+                                                               file.getProperty(Property.JCR_PATH).remove();
+                                               } else {
+                                                       file.setProperty(Property.JCR_PATH, target.getPath());
+                                                       if (file.hasProperty(Property.JCR_ID))
+                                                               file.getProperty(Property.JCR_ID).remove();
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if (primaryInstance == null)
+                       throw new IllegalArgumentException("No primary instance found in " + form);
+               if (!primaryInstance.hasNodes())
+                       throw new IllegalArgumentException("No data found in primary instance of " + form);
+               NodeIterator primaryInstanceChildren = primaryInstance.getNodes();
+               Node data = primaryInstanceChildren.nextNode();
+               if (primaryInstanceChildren.hasNext())
+                       throw new IllegalArgumentException("More than one data found in primary instance of " + form);
+               String formId = data.getProperty("id").getString();
+               if (previousFormId != null && !formId.equals(previousFormId))
+                       log.warn("Form id of " + form + " changed from " + previousFormId + " to " + formId);
+               form.setProperty(OrxListName.formID.get(), formId);
+               String formVersion = data.getProperty("version").getString();
+
+               if (previousCsum == null)// save before checksuming
+                       s.save();
+               String newCsum;
+               try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+                       s.exportDocumentView(form.getPath() + "/" + OdkNames.H_HTML, out, true, false);
+                       newCsum = DigestUtils.digest(DigestUtils.MD5, out.toByteArray());
+               }
+               if (previousCsum == null) {
+                       JcrxApi.addChecksum(form, newCsum);
+                       JcrUtils.updateLastModified(form);
+                       form.setProperty(OrxListName.version.get(), formVersion);
+                       s.save();
+                       s.getWorkspace().getVersionManager().checkpoint(form.getPath());
+                       if (log.isDebugEnabled())
+                               log.debug("New form " + form);
+               } else {
+                       if (newCsum.equals(previousCsum)) {
+                               // discard
+                               s.refresh(false);
+                               if (log.isDebugEnabled())
+                                       log.debug("Unmodified form " + form);
+                               return form;
+                       } else {
+                               if (formVersion.equals(previousFormVersion)) {
+                                       s.refresh(false);
+                                       throw new IllegalArgumentException("Form " + form + " has been changed but version " + formVersion
+                                                       + " has not been changed, discarding changes...");
+                               }
+                               form.setProperty(OrxListName.version.get(), formVersion);
+                               JcrxApi.addChecksum(form, newCsum);
+                               JcrUtils.updateLastModified(form);
+                               s.save();
+                               s.getWorkspace().getVersionManager().checkpoint(form.getPath());
+                               if (log.isDebugEnabled()) {
+                                       log.debug("Updated form " + form);
+                                       log.debug("Previous csum " + previousCsum);
+                                       log.debug("New csum " + newCsum);
+                               }
+                       }
+               }
+               return form;
+       }
+
+       /** Singleton. */
+       private OdkUtils() {
+
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OrxListName.java b/org.argeo.app.core/src/org/argeo/app/odk/OrxListName.java
new file mode 100644 (file)
index 0000000..ec9b699
--- /dev/null
@@ -0,0 +1,29 @@
+package org.argeo.app.odk;
+
+import org.argeo.app.api.JcrName;
+
+/** Types related to the http://openrosa.org/xforms/xformsList namespace. */
+public enum OrxListName implements JcrName {
+       xform,
+       // names
+       formID, version;
+
+       @Override
+       public String getPrefix() {
+               return prefix();
+       }
+
+       public static String prefix() {
+               return "orxList";
+       }
+
+       @Override
+       public String getNamespace() {
+               return namespace();
+       }
+
+       public static String namespace() {
+               return "http://openrosa.org/xforms/xformsList";
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OrxManifestName.java b/org.argeo.app.core/src/org/argeo/app/odk/OrxManifestName.java
new file mode 100644 (file)
index 0000000..5c93c41
--- /dev/null
@@ -0,0 +1,27 @@
+package org.argeo.app.odk;
+
+import org.argeo.app.api.JcrName;
+
+/** Types related to the http://openrosa.org/xforms/xformsList namespace. */
+public enum OrxManifestName implements JcrName {
+       manifest, mediaFile;
+
+       @Override
+       public String getPrefix() {
+               return prefix();
+       }
+
+       public static String prefix() {
+               return "orxManifest";
+       }
+
+       @Override
+       public String getNamespace() {
+               return namespace();
+       }
+
+       public static String namespace() {
+               return "http://openrosa.org/xforms/xformsManifest";
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/odk/OrxType.java b/org.argeo.app.core/src/org/argeo/app/odk/OrxType.java
new file mode 100644 (file)
index 0000000..cf88eb9
--- /dev/null
@@ -0,0 +1,27 @@
+package org.argeo.app.odk;
+
+import org.argeo.app.api.JcrName;
+
+/** Types related to the http://openrosa.org/xforms/xformsList namespace. */
+public enum OrxType implements JcrName {
+       submission, xml_submission_file;
+
+       @Override
+       public String getPrefix() {
+               return prefix();
+       }
+
+       public static String prefix() {
+               return "orx";
+       }
+
+       @Override
+       public String getNamespace() {
+               return namespace();
+       }
+
+       public static String namespace() {
+               return "http://openrosa.org/xforms";
+       }
+
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/odk/odk.cnd b/org.argeo.app.core/src/org/argeo/app/odk/odk.cnd
new file mode 100644 (file)
index 0000000..d80096d
--- /dev/null
@@ -0,0 +1,56 @@
+<jr = "http://openrosa.org/javarosa">
+<orx = "http://openrosa.org/xforms">
+<orxList = "http://openrosa.org/xforms/xformsList">
+<orxManifest = "http://openrosa.org/xforms/xformsManifest">
+<odk = "http://www.opendatakit.org/xforms">
+
+
+[odk:head]
++ h:title (jcrx:xmlvalue) = jcrx:xmlvalue
++ xforms:model (odk:model) = odk:model
+
+[odk:body] > xforms:ui
+
+
+[odk:html] > mix:referenceable
++ h:head (odk:head) = odk:head
++ h:body (odk:body) = odk:body
+
+[odk:model] > xforms:model
++ odk:setgeopoint (odk:setgeopoint) = odk:setgeopoint
++ xforms:itext (odk:itext) = odk:itext
+
+[odk:itext]
++ xforms:translation (odk:translation) = odk:translation *
+
+[odk:translation]
+- lang (STRING) m
+- default (STRING)
++ xforms:text (odk:text) = odk:text *
+
+[odk:text]
+- id (STRING) m
++ xforms:value (jcrx:xmlvalue) = jcrx:xmlvalue
+
+[odk:setgeopoint]
+- event (STRING)
+- ref (STRING)
+
+// OpenRosa web API
+
+[orxList:xform] > mix:created, mix:lastModified, jcrx:csum, entity:form
+- orxList:formID (STRING)
+- orxList:version (STRING)
++ h:html (odk:html) = odk:html
++ manifest (orxManifest:manifest) = orxManifest:manifest
+
+[orxManifest:manifest]
++ * (orxManifest:mediaFile) = orxManifest:mediaFile
+
+[orxManifest:mediaFile] > nt:address, jcrx:csum
+
+[orx:submission] > mix:created, entity:formSubmission
++ xml_submission_file (nt:unstructured) = nt:unstructured
++ * (nt:file) *
+
+
diff --git a/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java b/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java
new file mode 100644 (file)
index 0000000..7122892
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.app.xforms;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/** Called when a user has received a new form submission. */
+public interface FormSubmissionListener {
+       /** Called after a form submission has been stored in the user area. */
+       void formSubmissionReceived(Node node) throws RepositoryException;
+}
diff --git a/org.argeo.app.core/src/org/argeo/app/xforms/xforms.cnd b/org.argeo.app.core/src/org/argeo/app/xforms/xforms.cnd
new file mode 100644 (file)
index 0000000..c24dbae
--- /dev/null
@@ -0,0 +1,39 @@
+<xforms = "http://www.w3.org/2002/xforms">
+
+[xforms:model]
++ xforms:instance (xforms:instance) = xforms:instance *
++ xforms:bind (xforms:bind) = xforms:bind *
++ xforms:setvalue (xforms:setvalue) = xforms:setvalue *
+
+[xforms:instance] > nt:unstructured
+
+[xforms:bind]
+- * (STRING)
+
+[xforms:setvalue]
+- * (STRING)
+
+[xforms:select] > xforms:input
++ xforms:itemset (xforms:itemset) = xforms:itemset
+
+[xforms:itemset]
+- nodeset (STRING)
++ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue
++ xforms:value (jcrx:xmlvalue) = jcrx:xmlvalue
+
+[xforms:ui]
+- * (STRING)
++ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue *
++ xforms:hint (jcrx:xmlvalue) = jcrx:xmlvalue *
++ xforms:input (xforms:input) = xforms:input *
++ xforms:select (xforms:select) = xforms:select *
++ xforms:select1 (xforms:select) = xforms:select *
++ xforms:trigger (xforms:input) = xforms:input *
++ xforms:upload (xforms:input) = xforms:input *
++ xforms:group (xforms:ui) = xforms:ui *
++ xforms:repeat (xforms:ui) = xforms:ui *
+
+[xforms:input]
+- * (STRING)
++ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue
++ xforms:hint (jcrx:xmlvalue) = jcrx:xmlvalue *
diff --git a/org.argeo.app.core/src/org/argeo/docbook/Dbk4Converter.java b/org.argeo.app.core/src/org/argeo/docbook/Dbk4Converter.java
deleted file mode 100644 (file)
index 916dddd..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-package org.argeo.docbook;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Templates;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-
-import org.apache.xalan.processor.TransformerFactoryImpl;
-import org.argeo.jcr.JcrException;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-/** Convert from DocBook v4 to DocBook v5, using the official XSL. */
-public class Dbk4Converter {
-       private final Templates templates;
-
-       public Dbk4Converter() {
-               try (InputStream in = getClass().getResourceAsStream("db4-upgrade.xsl")) {
-                       Source xsl = new StreamSource(in);
-                       TransformerFactory transformerFactory = new TransformerFactoryImpl();
-                       templates = transformerFactory.newTemplates(xsl);
-               } catch (IOException | TransformerConfigurationException e) {
-                       throw new RuntimeException("Cannot initialise DocBook v4 converter", e);
-               }
-       }
-
-       public void importXml(Node baseNode, InputStream in) throws IOException {
-               try (ByteArrayOutputStream out = new ByteArrayOutputStream();) {
-                       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-                       factory.setXIncludeAware(true);
-                       factory.setNamespaceAware(true);
-                       DocumentBuilder docBuilder = factory.newDocumentBuilder();
-                       Document doc = docBuilder.parse(new InputSource(in));
-                       Source xmlInput = new DOMSource(doc);
-
-//                     ContentHandler contentHandler = baseNode.getSession().getImportContentHandler(baseNode.getPath(),
-//                                     ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-
-                       Transformer transformer = templates.newTransformer();
-                       Result xmlOutput = new StreamResult(out);
-                       transformer.transform(xmlInput, xmlOutput);
-                       try (InputStream dbk5in = new ByteArrayInputStream(out.toByteArray())) {
-                               baseNode.getSession().importXML(baseNode.getPath(), dbk5in,
-                                               ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot import XML to " + baseNode, e);
-               } catch (TransformerException | SAXException | ParserConfigurationException e) {
-                       throw new RuntimeException("Cannot import DocBook v4 to " + baseNode, e);
-               }
-
-       }
-
-       public static void main(String[] args) {
-               try {
-
-                       Source xsl = new StreamSource(new File("/usr/share/xml/docbook5/stylesheet/upgrade/db4-upgrade.xsl"));
-                       TransformerFactory transformerFactory = new TransformerFactoryImpl();
-                       Templates templates = transformerFactory.newTemplates(xsl);
-
-                       File inputDir = new File(args[0]);
-                       File outputDir = new File(args[1]);
-
-                       for (File inputFile : inputDir.listFiles()) {
-                               Result xmlOutput = new StreamResult(new File(outputDir, inputFile.getName()));
-
-                               DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-                               factory.setXIncludeAware(true);
-                               factory.setNamespaceAware(true);
-                               DocumentBuilder docBuilder = factory.newDocumentBuilder();
-                               Document doc = docBuilder.parse(inputFile);
-                               Source xmlInput = new DOMSource(doc);
-                               Transformer transformer = templates.newTransformer();
-                               transformer.transform(xmlInput, xmlOutput);
-                       }
-               } catch (Throwable e) {
-                       e.printStackTrace();
-               }
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/docbook/DbkAttr.java b/org.argeo.app.core/src/org/argeo/docbook/DbkAttr.java
deleted file mode 100644 (file)
index 84097e2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.argeo.docbook;
-
-/** Supported DocBook attributes. */
-public enum DbkAttr {
-       role,
-       //
-       fileref, contentwidth, contentdepth
-       //
-       ;
-
-       public final static String XLINK_HREF = "xlink:href";
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/docbook/DbkMsg.java b/org.argeo.app.core/src/org/argeo/docbook/DbkMsg.java
deleted file mode 100644 (file)
index 8e87231..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.argeo.docbook;
-
-import org.argeo.cms.Localized;
-
-/** DocBook related messages. */
-public enum DbkMsg implements Localized {
-       paragraph, deleteParagraph,
-       //
-       section, deleteSection,
-       //
-       media, deleteMedia, insertPicture, insertVideo, insertParagraph,
-       //
-       ;
-}
diff --git a/org.argeo.app.core/src/org/argeo/docbook/DbkType.java b/org.argeo.app.core/src/org/argeo/docbook/DbkType.java
deleted file mode 100644 (file)
index 005d165..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.argeo.docbook;
-
-import org.argeo.entity.JcrName;
-
-/** Supported DocBook elements */
-public enum DbkType implements JcrName {
-       book, article, section,
-       //
-       info, title, para,
-       //
-       mediaobject, imageobject, imagedata, videoobject, videodata, caption,
-       //
-       link,
-       //
-       ;
-
-       @Override
-       public String getPrefix() {
-               return prefix();
-       }
-
-       public static String prefix() {
-               return "dbk";
-       }
-
-       @Override
-       public String getNamespace() {
-               return namespace();
-       }
-
-       public static String namespace() {
-               return "http://docbook.org/ns/docbook";
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/docbook/DbkUtils.java b/org.argeo.app.core/src/org/argeo/docbook/DbkUtils.java
deleted file mode 100644 (file)
index f4bf502..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-package org.argeo.docbook;
-
-import static org.argeo.docbook.DbkType.para;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.JcrxApi;
-
-/** Utilities around DocBook. */
-public class DbkUtils {
-       private final static CmsLog log = CmsLog.getLog(DbkUtils.class);
-
-       /** Get or add a DocBook element. */
-       public static Node getOrAddDbk(Node parent, DbkType child) {
-               try {
-                       if (!parent.hasNode(child.get())) {
-                               return addDbk(parent, child);
-                       } else {
-                               return parent.getNode(child.get());
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get or add element " + child.get() + " to " + parent, e);
-               }
-       }
-
-       /** Add a DocBook element to this node. */
-       public static Node addDbk(Node parent, DbkType child) {
-               try {
-                       Node node = parent.addNode(child.get(), child.get());
-                       return node;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot add element " + child.get() + " to " + parent, e);
-               }
-       }
-
-       /** Whether this DocBook element is of this type. */
-       public static boolean isDbk(Node node, DbkType type) {
-               return Jcr.getName(node).equals(type.get());
-       }
-
-       /** Whether this node is a DocBook type. */
-       public static boolean isDbk(Node node) {
-               String name = Jcr.getName(node);
-               for (DbkType type : DbkType.values()) {
-                       if (name.equals(type.get()))
-                               return true;
-               }
-               return false;
-       }
-
-       public static String getTitle(Node node) {
-               return JcrxApi.getXmlValue(node, DbkType.title.get());
-       }
-
-       public static void setTitle(Node node, String txt) {
-               Node titleNode = getOrAddDbk(node, DbkType.title);
-               JcrxApi.setXmlValue(node, titleNode, txt);
-       }
-
-       public static Node getMetadata(Node infoContainer) {
-               try {
-                       if (!infoContainer.hasNode(DbkType.info.get()))
-                               return null;
-                       Node info = infoContainer.getNode(DbkType.info.get());
-                       if (!info.hasNode(EntityType.local.get()))
-                               return null;
-                       return info.getNode(EntityType.local.get());
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot retrieve metadata from " + infoContainer, e);
-               }
-       }
-
-       public static Node getChildByRole(Node parent, String role) {
-               try {
-                       NodeIterator baseSections = parent.getNodes();
-                       while (baseSections.hasNext()) {
-                               Node n = baseSections.nextNode();
-                               String r = Jcr.get(n, DbkAttr.role.name());
-                               if (r != null && r.equals(role))
-                                       return n;
-                       }
-                       return null;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get child from " + parent + " with role " + role, e);
-               }
-       }
-
-       public static Node addParagraph(Node node, String txt) {
-               Node p = addDbk(node, para);
-               JcrxApi.setXmlValue(node, p, txt);
-               return p;
-       }
-
-       /**
-        * Removes a paragraph if it empty. The sesison is not saved.
-        * 
-        * @return true if the paragraph was empty and it was removed
-        */
-       public static boolean removeIfEmptyParagraph(Node node) {
-               try {
-                       if (isDbk(node, DbkType.para)) {
-                               NodeIterator nit = node.getNodes();
-                               if (!nit.hasNext()) {
-                                       node.remove();
-                                       return true;
-                               }
-                               Node first = nit.nextNode();
-                               if (nit.hasNext())
-                                       return false;
-                               if (first.getName().equals(Jcr.JCR_XMLTEXT)) {
-                                       String str = Jcr.get(first, Jcr.JCR_XMLCHARACTERS);
-                                       if (str != null && str.trim().equals("")) {
-                                               node.remove();
-                                               return true;
-                                       }
-                               } else {
-                                       return false;
-                               }
-                       }
-                       return false;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot remove possibly empty paragraph", e);
-               }
-       }
-
-       public static Node insertImageAfter(Node sibling) {
-               try {
-
-                       Node parent = sibling.getParent();
-                       Node mediaNode = addDbk(parent, DbkType.mediaobject);
-                       // TODO optimise?
-                       parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
-                                       sibling.getName() + "[" + sibling.getIndex() + "]");
-                       parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
-                                       mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
-
-                       Node imageNode = addDbk(mediaNode, DbkType.imageobject);
-                       Node imageDataNode = addDbk(imageNode, DbkType.imagedata);
-//                     Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
-//                     Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]);
-//                     fileNode.addMixin(EntityType.box.get());
-//                     fileNode.setProperty(EntityNames.SVG_WIDTH, 0);
-//                     fileNode.setProperty(EntityNames.SVG_LENGTH, 0);
-//                     fileNode.addMixin(NodeType.MIX_MIMETYPE);
-//
-//                     // we assume this is a folder next to the main DocBook document
-//                     // TODO make it more robust and generic
-//                     String fileRef = mediaNode.getName();
-//                     imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef);
-                       return mediaNode;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot insert empty image after " + sibling, e);
-               }
-       }
-
-       public static Node insertVideoAfter(Node sibling) {
-               try {
-
-                       Node parent = sibling.getParent();
-                       Node mediaNode = addDbk(parent, DbkType.mediaobject);
-                       // TODO optimise?
-                       parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
-                                       sibling.getName() + "[" + sibling.getIndex() + "]");
-                       parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
-                                       mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
-
-                       Node videoNode = addDbk(mediaNode, DbkType.videoobject);
-                       Node videoDataNode = addDbk(videoNode, DbkType.videodata);
-                       return mediaNode;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot insert empty image after " + sibling, e);
-               }
-       }
-
-       public static String getMediaFileref(Node node) {
-               try {
-                       Node mediadata;
-                       if (node.hasNode(DbkType.imageobject.get())) {
-                               mediadata = node.getNode(DbkType.imageobject.get()).getNode(DbkType.imagedata.get());
-                       } else if (node.hasNode(DbkType.videoobject.get())) {
-                               mediadata = node.getNode(DbkType.videoobject.get()).getNode(DbkType.videodata.get());
-                       } else {
-                               throw new IllegalArgumentException("Fileref not found in " + node);
-                       }
-
-                       if (mediadata.hasProperty(DbkAttr.fileref.name())) {
-                               return mediadata.getProperty(DbkAttr.fileref.name()).getString();
-                       } else {
-                               return null;
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot retrieve file ref from " + node, e);
-               }
-       }
-
-       public static void exportXml(Node node, OutputStream out) throws IOException {
-               try {
-                       node.getSession().exportDocumentView(node.getPath(), out, false, false);
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot export " + node + " to XML", e);
-               }
-       }
-
-       public static void exportToFs(Node baseNode, DbkType type, Path directory) {
-               String fileName = Jcr.getName(baseNode) + ".dbk.xml";
-               Path filePath = directory.resolve(fileName);
-               Node docBookNode = Jcr.getNode(baseNode, type.get());
-               if (docBookNode == null)
-                       throw new IllegalArgumentException("No " + type.get() + " under " + baseNode);
-               try {
-                       Files.createDirectories(directory);
-                       try (OutputStream out = Files.newOutputStream(filePath)) {
-                               exportXml(docBookNode, out);
-                       }
-                       JcrUtils.copyFilesToFs(baseNode, directory, true);
-                       if (log.isDebugEnabled())
-                               log.debug("DocBook " + baseNode + " exported to " + filePath.toAbsolutePath());
-               } catch (IOException e) {
-                       throw new RuntimeException(e);
-               }
-       }
-
-       public static void importXml(Node baseNode, InputStream in) throws IOException {
-               try {
-                       baseNode.getSession().importXML(baseNode.getPath(), in,
-                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot import XML to " + baseNode, e);
-               }
-
-       }
-
-       /** Singleton. */
-       private DbkUtils() {
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/docbook/db4-upgrade.xsl b/org.argeo.app.core/src/org/argeo/docbook/db4-upgrade.xsl
deleted file mode 100644 (file)
index 00096be..0000000
+++ /dev/null
@@ -1,1398 +0,0 @@
-<?xml version="1.0"?>
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-                xmlns:exsl="http://exslt.org/common"
-               xmlns:db = "http://docbook.org/ns/docbook"
-               xmlns:xlink="http://www.w3.org/1999/xlink"
-                exclude-result-prefixes="exsl db"
-                version="1.0">
-
-<!--
-# ======================================================================
-# This file is part of DocBook V5.0CR5
-#
-# Copyright 2005 Norman Walsh, Sun Microsystems, Inc., and the
-# Organization for the Advancement of Structured Information
-# Standards (OASIS).
-#
-# Release: $Id: db4-upgrade.xsl 7660 2008-02-06 13:48:36Z nwalsh $
-#
-# Permission to use, copy, modify and distribute this stylesheet
-# and its accompanying documentation for any purpose and without fee
-# is hereby granted in perpetuity, provided that the above copyright
-# notice and this paragraph appear in all copies. The copyright
-# holders make no representation about the suitability of the schema
-# for any purpose. It is provided "as is" without expressed or implied
-# warranty.
-#
-# Please direct all questions, bug reports, or suggestions for changes
-# to the docbook@lists.oasis-open.org mailing list. For more
-# information, see http://www.oasis-open.org/docbook/.
-#
-# ======================================================================
--->
-
-<xsl:variable name="version" select="'1.0'"/>
-
-<xsl:output method="xml" encoding="utf-8" indent="no" omit-xml-declaration="yes"/>
-
-<xsl:preserve-space elements="*"/>
-<xsl:param name="rootid">
-  <xsl:choose>
-  <xsl:when test="/*/@id">
-    <xsl:value-of select="/*/@id"/>
-  </xsl:when>
-  <xsl:otherwise>
-    <xsl:text>UNKNOWN</xsl:text>
-  </xsl:otherwise>
-  </xsl:choose>
-</xsl:param>
-
-<xsl:param name="defaultDate" select="''"/>
-
-<xsl:template match="/">
-  <xsl:variable name="converted">
-    <xsl:apply-templates/>
-  </xsl:variable>
-  <xsl:comment>
-    <xsl:text> Converted by db4-upgrade version </xsl:text>
-    <xsl:value-of select="$version"/>
-    <xsl:text> </xsl:text>
-  </xsl:comment>
-  <xsl:text>&#10;</xsl:text>
-  <xsl:apply-templates select="exsl:node-set($converted)/*" mode="addNS"/>
-</xsl:template>
-
-<xsl:template match="bookinfo|chapterinfo|articleinfo|artheader|appendixinfo
-                    |blockinfo
-                     |bibliographyinfo|glossaryinfo|indexinfo|setinfo
-                    |setindexinfo
-                     |sect1info|sect2info|sect3info|sect4info|sect5info
-                     |sectioninfo
-                     |refsect1info|refsect2info|refsect3info|refsectioninfo
-                    |referenceinfo|partinfo"
-              priority="200">
-  <info>
-    <xsl:call-template name="copy.attributes"/>
-
-    <!-- titles can be inside or outside or both. fix that -->
-    <xsl:choose>
-      <xsl:when test="title and following-sibling::title">
-        <xsl:if test="title != following-sibling::title">
-          <xsl:call-template name="emit-message">
-            <xsl:with-param name="message">
-              <xsl:text>Check </xsl:text>
-              <xsl:value-of select="name(..)"/>
-              <xsl:text> title.</xsl:text>
-            </xsl:with-param>
-          </xsl:call-template>
-        </xsl:if>
-        <xsl:apply-templates select="title" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="title">
-        <xsl:apply-templates select="title" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="following-sibling::title">
-        <xsl:apply-templates select="following-sibling::title" mode="copy"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:call-template name="emit-message">
-          <xsl:with-param name="message">
-            <xsl:text>Check </xsl:text>
-            <xsl:value-of select="name(..)"/>
-            <xsl:text>: no title.</xsl:text>
-          </xsl:with-param>
-        </xsl:call-template>
-      </xsl:otherwise>
-    </xsl:choose>
-
-    <xsl:choose>
-      <xsl:when test="titleabbrev and following-sibling::titleabbrev">
-        <xsl:if test="titleabbrev != following-sibling::titleabbrev">
-          <xsl:call-template name="emit-message">
-            <xsl:with-param name="message">
-              <xsl:text>Check </xsl:text>
-              <xsl:value-of select="name(..)"/>
-              <xsl:text> titleabbrev.</xsl:text>
-            </xsl:with-param>
-          </xsl:call-template>
-        </xsl:if>
-        <xsl:apply-templates select="titleabbrev" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="titleabbrev">
-        <xsl:apply-templates select="titleabbrev" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="following-sibling::titleabbrev">
-        <xsl:apply-templates select="following-sibling::titleabbrev" mode="copy"/>
-      </xsl:when>
-    </xsl:choose>
-
-    <xsl:choose>
-      <xsl:when test="subtitle and following-sibling::subtitle">
-        <xsl:if test="subtitle != following-sibling::subtitle">
-          <xsl:call-template name="emit-message">
-            <xsl:with-param name="message">
-              <xsl:text>Check </xsl:text>
-              <xsl:value-of select="name(..)"/>
-              <xsl:text> subtitle.</xsl:text>
-            </xsl:with-param>
-          </xsl:call-template>
-        </xsl:if>
-        <xsl:apply-templates select="subtitle" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="subtitle">
-        <xsl:apply-templates select="subtitle" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="following-sibling::subtitle">
-        <xsl:apply-templates select="following-sibling::subtitle" mode="copy"/>
-      </xsl:when>
-    </xsl:choose>
-
-    <xsl:apply-templates/>
-  </info>
-</xsl:template>
-
-<xsl:template match="objectinfo|prefaceinfo|refsynopsisdivinfo
-                    |screeninfo|sidebarinfo"
-             priority="200">
-  <info>
-    <xsl:call-template name="copy.attributes"/>
-
-    <!-- titles can be inside or outside or both. fix that -->
-    <xsl:choose>
-      <xsl:when test="title and following-sibling::title">
-        <xsl:if test="title != following-sibling::title">
-          <xsl:call-template name="emit-message">
-            <xsl:with-param name="message">
-              <xsl:text>Check </xsl:text>
-              <xsl:value-of select="name(..)"/>
-              <xsl:text> title.</xsl:text>
-            </xsl:with-param>
-          </xsl:call-template>
-        </xsl:if>
-        <xsl:apply-templates select="title" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="title">
-        <xsl:apply-templates select="title" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="following-sibling::title">
-        <xsl:apply-templates select="following-sibling::title" mode="copy"/>
-      </xsl:when>
-      <xsl:otherwise>
-       <!-- it's ok if there's no title on these -->
-      </xsl:otherwise>
-    </xsl:choose>
-
-    <xsl:choose>
-      <xsl:when test="titleabbrev and following-sibling::titleabbrev">
-        <xsl:if test="titleabbrev != following-sibling::titleabbrev">
-          <xsl:call-template name="emit-message">
-          <xsl:with-param name="message">
-            <xsl:text>Check </xsl:text>
-            <xsl:value-of select="name(..)"/>
-            <xsl:text> titleabbrev.</xsl:text>
-          </xsl:with-param>
-        </xsl:call-template>
-        </xsl:if>
-        <xsl:apply-templates select="titleabbrev" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="titleabbrev">
-        <xsl:apply-templates select="titleabbrev" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="following-sibling::titleabbrev">
-        <xsl:apply-templates select="following-sibling::titleabbrev" mode="copy"/>
-      </xsl:when>
-    </xsl:choose>
-
-    <xsl:choose>
-      <xsl:when test="subtitle and following-sibling::subtitle">
-        <xsl:if test="subtitle != following-sibling::subtitle">
-          <xsl:call-template name="emit-message">
-            <xsl:with-param name="message">
-              <xsl:text>Check </xsl:text>
-              <xsl:value-of select="name(..)"/>
-              <xsl:text> subtitle.</xsl:text>
-            </xsl:with-param>
-          </xsl:call-template>
-        </xsl:if>
-        <xsl:apply-templates select="subtitle" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="subtitle">
-        <xsl:apply-templates select="subtitle" mode="copy"/>
-      </xsl:when>
-      <xsl:when test="following-sibling::subtitle">
-        <xsl:apply-templates select="following-sibling::subtitle" mode="copy"/>
-      </xsl:when>
-    </xsl:choose>
-
-    <xsl:apply-templates/>
-  </info>
-</xsl:template>
-
-<xsl:template match="refentryinfo"
-              priority="200">
-  <info>
-    <xsl:call-template name="copy.attributes"/>
-
-    <!-- titles can be inside or outside or both. fix that -->
-    <xsl:if test="title">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Discarding title from refentryinfo!</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-    </xsl:if>
-
-    <xsl:if test="titleabbrev">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Discarding titleabbrev from refentryinfo!</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-    </xsl:if>
-
-    <xsl:if test="subtitle">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Discarding subtitle from refentryinfo!</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-    </xsl:if>
-
-    <xsl:apply-templates/>
-  </info>
-</xsl:template>
-
-<xsl:template match="refmiscinfo"
-              priority="200">
-  <refmiscinfo>
-    <xsl:call-template name="copy.attributes">
-      <xsl:with-param name="suppress" select="'class'"/>
-    </xsl:call-template>
-    <xsl:if test="@class">
-      <xsl:choose>
-       <xsl:when test="@class = 'source'
-                       or @class = 'version'
-                       or @class = 'manual'
-                       or @class = 'sectdesc'
-                       or @class = 'software'">
-         <xsl:attribute name="class">
-           <xsl:value-of select="@class"/>
-         </xsl:attribute>
-       </xsl:when>
-       <xsl:otherwise>
-         <xsl:attribute name="class">
-           <xsl:value-of select="'other'"/>
-         </xsl:attribute>
-         <xsl:attribute name="otherclass">
-           <xsl:value-of select="@class"/>
-         </xsl:attribute>
-       </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-    <xsl:apply-templates/>
-  </refmiscinfo>
-</xsl:template>
-
-<xsl:template match="corpauthor" priority="200">
-  <author>
-    <xsl:call-template name="copy.attributes"/>
-    <orgname>
-      <xsl:apply-templates/>
-    </orgname>
-  </author>
-</xsl:template>
-
-<xsl:template match="corpname" priority="200">
-  <orgname>
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </orgname>
-</xsl:template>
-
-<xsl:template match="author[not(personname)]|editor[not(personname)]|othercredit[not(personname)]" priority="200">
-  <xsl:copy>
-    <xsl:call-template name="copy.attributes"/>
-    <personname>
-      <xsl:apply-templates select="honorific|firstname|surname|othername|lineage"/>
-    </personname>
-    <xsl:apply-templates select="*[not(self::honorific|self::firstname|self::surname
-                                   |self::othername|self::lineage)]"/>
-  </xsl:copy>
-</xsl:template>
-
-<xsl:template match="address|programlisting|screen|funcsynopsisinfo
-                     |classsynopsisinfo|literallayout" priority="200">
-  <xsl:copy>
-    <xsl:call-template name="copy.attributes">
-      <xsl:with-param name="suppress" select="'format'"/>
-    </xsl:call-template>
-    <xsl:apply-templates/>
-  </xsl:copy>
-</xsl:template>
-
-<xsl:template match="productname[@class]" priority="200">
-  <xsl:call-template name="emit-message">
-    <xsl:with-param name="message">
-      <xsl:text>Dropping class attribute from productname</xsl:text>
-    </xsl:with-param>
-  </xsl:call-template>
-  <xsl:copy>
-    <xsl:call-template name="copy.attributes">
-      <xsl:with-param name="suppress" select="'class'"/>
-    </xsl:call-template>
-    <xsl:apply-templates/>
-  </xsl:copy>
-</xsl:template>
-
-<xsl:template match="dedication|preface|chapter|appendix|part|partintro
-                     |article|bibliography|glossary|glossdiv|index
-                    |reference[not(referenceinfo)]
-                     |book" priority="200">
-  <xsl:choose>
-    <xsl:when test="not(dedicationinfo|prefaceinfo|chapterinfo
-                       |appendixinfo|partinfo
-                        |articleinfo|artheader|bibliographyinfo
-                       |glossaryinfo|indexinfo
-                        |bookinfo)">
-      <xsl:copy>
-        <xsl:call-template name="copy.attributes"/>
-        <xsl:if test="title|subtitle|titleabbrev">
-          <info>
-            <xsl:apply-templates select="title" mode="copy"/>
-            <xsl:apply-templates select="titleabbrev" mode="copy"/>
-            <xsl:apply-templates select="subtitle" mode="copy"/>
-            <xsl:apply-templates select="abstract" mode="copy"/>
-          </info>
-        </xsl:if>
-        <xsl:apply-templates/>
-      </xsl:copy>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:copy>
-        <xsl:call-template name="copy.attributes"/>
-        <xsl:apply-templates/>
-      </xsl:copy>
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-<xsl:template match="formalpara|figure|table[tgroup]|example|blockquote
-                     |caution|important|note|warning|tip
-                     |bibliodiv|glossarydiv|indexdiv
-                    |orderedlist|itemizedlist|variablelist|procedure
-                    |task|tasksummary|taskprerequisites|taskrelated
-                    |sidebar"
-             priority="200">
-  <xsl:choose>
-    <xsl:when test="blockinfo">
-      <xsl:copy>
-        <xsl:call-template name="copy.attributes"/>
-        <xsl:apply-templates/>
-      </xsl:copy>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:copy>
-        <xsl:call-template name="copy.attributes"/>
-
-       <xsl:if test="title|titleabbrev|subtitle">
-         <info>
-           <xsl:apply-templates select="title" mode="copy"/>
-           <xsl:apply-templates select="titleabbrev" mode="copy"/>
-           <xsl:apply-templates select="subtitle" mode="copy"/>
-         </info>
-       </xsl:if>
-
-        <xsl:apply-templates/>
-      </xsl:copy>
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-<xsl:template match="equation" priority="200">
-  <xsl:choose>
-    <xsl:when test="not(title)">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param
-            name="message"
-            >Convert equation without title to informal equation.</xsl:with-param>
-      </xsl:call-template>
-      <informalequation>
-        <xsl:call-template name="copy.attributes"/>
-        <xsl:apply-templates/>
-      </informalequation>
-    </xsl:when>
-    <xsl:when test="blockinfo">
-      <xsl:copy>
-        <xsl:call-template name="copy.attributes"/>
-        <xsl:apply-templates/>
-      </xsl:copy>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:copy>
-        <xsl:call-template name="copy.attributes"/>
-        <info>
-          <xsl:apply-templates select="title" mode="copy"/>
-          <xsl:apply-templates select="titleabbrev" mode="copy"/>
-          <xsl:apply-templates select="subtitle" mode="copy"/>
-        </info>
-        <xsl:apply-templates/>
-      </xsl:copy>
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-<xsl:template match="sect1|sect2|sect3|sect4|sect5|section"
-             priority="200">
-  <section>
-    <xsl:call-template name="copy.attributes"/>
-
-    <xsl:if test="not(sect1info|sect2info|sect3info|sect4info|sect5info|sectioninfo)">
-      <info>
-        <xsl:apply-templates select="title" mode="copy"/>
-        <xsl:apply-templates select="titleabbrev" mode="copy"/>
-        <xsl:apply-templates select="subtitle" mode="copy"/>
-        <xsl:apply-templates select="abstract" mode="copy"/>
-      </info>
-    </xsl:if>
-    <xsl:apply-templates/>
-  </section>
-</xsl:template>
-
-<xsl:template match="simplesect"
-             priority="200">
-  <simplesect>
-    <xsl:call-template name="copy.attributes"/>
-    <info>
-      <xsl:apply-templates select="title" mode="copy"/>
-      <xsl:apply-templates select="titleabbrev" mode="copy"/>
-      <xsl:apply-templates select="subtitle" mode="copy"/>
-      <xsl:apply-templates select="abstract" mode="copy"/>
-    </info>
-    <xsl:apply-templates/>
-  </simplesect>
-</xsl:template>
-
-<xsl:template match="refsect1|refsect2|refsect3|refsection" priority="200">
-  <refsection>
-    <xsl:call-template name="copy.attributes"/>
-
-    <xsl:if test="not(refsect1info|refsect2info|refsect3info|refsectioninfo)">
-      <info>
-        <xsl:apply-templates select="title" mode="copy"/>
-        <xsl:apply-templates select="titleabbrev" mode="copy"/>
-        <xsl:apply-templates select="subtitle" mode="copy"/>
-        <xsl:apply-templates select="abstract" mode="copy"/>
-      </info>
-    </xsl:if>
-    <xsl:apply-templates/>
-  </refsection>
-</xsl:template>
-
-<xsl:template match="imagedata|videodata|audiodata|textdata" priority="200">
-  <xsl:copy>
-    <xsl:call-template name="copy.attributes">
-      <xsl:with-param name="suppress" select="'srccredit'"/>
-    </xsl:call-template>
-    <xsl:if test="@srccredit">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Check conversion of srccredit </xsl:text>
-          <xsl:text>(othercredit="srccredit").</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-      <info>
-        <othercredit class="other" otherclass="srccredit">
-          <orgname>???</orgname>
-          <contrib>
-            <xsl:value-of select="@srccredit"/>
-          </contrib>
-        </othercredit>
-      </info>
-    </xsl:if>
-  </xsl:copy>
-</xsl:template>
-
-<xsl:template match="sgmltag" priority="200">
-  <tag>
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:if test="@class = 'sgmlcomment'">
-      <xsl:attribute name="class">comment</xsl:attribute>
-    </xsl:if>
-    <xsl:apply-templates/>
-  </tag>
-</xsl:template>
-
-<xsl:template match="inlinegraphic[@format='linespecific']" priority="210">
-  <textobject>
-    <textdata>
-      <xsl:call-template name="copy.attributes"/>
-    </textdata>
-  </textobject>
-</xsl:template>
-
-<xsl:template match="inlinegraphic" priority="200">
-  <inlinemediaobject>
-    <imageobject>
-      <imagedata>
-       <xsl:call-template name="copy.attributes"/>
-      </imagedata>
-    </imageobject>
-  </inlinemediaobject>
-</xsl:template>
-
-<xsl:template match="graphic[@format='linespecific']" priority="210">
-  <mediaobject>
-    <textobject>
-      <textdata>
-       <xsl:call-template name="copy.attributes"/>
-      </textdata>
-    </textobject>
-  </mediaobject>
-</xsl:template>
-
-<xsl:template match="graphic" priority="200">
-  <mediaobject>
-    <imageobject>
-      <imagedata>
-       <xsl:call-template name="copy.attributes"/>
-      </imagedata>
-    </imageobject>
-  </mediaobject>
-</xsl:template>
-
-<xsl:template match="pubsnumber" priority="200">
-  <biblioid class="pubsnumber">
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </biblioid>
-</xsl:template>
-
-<xsl:template match="invpartnumber" priority="200">
-  <xsl:call-template name="emit-message">
-    <xsl:with-param name="message">
-      <xsl:text>Converting invpartnumber to biblioid otherclass="invpartnumber".</xsl:text>
-    </xsl:with-param>
-  </xsl:call-template>
-  <biblioid class="other" otherclass="invpartnumber">
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </biblioid>
-</xsl:template>
-
-<xsl:template match="contractsponsor" priority="200">
-  <xsl:variable name="contractnum"
-                select="preceding-sibling::contractnum|following-sibling::contractnum"/>
-
-  <xsl:call-template name="emit-message">
-    <xsl:with-param name="message">
-      <xsl:text>Converting contractsponsor to othercredit="contractsponsor".</xsl:text>
-    </xsl:with-param>
-  </xsl:call-template>
-
-  <othercredit class="other" otherclass="contractsponsor">
-    <orgname>
-      <xsl:call-template name="copy.attributes"/>
-      <xsl:apply-templates/>
-    </orgname>
-    <xsl:for-each select="$contractnum">
-      <contrib role="contractnum">
-        <xsl:apply-templates select="node()"/>
-      </contrib>
-    </xsl:for-each>
-  </othercredit>
-</xsl:template>
-
-<xsl:template match="contractnum" priority="200">
-  <xsl:if test="not(preceding-sibling::contractsponsor
-                    |following-sibling::contractsponsor)
-                and not(preceding-sibling::contractnum)">
-    <xsl:call-template name="emit-message">
-      <xsl:with-param name="message">
-        <xsl:text>Converting contractnum to othercredit="contractnum".</xsl:text>
-      </xsl:with-param>
-    </xsl:call-template>
-
-    <othercredit class="other" otherclass="contractnum">
-      <orgname>???</orgname>
-      <xsl:for-each select="self::contractnum
-                            |preceding-sibling::contractnum
-                            |following-sibling::contractnum">
-        <contrib>
-          <xsl:apply-templates select="node()"/>
-        </contrib>
-      </xsl:for-each>
-    </othercredit>
-  </xsl:if>
-</xsl:template>
-
-<xsl:template match="isbn|issn" priority="200">
-  <biblioid class="{local-name(.)}">
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </biblioid>
-</xsl:template>
-
-<xsl:template match="biblioid[count(*) = 1
-                             and ulink
-                             and normalize-space(text()) = '']" priority="200">
-  <biblioid xlink:href="{ulink/@url}">
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates select="ulink/node()"/>
-  </biblioid>
-</xsl:template>
-
-<xsl:template match="authorblurb" priority="200">
-  <personblurb>
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </personblurb>
-</xsl:template>
-
-<xsl:template match="collabname" priority="200">
-  <xsl:call-template name="emit-message">
-    <xsl:with-param name="message">
-      <xsl:text>Check conversion of collabname </xsl:text>
-      <xsl:text>(orgname role="collabname").</xsl:text>
-    </xsl:with-param>
-  </xsl:call-template>
-  <orgname role="collabname">
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </orgname>
-</xsl:template>
-
-<xsl:template match="modespec" priority="200">
-  <xsl:call-template name="emit-message">
-    <xsl:with-param name="message">
-      <xsl:text>Discarding modespec (</xsl:text>
-      <xsl:value-of select="."/>
-      <xsl:text>).</xsl:text>
-    </xsl:with-param>
-  </xsl:call-template>
-</xsl:template>
-
-<xsl:template match="mediaobjectco" priority="200">
-  <mediaobject>
-    <xsl:copy-of select="@*"/>
-    <xsl:apply-templates/>
-  </mediaobject>
-</xsl:template>
-
-<xsl:template match="remark" priority="200">
-  <!-- get rid of any embedded markup -->
-  <remark>
-    <xsl:copy-of select="@*"/>
-    <xsl:value-of select="."/>
-  </remark>
-</xsl:template>
-
-<xsl:template match="biblioentry/title
-                     |bibliomset/title
-                     |biblioset/title
-                     |bibliomixed/title" priority="400">
-  <citetitle>
-    <xsl:copy-of select="@*"/>
-    <xsl:apply-templates/>
-  </citetitle>
-</xsl:template>
-
-<xsl:template match="biblioentry/titleabbrev|biblioentry/subtitle
-                     |bibliomset/titleabbrev|bibliomset/subtitle
-                     |biblioset/titleabbrev|biblioset/subtitle
-                     |bibliomixed/titleabbrev|bibliomixed/subtitle"
-             priority="400">
-  <xsl:copy>
-    <xsl:copy-of select="@*"/>
-    <xsl:apply-templates/>
-  </xsl:copy>
-</xsl:template>
-
-<xsl:template match="biblioentry/contrib
-                     |bibliomset/contrib
-                     |bibliomixed/contrib" priority="200">
-  <xsl:call-template name="emit-message">
-    <xsl:with-param name="message">
-      <xsl:text>Check conversion of contrib </xsl:text>
-      <xsl:text>(othercontrib="contrib").</xsl:text>
-    </xsl:with-param>
-  </xsl:call-template>
-  <othercredit class="other" otherclass="contrib">
-    <orgname>???</orgname>
-    <contrib>
-      <xsl:call-template name="copy.attributes"/>
-      <xsl:apply-templates/>
-    </contrib>
-  </othercredit>
-</xsl:template>
-
-<xsl:template match="link" priority="200">
-  <xsl:copy>
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </xsl:copy>
-</xsl:template>
-
-<xsl:template match="ulink" priority="200">
-  <xsl:choose>
-    <xsl:when test="node()">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Converting ulink to link.</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-
-      <link xlink:href="{@url}">
-       <xsl:call-template name="copy.attributes">
-         <xsl:with-param name="suppress" select="'url'"/>
-       </xsl:call-template>
-       <xsl:apply-templates/>
-      </link>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Converting ulink to uri.</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-
-      <uri xlink:href="{@url}">
-       <xsl:call-template name="copy.attributes">
-         <xsl:with-param name="suppress" select="'url'"/>
-       </xsl:call-template>
-       <xsl:value-of select="@url"/>
-      </uri>
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-<xsl:template match="olink" priority="200">
-  <xsl:if test="@linkmode">
-    <xsl:call-template name="emit-message">
-      <xsl:with-param name="message">
-        <xsl:text>Discarding linkmode on olink.</xsl:text>
-      </xsl:with-param>
-    </xsl:call-template>
-  </xsl:if>
-
-  <xsl:choose>
-    <xsl:when test="@targetdocent">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Converting olink targetdocent to targetdoc.</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-
-      <olink targetdoc="{unparsed-entity-uri(@targetdocent)}">
-       <xsl:for-each select="@*">
-         <xsl:if test="name(.) != 'targetdocent'
-                       and name(.) != 'linkmode'">
-           <xsl:copy/>
-         </xsl:if>
-       </xsl:for-each>
-       <xsl:apply-templates/>
-      </olink>
-    </xsl:when>
-    <xsl:otherwise>
-      <olink>
-       <xsl:for-each select="@*">
-         <xsl:if test="name(.) != 'linkmode'">
-           <xsl:copy/>
-         </xsl:if>
-       </xsl:for-each>
-       <xsl:apply-templates/>
-      </olink>
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-<xsl:template match="biblioentry/firstname
-                     |biblioentry/surname
-                     |biblioentry/othername
-                     |biblioentry/lineage
-                     |biblioentry/honorific
-                     |bibliomset/firstname
-                     |bibliomset/surname
-                     |bibliomset/othername
-                     |bibliomset/lineage
-                     |bibliomset/honorific" priority="200">
-  <xsl:choose>
-    <xsl:when test="preceding-sibling::firstname
-                    |preceding-sibling::surname
-                    |preceding-sibling::othername
-                    |preceding-sibling::lineage
-                    |preceding-sibling::honorific">
-      <!-- nop -->
-    </xsl:when>
-    <xsl:otherwise>
-      <personname>
-        <xsl:apply-templates select="../firstname
-                                     |../surname
-                                     |../othername
-                                     |../lineage
-                                     |../honorific" mode="copy"/>
-      </personname>
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-<xsl:template match="areaset" priority="200">
-  <xsl:copy>
-    <xsl:call-template name="copy.attributes">
-      <xsl:with-param name="suppress" select="'coords'"/>
-    </xsl:call-template>
-    <xsl:apply-templates/>
-  </xsl:copy>
-</xsl:template>
-
-<xsl:template match="date|pubdate" priority="200">
-  <xsl:variable name="rp1" select="substring-before(normalize-space(.), ' ')"/>
-  <xsl:variable name="rp2"
-               select="substring-before(substring-after(normalize-space(.), ' '),
-                                        ' ')"/>
-  <xsl:variable name="rp3"
-               select="substring-after(substring-after(normalize-space(.), ' '), ' ')"/>
-
-  <xsl:variable name="p1">
-    <xsl:choose>
-      <xsl:when test="contains($rp1, ',')">
-       <xsl:value-of select="substring-before($rp1, ',')"/>
-      </xsl:when>
-      <xsl:otherwise>
-       <xsl:value-of select="$rp1"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:variable>
-
-  <xsl:variable name="p2">
-    <xsl:choose>
-      <xsl:when test="contains($rp2, ',')">
-       <xsl:value-of select="substring-before($rp2, ',')"/>
-      </xsl:when>
-      <xsl:otherwise>
-       <xsl:value-of select="$rp2"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:variable>
-
-  <xsl:variable name="p3">
-    <xsl:choose>
-      <xsl:when test="contains($rp3, ',')">
-       <xsl:value-of select="substring-before($rp3, ',')"/>
-      </xsl:when>
-      <xsl:otherwise>
-       <xsl:value-of select="$rp3"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:variable>
-
-  <xsl:variable name="date">
-    <xsl:choose>
-      <xsl:when test="string($p1+1) != 'NaN' and string($p3+1) != 'NaN'">
-       <xsl:choose>
-         <xsl:when test="$p2 = 'Jan' or $p2 = 'January'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-01-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Feb' or $p2 = 'February'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-02-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Mar' or $p2 = 'March'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-03-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Apr' or $p2 = 'April'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-04-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'May'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-05-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Jun' or $p2 = 'June'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-06-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Jul' or $p2 = 'July'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-07-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Aug' or $p2 = 'August'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-08-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Sep' or $p2 = 'September'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-09-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Oct' or $p2 = 'October'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-10-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Nov' or $p2 = 'November'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-11-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p2 = 'Dec' or $p2 = 'December'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-12-</xsl:text>
-           <xsl:number value="$p1" format="01"/>
-         </xsl:when>
-         <xsl:otherwise>
-           <xsl:apply-templates/>
-         </xsl:otherwise>
-       </xsl:choose>
-      </xsl:when>
-      <xsl:when test="string($p2+1) != 'NaN' and string($p3+1) != 'NaN'">
-       <xsl:choose>
-         <xsl:when test="$p1 = 'Jan' or $p1 = 'January'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-01-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Feb' or $p1 = 'February'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-02-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Mar' or $p1 = 'March'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-03-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Apr' or $p1 = 'April'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-04-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'May'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-05-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Jun' or $p1 = 'June'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-06-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Jul' or $p1 = 'July'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-07-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Aug' or $p1 = 'August'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-08-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Sep' or $p1 = 'September'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-09-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Oct' or $p1 = 'October'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-10-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Nov' or $p1 = 'November'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-11-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:when test="$p1 = 'Dec' or $p1 = 'December'">
-           <xsl:number value="$p3" format="0001"/>
-           <xsl:text>-12-</xsl:text>
-           <xsl:number value="$p2" format="01"/>
-         </xsl:when>
-         <xsl:otherwise>
-           <xsl:apply-templates/>
-         </xsl:otherwise>
-       </xsl:choose>
-      </xsl:when>
-      <xsl:otherwise>
-       <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:variable>
-
-  <xsl:choose>
-    <xsl:when test="normalize-space($date) != normalize-space(.)">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Converted </xsl:text>
-          <xsl:value-of select="normalize-space(.)"/>
-          <xsl:text> into </xsl:text>
-          <xsl:value-of select="$date"/>
-          <xsl:text> for </xsl:text>
-          <xsl:value-of select="name(.)"/>
-        </xsl:with-param>
-      </xsl:call-template>
-
-      <xsl:copy>
-       <xsl:copy-of select="@*"/>
-       <xsl:value-of select="$date"/>
-      </xsl:copy>
-    </xsl:when>
-
-    <xsl:when test="$defaultDate != ''">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Unparseable date: </xsl:text>
-          <xsl:value-of select="normalize-space(.)"/>
-          <xsl:text> in </xsl:text>
-          <xsl:value-of select="name(.)"/>
-          <xsl:text> (Using default: </xsl:text>
-          <xsl:value-of select="$defaultDate"/>
-          <xsl:text>)</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-
-      <xsl:copy>
-       <xsl:copy-of select="@*"/>
-       <xsl:copy-of select="$defaultDate"/>
-       <xsl:comment>
-         <xsl:value-of select="."/>
-       </xsl:comment>
-      </xsl:copy>
-    </xsl:when>
-
-    <xsl:otherwise>
-      <!-- these don't really matter anymore
-           <xsl:call-template name="emit-message">
-           <xsl:with-param name="message">
-           <xsl:text>Unparseable date: </xsl:text>
-           <xsl:value-of select="normalize-space(.)"/>
-           <xsl:text> in </xsl:text>
-           <xsl:value-of select="name(.)"/>
-           </xsl:with-param>
-           </xsl:call-template>
-      -->
-      <xsl:copy>
-       <xsl:copy-of select="@*"/>
-       <xsl:apply-templates/>
-      </xsl:copy>
-    </xsl:otherwise>
-  </xsl:choose>      
-</xsl:template>
-
-<xsl:template match="title|subtitle|titleabbrev" priority="300">
-  <!-- nop -->
-</xsl:template>
-
-<xsl:template match="abstract" priority="300">
-  <xsl:if test="not(contains(name(parent::*),'info'))">
-    <xsl:call-template name="emit-message">
-      <xsl:with-param name="message">
-       <xsl:text>Check abstract; moved into info correctly?</xsl:text>
-      </xsl:with-param>
-    </xsl:call-template>
-  </xsl:if>
-</xsl:template>
-
-<xsl:template match="indexterm">
-  <!-- don't copy the defaulted significance='normal' attribute -->
-  <indexterm>
-    <xsl:call-template name="copy.attributes">
-      <xsl:with-param name="suppress">
-       <xsl:if test="@significance = 'normal'">significance</xsl:if>
-      </xsl:with-param>
-    </xsl:call-template>
-    <xsl:apply-templates/>
-  </indexterm>
-</xsl:template>
-
-<xsl:template match="ackno" priority="200">
-  <acknowledgements>
-    <xsl:copy-of select="@*"/>
-    <para>
-      <xsl:apply-templates/>
-    </para>
-  </acknowledgements>
-</xsl:template>
-
-<xsl:template match="lot|lotentry|tocback|tocchap|tocfront|toclevel1|
-                    toclevel2|toclevel3|toclevel4|toclevel5|tocpart" priority="200">
-  <tocdiv>
-    <xsl:copy-of select="@*"/>
-    <xsl:apply-templates/>
-  </tocdiv>
-</xsl:template>
-
-<xsl:template match="action" priority="200">
-  <phrase remap="action">
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </phrase>
-</xsl:template>
-
-<xsl:template match="beginpage" priority="200">
-  <xsl:comment> beginpage pagenum=<xsl:value-of select="@pagenum"/> </xsl:comment>
-  <xsl:call-template name="emit-message">
-    <xsl:with-param name="message">
-      <xsl:text>Replacing beginpage with comment</xsl:text>
-    </xsl:with-param>
-  </xsl:call-template>
-</xsl:template>
-
-<xsl:template match="structname|structfield" priority="200">
-  <varname remap="{local-name(.)}">
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </varname>
-</xsl:template>
-
-<!-- ====================================================================== -->
-
-<!-- 6 Feb 2008, ndw changed mode=copy so that it only copies the first level,
-     then it switches back to "normal" mode so that other rewriting templates
-     catch embedded fixes -->
-
-<!--
-<xsl:template match="ulink" priority="200" mode="copy">
-  <xsl:choose>
-    <xsl:when test="node()">
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Converting ulink to phrase.</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-
-      <phrase xlink:href="{@url}">
-       <xsl:call-template name="copy.attributes">
-         <xsl:with-param name="suppress" select="'url'"/>
-       </xsl:call-template>
-       <xsl:apply-templates/>
-      </phrase>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:call-template name="emit-message">
-        <xsl:with-param name="message">
-          <xsl:text>Converting ulink to uri.</xsl:text>
-        </xsl:with-param>
-      </xsl:call-template>
-
-      <uri xlink:href="{@url}">
-       <xsl:call-template name="copy.attributes">
-         <xsl:with-param name="suppress" select="'url'"/>
-       </xsl:call-template>
-       <xsl:value-of select="@url"/>
-      </uri>
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-<xsl:template match="sgmltag" priority="200" mode="copy">
-  <tag>
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </tag>
-</xsl:template>
--->
-
-<xsl:template match="*" mode="copy">
-  <xsl:copy>
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </xsl:copy>
-</xsl:template>
-
-<!--
-<xsl:template match="comment()|processing-instruction()|text()" mode="copy">
-  <xsl:copy/>
-</xsl:template>
--->
-
-<!-- ====================================================================== -->
-
-<xsl:template match="*">
-  <xsl:copy>
-    <xsl:call-template name="copy.attributes"/>
-    <xsl:apply-templates/>
-  </xsl:copy>
-</xsl:template>
-
-<xsl:template match="comment()|processing-instruction()|text()">
-  <xsl:copy/>
-</xsl:template>
-
-<!-- ====================================================================== -->
-
-<xsl:template name="copy.attributes">
-  <xsl:param name="src" select="."/>
-  <xsl:param name="suppress" select="''"/>
-
-  <xsl:for-each select="$src/@*">
-    <xsl:choose>
-      <xsl:when test="local-name(.) = 'moreinfo'">
-        <xsl:call-template name="emit-message">
-          <xsl:with-param name="message">
-            <xsl:text>Discarding moreinfo on </xsl:text>
-            <xsl:value-of select="local-name($src)"/>
-          </xsl:with-param>
-        </xsl:call-template>
-      </xsl:when>
-      <xsl:when test="local-name(.) = 'lang'">
-        <xsl:attribute name="xml:lang">
-          <xsl:value-of select="."/>
-        </xsl:attribute>
-      </xsl:when>
-      <xsl:when test="local-name(.) = 'id'">
-        <xsl:attribute name="xml:id">
-          <xsl:value-of select="."/>
-        </xsl:attribute>
-      </xsl:when>
-      <xsl:when test="$suppress = local-name(.)"/>
-      <xsl:when test="local-name(.) = 'float'">
-       <xsl:choose>
-         <xsl:when test=". = '1'">
-            <xsl:call-template name="emit-message">
-              <xsl:with-param name="message">
-                <xsl:text>Discarding float on </xsl:text>
-                <xsl:value-of select="local-name($src)"/>
-              </xsl:with-param>
-            </xsl:call-template>
-            <xsl:if test="not($src/@floatstyle)">
-             <xsl:call-template name="emit-message">
-                <xsl:with-param name="message">
-                  <xsl:text>Adding floatstyle='normal' on </xsl:text>
-                  <xsl:value-of select="local-name($src)"/>
-                </xsl:with-param>
-              </xsl:call-template>
-              <xsl:attribute name="floatstyle">
-                <xsl:text>normal</xsl:text>
-             </xsl:attribute>
-           </xsl:if>
-         </xsl:when>
-         <xsl:when test=". = '0'">
-           <xsl:call-template name="emit-message">
-              <xsl:with-param name="message">
-                <xsl:text>Discarding float on </xsl:text>
-                <xsl:value-of select="local-name($src)"/>
-              </xsl:with-param>
-            </xsl:call-template>
-          </xsl:when>
-         <xsl:otherwise>
-           <xsl:call-template name="emit-message">
-          <xsl:with-param name="message">
-            <xsl:text>Discarding float on </xsl:text>
-            <xsl:value-of select="local-name($src)"/>
-          </xsl:with-param>
-            </xsl:call-template>
-            <xsl:if test="not($src/@floatstyle)">
-              <xsl:call-template name="emit-message">
-                <xsl:with-param name="message">
-                  <xsl:text>Adding floatstyle='</xsl:text>
-                  <xsl:value-of select="."/>
-                  <xsl:text>' on </xsl:text>
-                  <xsl:value-of select="local-name($src)"/>
-                </xsl:with-param>
-              </xsl:call-template>
-              <xsl:attribute name="floatstyle">
-               <xsl:value-of select="."/>
-             </xsl:attribute>
-           </xsl:if>
-         </xsl:otherwise>
-       </xsl:choose>
-      </xsl:when>
-      <xsl:when test="local-name(.) = 'entityref'">
-       <xsl:attribute name="fileref">
-         <xsl:value-of select="unparsed-entity-uri(@entityref)"/>
-       </xsl:attribute>
-      </xsl:when>
-
-      <xsl:when test="local-name($src) = 'simplemsgentry'
-                     and local-name(.) = 'audience'">
-        <xsl:attribute name="msgaud">
-          <xsl:value-of select="."/>
-        </xsl:attribute>
-      </xsl:when>
-      <xsl:when test="local-name($src) = 'simplemsgentry'
-                     and local-name(.) = 'origin'">
-        <xsl:attribute name="msgorig">
-          <xsl:value-of select="."/>
-        </xsl:attribute>
-      </xsl:when>
-      <xsl:when test="local-name($src) = 'simplemsgentry'
-                     and local-name(.) = 'level'">
-        <xsl:attribute name="msglevel">
-          <xsl:value-of select="."/>
-        </xsl:attribute>
-      </xsl:when>
-
-      <!-- * for upgrading XSL litprog params documentation -->
-      <xsl:when test="local-name($src) = 'refmiscinfo'
-                      and local-name(.) = 'role'
-                      and . = 'type'
-                      ">
-        <xsl:call-template name="emit-message">
-          <xsl:with-param name="message">
-            <xsl:text>Converting refmiscinfo@role=type to </xsl:text>
-            <xsl:text>@class=other,otherclass=type</xsl:text>
-          </xsl:with-param>
-        </xsl:call-template>
-        <xsl:attribute name="class">other</xsl:attribute>
-        <xsl:attribute name="otherclass">type</xsl:attribute>
-      </xsl:when>
-
-      <xsl:otherwise>
-        <xsl:copy/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:for-each>
-</xsl:template>
-
-<!-- ====================================================================== -->
-
-<xsl:template match="*" mode="addNS">
-  <xsl:choose>
-    <xsl:when test="namespace-uri(.) = ''">
-      <xsl:element name="{local-name(.)}"
-                  namespace="http://docbook.org/ns/docbook">
-       <xsl:if test="not(parent::*)">
-         <xsl:attribute name="version">5.0</xsl:attribute>
-       </xsl:if>
-       <xsl:copy-of select="@*"/>
-       <xsl:apply-templates mode="addNS"/>
-      </xsl:element>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:copy>
-       <xsl:if test="not(parent::*)">
-         <xsl:attribute name="version">5.0</xsl:attribute>
-       </xsl:if>
-       <xsl:copy-of select="@*"/>
-       <xsl:apply-templates mode="addNS"/>
-      </xsl:copy>
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-<xsl:template match="comment()|processing-instruction()|text()" mode="addNS">
-  <xsl:copy/>
-</xsl:template>
-
-<!-- ====================================================================== -->
-
-<xsl:template name="emit-message">
-  <xsl:param name="message"/>
-  <xsl:message>
-    <xsl:value-of select="$message"/>
-    <xsl:text> (</xsl:text>
-    <xsl:value-of select="$rootid"/>
-    <xsl:text>)</xsl:text>
-  </xsl:message>
-</xsl:template>
-
-</xsl:stylesheet>
diff --git a/org.argeo.app.core/src/org/argeo/docbook/docbook-full.cnd b/org.argeo.app.core/src/org/argeo/docbook/docbook-full.cnd
deleted file mode 100644 (file)
index 79c3882..0000000
+++ /dev/null
@@ -1,2998 +0,0 @@
-<dbk = 'http://docbook.org/ns/docbook'>
-<argeodbk = 'http://www.argeo.org/ns/argeodbk'>
-<xlink = 'http://www.w3.org/1999/xlink'>
-//<xs = 'http://www.w3.org/2001/XMLSchema'>
-
-[argeodbk:titled]
-mixin
- + dbk:info (dbk:info) = dbk:info *
- + dbk:title (dbk:title) = dbk:title *
- + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
-
-[argeodbk:linkingAttributes]
-mixin
- - linkend (String)
- - xlink:actuate (String)
- - xlink:arcrole (String)
- - xlink:href (String)
- - xlink:role (String)
- - xlink:show (String)
- - xlink:title (String)
- - xlink:type (String)
-
-[argeodbk:freeText]
-mixin
- + dbk:phrase (dbk:phrase) = dbk:phrase *
- + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[argeodbk:markupInlines]
-mixin
- + dbk:code (dbk:code) = dbk:code *
- + dbk:constant (dbk:constant) = dbk:constant *
- + dbk:email (dbk:email) = dbk:email *
- + dbk:literal (dbk:literal) = dbk:literal *
- + dbk:markup (dbk:markup) = dbk:markup *
- + dbk:symbol (dbk:symbol) = dbk:symbol *
- + dbk:tag (dbk:tag) = dbk:tag *
- + dbk:token (dbk:token) = dbk:token *
- + dbk:uri (dbk:uri) = dbk:uri *
-
-[argeodbk:listElements]
-mixin
- + dbk:bibliolist (dbk:bibliolist) = dbk:bibliolist *
- + dbk:calloutlist (dbk:calloutlist) = dbk:calloutlist *
- + dbk:glosslist (dbk:glosslist) = dbk:glosslist *
- + dbk:itemizedlist (dbk:itemizedlist) = dbk:itemizedlist *
- + dbk:orderedlist (dbk:orderedlist) = dbk:orderedlist *
- + dbk:procedure (dbk:procedure) = dbk:procedure *
- + dbk:qandaset (dbk:qandaset) = dbk:qandaset *
- + dbk:segmentedlist (dbk:segmentedlist) = dbk:segmentedlist *
- + dbk:simplelist (dbk:simplelist) = dbk:simplelist *
- + dbk:variablelist (dbk:variablelist) = dbk:variablelist *
-
-[argeodbk:paragraphElements]
-mixin
- + dbk:formalpara (dbk:formalpara) = dbk:formalpara *
- + dbk:para (dbk:para) = dbk:para *
- + dbk:simpara (dbk:simpara) = dbk:simpara *
-
-[argeodbk:indexingInlines]
-mixin
- + dbk:indexterm (dbk:indexterm) = dbk:indexterm *
-
-[argeodbk:techDocElements]
-mixin
- + dbk:caution (dbk:caution) = dbk:caution *
- + dbk:classsynopsis (dbk:classsynopsis) = dbk:classsynopsis *
- + dbk:cmdsynopsis (dbk:cmdsynopsis) = dbk:cmdsynopsis *
- + dbk:constraintdef (dbk:constraintdef) = dbk:constraintdef *
- + dbk:constructorsynopsis (dbk:constructorsynopsis) = dbk:constructorsynopsis *
- + dbk:destructorsynopsis (dbk:destructorsynopsis) = dbk:destructorsynopsis *
- + dbk:equation (dbk:equation) = dbk:equation *
- + dbk:example (dbk:example) = dbk:example *
- + dbk:fieldsynopsis (dbk:fieldsynopsis) = dbk:fieldsynopsis *
- + dbk:figure (dbk:figure) = dbk:figure *
- + dbk:funcsynopsis (dbk:funcsynopsis) = dbk:funcsynopsis *
- + dbk:important (dbk:important) = dbk:important *
- + dbk:informalequation (dbk:informalequation) = dbk:informalequation *
- + dbk:informalexample (dbk:informalexample) = dbk:informalexample *
- + dbk:informalfigure (dbk:informalfigure) = dbk:informalfigure *
- + dbk:informaltable (dbk:informaltable) = dbk:informaltable *
- + dbk:literallayout (dbk:literallayout) = dbk:literallayout *
- + dbk:methodsynopsis (dbk:methodsynopsis) = dbk:methodsynopsis *
- + dbk:msgset (dbk:msgset) = dbk:msgset *
- + dbk:note (dbk:note) = dbk:note *
- + dbk:productionset (dbk:productionset) = dbk:productionset *
- + dbk:programlisting (dbk:programlisting) = dbk:programlisting *
- + dbk:programlistingco (dbk:programlistingco) = dbk:programlistingco *
- + dbk:screen (dbk:screen) = dbk:screen *
- + dbk:screenco (dbk:screenco) = dbk:screenco *
- + dbk:synopsis (dbk:synopsis) = dbk:synopsis *
- + dbk:table (dbk:table) = dbk:table *
- + dbk:task (dbk:task) = dbk:task *
- + dbk:tip (dbk:tip) = dbk:tip *
- + dbk:warning (dbk:warning) = dbk:warning *
-
-[argeodbk:techDocInlines]
-mixin
- + dbk:accel (dbk:accel) = dbk:accel *
- + dbk:application (dbk:application) = dbk:application *
- + dbk:classname (dbk:classname) = dbk:classname *
- + dbk:command (dbk:command) = dbk:command *
- + dbk:computeroutput (dbk:computeroutput) = dbk:computeroutput *
- + dbk:database (dbk:database) = dbk:database *
- + dbk:envar (dbk:envar) = dbk:envar *
- + dbk:errorcode (dbk:errorcode) = dbk:errorcode *
- + dbk:errorname (dbk:errorname) = dbk:errorname *
- + dbk:errortext (dbk:errortext) = dbk:errortext *
- + dbk:errortype (dbk:errortype) = dbk:errortype *
- + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
- + dbk:filename (dbk:filename) = dbk:filename *
- + dbk:function (dbk:function) = dbk:function *
- + dbk:guibutton (dbk:guibutton) = dbk:guibutton *
- + dbk:guiicon (dbk:guiicon) = dbk:guiicon *
- + dbk:guilabel (dbk:guilabel) = dbk:guilabel *
- + dbk:guimenu (dbk:guimenu) = dbk:guimenu *
- + dbk:guimenuitem (dbk:guimenuitem) = dbk:guimenuitem *
- + dbk:guisubmenu (dbk:guisubmenu) = dbk:guisubmenu *
- + dbk:hardware (dbk:hardware) = dbk:hardware *
- + dbk:initializer (dbk:initializer) = dbk:initializer *
- + dbk:inlineequation (dbk:inlineequation) = dbk:inlineequation *
- + dbk:interfacename (dbk:interfacename) = dbk:interfacename *
- + dbk:keycap (dbk:keycap) = dbk:keycap *
- + dbk:keycode (dbk:keycode) = dbk:keycode *
- + dbk:keycombo (dbk:keycombo) = dbk:keycombo *
- + dbk:keysym (dbk:keysym) = dbk:keysym *
- + dbk:menuchoice (dbk:menuchoice) = dbk:menuchoice *
- + dbk:methodname (dbk:methodname) = dbk:methodname *
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:mousebutton (dbk:mousebutton) = dbk:mousebutton *
- + dbk:nonterminal (dbk:nonterminal) = dbk:nonterminal *
- + dbk:ooclass (dbk:ooclass) = dbk:ooclass *
- + dbk:ooexception (dbk:ooexception) = dbk:ooexception *
- + dbk:oointerface (dbk:oointerface) = dbk:oointerface *
- + dbk:option (dbk:option) = dbk:option *
- + dbk:optional (dbk:optional) = dbk:optional *
- + dbk:package (dbk:package) = dbk:package *
- + dbk:parameter (dbk:parameter) = dbk:parameter *
- + dbk:productname (dbk:productname) = dbk:productname *
- + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
- + dbk:prompt (dbk:prompt) = dbk:prompt *
- + dbk:property (dbk:property) = dbk:property *
- + dbk:returnvalue (dbk:returnvalue) = dbk:returnvalue *
- + dbk:shortcut (dbk:shortcut) = dbk:shortcut *
- + dbk:systemitem (dbk:systemitem) = dbk:systemitem *
- + dbk:termdef (dbk:termdef) = dbk:termdef *
- + dbk:trademark (dbk:trademark) = dbk:trademark *
- + dbk:type (dbk:type) = dbk:type *
- + dbk:userinput (dbk:userinput) = dbk:userinput *
- + dbk:varname (dbk:varname) = dbk:varname *
-
-[argeodbk:publishingElements]
-mixin
- + dbk:address (dbk:address) = dbk:address *
- + dbk:blockquote (dbk:blockquote) = dbk:blockquote *
- + dbk:epigraph (dbk:epigraph) = dbk:epigraph *
- + dbk:sidebar (dbk:sidebar) = dbk:sidebar *
-
-[argeodbk:ubiquitousInlines]
-mixin
- + dbk:alt (dbk:alt) = dbk:alt *
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:biblioref (dbk:biblioref) = dbk:biblioref *
- + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
- + dbk:link (dbk:link) = dbk:link *
- + dbk:olink (dbk:olink) = dbk:olink *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:subscript (dbk:subscript) = dbk:subscript *
- + dbk:superscript (dbk:superscript) = dbk:superscript *
- + dbk:xref (dbk:xref) = dbk:xref *
-
-[argeodbk:abstractSection]
-mixin
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bibliography (dbk:bibliography) = dbk:bibliography *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:glossary (dbk:glossary) = dbk:glossary *
- + dbk:index (dbk:index) = dbk:index *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:toc (dbk:toc) = dbk:toc *
- - label (String)
- - status (String)
-
-[argeodbk:bibliographyInlines]
-mixin
- + dbk:author (dbk:author) = dbk:author *
- + dbk:citation (dbk:citation) = dbk:citation *
- + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
- + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
- + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:jobtitle (dbk:jobtitle) = dbk:jobtitle *
- + dbk:org (dbk:org) = dbk:org *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:person (dbk:person) = dbk:person *
- + dbk:personname (dbk:personname) = dbk:personname *
-
-[argeodbk:publishingInlines]
-mixin
- + dbk:abbrev (dbk:abbrev) = dbk:abbrev *
- + dbk:acronym (dbk:acronym) = dbk:acronym *
- + dbk:coref (dbk:coref) = dbk:coref *
- + dbk:date (dbk:date) = dbk:date *
- + dbk:emphasis (dbk:emphasis) = dbk:emphasis *
- + dbk:firstterm (dbk:firstterm) = dbk:firstterm *
- + dbk:footnote (dbk:footnote) = dbk:footnote *
- + dbk:footnoteref (dbk:footnoteref) = dbk:footnoteref *
- + dbk:foreignphrase (dbk:foreignphrase) = dbk:foreignphrase *
- + dbk:glossterm (dbk:glossterm) = dbk:glossterm *
- + dbk:quote (dbk:quote) = dbk:quote *
- + dbk:wordasword (dbk:wordasword) = dbk:wordasword *
-
-[argeodbk:base]
-abstract
-orderable
- - annotations (String)
- - arch (String)
- - audience (String)
- - condition (String)
- - conformance (String)
- - dir (String)
- - os (String)
- - remap (String)
- - revision (String)
- - revisionflag (String)
- - role (String)
- - security (String)
- - userlevel (String)
- - vendor (String)
- - version (String)
- - wordsize (String)
- - xreflabel (String)
-
-[dbk:abbrev] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:trademark (dbk:trademark) = dbk:trademark *
-
-[dbk:abstract] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
-
-[dbk:accel] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:acknowledgements] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:acronym] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:trademark (dbk:trademark) = dbk:trademark *
-
-[dbk:address] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:city (dbk:city) = dbk:city *
- + dbk:country (dbk:country) = dbk:country *
- + dbk:email (dbk:email) = dbk:email *
- + dbk:fax (dbk:fax) = dbk:fax *
- + dbk:otheraddr (dbk:otheraddr) = dbk:otheraddr *
- + dbk:personname (dbk:personname) = dbk:personname *
- + dbk:phone (dbk:phone) = dbk:phone *
- + dbk:pob (dbk:pob) = dbk:pob *
- + dbk:postcode (dbk:postcode) = dbk:postcode *
- + dbk:state (dbk:state) = dbk:state *
- + dbk:street (dbk:street) = dbk:street *
- + dbk:uri (dbk:uri) = dbk:uri *
- - continuation (String) 
- - language (String) 
- - linenumbering (String) 
- - startinglinenumber (String) 
- - xml:space (String) 
-
-[dbk:affiliation] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:address (dbk:address) = dbk:address *
- + dbk:jobtitle (dbk:jobtitle) = dbk:jobtitle *
- + dbk:org (dbk:org) = dbk:org
- + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
- + dbk:orgname (dbk:orgname) = dbk:orgname
- + dbk:shortaffil (dbk:shortaffil) = dbk:shortaffil
-
-[dbk:alt] > argeodbk:base
- + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:anchor] > argeodbk:base
-
-[dbk:annotation] > argeodbk:base, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - annotates (String) 
-
-[dbk:answer] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:label (dbk:label) = dbk:label
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:appendix] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refentry (dbk:refentry) = dbk:refentry *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect1 (dbk:sect1) = dbk:sect1 *
- + dbk:section (dbk:section) = dbk:section *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:application] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
-
-[dbk:arc] > argeodbk:base
- - xlink:from (String) 
- - xlink:to (String) 
-
-[dbk:area] > argeodbk:base
- + dbk:alt (dbk:alt) = dbk:alt
- - coords (String) 
- - label (String) 
- - linkends (String) 
- - otherunits (String) 
- - units (String) 
-
-[dbk:areaset] > argeodbk:base
- + dbk:area (dbk:area) = dbk:area *
- - label (String) 
- - linkends (String) 
- - otherunits (String) 
- - units (String) 
-
-[dbk:areaspec] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:area (dbk:area) = dbk:area *
- + dbk:areaset (dbk:areaset) = dbk:areaset *
- - otherunits (String) 
- - units (String) 
-
-[dbk:arg] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:arg (dbk:arg) = dbk:arg *
- + dbk:group (dbk:group) = dbk:group *
- + dbk:option (dbk:option) = dbk:option *
- + dbk:sbr (dbk:sbr) = dbk:sbr *
- + dbk:synopfragmentref (dbk:synopfragmentref) = dbk:synopfragmentref *
- - choice (String) 
- - rep (String) 
-
-[dbk:article] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:acknowledgements (dbk:acknowledgements) = dbk:acknowledgements *
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:appendix (dbk:appendix) = dbk:appendix *
- + dbk:colophon (dbk:colophon) = dbk:colophon *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refentry (dbk:refentry) = dbk:refentry *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect1 (dbk:sect1) = dbk:sect1 *
- + dbk:section (dbk:section) = dbk:section *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- - class (String) 
-
-[dbk:artpagenums] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:attribution] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:citation (dbk:citation) = dbk:citation *
- + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
- + dbk:person (dbk:person) = dbk:person *
- + dbk:personname (dbk:personname) = dbk:personname *
-
-[dbk:audiodata] > argeodbk:base
- + dbk:info (dbk:info) = dbk:info
- - entityref (String) 
- - fileref (String) 
- - format (String) 
-
-[dbk:audioobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:audiodata (dbk:audiodata) = dbk:audiodata
- + dbk:info (dbk:info) = dbk:info
-
-[dbk:author] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:address (dbk:address) = dbk:address *
- + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
- + dbk:contrib (dbk:contrib) = dbk:contrib *
- + dbk:email (dbk:email) = dbk:email *
- + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
- + dbk:orgname (dbk:orgname) = dbk:orgname
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname
- + dbk:uri (dbk:uri) = dbk:uri *
-
-[dbk:authorgroup] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:author (dbk:author) = dbk:author *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
-
-[dbk:authorinitials] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:bibliocoverage] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - otherspatial (String) 
- - othertemporal (String) 
- - spatial (String) 
- - temporal (String) 
-
-[dbk:bibliodiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:biblioentry (dbk:biblioentry) = dbk:biblioentry *
- + dbk:bibliomixed (dbk:bibliomixed) = dbk:bibliomixed *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:biblioentry] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:publishingInlines
- + dbk:abstract (dbk:abstract) = dbk:abstract *
- + dbk:address (dbk:address) = dbk:address *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
- + dbk:author (dbk:author) = dbk:author *
- + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
- + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
- + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
- + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
- + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
- + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
- + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
- + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
- + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
- + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
- + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
- + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
- + dbk:collab (dbk:collab) = dbk:collab *
- + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
- + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
- + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
- + dbk:copyright (dbk:copyright) = dbk:copyright *
- + dbk:cover (dbk:cover) = dbk:cover *
- + dbk:edition (dbk:edition) = dbk:edition *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
- + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
- + dbk:itermset (dbk:itermset) = dbk:itermset *
- + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
- + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:org (dbk:org) = dbk:org *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
- + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
- + dbk:person (dbk:person) = dbk:person *
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname *
- + dbk:phrase (dbk:phrase) = dbk:phrase *
- + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
- + dbk:productname (dbk:productname) = dbk:productname *
- + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
- + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
- + dbk:publisher (dbk:publisher) = dbk:publisher *
- + dbk:publishername (dbk:publishername) = dbk:publishername *
- + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
- + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
- + dbk:subscript (dbk:subscript) = dbk:subscript *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:superscript (dbk:superscript) = dbk:superscript *
- + dbk:title (dbk:title) = dbk:title *
- + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
- + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
-
-[dbk:bibliography] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bibliodiv (dbk:bibliodiv) = dbk:bibliodiv *
- + dbk:biblioentry (dbk:biblioentry) = dbk:biblioentry *
- + dbk:bibliomixed (dbk:bibliomixed) = dbk:bibliomixed *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:biblioid] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - otherclass (String) 
-
-[dbk:bibliolist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:biblioentry (dbk:biblioentry) = dbk:biblioentry *
- + dbk:bibliomixed (dbk:bibliomixed) = dbk:bibliomixed *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:bibliomisc] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:bibliomixed] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:publishingInlines
- + dbk:abstract (dbk:abstract) = dbk:abstract *
- + dbk:address (dbk:address) = dbk:address *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
- + dbk:author (dbk:author) = dbk:author *
- + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
- + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
- + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
- + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
- + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
- + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
- + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
- + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
- + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
- + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
- + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
- + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
- + dbk:collab (dbk:collab) = dbk:collab *
- + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
- + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
- + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
- + dbk:copyright (dbk:copyright) = dbk:copyright *
- + dbk:cover (dbk:cover) = dbk:cover *
- + dbk:edition (dbk:edition) = dbk:edition *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
- + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
- + dbk:itermset (dbk:itermset) = dbk:itermset *
- + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
- + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:org (dbk:org) = dbk:org *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
- + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
- + dbk:person (dbk:person) = dbk:person *
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname *
- + dbk:phrase (dbk:phrase) = dbk:phrase *
- + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
- + dbk:productname (dbk:productname) = dbk:productname *
- + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
- + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
- + dbk:publisher (dbk:publisher) = dbk:publisher *
- + dbk:publishername (dbk:publishername) = dbk:publishername *
- + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
- + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
- + dbk:subscript (dbk:subscript) = dbk:subscript *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:superscript (dbk:superscript) = dbk:superscript *
- + dbk:title (dbk:title) = dbk:title *
- + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
- + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:bibliomset] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:publishingInlines, argeodbk:ubiquitousInlines
- + dbk:abstract (dbk:abstract) = dbk:abstract *
- + dbk:address (dbk:address) = dbk:address *
- + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
- + dbk:author (dbk:author) = dbk:author *
- + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
- + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
- + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
- + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
- + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
- + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
- + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
- + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
- + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
- + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
- + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
- + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
- + dbk:collab (dbk:collab) = dbk:collab *
- + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
- + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
- + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
- + dbk:copyright (dbk:copyright) = dbk:copyright *
- + dbk:cover (dbk:cover) = dbk:cover *
- + dbk:edition (dbk:edition) = dbk:edition *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
- + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
- + dbk:itermset (dbk:itermset) = dbk:itermset *
- + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
- + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:org (dbk:org) = dbk:org *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
- + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
- + dbk:person (dbk:person) = dbk:person *
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname *
- + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
- + dbk:productname (dbk:productname) = dbk:productname *
- + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
- + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
- + dbk:publisher (dbk:publisher) = dbk:publisher *
- + dbk:publishername (dbk:publishername) = dbk:publishername *
- + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
- + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:title (dbk:title) = dbk:title *
- + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
- + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
- - relation (String) 
-
-[dbk:biblioref] > argeodbk:base, argeodbk:linkingAttributes
- - begin (String) 
- - end (String) 
- - endterm (Reference) 
- - units (String) 
- - xrefstyle (String) 
-
-[dbk:bibliorelation] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - otherclass (String) 
- - othertype (String) 
- - type (String) 
-
-[dbk:biblioset] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:publishingInlines
- + dbk:abstract (dbk:abstract) = dbk:abstract *
- + dbk:address (dbk:address) = dbk:address *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
- + dbk:author (dbk:author) = dbk:author *
- + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
- + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
- + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
- + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
- + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
- + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
- + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
- + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
- + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
- + dbk:citebiblioid (dbk:citebiblioid) = dbk:citebiblioid *
- + dbk:citerefentry (dbk:citerefentry) = dbk:citerefentry *
- + dbk:citetitle (dbk:citetitle) = dbk:citetitle *
- + dbk:collab (dbk:collab) = dbk:collab *
- + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
- + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
- + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
- + dbk:copyright (dbk:copyright) = dbk:copyright *
- + dbk:cover (dbk:cover) = dbk:cover *
- + dbk:edition (dbk:edition) = dbk:edition *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
- + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
- + dbk:itermset (dbk:itermset) = dbk:itermset *
- + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
- + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:org (dbk:org) = dbk:org *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
- + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
- + dbk:person (dbk:person) = dbk:person *
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname *
- + dbk:phrase (dbk:phrase) = dbk:phrase *
- + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
- + dbk:productname (dbk:productname) = dbk:productname *
- + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
- + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
- + dbk:publisher (dbk:publisher) = dbk:publisher *
- + dbk:publishername (dbk:publishername) = dbk:publishername *
- + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
- + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
- + dbk:subscript (dbk:subscript) = dbk:subscript *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:superscript (dbk:superscript) = dbk:superscript *
- + dbk:title (dbk:title) = dbk:title *
- + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
- + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
- - relation (String) 
-
-[dbk:bibliosource] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - otherclass (String) 
-
-[dbk:blockquote] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:attribution (dbk:attribution) = dbk:attribution
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:book] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:acknowledgements (dbk:acknowledgements) = dbk:acknowledgements *
- + dbk:appendix (dbk:appendix) = dbk:appendix *
- + dbk:article (dbk:article) = dbk:article *
- + dbk:bibliography (dbk:bibliography) = dbk:bibliography *
- + dbk:chapter (dbk:chapter) = dbk:chapter *
- + dbk:colophon (dbk:colophon) = dbk:colophon *
- + dbk:dedication (dbk:dedication) = dbk:dedication *
- + dbk:glossary (dbk:glossary) = dbk:glossary *
- + dbk:index (dbk:index) = dbk:index *
- + dbk:part (dbk:part) = dbk:part *
- + dbk:preface (dbk:preface) = dbk:preface *
- + dbk:reference (dbk:reference) = dbk:reference *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:toc (dbk:toc) = dbk:toc *
- - label (String) 
- - status (String) 
-
-[dbk:bridgehead] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - otherrenderas (String) 
- - renderas (String) 
-
-[dbk:callout] > argeodbk:base, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - arearefs (String) 
-
-[dbk:calloutlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:callout (dbk:callout) = dbk:callout *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:caption] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
- - class (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - style (String) 
- - title (String) 
-
-[dbk:caution] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:chapter] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refentry (dbk:refentry) = dbk:refentry *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect1 (dbk:sect1) = dbk:sect1 *
- + dbk:section (dbk:section) = dbk:section *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:citation] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:citebiblioid] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - otherclass (String) 
-
-[dbk:citerefentry] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:manvolnum (dbk:manvolnum) = dbk:manvolnum
- + dbk:refentrytitle (dbk:refentrytitle) = dbk:refentrytitle
-
-[dbk:citetitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - pubwork (String) 
-
-[dbk:city] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:classname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:classsynopsis] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:classsynopsisinfo (dbk:classsynopsisinfo) = dbk:classsynopsisinfo *
- + dbk:constructorsynopsis (dbk:constructorsynopsis) = dbk:constructorsynopsis *
- + dbk:destructorsynopsis (dbk:destructorsynopsis) = dbk:destructorsynopsis *
- + dbk:fieldsynopsis (dbk:fieldsynopsis) = dbk:fieldsynopsis *
- + dbk:methodsynopsis (dbk:methodsynopsis) = dbk:methodsynopsis *
- + dbk:ooclass (dbk:ooclass) = dbk:ooclass *
- + dbk:ooexception (dbk:ooexception) = dbk:ooexception *
- + dbk:oointerface (dbk:oointerface) = dbk:oointerface *
- - class (String) 
- - language (String) 
-
-[dbk:classsynopsisinfo] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- + dbk:info (dbk:info) = dbk:info *
- + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- - continuation (String) 
- - language (String) 
- - linenumbering (String) 
- - startinglinenumber (String) 
- - xml:space (String) 
-
-[dbk:cmdsynopsis] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:arg (dbk:arg) = dbk:arg *
- + dbk:command (dbk:command) = dbk:command *
- + dbk:group (dbk:group) = dbk:group *
- + dbk:info (dbk:info) = dbk:info
- + dbk:sbr (dbk:sbr) = dbk:sbr *
- + dbk:synopfragment (dbk:synopfragment) = dbk:synopfragment *
- - cmdlength (String) 
- - label (String) 
- - sepchar (String) 
-
-[dbk:co] > argeodbk:base
- - label (String) 
- - linkends (String) 
-
-[dbk:code] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:classname (dbk:classname) = dbk:classname *
- + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
- + dbk:function (dbk:function) = dbk:function *
- + dbk:initializer (dbk:initializer) = dbk:initializer *
- + dbk:interfacename (dbk:interfacename) = dbk:interfacename *
- + dbk:methodname (dbk:methodname) = dbk:methodname *
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:ooclass (dbk:ooclass) = dbk:ooclass *
- + dbk:ooexception (dbk:ooexception) = dbk:ooexception *
- + dbk:oointerface (dbk:oointerface) = dbk:oointerface *
- + dbk:parameter (dbk:parameter) = dbk:parameter *
- + dbk:returnvalue (dbk:returnvalue) = dbk:returnvalue *
- + dbk:type (dbk:type) = dbk:type *
- + dbk:varname (dbk:varname) = dbk:varname *
- - language (String) 
-
-[dbk:col] > nt:base
- - align (String) 
- - annotations (String) 
- - arch (String) 
- - audience (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - condition (String) 
- - conformance (String) 
- - dir (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - os (String) 
- - remap (String) 
- - revision (String) 
- - revisionflag (String) 
- - security (String) 
- - span (String) 
- - style (String) 
- - title (String) 
- - userlevel (String) 
- - valign (String) 
- - vendor (String) 
- - version (String) 
- - width (String) 
- - wordsize (String) 
- - xreflabel (String) 
- - xml:base (String) 
- - xml:id (String) 
- - xml:lang (String) 
-
-[dbk:colgroup] > nt:base
- + dbk:col (dbk:col) = dbk:col *
- - align (String) 
- - annotations (String) 
- - arch (String) 
- - audience (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - condition (String) 
- - conformance (String) 
- - dir (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - os (String) 
- - remap (String) 
- - revision (String) 
- - revisionflag (String) 
- - security (String) 
- - span (String) 
- - style (String) 
- - title (String) 
- - userlevel (String) 
- - valign (String) 
- - vendor (String) 
- - version (String) 
- - width (String) 
- - wordsize (String) 
- - xreflabel (String) 
- - xml:base (String) 
- - xml:id (String) 
- - xml:lang (String) 
-
-[dbk:collab] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
- + dbk:org (dbk:org) = dbk:org *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:person (dbk:person) = dbk:person *
- + dbk:personname (dbk:personname) = dbk:personname *
-
-[dbk:colophon] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:colspec] > argeodbk:base, argeodbk:linkingAttributes
- - align (String) 
- - char (String) 
- - charoff (String) 
- - colname (String) 
- - colnum (String) 
- - colsep (String) 
- - colwidth (String) 
- - rowsep (String) 
-
-[dbk:command] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:computeroutput] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- + dbk:command (dbk:command) = dbk:command *
- + dbk:computeroutput (dbk:computeroutput) = dbk:computeroutput *
- + dbk:envar (dbk:envar) = dbk:envar *
- + dbk:filename (dbk:filename) = dbk:filename *
- + dbk:nonterminal (dbk:nonterminal) = dbk:nonterminal *
- + dbk:option (dbk:option) = dbk:option *
- + dbk:optional (dbk:optional) = dbk:optional *
- + dbk:package (dbk:package) = dbk:package *
- + dbk:parameter (dbk:parameter) = dbk:parameter *
- + dbk:prompt (dbk:prompt) = dbk:prompt *
- + dbk:property (dbk:property) = dbk:property *
- + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
- + dbk:systemitem (dbk:systemitem) = dbk:systemitem *
- + dbk:termdef (dbk:termdef) = dbk:termdef *
- + dbk:userinput (dbk:userinput) = dbk:userinput *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:confdates] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:confgroup] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:address (dbk:address) = dbk:address *
- + dbk:confdates (dbk:confdates) = dbk:confdates *
- + dbk:confnum (dbk:confnum) = dbk:confnum *
- + dbk:confsponsor (dbk:confsponsor) = dbk:confsponsor *
- + dbk:conftitle (dbk:conftitle) = dbk:conftitle *
-
-[dbk:confnum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:confsponsor] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:conftitle] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:constant] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
-
-[dbk:constraint] > argeodbk:base, argeodbk:linkingAttributes
-
-[dbk:constraintdef] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:constructorsynopsis] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
- + dbk:methodname (dbk:methodname) = dbk:methodname
- + dbk:methodparam (dbk:methodparam) = dbk:methodparam *
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:void (dbk:void) = dbk:void
- - language (String) 
-
-[dbk:contractnum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:contractsponsor] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:contrib] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:copyright] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:holder (dbk:holder) = dbk:holder *
- + dbk:year (dbk:year) = dbk:year *
-
-[dbk:coref] > argeodbk:base, argeodbk:linkingAttributes
- - label (String) 
-
-[dbk:country] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:cover] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:classsynopsis (dbk:classsynopsis) = dbk:classsynopsis *
- + dbk:cmdsynopsis (dbk:cmdsynopsis) = dbk:cmdsynopsis *
- + dbk:constraintdef (dbk:constraintdef) = dbk:constraintdef *
- + dbk:constructorsynopsis (dbk:constructorsynopsis) = dbk:constructorsynopsis *
- + dbk:destructorsynopsis (dbk:destructorsynopsis) = dbk:destructorsynopsis *
- + dbk:fieldsynopsis (dbk:fieldsynopsis) = dbk:fieldsynopsis *
- + dbk:funcsynopsis (dbk:funcsynopsis) = dbk:funcsynopsis *
- + dbk:informalequation (dbk:informalequation) = dbk:informalequation *
- + dbk:informalexample (dbk:informalexample) = dbk:informalexample *
- + dbk:informalfigure (dbk:informalfigure) = dbk:informalfigure *
- + dbk:informaltable (dbk:informaltable) = dbk:informaltable *
- + dbk:literallayout (dbk:literallayout) = dbk:literallayout *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:methodsynopsis (dbk:methodsynopsis) = dbk:methodsynopsis *
- + dbk:msgset (dbk:msgset) = dbk:msgset *
- + dbk:productionset (dbk:productionset) = dbk:productionset *
- + dbk:programlisting (dbk:programlisting) = dbk:programlisting *
- + dbk:programlistingco (dbk:programlistingco) = dbk:programlistingco *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screen (dbk:screen) = dbk:screen *
- + dbk:screenco (dbk:screenco) = dbk:screenco *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:synopsis (dbk:synopsis) = dbk:synopsis *
- + dbk:task (dbk:task) = dbk:task *
-
-[dbk:database] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
-
-[dbk:date] > argeodbk:base, argeodbk:linkingAttributes
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:dedication] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:destructorsynopsis] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
- + dbk:methodname (dbk:methodname) = dbk:methodname
- + dbk:methodparam (dbk:methodparam) = dbk:methodparam *
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:void (dbk:void) = dbk:void
- - language (String) 
-
-[dbk:edition] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:editor] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:address (dbk:address) = dbk:address *
- + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
- + dbk:contrib (dbk:contrib) = dbk:contrib *
- + dbk:email (dbk:email) = dbk:email *
- + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
- + dbk:orgname (dbk:orgname) = dbk:orgname
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname
- + dbk:uri (dbk:uri) = dbk:uri *
-
-[dbk:email] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:emphasis] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:entry] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:markupInlines, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - align (String) 
- - char (String) 
- - charoff (String) 
- - colname (String) 
- - colsep (String) 
- - morerows (String) 
- - nameend (String) 
- - namest (String) 
- - rotate (String) 
- - rowsep (String) 
- - spanname (String) 
- - valign (String) 
-
-[dbk:entrytbl] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:colspec (dbk:colspec) = dbk:colspec *
- + dbk:spanspec (dbk:spanspec) = dbk:spanspec *
- + dbk:tbody (dbk:tbody) = dbk:tbody
- + dbk:thead (dbk:thead) = dbk:thead
- - align (String) 
- - char (String) 
- - charoff (String) 
- - colname (String) 
- - cols (String) 
- - colsep (String) 
- - nameend (String) 
- - namest (String) 
- - rowsep (String) 
- - spanname (String) 
- - tgroupstyle (String) 
-
-[dbk:envar] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:epigraph] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:attribution (dbk:attribution) = dbk:attribution
- + dbk:info (dbk:info) = dbk:info
- + dbk:literallayout (dbk:literallayout) = dbk:literallayout *
-
-[dbk:equation] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:alt (dbk:alt) = dbk:alt
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:mathphrase (dbk:mathphrase) = dbk:mathphrase *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- - floatstyle (String) 
- - label (String) 
- - pgwide (String) 
-
-[dbk:errorcode] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:errorname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:errortext] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:errortype] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:example] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - floatstyle (String) 
- - label (String) 
- - pgwide (String) 
- - width (String) 
-
-[dbk:exceptionname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:extendedlink] > argeodbk:base
- + dbk:arc (dbk:arc) = dbk:arc *
- + dbk:locator (dbk:locator) = dbk:locator *
-
-[dbk:fax] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:fieldsynopsis] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:initializer (dbk:initializer) = dbk:initializer
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:type (dbk:type) = dbk:type
- + dbk:varname (dbk:varname) = dbk:varname
- - language (String) 
-
-[dbk:figure] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - floatstyle (String) 
- - label (String) 
- - pgwide (String) 
-
-[dbk:filename] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - path (String) 
-
-[dbk:firstname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:firstterm] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - baseform (String) 
-
-[dbk:footnote] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - label (String) 
-
-[dbk:footnoteref] > argeodbk:base, argeodbk:linkingAttributes
- - label (String) 
-
-[dbk:foreignphrase] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:publishingInlines
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:application (dbk:application) = dbk:application *
- + dbk:biblioref (dbk:biblioref) = dbk:biblioref *
- + dbk:database (dbk:database) = dbk:database *
- + dbk:hardware (dbk:hardware) = dbk:hardware *
- + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
- + dbk:link (dbk:link) = dbk:link *
- + dbk:olink (dbk:olink) = dbk:olink *
- + dbk:phrase (dbk:phrase) = dbk:phrase *
- + dbk:productname (dbk:productname) = dbk:productname *
- + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
- + dbk:subscript (dbk:subscript) = dbk:subscript *
- + dbk:superscript (dbk:superscript) = dbk:superscript *
- + dbk:trademark (dbk:trademark) = dbk:trademark *
- + dbk:xref (dbk:xref) = dbk:xref *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:formalpara] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:para (dbk:para) = dbk:para
-
-[dbk:funcdef] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:function (dbk:function) = dbk:function *
- + dbk:type (dbk:type) = dbk:type *
-
-[dbk:funcparams] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:funcprototype] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:funcdef (dbk:funcdef) = dbk:funcdef
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:paramdef (dbk:paramdef) = dbk:paramdef *
- + dbk:varargs (dbk:varargs) = dbk:varargs
- + dbk:varargs (dbk:varargs) = dbk:varargs
- + dbk:void (dbk:void) = dbk:void
-
-[dbk:funcsynopsis] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:funcprototype (dbk:funcprototype) = dbk:funcprototype *
- + dbk:funcsynopsisinfo (dbk:funcsynopsisinfo) = dbk:funcsynopsisinfo *
- + dbk:info (dbk:info) = dbk:info
- - language (String) 
-
-[dbk:funcsynopsisinfo] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- + dbk:info (dbk:info) = dbk:info *
- + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- - continuation (String) 
- - language (String) 
- - linenumbering (String) 
- - startinglinenumber (String) 
- - xml:space (String) 
-
-[dbk:function] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:glossary] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bibliography (dbk:bibliography) = dbk:bibliography
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:glossdiv (dbk:glossdiv) = dbk:glossdiv *
- + dbk:glossentry (dbk:glossentry) = dbk:glossentry *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:glossdef] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:glossseealso (dbk:glossseealso) = dbk:glossseealso *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - subject (String) 
-
-[dbk:glossdiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:glossentry (dbk:glossentry) = dbk:glossentry *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:glossentry] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes
- + dbk:abbrev (dbk:abbrev) = dbk:abbrev
- + dbk:acronym (dbk:acronym) = dbk:acronym
- + dbk:glossdef (dbk:glossdef) = dbk:glossdef *
- + dbk:glosssee (dbk:glosssee) = dbk:glosssee
- + dbk:glossterm (dbk:glossterm) = dbk:glossterm
- - sortas (String) 
-
-[dbk:glosslist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:glossentry (dbk:glossentry) = dbk:glossentry *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:glosssee] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - otherterm (Reference) 
-
-[dbk:glossseealso] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - otherterm (Reference) 
-
-[dbk:glossterm] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - baseform (String) 
-
-[dbk:group] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:arg (dbk:arg) = dbk:arg *
- + dbk:group (dbk:group) = dbk:group *
- + dbk:option (dbk:option) = dbk:option *
- + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
- + dbk:sbr (dbk:sbr) = dbk:sbr *
- + dbk:synopfragmentref (dbk:synopfragmentref) = dbk:synopfragmentref *
- - choice (String) 
- - rep (String) 
-
-[dbk:guibutton] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:accel (dbk:accel) = dbk:accel *
-
-[dbk:guiicon] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:accel (dbk:accel) = dbk:accel *
-
-[dbk:guilabel] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:accel (dbk:accel) = dbk:accel *
-
-[dbk:guimenu] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:accel (dbk:accel) = dbk:accel *
-
-[dbk:guimenuitem] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:accel (dbk:accel) = dbk:accel *
-
-[dbk:guisubmenu] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:accel (dbk:accel) = dbk:accel *
-
-[dbk:hardware] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:holder] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:honorific] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:imagedata] > argeodbk:base
- + dbk:info (dbk:info) = dbk:info
- - align (String) 
- - contentdepth (String) 
- - contentwidth (String) 
- - depth (String) 
- - entityref (String) 
- - fileref (String) 
- - format (String) 
- - scale (String) 
- - scalefit (String) 
- - valign (String) 
- - width (String) 
-
-[dbk:imageobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:imagedata (dbk:imagedata) = dbk:imagedata
- + dbk:info (dbk:info) = dbk:info
-
-[dbk:imageobjectco] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:areaspec (dbk:areaspec) = dbk:areaspec
- + dbk:calloutlist (dbk:calloutlist) = dbk:calloutlist *
- + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
- + dbk:info (dbk:info) = dbk:info
-
-[dbk:important] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:index] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:indexdiv (dbk:indexdiv) = dbk:indexdiv *
- + dbk:indexentry (dbk:indexentry) = dbk:indexentry *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
- - type (String) 
-
-[dbk:indexdiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:indexentry (dbk:indexentry) = dbk:indexentry *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:indexentry] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:primaryie (dbk:primaryie) = dbk:primaryie
- + dbk:secondaryie (dbk:secondaryie) = dbk:secondaryie *
- + dbk:seealsoie (dbk:seealsoie) = dbk:seealsoie *
- + dbk:seeie (dbk:seeie) = dbk:seeie *
- + dbk:tertiaryie (dbk:tertiaryie) = dbk:tertiaryie *
-
-[dbk:indexterm] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:primary (dbk:primary) = dbk:primary
- + dbk:secondary (dbk:secondary) = dbk:secondary
- + dbk:see (dbk:see) = dbk:see
- + dbk:seealso (dbk:seealso) = dbk:seealso *
- + dbk:tertiary (dbk:tertiary) = dbk:tertiary
- - class (String) 
- - pagenum (String) 
- - scope (String) 
- - significance (String) 
- - startref (Reference) 
- - type (String) 
- - zone (String) 
-
-[dbk:info] > argeodbk:base
- + dbk:abstract (dbk:abstract) = dbk:abstract *
- + dbk:address (dbk:address) = dbk:address *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:artpagenums (dbk:artpagenums) = dbk:artpagenums *
- + dbk:author (dbk:author) = dbk:author *
- + dbk:authorgroup (dbk:authorgroup) = dbk:authorgroup *
- + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
- + dbk:bibliocoverage (dbk:bibliocoverage) = dbk:bibliocoverage *
- + dbk:biblioid (dbk:biblioid) = dbk:biblioid *
- + dbk:bibliomisc (dbk:bibliomisc) = dbk:bibliomisc *
- + dbk:bibliomset (dbk:bibliomset) = dbk:bibliomset *
- + dbk:bibliorelation (dbk:bibliorelation) = dbk:bibliorelation *
- + dbk:biblioset (dbk:biblioset) = dbk:biblioset *
- + dbk:bibliosource (dbk:bibliosource) = dbk:bibliosource *
- + dbk:collab (dbk:collab) = dbk:collab *
- + dbk:confgroup (dbk:confgroup) = dbk:confgroup *
- + dbk:contractnum (dbk:contractnum) = dbk:contractnum *
- + dbk:contractsponsor (dbk:contractsponsor) = dbk:contractsponsor *
- + dbk:copyright (dbk:copyright) = dbk:copyright *
- + dbk:cover (dbk:cover) = dbk:cover *
- + dbk:date (dbk:date) = dbk:date *
- + dbk:edition (dbk:edition) = dbk:edition *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:extendedlink (dbk:extendedlink) = dbk:extendedlink *
- + dbk:issuenum (dbk:issuenum) = dbk:issuenum *
- + dbk:itermset (dbk:itermset) = dbk:itermset *
- + dbk:keywordset (dbk:keywordset) = dbk:keywordset *
- + dbk:legalnotice (dbk:legalnotice) = dbk:legalnotice *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:org (dbk:org) = dbk:org *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:othercredit (dbk:othercredit) = dbk:othercredit *
- + dbk:pagenums (dbk:pagenums) = dbk:pagenums *
- + dbk:printhistory (dbk:printhistory) = dbk:printhistory *
- + dbk:productname (dbk:productname) = dbk:productname *
- + dbk:productnumber (dbk:productnumber) = dbk:productnumber *
- + dbk:pubdate (dbk:pubdate) = dbk:pubdate *
- + dbk:publisher (dbk:publisher) = dbk:publisher *
- + dbk:publishername (dbk:publishername) = dbk:publishername *
- + dbk:releaseinfo (dbk:releaseinfo) = dbk:releaseinfo *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:seriesvolnums (dbk:seriesvolnums) = dbk:seriesvolnums *
- + dbk:subjectset (dbk:subjectset) = dbk:subjectset *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:title (dbk:title) = dbk:title *
- + dbk:titleabbrev (dbk:titleabbrev) = dbk:titleabbrev *
- + dbk:volumenum (dbk:volumenum) = dbk:volumenum *
- + * (nt:base) = nt:unstructured *
-
-[dbk:informalequation] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:alt (dbk:alt) = dbk:alt
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:info (dbk:info) = dbk:info
- + dbk:mathphrase (dbk:mathphrase) = dbk:mathphrase *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
-
-[dbk:informalexample] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:info (dbk:info) = dbk:info
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - floatstyle (String) 
- - width (String) 
-
-[dbk:informalfigure] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:info (dbk:info) = dbk:info
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - floatstyle (String) 
- - label (String) 
- - pgwide (String) 
-
-[dbk:informaltable] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:col (dbk:col) = dbk:col *
- + dbk:colgroup (dbk:colgroup) = dbk:colgroup *
- + dbk:info (dbk:info) = dbk:info
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:tbody (dbk:tbody) = dbk:tbody *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- + dbk:tfoot (dbk:tfoot) = dbk:tfoot
- + dbk:tgroup (dbk:tgroup) = dbk:tgroup *
- + dbk:thead (dbk:thead) = dbk:thead
- + dbk:tr (dbk:tr) = dbk:tr *
- - border (String) 
- - cellpadding (String) 
- - cellspacing (String) 
- - class (String) 
- - colsep (String) 
- - floatstyle (String) 
- - frame (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - orient (String) 
- - pgwide (String) 
- - rowheader (String) 
- - rowsep (String) 
- - rules (String) 
- - style (String) 
- - summary (String) 
- - tabstyle (String) 
- - title (String) 
- - width (String) 
-
-[dbk:initializer] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:inlineequation] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:alt (dbk:alt) = dbk:alt
- + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
- + dbk:mathphrase (dbk:mathphrase) = dbk:mathphrase *
-
-[dbk:inlinemediaobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:alt (dbk:alt) = dbk:alt
- + dbk:audioobject (dbk:audioobject) = dbk:audioobject *
- + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
- + dbk:imageobjectco (dbk:imageobjectco) = dbk:imageobjectco *
- + dbk:info (dbk:info) = dbk:info
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- + dbk:videoobject (dbk:videoobject) = dbk:videoobject *
-
-[dbk:interfacename] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:issuenum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:itemizedlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:listitem (dbk:listitem) = dbk:listitem *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - mark (String) 
- - spacing (String) 
-
-[dbk:itermset] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes
-
-[dbk:jobtitle] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:keycap] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - function (String) 
- - otherfunction (String) 
-
-[dbk:keycode] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:keycombo] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:keycap (dbk:keycap) = dbk:keycap *
- + dbk:keycombo (dbk:keycombo) = dbk:keycombo *
- + dbk:keysym (dbk:keysym) = dbk:keysym *
- + dbk:mousebutton (dbk:mousebutton) = dbk:mousebutton *
- - action (String) 
- - otheraction (String) 
-
-[dbk:keysym] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:keyword] > argeodbk:base, argeodbk:linkingAttributes
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:keywordset] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:keyword (dbk:keyword) = dbk:keyword *
-
-[dbk:label] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:legalnotice] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:lhs] > argeodbk:base, argeodbk:linkingAttributes
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:lineage] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:lineannotation] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:link] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - endterm (Reference) 
- - xrefstyle (String) 
-
-[dbk:listitem] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - override (String) 
-
-[dbk:literal] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:literallayout] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- + dbk:info (dbk:info) = dbk:info *
- + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- - class (String) 
- - continuation (String) 
- - language (String) 
- - linenumbering (String) 
- - startinglinenumber (String) 
- - xml:space (String) 
-
-[dbk:locator] > argeodbk:base
- - xlink:label (String) 
-
-[dbk:manvolnum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:markup] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:mathphrase] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:emphasis (dbk:emphasis) = dbk:emphasis *
-
-[dbk:mediaobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:alt (dbk:alt) = dbk:alt
- + dbk:audioobject (dbk:audioobject) = dbk:audioobject *
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
- + dbk:imageobjectco (dbk:imageobjectco) = dbk:imageobjectco *
- + dbk:info (dbk:info) = dbk:info
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- + dbk:videoobject (dbk:videoobject) = dbk:videoobject *
-
-[dbk:member] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:menuchoice] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:guibutton (dbk:guibutton) = dbk:guibutton *
- + dbk:guiicon (dbk:guiicon) = dbk:guiicon *
- + dbk:guilabel (dbk:guilabel) = dbk:guilabel *
- + dbk:guimenu (dbk:guimenu) = dbk:guimenu *
- + dbk:guimenuitem (dbk:guimenuitem) = dbk:guimenuitem *
- + dbk:guisubmenu (dbk:guisubmenu) = dbk:guisubmenu *
- + dbk:shortcut (dbk:shortcut) = dbk:shortcut
-
-[dbk:methodname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:methodparam] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:funcparams (dbk:funcparams) = dbk:funcparams
- + dbk:initializer (dbk:initializer) = dbk:initializer
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:parameter (dbk:parameter) = dbk:parameter
- + dbk:type (dbk:type) = dbk:type *
- - choice (String) 
- - rep (String) 
-
-[dbk:methodsynopsis] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname *
- + dbk:methodname (dbk:methodname) = dbk:methodname
- + dbk:methodparam (dbk:methodparam) = dbk:methodparam *
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:type (dbk:type) = dbk:type
- + dbk:void (dbk:void) = dbk:void
- - language (String) 
-
-[dbk:modifier] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - xml:space (String) 
-
-[dbk:mousebutton] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:msg] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:msgmain (dbk:msgmain) = dbk:msgmain
- + dbk:msgrel (dbk:msgrel) = dbk:msgrel *
- + dbk:msgsub (dbk:msgsub) = dbk:msgsub *
-
-[dbk:msgaud] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:msgentry] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:msg (dbk:msg) = dbk:msg *
- + dbk:msgexplan (dbk:msgexplan) = dbk:msgexplan *
- + dbk:msginfo (dbk:msginfo) = dbk:msginfo
-
-[dbk:msgexplan] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:msginfo] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:msgaud (dbk:msgaud) = dbk:msgaud *
- + dbk:msglevel (dbk:msglevel) = dbk:msglevel *
- + dbk:msgorig (dbk:msgorig) = dbk:msgorig *
-
-[dbk:msglevel] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:msgmain] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:msgtext (dbk:msgtext) = dbk:msgtext
-
-[dbk:msgorig] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:msgrel] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:msgtext (dbk:msgtext) = dbk:msgtext
-
-[dbk:msgset] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:msgentry (dbk:msgentry) = dbk:msgentry *
- + dbk:simplemsgentry (dbk:simplemsgentry) = dbk:simplemsgentry *
-
-[dbk:msgsub] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:msgtext (dbk:msgtext) = dbk:msgtext
-
-[dbk:msgtext] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:nonterminal] > argeodbk:base, argeodbk:linkingAttributes
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
- - def (String) 
-
-[dbk:note] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:olink] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - localinfo (String) 
- - targetdoc (String) 
- - targetptr (String) 
- - type (String) 
- - xrefstyle (String) 
-
-[dbk:ooclass] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:classname (dbk:classname) = dbk:classname
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:package (dbk:package) = dbk:package *
-
-[dbk:ooexception] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:exceptionname (dbk:exceptionname) = dbk:exceptionname
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:package (dbk:package) = dbk:package *
-
-[dbk:oointerface] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:interfacename (dbk:interfacename) = dbk:interfacename
- + dbk:modifier (dbk:modifier) = dbk:modifier *
- + dbk:package (dbk:package) = dbk:package *
-
-[dbk:option] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:optional] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:orderedlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:listitem (dbk:listitem) = dbk:listitem *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - continuation (String) 
- - inheritnum (String) 
- - numeration (String) 
- - spacing (String) 
- - startingnumber (String) 
-
-[dbk:org] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:address (dbk:address) = dbk:address *
- + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
- + dbk:email (dbk:email) = dbk:email *
- + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
- + dbk:orgname (dbk:orgname) = dbk:orgname
- + dbk:uri (dbk:uri) = dbk:uri *
-
-[dbk:orgdiv] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:orgname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - otherclass (String) 
-
-[dbk:otheraddr] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:othercredit] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:address (dbk:address) = dbk:address *
- + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
- + dbk:contrib (dbk:contrib) = dbk:contrib *
- + dbk:email (dbk:email) = dbk:email *
- + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
- + dbk:orgname (dbk:orgname) = dbk:orgname
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname
- + dbk:uri (dbk:uri) = dbk:uri *
- - class (String) 
- - otherclass (String) 
-
-[dbk:othername] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:package] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:pagenums] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:para] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:markupInlines, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:info (dbk:info) = dbk:info *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:paramdef] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:funcparams (dbk:funcparams) = dbk:funcparams *
- + dbk:initializer (dbk:initializer) = dbk:initializer *
- + dbk:parameter (dbk:parameter) = dbk:parameter *
- + dbk:type (dbk:type) = dbk:type *
- - choice (String) 
-
-[dbk:parameter] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
-
-[dbk:part] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:acknowledgements (dbk:acknowledgements) = dbk:acknowledgements *
- + dbk:appendix (dbk:appendix) = dbk:appendix *
- + dbk:article (dbk:article) = dbk:article *
- + dbk:bibliography (dbk:bibliography) = dbk:bibliography *
- + dbk:chapter (dbk:chapter) = dbk:chapter *
- + dbk:colophon (dbk:colophon) = dbk:colophon *
- + dbk:dedication (dbk:dedication) = dbk:dedication *
- + dbk:glossary (dbk:glossary) = dbk:glossary *
- + dbk:index (dbk:index) = dbk:index *
- + dbk:partintro (dbk:partintro) = dbk:partintro
- + dbk:preface (dbk:preface) = dbk:preface *
- + dbk:refentry (dbk:refentry) = dbk:refentry *
- + dbk:reference (dbk:reference) = dbk:reference *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:toc (dbk:toc) = dbk:toc *
- - label (String) 
- - status (String) 
-
-[dbk:partintro] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refentry (dbk:refentry) = dbk:refentry *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect1 (dbk:sect1) = dbk:sect1 *
- + dbk:section (dbk:section) = dbk:section *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:person] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:address (dbk:address) = dbk:address *
- + dbk:affiliation (dbk:affiliation) = dbk:affiliation *
- + dbk:email (dbk:email) = dbk:email *
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname
- + dbk:uri (dbk:uri) = dbk:uri *
-
-[dbk:personblurb] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
-
-[dbk:personname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:firstname (dbk:firstname) = dbk:firstname *
- + dbk:honorific (dbk:honorific) = dbk:honorific *
- + dbk:lineage (dbk:lineage) = dbk:lineage *
- + dbk:othername (dbk:othername) = dbk:othername *
- + dbk:surname (dbk:surname) = dbk:surname *
-
-[dbk:phone] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:phrase] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:pob] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:postcode] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:preface] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refentry (dbk:refentry) = dbk:refentry *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect1 (dbk:sect1) = dbk:sect1 *
- + dbk:section (dbk:section) = dbk:section *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:primary] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - sortas (String) 
-
-[dbk:primaryie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - linkends (String) 
-
-[dbk:printhistory] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
-
-[dbk:procedure] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:step (dbk:step) = dbk:step *
-
-[dbk:production] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:constraint (dbk:constraint) = dbk:constraint *
- + dbk:lhs (dbk:lhs) = dbk:lhs
- + dbk:rhs (dbk:rhs) = dbk:rhs
-
-[dbk:productionrecap] > argeodbk:base, argeodbk:linkingAttributes
-
-[dbk:productionset] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:production (dbk:production) = dbk:production *
- + dbk:productionrecap (dbk:productionrecap) = dbk:productionrecap *
-
-[dbk:productname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
-
-[dbk:productnumber] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:programlisting] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- + dbk:info (dbk:info) = dbk:info *
- + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- - continuation (String) 
- - language (String) 
- - linenumbering (String) 
- - startinglinenumber (String) 
- - width (String) 
- - xml:space (String) 
-
-[dbk:programlistingco] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:areaspec (dbk:areaspec) = dbk:areaspec
- + dbk:calloutlist (dbk:calloutlist) = dbk:calloutlist *
- + dbk:info (dbk:info) = dbk:info
- + dbk:programlisting (dbk:programlisting) = dbk:programlisting
-
-[dbk:prompt] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
-
-[dbk:property] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:pubdate] > argeodbk:base, argeodbk:linkingAttributes
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:publisher] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:address (dbk:address) = dbk:address *
- + dbk:publishername (dbk:publishername) = dbk:publishername
-
-[dbk:publishername] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:qandadiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:qandadiv (dbk:qandadiv) = dbk:qandadiv *
- + dbk:qandaentry (dbk:qandaentry) = dbk:qandaentry *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:qandaentry] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:answer (dbk:answer) = dbk:answer *
- + dbk:question (dbk:question) = dbk:question
-
-[dbk:qandaset] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:qandadiv (dbk:qandadiv) = dbk:qandadiv *
- + dbk:qandaentry (dbk:qandaentry) = dbk:qandaentry *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - defaultlabel (String) 
-
-[dbk:question] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:label (dbk:label) = dbk:label
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:quote] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:refclass] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:application (dbk:application) = dbk:application *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:refdescriptor] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:refentry] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes
- + dbk:info (dbk:info) = dbk:info
- + dbk:refmeta (dbk:refmeta) = dbk:refmeta
- + dbk:refnamediv (dbk:refnamediv) = dbk:refnamediv *
- + dbk:refsect1 (dbk:refsect1) = dbk:refsect1 *
- + dbk:refsection (dbk:refsection) = dbk:refsection *
- + dbk:refsynopsisdiv (dbk:refsynopsisdiv) = dbk:refsynopsisdiv
- - label (String) 
- - status (String) 
-
-[dbk:refentrytitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:reference] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:partintro (dbk:partintro) = dbk:partintro
- + dbk:refentry (dbk:refentry) = dbk:refentry *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:refmeta] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes
- + dbk:manvolnum (dbk:manvolnum) = dbk:manvolnum
- + dbk:refentrytitle (dbk:refentrytitle) = dbk:refentrytitle
- + dbk:refmiscinfo (dbk:refmiscinfo) = dbk:refmiscinfo *
-
-[dbk:refmiscinfo] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - otherclass (String) 
-
-[dbk:refname] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:refnamediv] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:refclass (dbk:refclass) = dbk:refclass *
- + dbk:refdescriptor (dbk:refdescriptor) = dbk:refdescriptor
- + dbk:refname (dbk:refname) = dbk:refname *
- + dbk:refpurpose (dbk:refpurpose) = dbk:refpurpose
-
-[dbk:refpurpose] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:refsect1] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refsect2 (dbk:refsect2) = dbk:refsect2 *
- + dbk:refsect2 (dbk:refsect2) = dbk:refsect2 *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:refsect2] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refsect3 (dbk:refsect3) = dbk:refsect3 *
- + dbk:refsect3 (dbk:refsect3) = dbk:refsect3 *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:refsect3] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:refsection] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refsection (dbk:refsection) = dbk:refsection *
- + dbk:refsection (dbk:refsection) = dbk:refsection *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:refsynopsisdiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refsect2 (dbk:refsect2) = dbk:refsect2 *
- + dbk:refsection (dbk:refsection) = dbk:refsection *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
-
-[dbk:releaseinfo] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:remark] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:replaceable] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- - class (String) 
-
-[dbk:returnvalue] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:revdescription] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:revhistory] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:revision (dbk:revision) = dbk:revision *
-
-[dbk:revision] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:author (dbk:author) = dbk:author *
- + dbk:authorinitials (dbk:authorinitials) = dbk:authorinitials *
- + dbk:date (dbk:date) = dbk:date
- + dbk:revdescription (dbk:revdescription) = dbk:revdescription
- + dbk:revnumber (dbk:revnumber) = dbk:revnumber
- + dbk:revremark (dbk:revremark) = dbk:revremark
-
-[dbk:revnumber] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:revremark] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:rhs] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
- + dbk:nonterminal (dbk:nonterminal) = dbk:nonterminal *
- + dbk:sbr (dbk:sbr) = dbk:sbr *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:row] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:entry (dbk:entry) = dbk:entry *
- + dbk:entrytbl (dbk:entrytbl) = dbk:entrytbl *
- - rowsep (String) 
- - valign (String) 
-
-[dbk:sbr] > argeodbk:base
-
-[dbk:screen] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- + dbk:info (dbk:info) = dbk:info *
- + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- - continuation (String) 
- - language (String) 
- - linenumbering (String) 
- - startinglinenumber (String) 
- - width (String) 
- - xml:space (String) 
-
-[dbk:screenco] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:areaspec (dbk:areaspec) = dbk:areaspec
- + dbk:calloutlist (dbk:calloutlist) = dbk:calloutlist *
- + dbk:info (dbk:info) = dbk:info
- + dbk:screen (dbk:screen) = dbk:screen
-
-[dbk:screenshot] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
-
-[dbk:secondary] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - sortas (String) 
-
-[dbk:secondaryie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - linkends (String) 
-
-[dbk:sect1] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect2 (dbk:sect2) = dbk:sect2 *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:sect2] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect3 (dbk:sect3) = dbk:sect3 *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:sect3] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect4 (dbk:sect4) = dbk:sect4 *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:sect4] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:sect5 (dbk:sect5) = dbk:sect5 *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:sect5] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:section] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:refentry (dbk:refentry) = dbk:refentry *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:section (dbk:section) = dbk:section *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
- + dbk:simplesect (dbk:simplesect) = dbk:simplesect *
-
-[dbk:see] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:seealso] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:seealsoie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - linkends (String) 
-
-[dbk:seeie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:seg] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:seglistitem] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:seg (dbk:seg) = dbk:seg *
-
-[dbk:segmentedlist] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:seglistitem (dbk:seglistitem) = dbk:seglistitem *
- + dbk:segtitle (dbk:segtitle) = dbk:segtitle *
-
-[dbk:segtitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:seriesvolnums] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:set] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:book (dbk:book) = dbk:book *
- + dbk:set (dbk:set) = dbk:set *
- + dbk:setindex (dbk:setindex) = dbk:setindex
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:toc (dbk:toc) = dbk:toc
- - label (String) 
- - status (String) 
-
-[dbk:setindex] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:indexdiv (dbk:indexdiv) = dbk:indexdiv *
- + dbk:indexentry (dbk:indexentry) = dbk:indexentry *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
- - type (String) 
-
-[dbk:shortaffil] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:shortcut] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:keycap (dbk:keycap) = dbk:keycap *
- + dbk:keycombo (dbk:keycombo) = dbk:keycombo *
- + dbk:keysym (dbk:keysym) = dbk:keysym *
- + dbk:mousebutton (dbk:mousebutton) = dbk:mousebutton *
- - action (String) 
- - otheraction (String) 
-
-[dbk:sidebar] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:simpara] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:info (dbk:info) = dbk:info *
-
-[dbk:simplelist] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:member (dbk:member) = dbk:member *
- - columns (String) 
- - type (String) 
-
-[dbk:simplemsgentry] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:msgexplan (dbk:msgexplan) = dbk:msgexplan *
- + dbk:msgtext (dbk:msgtext) = dbk:msgtext
- - msgaud (String) 
- - msglevel (String) 
- - msgorig (String) 
-
-[dbk:simplesect] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:spanspec] > argeodbk:base, argeodbk:linkingAttributes
- - align (String) 
- - char (String) 
- - charoff (String) 
- - colsep (String) 
- - nameend (String) 
- - namest (String) 
- - rowsep (String) 
- - spanname (String) 
-
-[dbk:state] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:step] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:stepalternatives (dbk:stepalternatives) = dbk:stepalternatives
- + dbk:substeps (dbk:substeps) = dbk:substeps
- - performance (String) 
-
-[dbk:stepalternatives] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:info (dbk:info) = dbk:info
- + dbk:step (dbk:step) = dbk:step *
- - performance (String) 
-
-[dbk:street] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:subject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:subjectterm (dbk:subjectterm) = dbk:subjectterm *
- - weight (String) 
-
-[dbk:subjectset] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:subject (dbk:subject) = dbk:subject *
- - scheme (String) 
-
-[dbk:subjectterm] > argeodbk:base, argeodbk:linkingAttributes
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:subscript] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:substeps] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:step (dbk:step) = dbk:step *
- - performance (String) 
-
-[dbk:subtitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:superscript] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:surname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:symbol] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
-
-[dbk:synopfragment] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:arg (dbk:arg) = dbk:arg *
- + dbk:group (dbk:group) = dbk:group *
-
-[dbk:synopfragmentref] > argeodbk:base, argeodbk:linkingAttributes
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:synopsis] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- + dbk:info (dbk:info) = dbk:info *
- + dbk:lineannotation (dbk:lineannotation) = dbk:lineannotation *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- - continuation (String) 
- - label (String) 
- - language (String) 
- - linenumbering (String) 
- - startinglinenumber (String) 
- - xml:space (String) 
-
-[dbk:systemitem] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- + dbk:co (dbk:co) = dbk:co *
- - class (String) 
-
-[dbk:table] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:col (dbk:col) = dbk:col *
- + dbk:colgroup (dbk:colgroup) = dbk:colgroup *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:tbody (dbk:tbody) = dbk:tbody *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- + dbk:tfoot (dbk:tfoot) = dbk:tfoot
- + dbk:tgroup (dbk:tgroup) = dbk:tgroup *
- + dbk:thead (dbk:thead) = dbk:thead
- + dbk:tr (dbk:tr) = dbk:tr *
- - border (String) 
- - cellpadding (String) 
- - cellspacing (String) 
- - class (String) 
- - colsep (String) 
- - floatstyle (String) 
- - frame (String) 
- - label (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - orient (String) 
- - pgwide (String) 
- - rowheader (String) 
- - rowsep (String) 
- - rules (String) 
- - shortentry (String) 
- - style (String) 
- - summary (String) 
- - tabstyle (String) 
- - title (String) 
- - tocentry (String) 
- - width (String) 
-
-[dbk:tag] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - namespace (String) 
-
-[dbk:task] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:example (dbk:example) = dbk:example *
- + dbk:procedure (dbk:procedure) = dbk:procedure
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:taskprerequisites (dbk:taskprerequisites) = dbk:taskprerequisites
- + dbk:taskrelated (dbk:taskrelated) = dbk:taskrelated
- + dbk:tasksummary (dbk:tasksummary) = dbk:tasksummary
-
-[dbk:taskprerequisites] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:taskrelated] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:tasksummary] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:tbody] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:row (dbk:row) = dbk:row *
- + dbk:tr (dbk:tr) = dbk:tr *
- - align (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - style (String) 
- - title (String) 
- - valign (String) 
-
-[dbk:td] > argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:markupInlines, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - abbr (String) 
- - align (String) 
- - annotations (String) 
- - arch (String) 
- - audience (String) 
- - axis (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - colspan (String) 
- - condition (String) 
- - conformance (String) 
- - dir (String) 
- - headers (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - os (String) 
- - remap (String) 
- - revision (String) 
- - revisionflag (String) 
- - rowspan (String) 
- - scope (String) 
- - security (String) 
- - style (String) 
- - title (String) 
- - userlevel (String) 
- - valign (String) 
- - vendor (String) 
- - version (String) 
- - wordsize (String) 
- - xreflabel (String) 
- - xml:base (String) 
- - xml:id (String) 
- - xml:lang (String) 
-
-[dbk:term] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:termdef] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - baseform (String) 
- - sortas (String) 
-
-[dbk:tertiary] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - sortas (String) 
-
-[dbk:tertiaryie] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - linkends (String) 
-
-[dbk:textdata] > argeodbk:base
- + dbk:info (dbk:info) = dbk:info
- - encoding (String) 
- - entityref (String) 
- - fileref (String) 
- - format (String) 
-
-[dbk:textobject] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:info (dbk:info) = dbk:info
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:phrase (dbk:phrase) = dbk:phrase
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:textdata (dbk:textdata) = dbk:textdata
-
-[dbk:tfoot] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:colspec (dbk:colspec) = dbk:colspec *
- + dbk:row (dbk:row) = dbk:row *
- + dbk:tr (dbk:tr) = dbk:tr *
- - align (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - style (String) 
- - title (String) 
- - valign (String) 
-
-[dbk:tgroup] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:colspec (dbk:colspec) = dbk:colspec *
- + dbk:spanspec (dbk:spanspec) = dbk:spanspec *
- + dbk:tbody (dbk:tbody) = dbk:tbody
- + dbk:tfoot (dbk:tfoot) = dbk:tfoot
- + dbk:thead (dbk:thead) = dbk:thead
- - align (String) 
- - char (String) 
- - charoff (String) 
- - cols (String) 
- - colsep (String) 
- - rowsep (String) 
- - tgroupstyle (String) 
-
-[dbk:th] > argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:markupInlines, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- - abbr (String) 
- - align (String) 
- - annotations (String) 
- - arch (String) 
- - audience (String) 
- - axis (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - colspan (String) 
- - condition (String) 
- - conformance (String) 
- - dir (String) 
- - headers (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - os (String) 
- - remap (String) 
- - revision (String) 
- - revisionflag (String) 
- - rowspan (String) 
- - scope (String) 
- - security (String) 
- - style (String) 
- - title (String) 
- - userlevel (String) 
- - valign (String) 
- - vendor (String) 
- - version (String) 
- - wordsize (String) 
- - xreflabel (String) 
- - xml:base (String) 
- - xml:id (String) 
- - xml:lang (String) 
-
-[dbk:thead] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:colspec (dbk:colspec) = dbk:colspec *
- + dbk:row (dbk:row) = dbk:row *
- + dbk:tr (dbk:tr) = dbk:tr *
- - align (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - style (String) 
- - title (String) 
- - valign (String) 
-
-[dbk:tip] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:title] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:titleabbrev] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:toc] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:tocdiv (dbk:tocdiv) = dbk:tocdiv *
- + dbk:tocentry (dbk:tocentry) = dbk:tocentry *
-
-[dbk:tocdiv] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:tocdiv (dbk:tocdiv) = dbk:tocdiv *
- + dbk:tocentry (dbk:tocentry) = dbk:tocentry *
- - pagenum (String) 
-
-[dbk:tocentry] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - pagenum (String) 
-
-[dbk:token] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:tr] > nt:base
- + dbk:td (dbk:td) = dbk:td *
- + dbk:th (dbk:th) = dbk:th *
- - align (String) 
- - annotations (String) 
- - arch (String) 
- - audience (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - condition (String) 
- - conformance (String) 
- - dir (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - os (String) 
- - remap (String) 
- - revision (String) 
- - revisionflag (String) 
- - security (String) 
- - style (String) 
- - title (String) 
- - userlevel (String) 
- - valign (String) 
- - vendor (String) 
- - version (String) 
- - wordsize (String) 
- - xreflabel (String) 
- - xml:base (String) 
- - xml:id (String) 
- - xml:lang (String) 
-
-[dbk:trademark] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
-
-[dbk:type] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:uri] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - type (String) 
-
-[dbk:userinput] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:ubiquitousInlines
- + dbk:accel (dbk:accel) = dbk:accel *
- + dbk:co (dbk:co) = dbk:co *
- + dbk:command (dbk:command) = dbk:command *
- + dbk:computeroutput (dbk:computeroutput) = dbk:computeroutput *
- + dbk:envar (dbk:envar) = dbk:envar *
- + dbk:filename (dbk:filename) = dbk:filename *
- + dbk:guibutton (dbk:guibutton) = dbk:guibutton *
- + dbk:guiicon (dbk:guiicon) = dbk:guiicon *
- + dbk:guilabel (dbk:guilabel) = dbk:guilabel *
- + dbk:guimenu (dbk:guimenu) = dbk:guimenu *
- + dbk:guimenuitem (dbk:guimenuitem) = dbk:guimenuitem *
- + dbk:guisubmenu (dbk:guisubmenu) = dbk:guisubmenu *
- + dbk:keycap (dbk:keycap) = dbk:keycap *
- + dbk:keycode (dbk:keycode) = dbk:keycode *
- + dbk:keycombo (dbk:keycombo) = dbk:keycombo *
- + dbk:keysym (dbk:keysym) = dbk:keysym *
- + dbk:menuchoice (dbk:menuchoice) = dbk:menuchoice *
- + dbk:mousebutton (dbk:mousebutton) = dbk:mousebutton *
- + dbk:nonterminal (dbk:nonterminal) = dbk:nonterminal *
- + dbk:option (dbk:option) = dbk:option *
- + dbk:optional (dbk:optional) = dbk:optional *
- + dbk:package (dbk:package) = dbk:package *
- + dbk:parameter (dbk:parameter) = dbk:parameter *
- + dbk:prompt (dbk:prompt) = dbk:prompt *
- + dbk:property (dbk:property) = dbk:property *
- + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
- + dbk:shortcut (dbk:shortcut) = dbk:shortcut *
- + dbk:systemitem (dbk:systemitem) = dbk:systemitem *
- + dbk:termdef (dbk:termdef) = dbk:termdef *
- + dbk:userinput (dbk:userinput) = dbk:userinput *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:varargs] > argeodbk:base, argeodbk:linkingAttributes
-
-[dbk:variablelist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
- + dbk:varlistentry (dbk:varlistentry) = dbk:varlistentry *
- - spacing (String) 
- - termlength (String) 
-
-[dbk:varlistentry] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:listitem (dbk:listitem) = dbk:listitem
- + dbk:term (dbk:term) = dbk:term *
-
-[dbk:varname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:videodata] > argeodbk:base
- + dbk:info (dbk:info) = dbk:info
- - align (String) 
- - contentdepth (String) 
- - contentwidth (String) 
- - depth (String) 
- - entityref (String) 
- - fileref (String) 
- - format (String) 
- - scale (String) 
- - scalefit (String) 
- - valign (String) 
- - width (String) 
-
-[dbk:videoobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:info (dbk:info) = dbk:info
- + dbk:videodata (dbk:videodata) = dbk:videodata
-
-[dbk:void] > argeodbk:base, argeodbk:linkingAttributes
-
-[dbk:volumenum] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:warning] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:bridgehead (dbk:bridgehead) = dbk:bridgehead *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:revhistory (dbk:revhistory) = dbk:revhistory *
- + dbk:screenshot (dbk:screenshot) = dbk:screenshot *
-
-[dbk:wordasword] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:xref] > argeodbk:base, argeodbk:linkingAttributes
- - endterm (Reference) 
- - xrefstyle (String) 
-
-[dbk:year] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-//[xs:anyType] > nt:base
-// + * (nt:base) 
-// + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-// - * (undefined) 
-
-
diff --git a/org.argeo.app.core/src/org/argeo/docbook/docbook.cnd b/org.argeo.app.core/src/org/argeo/docbook/docbook.cnd
deleted file mode 100644 (file)
index 5514e64..0000000
+++ /dev/null
@@ -1,527 +0,0 @@
-<dbk = 'http://docbook.org/ns/docbook'>
-<argeodbk = 'http://www.argeo.org/ns/argeodbk'>
-<xlink = 'http://www.w3.org/1999/xlink'>
-
-[argeodbk:titled]
-mixin
- + dbk:info (dbk:info) = dbk:info *
- + dbk:title (dbk:title) = dbk:title *
-
-[argeodbk:linkingAttributes]
-mixin
- - linkend (String)
- - xlink:actuate (String)
- - xlink:arcrole (String)
- - xlink:href (String)
- - xlink:role (String)
- - xlink:show (String)
- - xlink:title (String)
- - xlink:type (String)
-
-[argeodbk:freeText]
-mixin
- + dbk:phrase (dbk:phrase) = dbk:phrase *
- + dbk:replaceable (dbk:replaceable) = dbk:replaceable *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[argeodbk:markupInlines]
-mixin
-
-[argeodbk:listElements]
-mixin
- + dbk:itemizedlist (dbk:itemizedlist) = dbk:itemizedlist *
- + dbk:orderedlist (dbk:orderedlist) = dbk:orderedlist *
- + dbk:simplelist (dbk:simplelist) = dbk:simplelist *
-
-[argeodbk:paragraphElements]
-mixin
- + dbk:para (dbk:para) = dbk:para *
-
-[argeodbk:indexingInlines]
-mixin
-
-[argeodbk:techDocElements]
-mixin
- + dbk:table (dbk:table) = dbk:table *
-
-[argeodbk:techDocInlines]
-mixin
-
-[argeodbk:publishingElements]
-mixin
-
-[argeodbk:ubiquitousInlines]
-mixin
- + dbk:alt (dbk:alt) = dbk:alt *
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:biblioref (dbk:biblioref) = dbk:biblioref *
- + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
- + dbk:link (dbk:link) = dbk:link *
- + dbk:olink (dbk:olink) = dbk:olink *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:subscript (dbk:subscript) = dbk:subscript *
- + dbk:superscript (dbk:superscript) = dbk:superscript *
- + dbk:xref (dbk:xref) = dbk:xref *
-
-[argeodbk:abstractSection]
-mixin
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:remark (dbk:remark) = dbk:remark *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String)
- - status (String)
-
-[argeodbk:bibliographyInlines]
-mixin
- + dbk:author (dbk:author) = dbk:author *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:personname (dbk:personname) = dbk:personname *
-
-[argeodbk:publishingInlines]
-mixin
- + dbk:emphasis (dbk:emphasis) = dbk:emphasis *
-
-[argeodbk:base]
-abstract
-orderable
- - annotations (String)
- - arch (String)
- - audience (String)
- - condition (String)
- - conformance (String)
- - dir (String)
- - os (String)
- - remap (String)
- - revision (String)
- - revisionflag (String)
- - role (String)
- - security (String)
- - userlevel (String)
- - vendor (String)
- - version (String)
- - wordsize (String)
- - xreflabel (String)
-
-[dbk:alt] > argeodbk:base
- + dbk:inlinemediaobject (dbk:inlinemediaobject) = dbk:inlinemediaobject *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
-
-[dbk:anchor] > argeodbk:base
-
-[dbk:annotation] > argeodbk:base, argeodbk:indexingInlines, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- - annotates (String) 
-
-[dbk:article] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:section (dbk:section) = dbk:section *
- - class (String) 
-
-[dbk:audiodata] > argeodbk:base
- + dbk:info (dbk:info) = dbk:info
- - entityref (String) 
- - fileref (String) 
- - format (String) 
-
-[dbk:audioobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:audiodata (dbk:audiodata) = dbk:audiodata
- + dbk:info (dbk:info) = dbk:info
-
-[dbk:author] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
- + dbk:orgname (dbk:orgname) = dbk:orgname
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname
-
-[dbk:biblioref] > argeodbk:base, argeodbk:linkingAttributes
- - begin (String) 
- - end (String) 
- - endterm (Reference) 
- - units (String) 
- - xrefstyle (String) 
-
-[dbk:book] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:article (dbk:article) = dbk:article *
- + dbk:chapter (dbk:chapter) = dbk:chapter *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:caption] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- + jcr:xmltext (jcrx:xmltext) = jcrx:xmltext *
- - class (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - style (String) 
- - title (String) 
-
-[dbk:chapter] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:section (dbk:section) = dbk:section *
-
-[dbk:colspec] > argeodbk:base, argeodbk:linkingAttributes
- - align (String) 
- - char (String) 
- - charoff (String) 
- - colname (String) 
- - colnum (String) 
- - colsep (String) 
- - colwidth (String) 
- - rowsep (String) 
-
-[dbk:editor] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:orgdiv (dbk:orgdiv) = dbk:orgdiv *
- + dbk:orgname (dbk:orgname) = dbk:orgname
- + dbk:personblurb (dbk:personblurb) = dbk:personblurb *
- + dbk:personname (dbk:personname) = dbk:personname
-
-[dbk:emphasis] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:entry] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:markupInlines, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- - align (String) 
- - char (String) 
- - charoff (String) 
- - colname (String) 
- - colsep (String) 
- - morerows (String) 
- - nameend (String) 
- - namest (String) 
- - rotate (String) 
- - rowsep (String) 
- - spanname (String) 
- - valign (String) 
-
-[dbk:entrytbl] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:colspec (dbk:colspec) = dbk:colspec *
- + dbk:spanspec (dbk:spanspec) = dbk:spanspec *
- + dbk:tbody (dbk:tbody) = dbk:tbody
- + dbk:thead (dbk:thead) = dbk:thead
- - align (String) 
- - char (String) 
- - charoff (String) 
- - colname (String) 
- - cols (String) 
- - colsep (String) 
- - nameend (String) 
- - namest (String) 
- - rowsep (String) 
- - spanname (String) 
- - tgroupstyle (String) 
-
-[dbk:imagedata] > argeodbk:base
- + dbk:info (dbk:info) = dbk:info
- - align (String) 
- - contentdepth (String) 
- - contentwidth (String) 
- - depth (String) 
- - entityref (String) 
- - fileref (String) 
- - format (String) 
- - scale (String) 
- - scalefit (String) 
- - valign (String) 
- - width (String) 
-
-[dbk:imageobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:imagedata (dbk:imagedata) = dbk:imagedata
- + dbk:info (dbk:info) = dbk:info
-
-[dbk:info] > argeodbk:base
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:author (dbk:author) = dbk:author *
- + dbk:editor (dbk:editor) = dbk:editor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:orgname (dbk:orgname) = dbk:orgname *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- + dbk:title (dbk:title) = dbk:title *
- + * (nt:base) = nt:unstructured *
-
-[dbk:inlinemediaobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:alt (dbk:alt) = dbk:alt
- + dbk:audioobject (dbk:audioobject) = dbk:audioobject *
- + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
- + dbk:info (dbk:info) = dbk:info
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- + dbk:videoobject (dbk:videoobject) = dbk:videoobject *
-
-[dbk:itemizedlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:listitem (dbk:listitem) = dbk:listitem *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- - mark (String) 
- - spacing (String) 
-
-[dbk:link] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - endterm (Reference) 
- - xrefstyle (String) 
-
-[dbk:listitem] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- - override (String) 
-
-[dbk:mediaobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:alt (dbk:alt) = dbk:alt
- + dbk:audioobject (dbk:audioobject) = dbk:audioobject *
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:imageobject (dbk:imageobject) = dbk:imageobject *
- + dbk:info (dbk:info) = dbk:info
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- + dbk:videoobject (dbk:videoobject) = dbk:videoobject *
-
-[dbk:olink] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- - localinfo (String) 
- - targetdoc (String) 
- - targetptr (String) 
- - type (String) 
- - xrefstyle (String) 
-
-[dbk:orderedlist] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:listitem (dbk:listitem) = dbk:listitem *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:remark (dbk:remark) = dbk:remark *
- - continuation (String) 
- - inheritnum (String) 
- - numeration (String) 
- - spacing (String) 
- - startingnumber (String) 
-
-[dbk:orgdiv] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:orgname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
- - otherclass (String) 
-
-[dbk:para] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:markupInlines, argeodbk:publishingElements, argeodbk:publishingInlines, argeodbk:techDocElements, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
- + dbk:info (dbk:info) = dbk:info *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
-
-[dbk:personblurb] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:paragraphElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
-
-[dbk:personname] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:phrase] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:remark] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:replaceable] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
- - class (String) 
-
-[dbk:row] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:entry (dbk:entry) = dbk:entry *
- + dbk:entrytbl (dbk:entrytbl) = dbk:entrytbl *
- - rowsep (String) 
- - valign (String) 
-
-[dbk:section] > argeodbk:abstractSection, argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements, argeodbk:titled
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:section (dbk:section) = dbk:section *
-
-[dbk:set] > argeodbk:base, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:book (dbk:book) = dbk:book *
- + dbk:set (dbk:set) = dbk:set *
- + dbk:subtitle (dbk:subtitle) = dbk:subtitle *
- - label (String) 
- - status (String) 
-
-[dbk:simplelist] > argeodbk:base, argeodbk:linkingAttributes
- - columns (String) 
- - type (String) 
-
-[dbk:spanspec] > argeodbk:base, argeodbk:linkingAttributes
- - align (String) 
- - char (String) 
- - charoff (String) 
- - colsep (String) 
- - nameend (String) 
- - namest (String) 
- - rowsep (String) 
- - spanname (String) 
-
-[dbk:subscript] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:subtitle] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:superscript] > argeodbk:base, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:ubiquitousInlines
-
-[dbk:table] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:titled
- + dbk:caption (dbk:caption) = dbk:caption
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:tbody (dbk:tbody) = dbk:tbody *
- + dbk:textobject (dbk:textobject) = dbk:textobject *
- + dbk:tfoot (dbk:tfoot) = dbk:tfoot
- + dbk:tgroup (dbk:tgroup) = dbk:tgroup *
- + dbk:thead (dbk:thead) = dbk:thead
- - border (String) 
- - cellpadding (String) 
- - cellspacing (String) 
- - class (String) 
- - colsep (String) 
- - floatstyle (String) 
- - frame (String) 
- - label (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - orient (String) 
- - pgwide (String) 
- - rowheader (String) 
- - rowsep (String) 
- - rules (String) 
- - shortentry (String) 
- - style (String) 
- - summary (String) 
- - tabstyle (String) 
- - title (String) 
- - tocentry (String) 
- - width (String) 
-
-[dbk:tbody] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:row (dbk:row) = dbk:row *
- - align (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - style (String) 
- - title (String) 
- - valign (String) 
-
-[dbk:textobject] > argeodbk:base, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:listElements, argeodbk:paragraphElements, argeodbk:publishingElements, argeodbk:techDocElements
- + dbk:anchor (dbk:anchor) = dbk:anchor *
- + dbk:annotation (dbk:annotation) = dbk:annotation *
- + dbk:info (dbk:info) = dbk:info
- + dbk:mediaobject (dbk:mediaobject) = dbk:mediaobject *
- + dbk:phrase (dbk:phrase) = dbk:phrase
- + dbk:remark (dbk:remark) = dbk:remark *
-
-[dbk:tfoot] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:colspec (dbk:colspec) = dbk:colspec *
- + dbk:row (dbk:row) = dbk:row *
- - align (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - style (String) 
- - title (String) 
- - valign (String) 
-
-[dbk:tgroup] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:colspec (dbk:colspec) = dbk:colspec *
- + dbk:spanspec (dbk:spanspec) = dbk:spanspec *
- + dbk:tbody (dbk:tbody) = dbk:tbody
- + dbk:tfoot (dbk:tfoot) = dbk:tfoot
- + dbk:thead (dbk:thead) = dbk:thead
- - align (String) 
- - char (String) 
- - charoff (String) 
- - cols (String) 
- - colsep (String) 
- - rowsep (String) 
- - tgroupstyle (String) 
-
-[dbk:thead] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:colspec (dbk:colspec) = dbk:colspec *
- + dbk:row (dbk:row) = dbk:row *
- - align (String) 
- - char (String) 
- - charoff (String) 
- - class (String) 
- - lang (String) 
- - onclick (String) 
- - ondblclick (String) 
- - onkeydown (String) 
- - onkeypress (String) 
- - onkeyup (String) 
- - onmousedown (String) 
- - onmousemove (String) 
- - onmouseout (String) 
- - onmouseover (String) 
- - onmouseup (String) 
- - style (String) 
- - title (String) 
- - valign (String) 
-
-[dbk:title] > argeodbk:base, argeodbk:bibliographyInlines, argeodbk:freeText, argeodbk:indexingInlines, argeodbk:linkingAttributes, argeodbk:markupInlines, argeodbk:publishingInlines, argeodbk:techDocInlines, argeodbk:ubiquitousInlines
-
-[dbk:videodata] > argeodbk:base
- + dbk:info (dbk:info) = dbk:info
- - align (String) 
- - contentdepth (String) 
- - contentwidth (String) 
- - depth (String) 
- - entityref (String) 
- - fileref (String) 
- - format (String) 
- - scale (String) 
- - scalefit (String) 
- - valign (String) 
- - width (String) 
-
-[dbk:videoobject] > argeodbk:base, argeodbk:linkingAttributes
- + dbk:info (dbk:info) = dbk:info
- + dbk:videodata (dbk:videodata) = dbk:videodata
-
-[dbk:xref] > argeodbk:base, argeodbk:linkingAttributes
- - endterm (Reference) 
- - xrefstyle (String) 
-
-
diff --git a/org.argeo.app.core/src/org/argeo/entity/core/JcrEntityDefinition.java b/org.argeo.app.core/src/org/argeo/entity/core/JcrEntityDefinition.java
deleted file mode 100644 (file)
index d6d1246..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.cms.jcr.CmsJcrUtils;
-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 defaultEditorId;
-
-       public void init(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
-               Session adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
-               try {
-                       type = properties.get(EntityConstants.TYPE);
-                       if (type == null)
-                               throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set.");
-                       defaultEditorId = properties.get(EntityConstants.DEFAULT_EDITOR_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 defaultEditorId;
-       }
-
-       @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.app.core/src/org/argeo/geo/GeoJsonUtils.java b/org.argeo.app.core/src/org/argeo/geo/GeoJsonUtils.java
deleted file mode 100644 (file)
index 0d58480..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.argeo.geo;
-
-import java.util.Map;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-/** Geo data utilities. */
-public class GeoJsonUtils {
-
-       /** Add these properties to all features. */
-       public static void addProperties(JsonNode tree, Map<String, String> map) {
-               for (JsonNode feature : tree.get("features")) {
-                       ObjectNode properties = (ObjectNode) feature.get("properties");
-                       for (String key : map.keySet()) {
-                               properties.put(key, map.get(key));
-                       }
-               }
-       }
-
-       /** Singleton. */
-       private GeoJsonUtils() {
-       }
-}
diff --git a/org.argeo.app.core/src/org/argeo/geo/GeoToSvg.java b/org.argeo.app.core/src/org/argeo/geo/GeoToSvg.java
deleted file mode 100644 (file)
index 4d593f2..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.argeo.geo;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-/** Converts a geographical feature to an SVG. */
-public class GeoToSvg {
-       public void convertGeoJsonToSvg(Path source, Path target) {
-               ObjectMapper objectMapper = new ObjectMapper();
-               try (InputStream in = Files.newInputStream(source);
-                               Writer out = Files.newBufferedWriter(target, StandardCharsets.UTF_8)) {
-                       JsonNode tree = objectMapper.readTree(in);
-                       JsonNode coord = tree.get("features").get(0).get("geometry").get("coordinates");
-                       double ratio = 100;
-                       double minX = Double.POSITIVE_INFINITY;
-                       double maxX = Double.NEGATIVE_INFINITY;
-                       double minY = Double.POSITIVE_INFINITY;
-                       double maxY = Double.NEGATIVE_INFINITY;
-                       List<String> shapes = new ArrayList<>();
-                       for (JsonNode shape : coord) {
-                               StringBuffer sb = new StringBuffer();
-                               sb.append("<polyline style=\"stroke-width:0.00000003;stroke:#000000;\" points=\"");
-                               for (JsonNode latlng : shape) {
-                                       double lat = latlng.get(0).asDouble();
-                                       double y = lat * ratio;
-                                       if (y < minY)
-                                               minY = y;
-                                       if (y > maxY)
-                                               maxY = y;
-                                       double lng = latlng.get(1).asDouble();
-                                       double x = lng * ratio;
-                                       if (x < minX)
-                                               minX = x;
-                                       if (x > maxX)
-                                               maxX = x;
-                                       sb.append(y + "," + x + " ");
-                               }
-                               sb.append("\">");
-                               sb.append("</polyline>\n");
-                               shapes.add(sb.toString());
-                       }
-
-                       double width = maxX - minX;
-                       double height = maxY - minY;
-                       out.write("<svg xmlns=\"http://www.w3.org/2000/svg\"\n");
-                       out.write(" width=\"" + (int) (width * 1000) + "\"\n");
-                       out.write(" height=\"" + (int) (height * 1000) + "\"\n");
-                       out.write(" viewBox=\"" + minX + "," + minY + "," + width + "," + height + "\"\n");
-                       out.write(">\n");
-                       for (String shape : shapes) {
-                               out.write(shape);
-                               out.write("\n");
-                       }
-                       out.write("</svg>");
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot convert " + source + " to " + target, e);
-               }
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/suite/RankedObject.java b/org.argeo.app.core/src/org/argeo/suite/RankedObject.java
deleted file mode 100644 (file)
index b3ba37d..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-package org.argeo.suite;
-
-import java.util.Map;
-
-import org.argeo.api.cms.CmsLog;
-
-/**
- * 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 CmsLog log = CmsLog.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.app.core/src/org/argeo/suite/RankingKey.java b/org.argeo.app.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.app.core/src/org/argeo/suite/SuiteRole.java b/org.argeo.app.core/src/org/argeo/suite/SuiteRole.java
deleted file mode 100644 (file)
index 7f3af76..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.suite;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.util.naming.Distinguished;
-import org.argeo.util.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(CmsConstants.ROLES_BASEDN).toString();
-       }
-}
diff --git a/org.argeo.app.core/src/org/argeo/suite/SuiteUtils.java b/org.argeo.app.core/src/org/argeo/suite/SuiteUtils.java
deleted file mode 100644 (file)
index e6d4960..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-package org.argeo.suite;
-
-import java.util.HashSet;
-import java.util.Set;
-
-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.cms.CmsSession;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.entity.EntityType;
-import org.argeo.jackrabbit.security.JackrabbitSecurityUtils;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.util.naming.LdapAttrs;
-
-/** Utilities around the Argeo Suite APIs. */
-public class SuiteUtils {
-
-       public 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(), CmsConstants.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() {
-
-       }
-
-       public static Set<String> extractRoles(String[] semiColArr) {
-               Set<String> res = new HashSet<>();
-               // TODO factorize and make it more robust
-               final String rolesPrefix = "roles:=\"";
-               // first one is layer id
-               for (int i = 1; i < semiColArr.length; i++) {
-                       if (semiColArr[i].startsWith(rolesPrefix)) {
-                               String rolesStr = semiColArr[i].substring(rolesPrefix.length());
-                               // remove last "
-                               rolesStr = rolesStr.substring(0, rolesStr.lastIndexOf('\"'));
-                               // TODO support AND (&) as well
-                               String[] roles = rolesStr.split("\\|");// OR (|)
-                               for (String role : roles) {
-                                       res.add(role.trim());
-                               }
-                       }
-               }
-               return res;
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/suite/core/CustomMaintenanceService.java b/org.argeo.app.core/src/org/argeo/suite/core/CustomMaintenanceService.java
deleted file mode 100644 (file)
index 4cd05cf..0000000
+++ /dev/null
@@ -1,73 +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.argeo.api.cms.CmsLog;
-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 CmsLog log = CmsLog.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);
-                       }
-                       // TODO do not save here, so that upper layers can decide when to save
-                       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.");
-                       // TODO do not save here, so that upper layers can decide when to save
-                       termsBase.getSession().save();
-               } catch (RepositoryException | IOException e) {
-                       log.error("Cannot load terms '" + name + "': " + e.getMessage());
-                       throw e;
-               }
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/suite/core/SuiteMaintenanceService.java b/org.argeo.app.core/src/org/argeo/suite/core/SuiteMaintenanceService.java
deleted file mode 100644 (file)
index ab2043f..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.cms.CmsConstants;
-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(), CmsConstants.ROLE_USER_ADMIN,
-                               Privilege.JCR_ALL);
-               //JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), Privilege.JCR_READ);
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/suite/core/SuiteTerm.java b/org.argeo.app.core/src/org/argeo/suite/core/SuiteTerm.java
deleted file mode 100644 (file)
index 227b567..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.argeo.suite.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.entity.Term;
-
-/**
- * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
- */
-class SuiteTerm implements Term {
-       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 + 1);
-               } else {
-                       this.name = relativePath;
-               }
-               id = typology.getName() + '/' + relativePath;
-       }
-
-       @Override
-       public String getId() {
-               return id;
-       }
-
-       @Override
-       public String getName() {
-               return name;
-       }
-
-       public String getRelativePath() {
-               return relativePath;
-       }
-
-       @Override
-       public SuiteTypology getTypology() {
-               return typology;
-       }
-
-       @Override
-       public List<SuiteTerm> getSubTerms() {
-               return subTerms;
-       }
-
-       @Override
-       public SuiteTerm getParentTerm() {
-               return parentTerm;
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/suite/core/SuiteTermsManager.java b/org.argeo.app.core/src/org/argeo/suite/core/SuiteTermsManager.java
deleted file mode 100644 (file)
index 41126c3..0000000
+++ /dev/null
@@ -1,103 +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.cms.CmsConstants;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.entity.Term;
-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 = CmsJcrUtils.openDataAdminSession(repository, CmsConstants.SYS_WORKSPACE);
-       }
-
-       @Override
-       public List<Term> listAllTerms(String typology) {
-               List<Term> res = new ArrayList<>();
-               SuiteTypology t = getTypology(typology);
-               for (SuiteTerm term : t.getAllTerms()) {
-                       res.add(term);
-               }
-               return res;
-       }
-
-       @Override
-       public SuiteTerm getTerm(String termId) {
-               return terms.get(termId);
-       }
-
-       @Override
-       public 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.app.core/src/org/argeo/suite/core/SuiteTypology.java b/org.argeo.app.core/src/org/argeo/suite/core/SuiteTypology.java
deleted file mode 100644 (file)
index d9d6673..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.argeo.suite.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-
-import org.argeo.entity.Term;
-import org.argeo.entity.Typology;
-import org.argeo.jcr.Jcr;
-
-/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
-class SuiteTypology implements Typology {
-       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);
-       }
-
-       @Override
-       public String getId() {
-               return name;
-       }
-
-       public String getName() {
-               return name;
-       }
-
-       public Node getNode() {
-               return node;
-       }
-
-       void markNotFlat() {
-               if (isFlat)
-                       isFlat = false;
-       }
-
-       @Override
-       public boolean isFlat() {
-               return isFlat;
-       }
-
-       @Override
-       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;
-               }
-       }
-
-       public Term findTermByName(String name) {
-               List<SuiteTerm> collected = new ArrayList<>();
-               for (SuiteTerm subTerm : subTerms) {
-                       collectTermsByName(subTerm, name, collected);
-               }
-               if (collected.isEmpty())
-                       return null;
-               if (collected.size() == 1)
-                       return collected.get(0);
-               throw new IllegalArgumentException(
-                               "There are " + collected.size() + " terms with name " + name + " in typology " + getId());
-       }
-
-       private void collectTermsByName(SuiteTerm term, String name, List<SuiteTerm> collected) {
-               if (term.getName().equals(name)) {
-                       collected.add(term);
-               }
-               for (SuiteTerm subTerm : term.getSubTerms()) {
-                       collectTermsByName(subTerm, name, collected);
-               }
-       }
-
-       private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
-               for (SuiteTerm subTerm : term.getSubTerms()) {
-                       terms.add(subTerm);
-                       collectSubTerms(terms, subTerm);
-               }
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/suite/library/DocxExtractor.java b/org.argeo.app.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.app.core/src/org/argeo/suite/util/XPathUtils.java b/org.argeo.app.core/src/org/argeo/suite/util/XPathUtils.java
deleted file mode 100644 (file)
index df56d3f..0000000
+++ /dev/null
@@ -1,176 +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.jackrabbit.util.ISO9075;
-import org.argeo.api.cms.CmsLog;
-
-/** Ease XPath generation for JCR requests */
-public class XPathUtils {
-       private final static CmsLog log = CmsLog.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.app.core/src/org/argeo/support/geonames/GeonamesAdm.java b/org.argeo.app.core/src/org/argeo/support/geonames/GeonamesAdm.java
deleted file mode 100644 (file)
index d578272..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-package org.argeo.support.geonames;
-
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-
-/** A Geonames administrative subdivision. */
-public class GeonamesAdm {
-       private final Long geonameId;
-       private final String countryCode;
-       private final String adminCode1;
-       private final String admLevel;
-       private final Integer level;
-       private final String name;
-       private final String asciiName;
-       private final List<String> alternateNames;
-       private final Double lat;
-       private final Double lng;
-       private final LocalDate lastUpdated;
-       private final ZoneId timeZone;
-
-       private final Long[] upperLevelIds = new Long[5];
-       private final List<GeonamesAdm> upperLevels = new ArrayList<>();
-
-       private List<String> row;
-
-       /** Initialise from a row in the main Geonames table. */
-       public GeonamesAdm(List<String> row) {
-               geonameId = Long.parseLong(row.get(0));
-               admLevel = row.get(7);
-               countryCode = row.get(8);
-               adminCode1 = row.get(10);
-               if (admLevel.startsWith("ADM")) {
-                       if (admLevel.endsWith("H"))
-                               level = Integer.parseInt(admLevel.substring(3, admLevel.length() - 1));
-                       else
-                               level = Integer.parseInt(admLevel.substring(3));
-               } else if (admLevel.equals("PCLI")) {
-                       level = 0;
-               } else {
-                       throw new IllegalArgumentException("Unsupported admin level " + admLevel);
-               }
-               name = row.get(1);
-               asciiName = row.get(2);
-               alternateNames = Arrays.asList(row.get(3).split(","));
-               lat = Double.parseDouble(row.get(4));
-               lng = Double.parseDouble(row.get(5));
-               lastUpdated = LocalDate.parse(row.get(18));
-               timeZone = ZoneId.of(row.get(17));
-               // upper levels
-               if (row.get(11) != null && !row.get(11).trim().equals(""))
-                       upperLevelIds[2] = Long.parseLong(row.get(11));
-               if (row.get(12) != null && !row.get(12).trim().equals(""))
-                       upperLevelIds[3] = Long.parseLong(row.get(12));
-               if (row.get(13) != null && !row.get(13).trim().equals(""))
-                       upperLevelIds[4] = Long.parseLong(row.get(13));
-               this.row = row;
-       }
-
-       public void mapUpperLevels(Map<Long, GeonamesAdm> index) {
-               for (int i = 0; i < level; i++) {
-                       Long geonameId = upperLevelIds[i];
-                       upperLevels.add(i, index.get(geonameId));
-               }
-       }
-
-       public Long getGeonameId() {
-               return geonameId;
-       }
-
-       public Integer getLevel() {
-               return level;
-       }
-
-       public String getName() {
-               return name;
-       }
-
-       public String getName(Function<String, String> transform) {
-               if (transform != null)
-                       return transform.apply(name);
-               else
-                       return name;
-
-       }
-
-       public String getAsciiName() {
-               return asciiName;
-       }
-
-       public List<String> getAlternateNames() {
-               return alternateNames;
-       }
-
-       public Double getLat() {
-               return lat;
-       }
-
-       public Double getLng() {
-               return lng;
-       }
-
-       public String getCountryCode() {
-               return countryCode;
-       }
-
-       public String getAdmLevel() {
-               return admLevel;
-       }
-
-       public List<String> getRow() {
-               return row;
-       }
-
-       public LocalDate getLastUpdated() {
-               return lastUpdated;
-       }
-
-       public ZoneId getTimeZone() {
-               return timeZone;
-       }
-
-       public String getAdminCode1() {
-               return adminCode1;
-       }
-
-       public Long[] getUpperLevelIds() {
-               return upperLevelIds;
-       }
-
-       public List<GeonamesAdm> getUpperLevels() {
-               return upperLevels;
-       }
-
-       @Override
-       public int hashCode() {
-               return geonameId.intValue();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (!(obj instanceof GeonamesAdm))
-                       return false;
-               GeonamesAdm other = (GeonamesAdm) obj;
-               return geonameId.equals(other.geonameId);
-       }
-
-       @Override
-       public String toString() {
-               return name + " (ADM" + level + " " + geonameId + ")";
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/geonames/ImportGeonamesAdmin.java b/org.argeo.app.core/src/org/argeo/support/geonames/ImportGeonamesAdmin.java
deleted file mode 100644 (file)
index 9af5987..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-package org.argeo.support.geonames;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.argeo.util.CsvParser;
-import org.argeo.util.CsvWriter;
-
-/** Import GeoNames administrative division from the main table. */
-public class ImportGeonamesAdmin {
-       // private Log log = LogFactory.getLog(ImportGeonamesAdmin.class);
-       private Map<Long, GeonamesAdm> geonamesAdms = new HashMap<>();
-
-       /** Loads the data. */
-       public void parse(InputStream in) {
-               Map<String, Long> countryGeonameIds = new HashMap<>();
-               Map<String, Long> admin1GeonameIds = new HashMap<>();
-               CsvParser csvParser = new CsvParser() {
-
-                       @Override
-                       protected void processLine(Integer lineNumber, List<String> header, List<String> tokens) {
-                               if (!"A".equals(tokens.get(6)))
-                                       return;
-                               GeonamesAdm geonamesAdm = new GeonamesAdm(tokens);
-                               geonamesAdms.put(geonamesAdm.getGeonameId(), geonamesAdm);
-                               if (geonamesAdm.getAdmLevel().equals("PCLI"))
-                                       countryGeonameIds.put(geonamesAdm.getCountryCode(), geonamesAdm.getGeonameId());
-                               if (geonamesAdm.getAdmLevel().equals("ADM1"))
-                                       admin1GeonameIds.put(geonamesAdm.getAdminCode1(), geonamesAdm.getGeonameId());
-                       }
-               };
-               csvParser.setSeparator('\t');
-               csvParser.setNoHeader(true);
-               csvParser.parse(in, StandardCharsets.UTF_8);
-
-               // fill upper levels
-               for (GeonamesAdm adm : geonamesAdms.values()) {
-                       adm.getUpperLevelIds()[0] = countryGeonameIds.get(adm.getCountryCode());
-                       if (adm.getLevel() > 0)
-                               adm.getUpperLevelIds()[1] = admin1GeonameIds.get(adm.getAdminCode1());
-                       adm.mapUpperLevels(geonamesAdms);
-               }
-
-       }
-
-       public Map<Long, GeonamesAdm> getGeonamesAdms() {
-               return geonamesAdms;
-       }
-
-       /**
-        * Copies only the Geonames of feature class 'A' (administrative subdivisions).
-        */
-       public static void filterGeonamesAdm(InputStream in, OutputStream out) {
-               CsvWriter csvWriter = new CsvWriter(out, StandardCharsets.UTF_8);
-               csvWriter.setSeparator('\t');
-               CsvParser csvParser = new CsvParser() {
-
-                       @Override
-                       protected void processLine(Integer lineNumber, List<String> header, List<String> tokens) {
-                               if (tokens.size() < 7 || !"A".equals(tokens.get(6)))
-                                       return;
-                               csvWriter.writeLine(tokens);
-                       }
-               };
-               csvParser.setSeparator('\t');
-               csvParser.setNoHeader(true);
-               csvParser.parse(in, StandardCharsets.UTF_8);
-       }
-
-       public static void main(String[] args) throws IOException {
-//             String country = "allCountries";
-               String country = "CI";
-//             try (InputStream in = Files
-//                             .newInputStream(Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + ".txt"));
-//                             OutputStream out = Files.newOutputStream(
-//                                             Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) {
-//                     ImportGeonamesAdmin.filterGeonamesAdm(in, out);
-//             }
-               try (InputStream in = Files.newInputStream(
-                               Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) {
-                       ImportGeonamesAdmin importGeonamesAdmin = new ImportGeonamesAdmin();
-                       importGeonamesAdmin.parse(in);
-               }
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/odk/BundleResourceOdkForm.java b/org.argeo.app.core/src/org/argeo/support/odk/BundleResourceOdkForm.java
deleted file mode 100644 (file)
index fc55f35..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.argeo.support.odk;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Map;
-
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.io.IOUtils;
-import org.argeo.util.DigestUtils;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-
-/** {@link OdkForm} implementation based on an OSGi {@link Bundle} resource. */
-public class BundleResourceOdkForm implements OdkForm {
-       private String formId;
-       private String name;
-       private String version;
-       private String description;
-       private String hash;
-       private String fileName;
-
-       private byte[] data;
-
-       public void init(Map<String, String> properties, BundleContext bundleContext) throws IOException {
-               String location = properties.get("location");
-               fileName = FilenameUtils.getName(location);
-               URL url = bundleContext.getBundle().getResource(location);
-               data = IOUtils.toByteArray(url.openStream());
-               hash = "md5:" + DigestUtils.digest(DigestUtils.MD5, data);
-
-               // TODO get it from the XML
-               formId = properties.get("formId");
-               version = properties.get("version");
-
-               name = properties.get("name");
-               description = properties.get("description");
-       }
-
-       @Override
-       public String getFormId() {
-               return formId;
-       }
-
-       @Override
-       public String getName() {
-               return name;
-       }
-
-       @Override
-       public String getVersion() {
-               return version;
-       }
-
-       @Override
-       public String getDescription() {
-               return description;
-       }
-
-       @Override
-       public String getHash(String hashType) {
-               return hash;
-       }
-
-       @Override
-       public String getFileName() {
-               return fileName;
-       }
-
-       @Override
-       public InputStream openStream() {
-               return new ByteArrayInputStream(data);
-       }
-
-       @Override
-       public int hashCode() {
-               assert formId != null;
-               assert version != null;
-               return formId.hashCode() + version.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               assert formId != null;
-               assert version != null;
-               if (!(obj instanceof OdkForm))
-                       return false;
-               OdkForm other = (OdkForm) obj;
-               assert other.getFormId() != null;
-               assert other.getVersion() != null;
-
-               return other.getFormId().equals(formId) && other.getVersion().equals(version);
-       }
-
-       @Override
-       public String toString() {
-               return "ODK Form " + formId + ", v" + version;
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/odk/OdkForm.java b/org.argeo.app.core/src/org/argeo/support/odk/OdkForm.java
deleted file mode 100644 (file)
index 7b79a13..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.argeo.support.odk;
-
-import java.io.InputStream;
-
-/** Abstraction of a single ODK form. */
-public interface OdkForm {
-       String getFormId();
-
-       String getName();
-
-       String getVersion();
-
-       String getDescription();
-
-       String getHash(String hashType);
-
-       String getFileName();
-
-       InputStream openStream();
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/odk/OdkNames.java b/org.argeo.app.core/src/org/argeo/support/odk/OdkNames.java
deleted file mode 100644 (file)
index fbb2087..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.argeo.support.odk;
-
-/** Names related to ODK. */
-public interface OdkNames {
-
-       public final static String H_HTML = "h:html";
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/odk/OdkUtils.java b/org.argeo.app.core/src/org/argeo/support/odk/OdkUtils.java
deleted file mode 100644 (file)
index 940103f..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-package org.argeo.support.odk;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.query.RowIterator;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.entity.EntityMimeType;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.JcrxApi;
-import org.argeo.util.DigestUtils;
-
-/** Utilities around ODK. */
-public class OdkUtils {
-       private final static CmsLog log = CmsLog.getLog(OdkUtils.class);
-
-       public static Node loadOdkForm(Node formBase, String name, InputStream in, InputStream... additionalNodes)
-                       throws RepositoryException, IOException {
-               if (!formBase.isNodeType(EntityType.formSet.get()))
-                       throw new IllegalArgumentException(
-                                       "Parent path " + formBase + " must be of type " + EntityType.formSet.get());
-               Node form = JcrUtils.getOrAdd(formBase, name, OrxListName.xform.get(), NodeType.MIX_VERSIONABLE);
-
-               String previousCsum = JcrxApi.getChecksum(form, JcrxApi.MD5);
-               String previousFormId = Jcr.get(form, OrxListName.formID.get());
-               String previousFormVersion = Jcr.get(form, OrxListName.version.get());
-
-               Session s = formBase.getSession();
-               s.importXML(form.getPath(), in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-
-               for (InputStream additionalIn : additionalNodes) {
-                       s.importXML(form.getPath(), additionalIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-               }
-               s.save();
-
-               // manage instances
-               // NodeIterator instances =
-               // form.getNodes("h:html/h:head/xforms:model/xforms:instance");
-               NodeIterator instances = form.getNode("h:html/h:head/xforms:model").getNodes("xforms:instance");
-               Node primaryInstance = null;
-               while (instances.hasNext()) {
-                       Node instance = instances.nextNode();
-                       if (primaryInstance == null) {
-                               primaryInstance = instance;
-                       } else {// secondary instances
-                               String instanceId = instance.getProperty("id").getString();
-                               URI instanceUri = null;
-                               if (instance.hasProperty("src"))
-                                       try {
-                                               instanceUri = new URI(instance.getProperty("src").getString());
-                                       } catch (URISyntaxException e) {
-                                               throw new IllegalArgumentException("Instance " + instanceId + " has a badly formatted URI", e);
-                                       }
-                               if (instanceUri != null) {
-                                       if ("jr".equals(instanceUri.getScheme())) {
-                                               String uuid;
-                                               String mimeType;
-                                               String encoding = StandardCharsets.UTF_8.name();
-                                               String type = instanceUri.getHost();
-                                               String path = instanceUri.getPath();
-                                               if ("file".equals(type)) {
-                                                       if (!path.endsWith(".xml"))
-                                                               throw new IllegalArgumentException("File uri " + instanceUri + " must end with .xml");
-                                                       // Work around bug in ODK Collect not supporting paths
-                                                       // path = path.substring(0, path.length() - ".xml".length());
-                                                       // Node target = file.getSession().getNode(path);
-                                                       uuid = path.substring(1, path.length() - ".xml".length());
-                                                       mimeType = EntityMimeType.XML.getMimeType();
-                                               } else if ("file-csv".equals(type)) {
-                                                       if (!path.endsWith(".csv"))
-                                                               throw new IllegalArgumentException("File uri " + instanceUri + " must end with .csv");
-                                                       // Work around bug in ODK Collect not supporting paths
-                                                       // path = path.substring(0, path.length() - ".csv".length());
-                                                       // Node target = file.getSession().getNode(path);
-                                                       uuid = path.substring(1, path.length() - ".csv".length());
-                                                       mimeType = EntityMimeType.CSV.getMimeType();
-                                               } else {
-                                                       throw new IllegalArgumentException("Unsupported instance type " + type);
-                                               }
-                                               Node manifest = JcrUtils.getOrAdd(form, OrxManifestName.manifest.name(),
-                                                               OrxManifestName.manifest.get());
-                                               Node file = JcrUtils.getOrAdd(manifest, instanceId);
-                                               file.addMixin(NodeType.MIX_MIMETYPE);
-                                               file.setProperty(Property.JCR_MIMETYPE, mimeType);
-                                               file.setProperty(Property.JCR_ENCODING, encoding);
-                                               Node target = file.getSession().getNodeByIdentifier(uuid);
-
-                                               if (target.isNodeType(NodeType.NT_QUERY)) {
-                                                       Query query = target.getSession().getWorkspace().getQueryManager().getQuery(target);
-                                                       query.setLimit(10);
-                                                       QueryResult queryResult = query.execute();
-                                                       RowIterator rit = queryResult.getRows();
-                                                       while (rit.hasNext()) {
-                                                               Row row = rit.nextRow();
-                                                               for (Value value : row.getValues()) {
-                                                                       System.out.print(value.getString());
-                                                                       System.out.print(',');
-                                                               }
-                                                               System.out.print('\n');
-                                                       }
-
-                                               }
-
-                                               if (target.isNodeType(NodeType.MIX_REFERENCEABLE)) {
-                                                       file.setProperty(Property.JCR_ID, target);
-                                                       if (file.hasProperty(Property.JCR_PATH))
-                                                               file.getProperty(Property.JCR_PATH).remove();
-                                               } else {
-                                                       file.setProperty(Property.JCR_PATH, target.getPath());
-                                                       if (file.hasProperty(Property.JCR_ID))
-                                                               file.getProperty(Property.JCR_ID).remove();
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               if (primaryInstance == null)
-                       throw new IllegalArgumentException("No primary instance found in " + form);
-               if (!primaryInstance.hasNodes())
-                       throw new IllegalArgumentException("No data found in primary instance of " + form);
-               NodeIterator primaryInstanceChildren = primaryInstance.getNodes();
-               Node data = primaryInstanceChildren.nextNode();
-               if (primaryInstanceChildren.hasNext())
-                       throw new IllegalArgumentException("More than one data found in primary instance of " + form);
-               String formId = data.getProperty("id").getString();
-               if (previousFormId != null && !formId.equals(previousFormId))
-                       log.warn("Form id of " + form + " changed from " + previousFormId + " to " + formId);
-               form.setProperty(OrxListName.formID.get(), formId);
-               String formVersion = data.getProperty("version").getString();
-
-               if (previousCsum == null)// save before checksuming
-                       s.save();
-               String newCsum;
-               try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-                       s.exportDocumentView(form.getPath() + "/" + OdkNames.H_HTML, out, true, false);
-                       newCsum = DigestUtils.digest(DigestUtils.MD5, out.toByteArray());
-               }
-               if (previousCsum == null) {
-                       JcrxApi.addChecksum(form, newCsum);
-                       JcrUtils.updateLastModified(form);
-                       form.setProperty(OrxListName.version.get(), formVersion);
-                       s.save();
-                       s.getWorkspace().getVersionManager().checkpoint(form.getPath());
-                       if (log.isDebugEnabled())
-                               log.debug("New form " + form);
-               } else {
-                       if (newCsum.equals(previousCsum)) {
-                               // discard
-                               s.refresh(false);
-                               if (log.isDebugEnabled())
-                                       log.debug("Unmodified form " + form);
-                               return form;
-                       } else {
-                               if (formVersion.equals(previousFormVersion)) {
-                                       s.refresh(false);
-                                       throw new IllegalArgumentException("Form " + form + " has been changed but version " + formVersion
-                                                       + " has not been changed, discarding changes...");
-                               }
-                               form.setProperty(OrxListName.version.get(), formVersion);
-                               JcrxApi.addChecksum(form, newCsum);
-                               JcrUtils.updateLastModified(form);
-                               s.save();
-                               s.getWorkspace().getVersionManager().checkpoint(form.getPath());
-                               if (log.isDebugEnabled()) {
-                                       log.debug("Updated form " + form);
-                                       log.debug("Previous csum " + previousCsum);
-                                       log.debug("New csum " + newCsum);
-                               }
-                       }
-               }
-               return form;
-       }
-
-       /** Singleton. */
-       private OdkUtils() {
-
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/odk/OrxListName.java b/org.argeo.app.core/src/org/argeo/support/odk/OrxListName.java
deleted file mode 100644 (file)
index 0404c90..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.argeo.support.odk;
-
-import org.argeo.entity.JcrName;
-
-/** Types related to the http://openrosa.org/xforms/xformsList namespace. */
-public enum OrxListName implements JcrName {
-       xform,
-       // names
-       formID, version;
-
-       @Override
-       public String getPrefix() {
-               return prefix();
-       }
-
-       public static String prefix() {
-               return "orxList";
-       }
-
-       @Override
-       public String getNamespace() {
-               return namespace();
-       }
-
-       public static String namespace() {
-               return "http://openrosa.org/xforms/xformsList";
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/odk/OrxManifestName.java b/org.argeo.app.core/src/org/argeo/support/odk/OrxManifestName.java
deleted file mode 100644 (file)
index c9fcc5d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.argeo.support.odk;
-
-import org.argeo.entity.JcrName;
-
-/** Types related to the http://openrosa.org/xforms/xformsList namespace. */
-public enum OrxManifestName implements JcrName {
-       manifest, mediaFile;
-
-       @Override
-       public String getPrefix() {
-               return prefix();
-       }
-
-       public static String prefix() {
-               return "orxManifest";
-       }
-
-       @Override
-       public String getNamespace() {
-               return namespace();
-       }
-
-       public static String namespace() {
-               return "http://openrosa.org/xforms/xformsManifest";
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/odk/OrxType.java b/org.argeo.app.core/src/org/argeo/support/odk/OrxType.java
deleted file mode 100644 (file)
index 3b5d601..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.argeo.support.odk;
-
-import org.argeo.entity.JcrName;
-
-/** Types related to the http://openrosa.org/xforms/xformsList namespace. */
-public enum OrxType implements JcrName {
-       submission, xml_submission_file;
-
-       @Override
-       public String getPrefix() {
-               return prefix();
-       }
-
-       public static String prefix() {
-               return "orx";
-       }
-
-       @Override
-       public String getNamespace() {
-               return namespace();
-       }
-
-       public static String namespace() {
-               return "http://openrosa.org/xforms";
-       }
-
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/odk/odk.cnd b/org.argeo.app.core/src/org/argeo/support/odk/odk.cnd
deleted file mode 100644 (file)
index d80096d..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<jr = "http://openrosa.org/javarosa">
-<orx = "http://openrosa.org/xforms">
-<orxList = "http://openrosa.org/xforms/xformsList">
-<orxManifest = "http://openrosa.org/xforms/xformsManifest">
-<odk = "http://www.opendatakit.org/xforms">
-
-
-[odk:head]
-+ h:title (jcrx:xmlvalue) = jcrx:xmlvalue
-+ xforms:model (odk:model) = odk:model
-
-[odk:body] > xforms:ui
-
-
-[odk:html] > mix:referenceable
-+ h:head (odk:head) = odk:head
-+ h:body (odk:body) = odk:body
-
-[odk:model] > xforms:model
-+ odk:setgeopoint (odk:setgeopoint) = odk:setgeopoint
-+ xforms:itext (odk:itext) = odk:itext
-
-[odk:itext]
-+ xforms:translation (odk:translation) = odk:translation *
-
-[odk:translation]
-- lang (STRING) m
-- default (STRING)
-+ xforms:text (odk:text) = odk:text *
-
-[odk:text]
-- id (STRING) m
-+ xforms:value (jcrx:xmlvalue) = jcrx:xmlvalue
-
-[odk:setgeopoint]
-- event (STRING)
-- ref (STRING)
-
-// OpenRosa web API
-
-[orxList:xform] > mix:created, mix:lastModified, jcrx:csum, entity:form
-- orxList:formID (STRING)
-- orxList:version (STRING)
-+ h:html (odk:html) = odk:html
-+ manifest (orxManifest:manifest) = orxManifest:manifest
-
-[orxManifest:manifest]
-+ * (orxManifest:mediaFile) = orxManifest:mediaFile
-
-[orxManifest:mediaFile] > nt:address, jcrx:csum
-
-[orx:submission] > mix:created, entity:formSubmission
-+ xml_submission_file (nt:unstructured) = nt:unstructured
-+ * (nt:file) *
-
-
diff --git a/org.argeo.app.core/src/org/argeo/support/xforms/FormSubmissionListener.java b/org.argeo.app.core/src/org/argeo/support/xforms/FormSubmissionListener.java
deleted file mode 100644 (file)
index e23ef36..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.argeo.support.xforms;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-/** Called when a user has received a new form submission. */
-public interface FormSubmissionListener {
-       /** Called after a form submission has been stored in the user area. */
-       void formSubmissionReceived(Node node) throws RepositoryException;
-}
diff --git a/org.argeo.app.core/src/org/argeo/support/xforms/xforms.cnd b/org.argeo.app.core/src/org/argeo/support/xforms/xforms.cnd
deleted file mode 100644 (file)
index c24dbae..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<xforms = "http://www.w3.org/2002/xforms">
-
-[xforms:model]
-+ xforms:instance (xforms:instance) = xforms:instance *
-+ xforms:bind (xforms:bind) = xforms:bind *
-+ xforms:setvalue (xforms:setvalue) = xforms:setvalue *
-
-[xforms:instance] > nt:unstructured
-
-[xforms:bind]
-- * (STRING)
-
-[xforms:setvalue]
-- * (STRING)
-
-[xforms:select] > xforms:input
-+ xforms:itemset (xforms:itemset) = xforms:itemset
-
-[xforms:itemset]
-- nodeset (STRING)
-+ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue
-+ xforms:value (jcrx:xmlvalue) = jcrx:xmlvalue
-
-[xforms:ui]
-- * (STRING)
-+ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue *
-+ xforms:hint (jcrx:xmlvalue) = jcrx:xmlvalue *
-+ xforms:input (xforms:input) = xforms:input *
-+ xforms:select (xforms:select) = xforms:select *
-+ xforms:select1 (xforms:select) = xforms:select *
-+ xforms:trigger (xforms:input) = xforms:input *
-+ xforms:upload (xforms:input) = xforms:input *
-+ xforms:group (xforms:ui) = xforms:ui *
-+ xforms:repeat (xforms:ui) = xforms:ui *
-
-[xforms:input]
-- * (STRING)
-+ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue
-+ xforms:hint (jcrx:xmlvalue) = jcrx:xmlvalue *
index 937b474a198f9e53d5a278c2a3324db671cfb68a..89adf623f79bc9e4f5044b9e22c4d84827483912 100644 (file)
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ODK Form List Servlet">
-   <implementation class="org.argeo.support.odk.servlet.OdkFormListServlet"/>
+   <implementation class="org.argeo.app.odk.servlet.OdkFormListServlet"/>
    <service>
       <provide interface="javax.servlet.Servlet"/>
    </service>
    <property name="osgi.http.whiteboard.servlet.pattern" type="String" value="/formList/*"/>
    <property name="osgi.http.whiteboard.context.select" type="String" value="(osgi.http.whiteboard.context.name=odkServletContext)"/>
-   <reference bind="addForm" cardinality="0..n" interface="org.argeo.support.odk.OdkForm" name="OdkForm" policy="dynamic" unbind="removeForm"/>
+   <reference bind="addForm" cardinality="0..n" interface="org.argeo.app.odk.OdkForm" name="OdkForm" policy="dynamic" unbind="removeForm"/>
    <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=odk)"/>
 </scr:component>
index 7f7e4dbfdf64076913ab875470a96b0e86ef6024..ee3103150ec2a66d5c4829fae518caacb3c853f0 100644 (file)
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ODK Form Servlet">
-   <implementation class="org.argeo.support.odk.servlet.OdkFormServlet"/>
+   <implementation class="org.argeo.app.odk.servlet.OdkFormServlet"/>
    <service>
       <provide interface="javax.servlet.Servlet"/>
    </service>
    <property name="osgi.http.whiteboard.servlet.pattern" type="String" value="/form/*"/>
    <property name="osgi.http.whiteboard.context.select" type="String" value="(osgi.http.whiteboard.context.name=odkServletContext)"/>
-   <reference bind="addForm" cardinality="0..n" interface="org.argeo.support.odk.OdkForm" name="OdkForm" policy="dynamic" unbind="removeForm"/>
+   <reference bind="addForm" cardinality="0..n" interface="org.argeo.app.odk.OdkForm" name="OdkForm" policy="dynamic" unbind="removeForm"/>
    <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=odk)"/>
 </scr:component>
index cfc56ef270d7a1a234f5879b4b038427085adabf..00fd3dbdd77efd519073c17a3eb262253f30819e 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ODK Manifest Servlet">
-   <implementation class="org.argeo.support.odk.servlet.OdkManifestServlet"/>
+   <implementation class="org.argeo.app.odk.servlet.OdkManifestServlet"/>
    <service>
       <provide interface="javax.servlet.Servlet"/>
    </service>
index 78b5b6682af385ea6c7b55721ef4f64b7dd31eeb..78c6af2c69374c3d334e03e3e0be7e60f388e443 100644 (file)
@@ -1,6 +1,6 @@
 <?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="ODK Servlet Context">
-   <implementation class="org.argeo.support.odk.servlet.OdkServletContext"/>
+   <implementation class="org.argeo.app.odk.servlet.OdkServletContext"/>
    <service>
       <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
    </service>
index bce66c41457f9c1f13078588ed4a2de1077923a9..bc7659217e931ba8ad34549ae49656ecff42c269 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ODK Submission Servlet">
-   <implementation class="org.argeo.support.odk.servlet.OdkSubmissionServlet"/>
+   <implementation class="org.argeo.app.odk.servlet.OdkSubmissionServlet"/>
    <service>
       <provide interface="javax.servlet.Servlet"/>
    </service>
@@ -8,5 +8,5 @@
    <property name="osgi.http.whiteboard.context.select" type="String" value="(osgi.http.whiteboard.context.name=odkServletContext)"/>
    <property name="osgi.http.whiteboard.servlet.multipart.enabled" type="String" value="true"/>
    <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=odk)"/>
-   <reference bind="addSubmissionListener" cardinality="0..n" interface="org.argeo.support.xforms.FormSubmissionListener" name="FormSubmissionListener" policy="dynamic" unbind="removeSubmissionListener"/>
+   <reference bind="addSubmissionListener" cardinality="0..n" interface="org.argeo.app.xforms.FormSubmissionListener" name="FormSubmissionListener" policy="dynamic" unbind="removeSubmissionListener"/>
 </scr:component>
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormListServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormListServlet.java
new file mode 100644 (file)
index 0000000..c88bf4a
--- /dev/null
@@ -0,0 +1,169 @@
+package org.argeo.app.servlet.odk;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.odk.OdkForm;
+import org.argeo.app.odk.OrxListName;
+import org.argeo.app.odk.OrxManifestName;
+import org.argeo.cms.auth.RemoteAuthUtils;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrxApi;
+
+/** Lists available forms. */
+public class OdkFormListServlet extends HttpServlet {
+       private static final long serialVersionUID = 2706191315048423321L;
+       private final static CmsLog log = CmsLog.getLog(OdkFormListServlet.class);
+
+       private Set<OdkForm> odkForms = Collections.synchronizedSet(new HashSet<>());
+
+//     private DateTimeFormatter versionFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HHmm")
+//                     .withZone(ZoneId.from(ZoneOffset.UTC));
+
+       private Repository repository;
+
+       @Override
+       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+               resp.setContentType("text/xml; charset=utf-8");
+               resp.setHeader("X-OpenRosa-Version", "1.0");
+               resp.setDateHeader("Date", System.currentTimeMillis());
+
+               String serverName = req.getServerName();
+               int serverPort = req.getServerPort();
+               String protocol = serverPort == 443 || req.isSecure() ? "https" : "http";
+
+               String pathInfo = req.getPathInfo();
+
+               Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, CmsConstants.SYS_WORKSPACE),
+                               new ServletHttpRequest(req));
+//             session = NodeUtils.openDataAdminSession(repository, NodeConstants.SYS_WORKSPACE);
+               Writer writer = resp.getWriter();
+               writer.append("<?xml version='1.0' encoding='UTF-8' ?>");
+               writer.append("<xforms xmlns=\"http://openrosa.org/xforms/xformsList\">");
+               boolean oldApproach = false;
+               if (!oldApproach) {
+                       try {
+
+                               Query query;
+                               if (pathInfo == null) {
+//                             query = session.getWorkspace().getQueryManager()
+//                                             .createQuery("SELECT * FROM [nt:unstructured]", Query.JCR_SQL2);
+                                       query = session.getWorkspace().getQueryManager()
+                                                       .createQuery("SELECT * FROM [" + OrxListName.xform.get() + "]", Query.JCR_SQL2);
+                               } else {
+                                       query = session.getWorkspace().getQueryManager()
+                                                       .createQuery(
+                                                                       "SELECT node FROM [" + OrxListName.xform.get()
+                                                                                       + "] AS node WHERE ISDESCENDANTNODE (node, '" + pathInfo + "')",
+                                                                       Query.JCR_SQL2);
+                               }
+                               QueryResult queryResult = query.execute();
+
+                               NodeIterator nit = queryResult.getNodes();
+//                             log.debug(session.getUserID());
+//                             log.debug(session.getWorkspace().getName());
+//                             NodeIterator nit = session.getRootNode().getNodes();
+//                             while (nit.hasNext()) {
+//                                     log.debug(nit.nextNode());
+//                             }
+                               while (nit.hasNext()) {
+                                       StringBuilder sb = new StringBuilder();
+                                       Node node = nit.nextNode();
+                                       if (node.isNodeType(OrxListName.xform.get())) {
+                                               sb.append("<xform>");
+                                               sb.append("<formID>" + node.getProperty(OrxListName.formID.get()).getString() + "</formID>");
+                                               sb.append("<name>" + Jcr.getTitle(node) + "</name>");
+                                               sb.append("<version>" + node.getProperty(OrxListName.version.get()).getString() + "</version>");
+                                               sb.append("<hash>md5:" + JcrxApi.getChecksum(node, JcrxApi.MD5) + "</hash>");
+                                               if (node.hasProperty(Property.JCR_DESCRIPTION))
+                                                       sb.append("<name>" + node.getProperty(Property.JCR_DESCRIPTION).getString() + "</name>");
+                                               sb.append("<downloadUrl>" + protocol + "://" + serverName
+                                                               + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/form"
+                                                               + node.getPath() + "</downloadUrl>");
+                                               if (node.hasNode(OrxManifestName.manifest.name())) {
+                                                       sb.append("<manifestUrl>" + protocol + "://" + serverName
+                                                                       + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort)
+                                                                       + "/api/odk/formManifest" + node.getNode(OrxManifestName.manifest.name()).getPath()
+                                                                       + "</manifestUrl>");
+                                               }
+                                               sb.append("</xform>");
+                                       } else if (node.isNodeType(EntityType.formSet.get())) {
+                                               sb.append("<xforms-group>");
+                                               sb.append("<groupId>" + node.getPath() + "</groupId>");
+                                               sb.append("<name>" + node.getProperty(Property.JCR_TITLE).getString() + "</name>");
+                                               sb.append("<listUrl>" + protocol + "://" + serverName
+                                                               + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/formList"
+                                                               + node.getPath() + "</listUrl>");
+                                               sb.append("</xforms-group>");
+                                       }
+                                       String str = sb.toString();
+                                       if (!str.equals("")) {
+                                               if (log.isDebugEnabled())
+                                                       log.debug(str);
+                                               writer.append(str);
+                                       }
+                               }
+                       } catch (RepositoryException e) {
+                               e.printStackTrace();
+                               // TODO error message
+                               // resp.sendError(500);
+                               resp.sendError(503);
+                       } finally {
+                               Jcr.logout(session);
+                       }
+
+               } else {
+                       for (OdkForm form : odkForms) {
+                               StringBuilder sb = new StringBuilder();
+                               sb.append("<xform>");
+                               sb.append("<formID>" + form.getFormId() + "</formID>");
+                               sb.append("<name>" + form.getName() + "</name>");
+                               sb.append("<version>" + form.getVersion() + "</version>");
+                               sb.append("<hash>" + form.getHash(null) + "</hash>");
+                               sb.append("<descriptionText>" + form.getDescription() + "</descriptionText>");
+                               sb.append("<downloadUrl>" + protocol + "://" + serverName
+                                               + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/form/"
+                                               + form.getFileName() + "</downloadUrl>");
+                               sb.append("</xform>");
+                               String str = sb.toString();
+                               if (log.isDebugEnabled())
+                                       log.debug(str);
+                               writer.append(str);
+                       }
+               }
+               writer.append("</xforms>");
+       }
+
+       public void addForm(OdkForm odkForm) {
+               odkForms.add(odkForm);
+       }
+
+       public void removeForm(OdkForm odkForm) {
+               odkForms.remove(odkForm);
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkFormServlet.java
new file mode 100644 (file)
index 0000000..067262e
--- /dev/null
@@ -0,0 +1,84 @@
+package org.argeo.app.servlet.odk;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.FilenameUtils;
+import org.argeo.app.odk.OdkForm;
+import org.argeo.app.odk.OdkNames;
+import org.argeo.cms.auth.RemoteAuthUtils;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.jcr.Jcr;
+
+/** Retrieves a single form. */
+public class OdkFormServlet extends HttpServlet {
+       private static final long serialVersionUID = 7838305967987687370L;
+
+       private Repository repository;
+       private Map<String, OdkForm> odkForms = Collections.synchronizedMap(new HashMap<>());
+
+       @Override
+       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+               resp.setContentType("text/xml; charset=utf-8");
+
+               Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req));
+
+               String pathInfo = req.getPathInfo();
+               if (pathInfo.startsWith("//"))
+                       pathInfo = pathInfo.substring(1);
+
+               boolean oldApproach = false;
+               try {
+                       if (!oldApproach) {
+                               String path = URLDecoder.decode(pathInfo, StandardCharsets.UTF_8);
+                               session.exportDocumentView(path + "/" + OdkNames.H_HTML, resp.getOutputStream(), true, false);
+                       } else {
+
+                               String fileName = FilenameUtils.getName(pathInfo);
+                               OdkForm form = odkForms.get(fileName);
+                               if (form == null)
+                                       throw new IllegalArgumentException("No form named " + fileName + " was found");
+
+                               byte[] buffer = new byte[1024];
+                               try (InputStream in = form.openStream(); OutputStream out = resp.getOutputStream();) {
+                                       int bytesRead;
+                                       while ((bytesRead = in.read(buffer)) != -1)
+                                               out.write(buffer, 0, bytesRead);
+                               }
+                       }
+               } catch (RepositoryException e) {
+                       e.printStackTrace();
+                       // TODO error message
+                       resp.sendError(500);
+               } finally {
+                       Jcr.logout(session);
+               }
+       }
+
+       public void addForm(OdkForm odkForm) {
+               odkForms.put(odkForm.getFileName(), odkForm);
+       }
+
+       public void removeForm(OdkForm odkForm) {
+               odkForms.remove(odkForm.getFileName());
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java
new file mode 100644 (file)
index 0000000..245e0f2
--- /dev/null
@@ -0,0 +1,190 @@
+package org.argeo.app.servlet.odk;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.Row;
+import javax.jcr.query.RowIterator;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.output.NullOutputStream;
+import org.argeo.app.api.EntityMimeType;
+import org.argeo.app.odk.OrxManifestName;
+import org.argeo.cms.auth.RemoteAuthUtils;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.argeo.util.CsvWriter;
+import org.argeo.util.DigestUtils;
+
+/** Describe additional files. */
+public class OdkManifestServlet extends HttpServlet {
+       private static final long serialVersionUID = 138030510865877478L;
+
+       private Repository repository;
+
+       @Override
+       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+               resp.setHeader("X-OpenRosa-Version", "1.0");
+               resp.setDateHeader("Date", System.currentTimeMillis());
+
+               String pathInfo = req.getPathInfo();
+               if (pathInfo.startsWith("//"))
+                       pathInfo = pathInfo.substring(1);
+
+               String serverName = req.getServerName();
+               int serverPort = req.getServerPort();
+               String protocol = serverPort == 443 || req.isSecure() ? "https" : "http";
+
+               Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req));
+
+               try {
+                       Node node = session.getNode(pathInfo);
+                       if (node.isNodeType(OrxManifestName.manifest.get())) {
+                               resp.setContentType(EntityMimeType.XML.toHttpContentType());
+                               Writer writer = resp.getWriter();
+                               writer.append("<?xml version='1.0' encoding='UTF-8' ?>");
+                               writer.append("<manifest xmlns=\"http://openrosa.org/xforms/xformsManifest\">");
+                               NodeIterator nit = node.getNodes();
+                               children: while (nit.hasNext()) {
+                                       Node file = nit.nextNode();
+                                       if (file.isNodeType(OrxManifestName.mediaFile.get())) {
+                                               EntityMimeType mimeType = EntityMimeType
+                                                               .find(file.getProperty(Property.JCR_MIMETYPE).getString());
+                                               Charset charset = Charset.forName(file.getProperty(Property.JCR_ENCODING).getString());
+
+                                               if (file.isNodeType(NodeType.NT_ADDRESS)) {
+                                                       Node target;
+                                                       try {
+                                                               target = file.getProperty(Property.JCR_ID).getNode();
+                                                       } catch (ItemNotFoundException e) {
+                                                               // TODO remove old manifests
+                                                               continue children;
+                                                       }
+                                                       writer.append("<mediaFile>");
+                                                       writer.append("<filename>");
+                                                       // Work around bug in ODK Collect not supporting paths
+                                                       // writer.append(target.getPath().substring(1) + ".xml");
+                                                       writer.append(target.getIdentifier() + "." + mimeType.getDefaultExtension());
+                                                       writer.append("</filename>");
+
+                                                       MessageDigest messageDigest = MessageDigest.getInstance(DigestUtils.MD5);
+                                                       // TODO cache a temp file ?
+                                                       try (DigestOutputStream out = new DigestOutputStream(new NullOutputStream(),
+                                                                       messageDigest)) {
+                                                               writeMediaFile(out, target, mimeType, charset);
+                                                               writer.append("<hash>");
+                                                               writer.append("md5sum:" + DigestUtils.encodeHexString(out.getMessageDigest().digest()));
+                                                               writer.append("</hash>");
+                                                       }
+
+//                                                     try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+//                                                             session.exportDocumentView(target.getPath(), out, true, false);
+//                                                             String fileCsum = DigestUtils.digest(DigestUtils.MD5, out.toByteArray());
+//                                                             writer.append("<hash>");
+//                                                             writer.append("md5sum:" + fileCsum);
+//                                                             writer.append("</hash>");
+//                                                     }
+                                                       writer.append("<downloadUrl>" + protocol + "://" + serverName
+                                                                       + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort)
+                                                                       + "/api/odk/formManifest" + file.getPath() + "</downloadUrl>");
+                                               }
+                                               writer.append("</mediaFile>");
+                                       }
+                               }
+
+                               writer.append("</manifest>");
+                       } else if (node.isNodeType(OrxManifestName.mediaFile.get())) {
+                               EntityMimeType mimeType = EntityMimeType.find(node.getProperty(Property.JCR_MIMETYPE).getString());
+                               Charset charset = Charset.forName(node.getProperty(Property.JCR_ENCODING).getString());
+                               resp.setContentType(mimeType.toHttpContentType(charset));
+                               if (node.isNodeType(NodeType.NT_ADDRESS)) {
+                                       Node target = node.getProperty(Property.JCR_ID).getNode();
+
+                                       writeMediaFile(resp.getOutputStream(), target, mimeType, charset);
+//                                     try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+//                                             session.exportDocumentView(target.getPath(), out, true, false);
+//                                             System.out.println(new String(out.toByteArray(), StandardCharsets.UTF_8));
+//                                             resp.getOutputStream().write(out.toByteArray());
+//                                     }
+                               } else {
+                                       throw new IllegalArgumentException("Unsupported node " + node);
+                               }
+                       } else {
+                               throw new IllegalArgumentException("Unsupported node " + node);
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               } catch (NoSuchAlgorithmException e) {
+                       throw new ServletException(e);
+               } finally {
+                       Jcr.logout(session);
+               }
+
+       }
+
+       protected void writeMediaFile(OutputStream out, Node target, EntityMimeType mimeType, Charset charset)
+                       throws RepositoryException, IOException {
+               if (target.isNodeType(NodeType.NT_QUERY)) {
+                       Query query = target.getSession().getWorkspace().getQueryManager().getQuery(target);
+                       QueryResult queryResult = query.execute();
+                       String[] columnNames = queryResult.getColumnNames();
+                       if (EntityMimeType.XML.equals(mimeType)) {
+                       } else if (EntityMimeType.CSV.equals(mimeType)) {
+                               CsvWriter csvWriter = new CsvWriter(out, charset);
+                               csvWriter.writeLine(columnNames);
+                               RowIterator rit = queryResult.getRows();
+                               while (rit.hasNext()) {
+                                       Row row = rit.nextRow();
+                                       Value[] values = row.getValues();
+                                       List<String> lst = new ArrayList<>();
+                                       for (Value value : values) {
+                                               lst.add(value.getString());
+                                       }
+                                       csvWriter.writeLine(lst);
+                               }
+                       }
+               } else {
+                       if (EntityMimeType.XML.equals(mimeType)) {
+                               target.getSession().exportDocumentView(target.getPath(), out, true, false);
+                       } else if (EntityMimeType.CSV.equals(mimeType)) {
+                               CsvWriter csvWriter = new CsvWriter(out, charset);
+                               csvWriter.writeLine(new String[] { "name", "label" });
+                               NodeIterator children = target.getNodes();
+                               while (children.hasNext()) {
+                                       Node child = children.nextNode();
+                                       String label = Jcr.getTitle(child);
+                                       csvWriter.writeLine(new String[] { child.getIdentifier(), label });
+                               }
+                       }
+
+               }
+
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkServletContext.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkServletContext.java
new file mode 100644 (file)
index 0000000..4e2d535
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.app.servlet.odk;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.argeo.cms.servlet.PrivateWwwAuthServletContext;
+
+/** ODK specific authentication (with additional headers).*/
+public class OdkServletContext extends PrivateWwwAuthServletContext {
+
+       @Override
+       protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) {
+               super.askForWwwAuth(request, response);
+               response.setHeader("X-OpenRosa-Version", "1.0");
+               response.setDateHeader("Date", System.currentTimeMillis());
+
+       }
+
+}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java
new file mode 100644 (file)
index 0000000..9596ebd
--- /dev/null
@@ -0,0 +1,131 @@
+package org.argeo.app.servlet.odk;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.Part;
+
+import org.argeo.api.cms.CmsSession;
+import org.argeo.app.core.SuiteUtils;
+import org.argeo.app.odk.OrxType;
+import org.argeo.app.xforms.FormSubmissionListener;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.auth.RemoteAuthRequest;
+import org.argeo.cms.auth.RemoteAuthUtils;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrUtils;
+
+/** Receives a form submission. */
+public class OdkSubmissionServlet extends HttpServlet {
+       private static final long serialVersionUID = 7834401404691302385L;
+       private final static CmsLog log = CmsLog.getLog(OdkSubmissionServlet.class);
+
+       private final static String XML_SUBMISSION_FILE = "xml_submission_file";
+
+       private DateTimeFormatter submissionNameFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HHmmssSSS")
+                       .withZone(ZoneId.from(ZoneOffset.UTC));
+
+       private Repository repository;
+
+       private Set<FormSubmissionListener> submissionListeners = new HashSet<>();
+
+       @Override
+       protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+               resp.setContentType("text/xml; charset=utf-8");
+               resp.setHeader("X-OpenRosa-Version", "1.0");
+               resp.setDateHeader("Date", System.currentTimeMillis());
+               resp.setIntHeader("X-OpenRosa-Accept-Content-Length", 1024 * 1024);
+
+               RemoteAuthRequest request = new ServletHttpRequest(req);
+               Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), request);
+
+               try {
+//                     Node submissions = JcrUtils.mkdirs(session,
+//                                     "/" + EntityType.form.get() + "/" + EntityNames.SUBMISSIONS_BASE);
+                       CmsSession cmsSession = RemoteAuthUtils.getCmsSession(request);
+
+                       ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
+                       Thread.currentThread().setContextClassLoader(RemoteAuthUtils.class.getClassLoader());
+                       Session adminSession = null;
+                       try {
+                               // TODO centralise at a deeper level
+                               adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
+                               SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
+                       } finally {
+                               Jcr.logout(adminSession);
+                               Thread.currentThread().setContextClassLoader(currentContextCl);
+                       }
+
+                       Node cmsSessionNode = SuiteUtils.getCmsSessionNode(session, cmsSession);
+                       Node submission = cmsSessionNode.addNode(submissionNameFormatter.format(Instant.now()),
+                                       OrxType.submission.get());
+                       for (Part part : req.getParts()) {
+                               if (log.isDebugEnabled())
+                                       log.debug("Part: " + part.getName() + ", " + part.getContentType());
+
+                               if (part.getName().equals(XML_SUBMISSION_FILE)) {
+                                       Node xml = submission.addNode(XML_SUBMISSION_FILE, NodeType.NT_UNSTRUCTURED);
+                                       session.importXML(xml.getPath(), part.getInputStream(),
+                                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+
+                               } else {
+                                       Node fileNode = JcrUtils.copyStreamAsFile(submission, part.getName(), part.getInputStream());
+                                       String contentType = part.getContentType();
+                                       if (contentType != null) {
+                                               fileNode.addMixin(NodeType.MIX_MIMETYPE);
+                                               fileNode.setProperty(Property.JCR_MIMETYPE, contentType);
+
+                                       }
+                                       if (part.getName().endsWith(".jpg") || part.getName().endsWith(".png")) {
+                                               // TODO meta data and thumbnails
+                                       }
+                               }
+                       }
+                       session.save();
+                       for (FormSubmissionListener submissionListener : submissionListeners) {
+                               submissionListener.formSubmissionReceived(submission);
+                       }
+               } catch (RepositoryException e) {
+                       e.printStackTrace();
+                       resp.setStatus(503);
+                       return;
+               } finally {
+                       Jcr.logout(session);
+               }
+
+               resp.setStatus(201);
+               resp.getWriter().write("<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">"
+                               + "<message>Form Received!</message>" + "</OpenRosaResponse>");
+
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+       public synchronized void addSubmissionListener(FormSubmissionListener listener) {
+               submissionListeners.add(listener);
+       }
+
+       public synchronized void removeSubmissionListener(FormSubmissionListener listener) {
+               submissionListeners.remove(listener);
+       }
+}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkFormListServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkFormListServlet.java
deleted file mode 100644 (file)
index 16e525a..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-package org.argeo.support.odk.servlet;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.auth.RemoteAuthUtils;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrxApi;
-import org.argeo.support.odk.OdkForm;
-import org.argeo.support.odk.OrxListName;
-import org.argeo.support.odk.OrxManifestName;
-
-/** Lists available forms. */
-public class OdkFormListServlet extends HttpServlet {
-       private static final long serialVersionUID = 2706191315048423321L;
-       private final static CmsLog log = CmsLog.getLog(OdkFormListServlet.class);
-
-       private Set<OdkForm> odkForms = Collections.synchronizedSet(new HashSet<>());
-
-//     private DateTimeFormatter versionFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HHmm")
-//                     .withZone(ZoneId.from(ZoneOffset.UTC));
-
-       private Repository repository;
-
-       @Override
-       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-               resp.setContentType("text/xml; charset=utf-8");
-               resp.setHeader("X-OpenRosa-Version", "1.0");
-               resp.setDateHeader("Date", System.currentTimeMillis());
-
-               String serverName = req.getServerName();
-               int serverPort = req.getServerPort();
-               String protocol = serverPort == 443 || req.isSecure() ? "https" : "http";
-
-               String pathInfo = req.getPathInfo();
-
-               Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, CmsConstants.SYS_WORKSPACE),
-                               new ServletHttpRequest(req));
-//             session = NodeUtils.openDataAdminSession(repository, NodeConstants.SYS_WORKSPACE);
-               Writer writer = resp.getWriter();
-               writer.append("<?xml version='1.0' encoding='UTF-8' ?>");
-               writer.append("<xforms xmlns=\"http://openrosa.org/xforms/xformsList\">");
-               boolean oldApproach = false;
-               if (!oldApproach) {
-                       try {
-
-                               Query query;
-                               if (pathInfo == null) {
-//                             query = session.getWorkspace().getQueryManager()
-//                                             .createQuery("SELECT * FROM [nt:unstructured]", Query.JCR_SQL2);
-                                       query = session.getWorkspace().getQueryManager()
-                                                       .createQuery("SELECT * FROM [" + OrxListName.xform.get() + "]", Query.JCR_SQL2);
-                               } else {
-                                       query = session.getWorkspace().getQueryManager()
-                                                       .createQuery(
-                                                                       "SELECT node FROM [" + OrxListName.xform.get()
-                                                                                       + "] AS node WHERE ISDESCENDANTNODE (node, '" + pathInfo + "')",
-                                                                       Query.JCR_SQL2);
-                               }
-                               QueryResult queryResult = query.execute();
-
-                               NodeIterator nit = queryResult.getNodes();
-//                             log.debug(session.getUserID());
-//                             log.debug(session.getWorkspace().getName());
-//                             NodeIterator nit = session.getRootNode().getNodes();
-//                             while (nit.hasNext()) {
-//                                     log.debug(nit.nextNode());
-//                             }
-                               while (nit.hasNext()) {
-                                       StringBuilder sb = new StringBuilder();
-                                       Node node = nit.nextNode();
-                                       if (node.isNodeType(OrxListName.xform.get())) {
-                                               sb.append("<xform>");
-                                               sb.append("<formID>" + node.getProperty(OrxListName.formID.get()).getString() + "</formID>");
-                                               sb.append("<name>" + Jcr.getTitle(node) + "</name>");
-                                               sb.append("<version>" + node.getProperty(OrxListName.version.get()).getString() + "</version>");
-                                               sb.append("<hash>md5:" + JcrxApi.getChecksum(node, JcrxApi.MD5) + "</hash>");
-                                               if (node.hasProperty(Property.JCR_DESCRIPTION))
-                                                       sb.append("<name>" + node.getProperty(Property.JCR_DESCRIPTION).getString() + "</name>");
-                                               sb.append("<downloadUrl>" + protocol + "://" + serverName
-                                                               + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/form"
-                                                               + node.getPath() + "</downloadUrl>");
-                                               if (node.hasNode(OrxManifestName.manifest.name())) {
-                                                       sb.append("<manifestUrl>" + protocol + "://" + serverName
-                                                                       + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort)
-                                                                       + "/api/odk/formManifest" + node.getNode(OrxManifestName.manifest.name()).getPath()
-                                                                       + "</manifestUrl>");
-                                               }
-                                               sb.append("</xform>");
-                                       } else if (node.isNodeType(EntityType.formSet.get())) {
-                                               sb.append("<xforms-group>");
-                                               sb.append("<groupId>" + node.getPath() + "</groupId>");
-                                               sb.append("<name>" + node.getProperty(Property.JCR_TITLE).getString() + "</name>");
-                                               sb.append("<listUrl>" + protocol + "://" + serverName
-                                                               + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/formList"
-                                                               + node.getPath() + "</listUrl>");
-                                               sb.append("</xforms-group>");
-                                       }
-                                       String str = sb.toString();
-                                       if (!str.equals("")) {
-                                               if (log.isDebugEnabled())
-                                                       log.debug(str);
-                                               writer.append(str);
-                                       }
-                               }
-                       } catch (RepositoryException e) {
-                               e.printStackTrace();
-                               // TODO error message
-                               // resp.sendError(500);
-                               resp.sendError(503);
-                       } finally {
-                               Jcr.logout(session);
-                       }
-
-               } else {
-                       for (OdkForm form : odkForms) {
-                               StringBuilder sb = new StringBuilder();
-                               sb.append("<xform>");
-                               sb.append("<formID>" + form.getFormId() + "</formID>");
-                               sb.append("<name>" + form.getName() + "</name>");
-                               sb.append("<version>" + form.getVersion() + "</version>");
-                               sb.append("<hash>" + form.getHash(null) + "</hash>");
-                               sb.append("<descriptionText>" + form.getDescription() + "</descriptionText>");
-                               sb.append("<downloadUrl>" + protocol + "://" + serverName
-                                               + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/form/"
-                                               + form.getFileName() + "</downloadUrl>");
-                               sb.append("</xform>");
-                               String str = sb.toString();
-                               if (log.isDebugEnabled())
-                                       log.debug(str);
-                               writer.append(str);
-                       }
-               }
-               writer.append("</xforms>");
-       }
-
-       public void addForm(OdkForm odkForm) {
-               odkForms.add(odkForm);
-       }
-
-       public void removeForm(OdkForm odkForm) {
-               odkForms.remove(odkForm);
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkFormServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkFormServlet.java
deleted file mode 100644 (file)
index 9f84e52..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.argeo.support.odk.servlet;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.io.FilenameUtils;
-import org.argeo.cms.auth.RemoteAuthUtils;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.jcr.Jcr;
-import org.argeo.support.odk.OdkForm;
-import org.argeo.support.odk.OdkNames;
-
-/** Retrieves a single form. */
-public class OdkFormServlet extends HttpServlet {
-       private static final long serialVersionUID = 7838305967987687370L;
-
-       private Repository repository;
-       private Map<String, OdkForm> odkForms = Collections.synchronizedMap(new HashMap<>());
-
-       @Override
-       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-               resp.setContentType("text/xml; charset=utf-8");
-
-               Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req));
-
-               String pathInfo = req.getPathInfo();
-               if (pathInfo.startsWith("//"))
-                       pathInfo = pathInfo.substring(1);
-
-               boolean oldApproach = false;
-               try {
-                       if (!oldApproach) {
-                               String path = URLDecoder.decode(pathInfo, StandardCharsets.UTF_8);
-                               session.exportDocumentView(path + "/" + OdkNames.H_HTML, resp.getOutputStream(), true, false);
-                       } else {
-
-                               String fileName = FilenameUtils.getName(pathInfo);
-                               OdkForm form = odkForms.get(fileName);
-                               if (form == null)
-                                       throw new IllegalArgumentException("No form named " + fileName + " was found");
-
-                               byte[] buffer = new byte[1024];
-                               try (InputStream in = form.openStream(); OutputStream out = resp.getOutputStream();) {
-                                       int bytesRead;
-                                       while ((bytesRead = in.read(buffer)) != -1)
-                                               out.write(buffer, 0, bytesRead);
-                               }
-                       }
-               } catch (RepositoryException e) {
-                       e.printStackTrace();
-                       // TODO error message
-                       resp.sendError(500);
-               } finally {
-                       Jcr.logout(session);
-               }
-       }
-
-       public void addForm(OdkForm odkForm) {
-               odkForms.put(odkForm.getFileName(), odkForm);
-       }
-
-       public void removeForm(OdkForm odkForm) {
-               odkForms.remove(odkForm.getFileName());
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkManifestServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkManifestServlet.java
deleted file mode 100644 (file)
index 63472fc..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-package org.argeo.support.odk.servlet;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.security.DigestOutputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.query.RowIterator;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.io.output.NullOutputStream;
-import org.argeo.cms.auth.RemoteAuthUtils;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.entity.EntityMimeType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.argeo.support.odk.OrxManifestName;
-import org.argeo.util.CsvWriter;
-import org.argeo.util.DigestUtils;
-
-/** Describe additional files. */
-public class OdkManifestServlet extends HttpServlet {
-       private static final long serialVersionUID = 138030510865877478L;
-
-       private Repository repository;
-
-       @Override
-       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-               resp.setHeader("X-OpenRosa-Version", "1.0");
-               resp.setDateHeader("Date", System.currentTimeMillis());
-
-               String pathInfo = req.getPathInfo();
-               if (pathInfo.startsWith("//"))
-                       pathInfo = pathInfo.substring(1);
-
-               String serverName = req.getServerName();
-               int serverPort = req.getServerPort();
-               String protocol = serverPort == 443 || req.isSecure() ? "https" : "http";
-
-               Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req));
-
-               try {
-                       Node node = session.getNode(pathInfo);
-                       if (node.isNodeType(OrxManifestName.manifest.get())) {
-                               resp.setContentType(EntityMimeType.XML.toHttpContentType());
-                               Writer writer = resp.getWriter();
-                               writer.append("<?xml version='1.0' encoding='UTF-8' ?>");
-                               writer.append("<manifest xmlns=\"http://openrosa.org/xforms/xformsManifest\">");
-                               NodeIterator nit = node.getNodes();
-                               children: while (nit.hasNext()) {
-                                       Node file = nit.nextNode();
-                                       if (file.isNodeType(OrxManifestName.mediaFile.get())) {
-                                               EntityMimeType mimeType = EntityMimeType
-                                                               .find(file.getProperty(Property.JCR_MIMETYPE).getString());
-                                               Charset charset = Charset.forName(file.getProperty(Property.JCR_ENCODING).getString());
-
-                                               if (file.isNodeType(NodeType.NT_ADDRESS)) {
-                                                       Node target;
-                                                       try {
-                                                               target = file.getProperty(Property.JCR_ID).getNode();
-                                                       } catch (ItemNotFoundException e) {
-                                                               // TODO remove old manifests
-                                                               continue children;
-                                                       }
-                                                       writer.append("<mediaFile>");
-                                                       writer.append("<filename>");
-                                                       // Work around bug in ODK Collect not supporting paths
-                                                       // writer.append(target.getPath().substring(1) + ".xml");
-                                                       writer.append(target.getIdentifier() + "." + mimeType.getDefaultExtension());
-                                                       writer.append("</filename>");
-
-                                                       MessageDigest messageDigest = MessageDigest.getInstance(DigestUtils.MD5);
-                                                       // TODO cache a temp file ?
-                                                       try (DigestOutputStream out = new DigestOutputStream(new NullOutputStream(),
-                                                                       messageDigest)) {
-                                                               writeMediaFile(out, target, mimeType, charset);
-                                                               writer.append("<hash>");
-                                                               writer.append("md5sum:" + DigestUtils.encodeHexString(out.getMessageDigest().digest()));
-                                                               writer.append("</hash>");
-                                                       }
-
-//                                                     try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-//                                                             session.exportDocumentView(target.getPath(), out, true, false);
-//                                                             String fileCsum = DigestUtils.digest(DigestUtils.MD5, out.toByteArray());
-//                                                             writer.append("<hash>");
-//                                                             writer.append("md5sum:" + fileCsum);
-//                                                             writer.append("</hash>");
-//                                                     }
-                                                       writer.append("<downloadUrl>" + protocol + "://" + serverName
-                                                                       + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort)
-                                                                       + "/api/odk/formManifest" + file.getPath() + "</downloadUrl>");
-                                               }
-                                               writer.append("</mediaFile>");
-                                       }
-                               }
-
-                               writer.append("</manifest>");
-                       } else if (node.isNodeType(OrxManifestName.mediaFile.get())) {
-                               EntityMimeType mimeType = EntityMimeType.find(node.getProperty(Property.JCR_MIMETYPE).getString());
-                               Charset charset = Charset.forName(node.getProperty(Property.JCR_ENCODING).getString());
-                               resp.setContentType(mimeType.toHttpContentType(charset));
-                               if (node.isNodeType(NodeType.NT_ADDRESS)) {
-                                       Node target = node.getProperty(Property.JCR_ID).getNode();
-
-                                       writeMediaFile(resp.getOutputStream(), target, mimeType, charset);
-//                                     try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-//                                             session.exportDocumentView(target.getPath(), out, true, false);
-//                                             System.out.println(new String(out.toByteArray(), StandardCharsets.UTF_8));
-//                                             resp.getOutputStream().write(out.toByteArray());
-//                                     }
-                               } else {
-                                       throw new IllegalArgumentException("Unsupported node " + node);
-                               }
-                       } else {
-                               throw new IllegalArgumentException("Unsupported node " + node);
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               } catch (NoSuchAlgorithmException e) {
-                       throw new ServletException(e);
-               } finally {
-                       Jcr.logout(session);
-               }
-
-       }
-
-       protected void writeMediaFile(OutputStream out, Node target, EntityMimeType mimeType, Charset charset)
-                       throws RepositoryException, IOException {
-               if (target.isNodeType(NodeType.NT_QUERY)) {
-                       Query query = target.getSession().getWorkspace().getQueryManager().getQuery(target);
-                       QueryResult queryResult = query.execute();
-                       String[] columnNames = queryResult.getColumnNames();
-                       if (EntityMimeType.XML.equals(mimeType)) {
-                       } else if (EntityMimeType.CSV.equals(mimeType)) {
-                               CsvWriter csvWriter = new CsvWriter(out, charset);
-                               csvWriter.writeLine(columnNames);
-                               RowIterator rit = queryResult.getRows();
-                               while (rit.hasNext()) {
-                                       Row row = rit.nextRow();
-                                       Value[] values = row.getValues();
-                                       List<String> lst = new ArrayList<>();
-                                       for (Value value : values) {
-                                               lst.add(value.getString());
-                                       }
-                                       csvWriter.writeLine(lst);
-                               }
-                       }
-               } else {
-                       if (EntityMimeType.XML.equals(mimeType)) {
-                               target.getSession().exportDocumentView(target.getPath(), out, true, false);
-                       } else if (EntityMimeType.CSV.equals(mimeType)) {
-                               CsvWriter csvWriter = new CsvWriter(out, charset);
-                               csvWriter.writeLine(new String[] { "name", "label" });
-                               NodeIterator children = target.getNodes();
-                               while (children.hasNext()) {
-                                       Node child = children.nextNode();
-                                       String label = Jcr.getTitle(child);
-                                       csvWriter.writeLine(new String[] { child.getIdentifier(), label });
-                               }
-                       }
-
-               }
-
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkServletContext.java b/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkServletContext.java
deleted file mode 100644 (file)
index f06965d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.support.odk.servlet;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.argeo.cms.servlet.PrivateWwwAuthServletContext;
-
-/** ODK specific authentication (with additional headers).*/
-public class OdkServletContext extends PrivateWwwAuthServletContext {
-
-       @Override
-       protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) {
-               super.askForWwwAuth(request, response);
-               response.setHeader("X-OpenRosa-Version", "1.0");
-               response.setDateHeader("Date", System.currentTimeMillis());
-
-       }
-
-}
diff --git a/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java
deleted file mode 100644 (file)
index 9e0c800..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-package org.argeo.support.odk.servlet;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
-import java.time.format.DateTimeFormatter;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.Part;
-
-import org.argeo.api.cms.CmsSession;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.auth.RemoteAuthRequest;
-import org.argeo.cms.auth.RemoteAuthUtils;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.suite.SuiteUtils;
-import org.argeo.support.odk.OrxType;
-import org.argeo.support.xforms.FormSubmissionListener;
-
-/** Receives a form submission. */
-public class OdkSubmissionServlet extends HttpServlet {
-       private static final long serialVersionUID = 7834401404691302385L;
-       private final static CmsLog log = CmsLog.getLog(OdkSubmissionServlet.class);
-
-       private final static String XML_SUBMISSION_FILE = "xml_submission_file";
-
-       private DateTimeFormatter submissionNameFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HHmmssSSS")
-                       .withZone(ZoneId.from(ZoneOffset.UTC));
-
-       private Repository repository;
-
-       private Set<FormSubmissionListener> submissionListeners = new HashSet<>();
-
-       @Override
-       protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-               resp.setContentType("text/xml; charset=utf-8");
-               resp.setHeader("X-OpenRosa-Version", "1.0");
-               resp.setDateHeader("Date", System.currentTimeMillis());
-               resp.setIntHeader("X-OpenRosa-Accept-Content-Length", 1024 * 1024);
-
-               RemoteAuthRequest request = new ServletHttpRequest(req);
-               Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), request);
-
-               try {
-//                     Node submissions = JcrUtils.mkdirs(session,
-//                                     "/" + EntityType.form.get() + "/" + EntityNames.SUBMISSIONS_BASE);
-                       CmsSession cmsSession = RemoteAuthUtils.getCmsSession(request);
-
-                       ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
-                       Thread.currentThread().setContextClassLoader(RemoteAuthUtils.class.getClassLoader());
-                       Session adminSession = null;
-                       try {
-                               // TODO centralise at a deeper level
-                               adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
-                               SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
-                       } finally {
-                               Jcr.logout(adminSession);
-                               Thread.currentThread().setContextClassLoader(currentContextCl);
-                       }
-
-                       Node cmsSessionNode = SuiteUtils.getCmsSessionNode(session, cmsSession);
-                       Node submission = cmsSessionNode.addNode(submissionNameFormatter.format(Instant.now()),
-                                       OrxType.submission.get());
-                       for (Part part : req.getParts()) {
-                               if (log.isDebugEnabled())
-                                       log.debug("Part: " + part.getName() + ", " + part.getContentType());
-
-                               if (part.getName().equals(XML_SUBMISSION_FILE)) {
-                                       Node xml = submission.addNode(XML_SUBMISSION_FILE, NodeType.NT_UNSTRUCTURED);
-                                       session.importXML(xml.getPath(), part.getInputStream(),
-                                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-
-                               } else {
-                                       Node fileNode = JcrUtils.copyStreamAsFile(submission, part.getName(), part.getInputStream());
-                                       String contentType = part.getContentType();
-                                       if (contentType != null) {
-                                               fileNode.addMixin(NodeType.MIX_MIMETYPE);
-                                               fileNode.setProperty(Property.JCR_MIMETYPE, contentType);
-
-                                       }
-                                       if (part.getName().endsWith(".jpg") || part.getName().endsWith(".png")) {
-                                               // TODO meta data and thumbnails
-                                       }
-                               }
-                       }
-                       session.save();
-                       for (FormSubmissionListener submissionListener : submissionListeners) {
-                               submissionListener.formSubmissionReceived(submission);
-                       }
-               } catch (RepositoryException e) {
-                       e.printStackTrace();
-                       resp.setStatus(503);
-                       return;
-               } finally {
-                       Jcr.logout(session);
-               }
-
-               resp.setStatus(201);
-               resp.getWriter().write("<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">"
-                               + "<message>Form Received!</message>" + "</OpenRosaResponse>");
-
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-       public synchronized void addSubmissionListener(FormSubmissionListener listener) {
-               submissionListeners.add(listener);
-       }
-
-       public synchronized void removeSubmissionListener(FormSubmissionListener listener) {
-               submissionListeners.remove(listener);
-       }
-}
index 66526d9904a1cfc449dda94fa49ad3f9c3d1e647..ccad6050cd0a12c0be2f689dc579b734ddc55868 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="DocBook 4 Converter">
-   <implementation class="org.argeo.docbook.Dbk4Converter"/>
+   <implementation class="org.argeo.app.docbook.Dbk4Converter"/>
    <service>
-      <provide interface="org.argeo.docbook.Dbk4Converter"/>
+      <provide interface="org.argeo.app.docbook.Dbk4Converter"/>
    </service>
 </scr:component>
index 05522d56b83cebb59f1641ba8e3221039077b1c2..34a7dcbc1bcf6ea7fb0c38747beb7ca5976f5d1a 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="DocBook Servlet">
-   <implementation class="org.argeo.publishing.servlet.DbkServlet"/>
+   <implementation class="org.argeo.app.servlet.publish.DbkServlet"/>
    <service>
       <provide interface="javax.servlet.Servlet"/>
    </service>
index 5cee79fb42177d779a9f55785fac71aa3039edcd..3711fd5d93009df7cc418c6ac1a789e7ae7bfcdb 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
-   <implementation class="org.argeo.publishing.ui.DocumentUiProvider"/>
+   <implementation class="org.argeo.app.ui.publish.DocumentUiProvider"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
    </service>
index 6ca1c412c7bb8bdfe9aaa099854852d76704edd6..7b7100803bd6c2bba788e8355365e35bac773d18 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
-   <implementation class="org.argeo.publishing.servlet.FontsServlet"/>
+   <implementation class="org.argeo.app.servlet.publish.FontsServlet"/>
    <service>
       <provide interface="javax.servlet.Servlet"/>
    </service>
index 497d652dbc89f3d3ff67d0dd7fac7859a1e7dea1..0fc0edb756d4b019517c0d3ac9dd69266770a59e 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy">
-   <implementation class="org.argeo.suite.ui.DefaultEditionLayer"/>
+   <implementation class="org.argeo.app.ui.DefaultEditionLayer"/>
    <properties entry="config/wwwLayer.properties"/>
    <service>
-      <provide interface="org.argeo.suite.ui.SuiteLayer"/>
+      <provide interface="org.argeo.app.ui.SuiteLayer"/>
    </service>
    <reference bind="setWorkArea" cardinality="1..1" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.publishing.ui.documentUiProvider)"/>
 </scr:component>
index 463e24b75b22e52ad0a08e092f1c09550926fa3f..b8c62f966b6401c2f3008ae3730f5b593778a23e 100644 (file)
@@ -2,13 +2,12 @@ Import-Package:\
 org.osgi.service.http.context,\
 javax.jcr.nodetype,\
 org.osgi.service.event,\
-org.argeo.suite.ui,\
 org.eclipse.swt,\
 org.eclipse.jface.viewers,\
 org.osgi.framework,\
 org.apache.xml.serializer,\
 org.eclipse.rap.rwt,\
-org.argeo.entity,\
+org.argeo.app.api,\
 *
 
 Provide-Capability:\
diff --git a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/DbkServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/DbkServlet.java
new file mode 100644 (file)
index 0000000..51f2332
--- /dev/null
@@ -0,0 +1,226 @@
+package org.argeo.app.servlet.publish;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Collections;
+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 javax.jcr.nodetype.NodeType;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.xalan.processor.TransformerFactoryImpl;
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.app.docbook.DbkUtils;
+import org.argeo.cms.auth.RemoteAuthUtils;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.w3c.dom.Document;
+
+/**
+ * A servlet transforming a dbk:* JCR node into HTML, using the DocBook XSL.
+ */
+public class DbkServlet extends HttpServlet {
+       private static final long serialVersionUID = 6906020513498289335L;
+
+       private Repository repository;
+
+       private DocumentBuilderFactory documentBuilderFactory;
+       private TransformerFactory transformerFactory;
+       private Templates docBoookTemplates;
+
+       private Map<String, CmsTheme> themes = Collections.synchronizedMap(new HashMap<>());
+
+       @Override
+       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+               String pathInfo = req.getPathInfo();
+               if (pathInfo.startsWith("//"))
+                       pathInfo = pathInfo.substring(1);
+               String path = URLDecoder.decode(pathInfo, StandardCharsets.UTF_8);
+
+               if (path.toLowerCase().endsWith(".css")) {
+                       path = path.substring(1);
+                       int firstSlash = path.indexOf('/');
+                       String themeId = path.substring(0, firstSlash);
+                       String cssPath = path.substring(firstSlash);
+                       CmsTheme cmsTheme = themes.get(themeId);
+                       if (cmsTheme == null)
+                               throw new IllegalArgumentException("Theme " + themeId + " not found.");
+                       resp.setContentType("text/css");
+                       IOUtils.copy(cmsTheme.getResourceAsStream(cssPath), resp.getOutputStream());
+                       return;
+               }
+
+               if (path.toLowerCase().endsWith("/index.html")) {
+                       path = path.substring(0, path.length() - "/index.html".length());
+               }
+
+               Session session = null;
+               try {
+                       session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req));
+                       Node node = session.getNode(path);
+
+                       if (node.hasNode(DbkType.article.get())) {
+                               Node dbkNode = node.getNode(DbkType.article.get());
+                               if (DbkUtils.isDbk(dbkNode)) {
+                                       CmsTheme cmsTheme = null;
+                                       String themeId = req.getParameter("themeId");
+                                       if (themeId != null) {
+                                               cmsTheme = themes.get(themeId);
+                                               if (cmsTheme == null)
+                                                       throw new IllegalArgumentException("Theme " + themeId + " not found.");
+                                       }
+
+                                       // TODO customise DocBook so that it outputs UTF-8
+                                       // see http://www.sagehill.net/docbookxsl/OutputEncoding.html
+                                       resp.setContentType("text/html; charset=ISO-8859-1");
+
+                                       // TODO optimise with pipes, SAX, etc. ?
+                                       byte[] arr;
+                                       try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+                                               session.exportDocumentView(dbkNode.getPath(), out, true, false);
+                                               arr = out.toByteArray();
+//                             System.out.println(new String(arr, StandardCharsets.UTF_8));
+                                       } catch (RepositoryException e) {
+                                               throw new JcrException(e);
+                                       }
+
+                                       try (InputStream in = new ByteArrayInputStream(arr);
+//                                     ByteArrayOutputStream out = new ByteArrayOutputStream();
+                                       ) {
+
+                                               Result xmlOutput = new StreamResult(resp.getOutputStream());
+
+                                               DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
+//                             Document doc = docBuilder.parse(new File(
+//                                             System.getProperty("user.home") + "/dev/git/gpl/argeo-qa/doc/platform/argeo-platform.dbk.xml"));
+                                               Document doc = docBuilder.parse(in);
+                                               Source xmlInput = new DOMSource(doc);
+
+                                               Transformer transformer = docBoookTemplates.newTransformer();
+
+                                               // gather CSS
+                                               if (cmsTheme != null) {
+                                                       StringBuilder sb = new StringBuilder();
+                                                       for (String cssPath : cmsTheme.getWebCssPaths()) {
+                                                               sb.append(req.getContextPath()).append(req.getServletPath()).append('/');
+                                                               sb.append(themeId).append('/').append(cssPath).append(' ');
+                                                       }
+                                                       // FIXME make it more generic
+                                                       sb.append("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap")
+                                                                       .append(' ');
+                                                       sb.append(
+                                                                       "https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,600;1,400&display=swap")
+                                                                       .append(' ');
+                                                       if (sb.length() > 0)
+                                                               transformer.setParameter("html.stylesheet", sb.toString());
+                                               }
+                                               transformer.transform(xmlInput, xmlOutput);
+//                             resp.getOutputStream().write(out.toByteArray());
+                                       } catch (Exception e) {
+                                               throw new ServletException("Cannot transform " + path, e);
+                                       }
+                               }
+                       } else {
+                               if (node.isNodeType(NodeType.NT_FILE)) {// media download etc.
+                                       String fileNameLowerCase = node.getName().toLowerCase();
+                                       if (fileNameLowerCase.endsWith(".jpg") || fileNameLowerCase.endsWith(".jpeg")) {
+                                               resp.setContentType("image/jpeg");
+                                       } else if (fileNameLowerCase.endsWith(".png")) {
+                                               resp.setContentType("image/png");
+                                       } else if (fileNameLowerCase.endsWith(".gif")) {
+                                               resp.setContentType("image/gif");
+                                       } else if (fileNameLowerCase.endsWith(".svg")) {
+                                               resp.setContentType("image/svg+xml");
+                                       } else {
+                                               // TODO know more content types...
+                                               resp.setHeader("Content-Disposition", "attachment; filename=\"" + node.getName() + "\"");
+                                       }
+                                       IOUtils.copy(JcrUtils.getFileAsStream(node), resp.getOutputStream());
+                               } else {
+                                       throw new IllegalArgumentException("Unsupported node " + node);
+                               }
+                       }
+               } catch (RepositoryException e1) {
+                       throw new JcrException(e1);
+               } finally {
+                       Jcr.logout(session);
+               }
+       }
+
+       @Override
+       public void init() throws ServletException {
+
+               // TODO improve configuration and provisioning of DocBook XSL
+               String xslBase = System.getProperty("argeo.docbook.xsl");
+               if (xslBase == null) {
+                       String defaultXslBase = "/opt/docbook-xsl";
+                       if (!Files.exists(Paths.get(defaultXslBase))) {
+                               throw new ServletException("System property argeo.docbook.xsl is not set and default location "
+                                               + defaultXslBase + " does not exist.");
+                       } else {
+                               xslBase = defaultXslBase;
+                       }
+               }
+               String xsl = xslBase + "/html/docbook.xsl";
+
+               documentBuilderFactory = DocumentBuilderFactory.newInstance();
+               documentBuilderFactory.setXIncludeAware(true);
+               documentBuilderFactory.setNamespaceAware(true);
+
+               // We must explicitly use the non-XSLTC transformer, as XSLTC is not working
+               // with DocBook stylesheets
+               transformerFactory = new TransformerFactoryImpl();
+
+               Source xslSource = new StreamSource(xsl);
+               try {
+                       docBoookTemplates = transformerFactory.newTemplates(xslSource);
+                       if (docBoookTemplates == null)
+                               throw new ServletException("Could not instantiate XSL " + xsl);
+               } catch (TransformerConfigurationException e) {
+                       throw new ServletException("Cannot instantiate XSL " + xsl, e);
+               }
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+       public void addTheme(CmsTheme theme, Map<String, String> properties) {
+               themes.put(theme.getThemeId(), theme);
+       }
+
+       public void removeTheme(CmsTheme theme, Map<String, String> properties) {
+               themes.remove(theme.getThemeId());
+       }
+
+}
diff --git a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FontsServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FontsServlet.java
new file mode 100644 (file)
index 0000000..01e212e
--- /dev/null
@@ -0,0 +1,51 @@
+package org.argeo.app.servlet.publish;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.api.cms.CmsTheme;
+
+/** Serves fonts locally. */
+public class FontsServlet extends HttpServlet {
+       private static final long serialVersionUID = 6009572962850708537L;
+       private Map<String, CmsTheme> themes = Collections.synchronizedMap(new HashMap<>());
+
+       @Override
+       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+               String font = req.getPathInfo();
+               font = font.substring(1, font.length());
+               for (CmsTheme theme : themes.values()) {
+                       for (String fontPath : theme.getFontsPaths()) {
+                               if (fontPath.endsWith(font)) {
+                                       if (font.endsWith(".woff"))
+                                               resp.setContentType("font/woff");
+                                       else if (font.endsWith(".woff2"))
+                                               resp.setContentType("font/woff2");
+                                       try (InputStream in = theme.loadPath(fontPath)) {
+                                               IOUtils.copy(in, resp.getOutputStream());
+                                               return;
+                                       }
+                               }
+                       }
+               }
+               resp.setStatus(404);
+       }
+
+       public void addTheme(CmsTheme theme, Map<String, String> properties) {
+               themes.put(theme.getThemeId(), theme);
+       }
+
+       public void removeTheme(CmsTheme theme, Map<String, String> properties) {
+               themes.remove(theme.getThemeId());
+       }
+
+}
diff --git a/org.argeo.app.servlet.publish/src/org/argeo/publishing/servlet/DbkServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/publishing/servlet/DbkServlet.java
deleted file mode 100644 (file)
index 26a0fed..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-package org.argeo.publishing.servlet;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.Collections;
-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 javax.jcr.nodetype.NodeType;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Templates;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.xalan.processor.TransformerFactoryImpl;
-import org.argeo.api.cms.CmsTheme;
-import org.argeo.cms.auth.RemoteAuthUtils;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.docbook.DbkType;
-import org.argeo.docbook.DbkUtils;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.w3c.dom.Document;
-
-/**
- * A servlet transforming a dbk:* JCR node into HTML, using the DocBook XSL.
- */
-public class DbkServlet extends HttpServlet {
-       private static final long serialVersionUID = 6906020513498289335L;
-
-       private Repository repository;
-
-       private DocumentBuilderFactory documentBuilderFactory;
-       private TransformerFactory transformerFactory;
-       private Templates docBoookTemplates;
-
-       private Map<String, CmsTheme> themes = Collections.synchronizedMap(new HashMap<>());
-
-       @Override
-       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
-               String pathInfo = req.getPathInfo();
-               if (pathInfo.startsWith("//"))
-                       pathInfo = pathInfo.substring(1);
-               String path = URLDecoder.decode(pathInfo, StandardCharsets.UTF_8);
-
-               if (path.toLowerCase().endsWith(".css")) {
-                       path = path.substring(1);
-                       int firstSlash = path.indexOf('/');
-                       String themeId = path.substring(0, firstSlash);
-                       String cssPath = path.substring(firstSlash);
-                       CmsTheme cmsTheme = themes.get(themeId);
-                       if (cmsTheme == null)
-                               throw new IllegalArgumentException("Theme " + themeId + " not found.");
-                       resp.setContentType("text/css");
-                       IOUtils.copy(cmsTheme.getResourceAsStream(cssPath), resp.getOutputStream());
-                       return;
-               }
-
-               if (path.toLowerCase().endsWith("/index.html")) {
-                       path = path.substring(0, path.length() - "/index.html".length());
-               }
-
-               Session session = null;
-               try {
-                       session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req));
-                       Node node = session.getNode(path);
-
-                       if (node.hasNode(DbkType.article.get())) {
-                               Node dbkNode = node.getNode(DbkType.article.get());
-                               if (DbkUtils.isDbk(dbkNode)) {
-                                       CmsTheme cmsTheme = null;
-                                       String themeId = req.getParameter("themeId");
-                                       if (themeId != null) {
-                                               cmsTheme = themes.get(themeId);
-                                               if (cmsTheme == null)
-                                                       throw new IllegalArgumentException("Theme " + themeId + " not found.");
-                                       }
-
-                                       // TODO customise DocBook so that it outputs UTF-8
-                                       // see http://www.sagehill.net/docbookxsl/OutputEncoding.html
-                                       resp.setContentType("text/html; charset=ISO-8859-1");
-
-                                       // TODO optimise with pipes, SAX, etc. ?
-                                       byte[] arr;
-                                       try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-                                               session.exportDocumentView(dbkNode.getPath(), out, true, false);
-                                               arr = out.toByteArray();
-//                             System.out.println(new String(arr, StandardCharsets.UTF_8));
-                                       } catch (RepositoryException e) {
-                                               throw new JcrException(e);
-                                       }
-
-                                       try (InputStream in = new ByteArrayInputStream(arr);
-//                                     ByteArrayOutputStream out = new ByteArrayOutputStream();
-                                       ) {
-
-                                               Result xmlOutput = new StreamResult(resp.getOutputStream());
-
-                                               DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
-//                             Document doc = docBuilder.parse(new File(
-//                                             System.getProperty("user.home") + "/dev/git/gpl/argeo-qa/doc/platform/argeo-platform.dbk.xml"));
-                                               Document doc = docBuilder.parse(in);
-                                               Source xmlInput = new DOMSource(doc);
-
-                                               Transformer transformer = docBoookTemplates.newTransformer();
-
-                                               // gather CSS
-                                               if (cmsTheme != null) {
-                                                       StringBuilder sb = new StringBuilder();
-                                                       for (String cssPath : cmsTheme.getWebCssPaths()) {
-                                                               sb.append(req.getContextPath()).append(req.getServletPath()).append('/');
-                                                               sb.append(themeId).append('/').append(cssPath).append(' ');
-                                                       }
-                                                       // FIXME make it more generic
-                                                       sb.append("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap")
-                                                                       .append(' ');
-                                                       sb.append(
-                                                                       "https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,600;1,400&display=swap")
-                                                                       .append(' ');
-                                                       if (sb.length() > 0)
-                                                               transformer.setParameter("html.stylesheet", sb.toString());
-                                               }
-                                               transformer.transform(xmlInput, xmlOutput);
-//                             resp.getOutputStream().write(out.toByteArray());
-                                       } catch (Exception e) {
-                                               throw new ServletException("Cannot transform " + path, e);
-                                       }
-                               }
-                       } else {
-                               if (node.isNodeType(NodeType.NT_FILE)) {// media download etc.
-                                       String fileNameLowerCase = node.getName().toLowerCase();
-                                       if (fileNameLowerCase.endsWith(".jpg") || fileNameLowerCase.endsWith(".jpeg")) {
-                                               resp.setContentType("image/jpeg");
-                                       } else if (fileNameLowerCase.endsWith(".png")) {
-                                               resp.setContentType("image/png");
-                                       } else if (fileNameLowerCase.endsWith(".gif")) {
-                                               resp.setContentType("image/gif");
-                                       } else if (fileNameLowerCase.endsWith(".svg")) {
-                                               resp.setContentType("image/svg+xml");
-                                       } else {
-                                               // TODO know more content types...
-                                               resp.setHeader("Content-Disposition", "attachment; filename=\"" + node.getName() + "\"");
-                                       }
-                                       IOUtils.copy(JcrUtils.getFileAsStream(node), resp.getOutputStream());
-                               } else {
-                                       throw new IllegalArgumentException("Unsupported node " + node);
-                               }
-                       }
-               } catch (RepositoryException e1) {
-                       throw new JcrException(e1);
-               } finally {
-                       Jcr.logout(session);
-               }
-       }
-
-       @Override
-       public void init() throws ServletException {
-
-               // TODO improve configuration and provisioning of DocBook XSL
-               String xslBase = System.getProperty("argeo.docbook.xsl");
-               if (xslBase == null) {
-                       String defaultXslBase = "/opt/docbook-xsl";
-                       if (!Files.exists(Paths.get(defaultXslBase))) {
-                               throw new ServletException("System property argeo.docbook.xsl is not set and default location "
-                                               + defaultXslBase + " does not exist.");
-                       } else {
-                               xslBase = defaultXslBase;
-                       }
-               }
-               String xsl = xslBase + "/html/docbook.xsl";
-
-               documentBuilderFactory = DocumentBuilderFactory.newInstance();
-               documentBuilderFactory.setXIncludeAware(true);
-               documentBuilderFactory.setNamespaceAware(true);
-
-               // We must explicitly use the non-XSLTC transformer, as XSLTC is not working
-               // with DocBook stylesheets
-               transformerFactory = new TransformerFactoryImpl();
-
-               Source xslSource = new StreamSource(xsl);
-               try {
-                       docBoookTemplates = transformerFactory.newTemplates(xslSource);
-                       if (docBoookTemplates == null)
-                               throw new ServletException("Could not instantiate XSL " + xsl);
-               } catch (TransformerConfigurationException e) {
-                       throw new ServletException("Cannot instantiate XSL " + xsl, e);
-               }
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-       public void addTheme(CmsTheme theme, Map<String, String> properties) {
-               themes.put(theme.getThemeId(), theme);
-       }
-
-       public void removeTheme(CmsTheme theme, Map<String, String> properties) {
-               themes.remove(theme.getThemeId());
-       }
-
-}
diff --git a/org.argeo.app.servlet.publish/src/org/argeo/publishing/servlet/FontsServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/publishing/servlet/FontsServlet.java
deleted file mode 100644 (file)
index aa116f5..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.argeo.publishing.servlet;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.api.cms.CmsTheme;
-
-/** Serves fonts locally. */
-public class FontsServlet extends HttpServlet {
-       private static final long serialVersionUID = 6009572962850708537L;
-       private Map<String, CmsTheme> themes = Collections.synchronizedMap(new HashMap<>());
-
-       @Override
-       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-               String font = req.getPathInfo();
-               font = font.substring(1, font.length());
-               for (CmsTheme theme : themes.values()) {
-                       for (String fontPath : theme.getFontsPaths()) {
-                               if (fontPath.endsWith(font)) {
-                                       if (font.endsWith(".woff"))
-                                               resp.setContentType("font/woff");
-                                       else if (font.endsWith(".woff2"))
-                                               resp.setContentType("font/woff2");
-                                       try (InputStream in = theme.loadPath(fontPath)) {
-                                               IOUtils.copy(in, resp.getOutputStream());
-                                               return;
-                                       }
-                               }
-                       }
-               }
-               resp.setStatus(404);
-       }
-
-       public void addTheme(CmsTheme theme, Map<String, String> properties) {
-               themes.put(theme.getThemeId(), theme);
-       }
-
-       public void removeTheme(CmsTheme theme, Map<String, String> properties) {
-               themes.remove(theme.getThemeId());
-       }
-
-}
index 0d060fb4a4cb26b5bd69bfda337e6768332b717c..0a2818af89e71f816c000f4280b9c4296520138a 100644 (file)
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="false" name="Admin Lead Pane">
-   <implementation class="org.argeo.suite.ui.DefaultLeadPane"/>
+   <implementation class="org.argeo.app.ui.DefaultLeadPane"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
    </service>
    <properties entry="config/adminLeadPane.properties"/>
    <property name="defaultLayers" type="String">argeo.suite.ui.termsLayer
    </property>
-   <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
+   <reference bind="addLayer" cardinality="1..n" interface="org.argeo.app.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
 </scr:component>
index bfb372a6456ed1bf91ee8dd363888d2c28ca78a5..20373ae9f9a6a3baa1ce23232347b2072328eb33 100644 (file)
@@ -1,6 +1,6 @@
 <?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"/>
+   <implementation class="org.argeo.app.ui.SuiteApp"/>
    <service>
       <provide interface="org.argeo.api.cms.CmsApp"/>
       <provide interface="org.osgi.service.event.EventHandler"/>
@@ -9,6 +9,6 @@
    <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.api.cms.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="addLayer" cardinality="1..n" interface="org.argeo.app.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>
index f678b5b482c6c14dd05a7222607a7347944638b8..9ee58572b1dacf9e61f3647cbe2576fa2216e568 100644 (file)
@@ -1,6 +1,6 @@
 <?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"/>
+   <implementation class="org.argeo.app.ui.DefaultDashboard"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
    </service>
index b60eafc45ed616627bc34f4885e431123d8fd7b3..436a8e6402cdabc5352fa76ab6ef31333882dfd1 100644 (file)
@@ -1,8 +1,8 @@
 <?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"/>
+   <implementation class="org.argeo.app.ui.DefaultEditionLayer"/>
    <service>
-      <provide interface="org.argeo.suite.ui.SuiteLayer"/>
+      <provide interface="org.argeo.app.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)"/>
index 49badfde808c21d27bd25563589dcf5fb2adfcb8..ab1a6ae2a7ab83be58742e53fc944efba6f11ef7 100644 (file)
@@ -1,6 +1,6 @@
 <?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="Event Recorder">
-   <implementation class="org.argeo.suite.ui.EventRecorder"/>
+   <implementation class="org.argeo.app.ui.EventRecorder"/>
    <service>
       <provide interface="org.osgi.service.event.EventHandler"/>
    </service>
index 3499b4f6b8f1f6f9bac27db17e523405d5e3f000..5e9a857a860e12b2224f20287dc526df10116c14 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="false" name="Default Suite Footer">
-   <implementation class="org.argeo.suite.ui.DefaultFooter"/>
+   <implementation class="org.argeo.app.ui.DefaultFooter"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
    </service>
index 526d9f9634ed6dd3d5dfbba00ec074fbf52969bd..0c83dc667b742f83660293cba64e3cb32ca51187 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="false" name="Default Suite Header">
-   <implementation class="org.argeo.suite.ui.DefaultHeader"/>
+   <implementation class="org.argeo.app.ui.DefaultHeader"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
    </service>
index c43d9336ace5ff523d8ef982da56cc0424a7b6cb..c2c21041166ba42a3e9ab47c96018101e1ae3315 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="false" name="Default Lead Pane">
-   <implementation class="org.argeo.suite.ui.DefaultLeadPane"/>
+   <implementation class="org.argeo.app.ui.DefaultLeadPane"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
    </service>
@@ -10,5 +10,5 @@ argeo.library.ui.contentLayer
 argeo.people.ui.peopleLayer
 argeo.geo.ui.mapLayer
    </property>
-   <reference bind="addLayer" cardinality="1..n" interface="org.argeo.suite.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
+   <reference bind="addLayer" cardinality="1..n" interface="org.argeo.app.ui.SuiteLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
 </scr:component>
index 0c5377a0b143b2dae678fa44ac3f1e35fb0fce28..ec7862d1f214c62a4ca6d029de4a70add786cbaa 100644 (file)
@@ -1,6 +1,6 @@
 <?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"/>
+   <implementation class="org.argeo.app.ui.DefaultLoginScreen"/>
    <properties entry="config/loginScreen.properties"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
index 8aaee16dab98ad3cf386706d631c47b962c628f3..21c23e3f3684022ceaaa842eec703d2f8ef1f22f 100644 (file)
@@ -1,6 +1,6 @@
 <?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"/>
+   <implementation class="org.argeo.app.ui.RecentItems"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
    </service>
index cfcae11f56584e37829e5537a4d5bfe9c09e5971..0435f6947d2c19c60bd43b747c68be194a1fafe1 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Terms Entry Area">
-   <implementation class="org.argeo.suite.ui.TermsEntryArea"/>
+   <implementation class="org.argeo.app.ui.TermsEntryArea"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
    </service>
index f320dd969f4bb46e952c919b3cc7224311a6e578..9483e05e7d7c647d1e41780d751a25e673393a8c 100644 (file)
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Terms Layer">
-   <implementation class="org.argeo.suite.ui.DefaultEditionLayer"/>
+   <implementation class="org.argeo.app.ui.DefaultEditionLayer"/>
    <service>
-      <provide interface="org.argeo.suite.ui.SuiteLayer"/>
+      <provide interface="org.argeo.app.ui.SuiteLayer"/>
    </service>
    <properties entry="config/termsLayer.properties"/>
    <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.suite.ui.termsEntryArea)"/>
index 4dc449b85c720f64e18acbf746fe4647a97d3c38..b21f4791d86d5d22ef92e4e9602703d24a7184c1 100644 (file)
@@ -16,7 +16,6 @@ Import-Package:\
 org.argeo.cms.ui.widgets,\
 org.eclipse.swt,\
 org.osgi.framework,\
-org.argeo.entity,\
 org.eclipse.core.commands.common,\
 org.eclipse.jface.window,\
 org.eclipse.jface.dialogs,\
index 7e5ea706bf2a4889c612cc9c4c4c2bcf4bb868b7..0a3e91b923f61ec2dc73458397f787949300bbdd 100644 (file)
@@ -18,7 +18,7 @@
                </dependency>
 <!--           <dependency> -->
 <!--                   <groupId>org.argeo.suite</groupId> -->
-<!--                   <artifactId>org.argeo.entity.ui</artifactId> -->
+<!--                   <artifactId>org.argeo.app.api.ui</artifactId> -->
 <!--                   <version>2.3-SNAPSHOT</version> -->
 <!--           </dependency> -->
 
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultDashboard.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultDashboard.java
new file mode 100644 (file)
index 0000000..50fbed6
--- /dev/null
@@ -0,0 +1,32 @@
+package org.argeo.app.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsView;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Provides a dashboard. */
+public class DefaultDashboard implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               parent.setLayout(new GridLayout());
+               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
+               if (cmsView.isAnonymous())
+                       throw new IllegalStateException("No user is not logged in");
+
+               Label lbl = new Label(parent, SWT.NONE);
+               lbl.setText("Welcome " + CurrentUser.getDisplayName() + "!");
+
+               return lbl;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultEditionLayer.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultEditionLayer.java
new file mode 100644 (file)
index 0000000..579157d
--- /dev/null
@@ -0,0 +1,286 @@
+package org.argeo.app.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.app.ui.widgets.TabbedArea;
+import org.argeo.cms.Localized;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.jcr.JcrException;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.wiring.BundleWiring;
+
+/** An app layer based on an entry area and an editor area. */
+public class DefaultEditionLayer implements SuiteLayer {
+       private CmsUiProvider entryArea;
+       private CmsUiProvider defaultView;
+       private CmsUiProvider workArea;
+       private List<String> weights = new ArrayList<>();
+       private boolean startMaximized = false;
+       private boolean fixedEntryArea = false;
+       private boolean singleTab = false;
+       private Localized title = null;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               // TODO Factorize more, or split into more specialised classes?
+               if (entryArea != null) {
+                       if (fixedEntryArea) {
+                               FixedEditionArea editionArea = new FixedEditionArea(parent, parent.getStyle());
+                               Control entryAreaC = entryArea.createUi(editionArea.getEntryArea(), context);
+                               CmsSwtUtils.style(entryAreaC, SuiteStyle.entryArea);
+                               if (this.defaultView != null) {
+                                       editionArea.getTabbedArea().view(defaultView, context);
+                               }
+                               return editionArea;
+                       } else {
+                               SashFormEditionArea editionArea = new SashFormEditionArea(parent, parent.getStyle());
+                               entryArea.createUi(editionArea.getEntryArea(), context);
+                               if (this.defaultView != null) {
+                                       editionArea.getTabbedArea().view(defaultView, context);
+                               }
+                               return editionArea;
+                       }
+               } else {
+                       if (this.workArea != null) {
+                               Composite area = new Composite(parent, SWT.NONE);
+                               this.workArea.createUi(area, context);
+                               return area;
+                       }
+                       CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
+                       TabbedArea tabbedArea = createTabbedArea(parent, theme);
+                       return tabbedArea;
+               }
+       }
+
+       @Override
+       public void view(CmsUiProvider uiProvider, Composite workAreaC, Node context) {
+               if (workArea != null) {
+                       try {
+                               CmsSwtUtils.clear(workAreaC);
+                               workArea.createUi(workAreaC, context);
+                               workAreaC.layout(true, true);
+                               return;
+                       } catch (RepositoryException e) {
+                               throw new JcrException("Cannot rebuild work area", e);
+                       }
+               }
+
+               // tabbed area
+               TabbedArea tabbedArea = findTabbedArea(workAreaC);
+               if (tabbedArea == null)
+                       throw new IllegalArgumentException("Unsupported work area " + workAreaC.getClass().getName());
+               if (uiProvider == null) {
+                       // reset
+                       tabbedArea.closeAllTabs();
+                       if (this.defaultView != null) {
+                               tabbedArea.view(defaultView, context);
+                       }
+               } else {
+                       tabbedArea.view(uiProvider, context);
+               }
+       }
+
+       @Override
+       public Node getCurrentContext(Composite workArea) {
+               TabbedArea tabbedArea = findTabbedArea(workArea);
+               if (tabbedArea == null)
+                       return null;
+               return tabbedArea.getCurrentContext();
+       }
+
+       private TabbedArea findTabbedArea(Composite workArea) {
+               TabbedArea tabbedArea = null;
+               if (workArea instanceof SashFormEditionArea) {
+                       tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
+               } else if (workArea instanceof FixedEditionArea) {
+                       tabbedArea = ((FixedEditionArea) workArea).getTabbedArea();
+               } else if (workArea instanceof TabbedArea) {
+                       tabbedArea = (TabbedArea) workArea;
+               }
+               return tabbedArea;
+       }
+
+       @Override
+       public void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
+               TabbedArea tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
+               tabbedArea.open(uiProvider, context);
+       }
+
+       @Override
+       public Localized getTitle() {
+               return title;
+       }
+
+       public void init(BundleContext bundleContext, Map<String, Object> properties) {
+               weights = LangUtils.toStringList(properties.get(Property.weights.name()));
+               startMaximized = properties.containsKey(Property.startMaximized.name())
+                               && "true".equals(properties.get(Property.startMaximized.name()));
+               fixedEntryArea = properties.containsKey(Property.fixedEntryArea.name())
+                               && "true".equals(properties.get(Property.fixedEntryArea.name()));
+               if (fixedEntryArea && weights.size() != 0) {
+                       throw new IllegalArgumentException("Property " + Property.weights.name() + " should not be set if property "
+                                       + Property.fixedEntryArea.name() + " is set.");
+               }
+               singleTab = properties.containsKey(Property.singleTab.name())
+                               && "true".equals(properties.get(Property.singleTab.name()));
+
+               String titleStr = (String) properties.get(SuiteLayer.Property.title.name());
+               if (titleStr != null) {
+                       if (titleStr.startsWith("%")) {
+                               title = new Localized() {
+
+                                       @Override
+                                       public String name() {
+                                               return titleStr;
+                                       }
+
+                                       @Override
+                                       public ClassLoader getL10nClassLoader() {
+                                               return bundleContext != null
+                                                               ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader()
+                                                               : getClass().getClassLoader();
+                                       }
+                               };
+                       } else {
+                               title = new Localized.Untranslated(titleStr);
+                       }
+               }
+       }
+
+       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+
+       }
+
+       public void setEntryArea(CmsUiProvider entryArea) {
+               this.entryArea = entryArea;
+       }
+
+       public void setWorkArea(CmsUiProvider workArea) {
+               this.workArea = workArea;
+       }
+
+       public void setDefaultView(CmsUiProvider defaultView) {
+               this.defaultView = defaultView;
+       }
+
+       TabbedArea createTabbedArea(Composite parent, CmsTheme theme) {
+               TabbedArea tabbedArea = new TabbedArea(parent, SWT.NONE);
+               tabbedArea.setSingleTab(singleTab);
+               tabbedArea.setBodyStyle(SuiteStyle.mainTabBody.style());
+               tabbedArea.setTabStyle(SuiteStyle.mainTab.style());
+               tabbedArea.setTabSelectedStyle(SuiteStyle.mainTabSelected.style());
+               tabbedArea.setCloseIcon(SuiteIcon.close.getSmallIcon(theme));
+               tabbedArea.setLayoutData(CmsSwtUtils.fillAll());
+               return tabbedArea;
+       }
+
+//     /** A work area based on an entry area and and a tabbed area. */
+       class SashFormEditionArea extends SashForm {
+               private static final long serialVersionUID = 2219125778722702618L;
+               private TabbedArea tabbedArea;
+               private Composite entryC;
+
+               SashFormEditionArea(Composite parent, int style) {
+                       super(parent, SWT.HORIZONTAL);
+                       CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
+
+                       Composite editorC;
+                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
+                               editorC = new Composite(this, SWT.BORDER);
+                               entryC = new Composite(this, SWT.BORDER);
+                       } else {
+                               entryC = new Composite(this, SWT.NONE);
+                               editorC = new Composite(this, SWT.NONE);
+                       }
+
+                       // sash form specific
+                       if (weights.size() != 0) {
+                               int[] actualWeight = new int[weights.size()];
+                               for (int i = 0; i < weights.size(); i++) {
+                                       actualWeight[i] = Integer.parseInt(weights.get(i));
+                               }
+                               setWeights(actualWeight);
+                       } else {
+                               int[] actualWeights = new int[] { 3000, 7000 };
+                               setWeights(actualWeights);
+                       }
+                       if (startMaximized)
+                               setMaximizedControl(editorC);
+
+                       GridLayout editorAreaLayout = CmsSwtUtils.noSpaceGridLayout();
+//                     editorAreaLayout.verticalSpacing = 0;
+//                     editorAreaLayout.marginBottom = 0;
+//                     editorAreaLayout.marginHeight = 0;
+//                     editorAreaLayout.marginLeft = 0;
+//                     editorAreaLayout.marginRight = 0;
+                       editorC.setLayout(editorAreaLayout);
+
+                       tabbedArea = createTabbedArea(editorC, theme);
+               }
+
+               TabbedArea getTabbedArea() {
+                       return tabbedArea;
+               }
+
+               Composite getEntryArea() {
+                       return entryC;
+               }
+
+       }
+
+       class FixedEditionArea extends Composite {
+               private static final long serialVersionUID = -5525672639277322465L;
+               private TabbedArea tabbedArea;
+               private Composite entryC;
+
+               public FixedEditionArea(Composite parent, int style) {
+                       super(parent, style);
+                       CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
+
+                       setLayout(CmsSwtUtils.noSpaceGridLayout(2));
+
+                       Composite editorC;
+                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
+                               editorC = new Composite(this, SWT.NONE);
+                               entryC = new Composite(this, SWT.NONE);
+                       } else {
+                               entryC = new Composite(this, SWT.NONE);
+                               editorC = new Composite(this, SWT.NONE);
+                       }
+                       entryC.setLayoutData(CmsSwtUtils.fillHeight());
+
+                       GridLayout editorAreaLayout = CmsSwtUtils.noSpaceGridLayout();
+//                     editorAreaLayout.verticalSpacing = 0;
+//                     editorAreaLayout.marginBottom = 0;
+//                     editorAreaLayout.marginHeight = 0;
+//                     editorAreaLayout.marginLeft = 0;
+//                     editorAreaLayout.marginRight = 0;
+                       editorC.setLayout(editorAreaLayout);
+                       editorC.setLayoutData(CmsSwtUtils.fillAll());
+
+                       tabbedArea = createTabbedArea(editorC, theme);
+               }
+
+               TabbedArea getTabbedArea() {
+                       return tabbedArea;
+               }
+
+               Composite getEntryArea() {
+                       return entryC;
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultFooter.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultFooter.java
new file mode 100644 (file)
index 0000000..62a3a23
--- /dev/null
@@ -0,0 +1,40 @@
+package org.argeo.app.ui;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.BundleContext;
+
+/** Footer of a standard Argeo Suite application. */
+public class DefaultFooter implements CmsUiProvider {
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               Composite content = new Composite(parent, SWT.NONE);
+               content.setLayoutData(new GridData(0, 0));
+               Control contentControl = createContent(content, context);
+
+               // TODO support and guarantee
+
+               return contentControl;
+       }
+
+       protected Control createContent(Composite parent, Node context) throws RepositoryException {
+               return parent;
+       }
+
+       public void init(BundleContext bundleContext, Map<String, String> properties) {
+       }
+
+       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultHeader.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultHeader.java
new file mode 100644 (file)
index 0000000..d304493
--- /dev/null
@@ -0,0 +1,119 @@
+package org.argeo.app.ui;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.api.cms.CmsView;
+import org.argeo.cms.Localized;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.wiring.BundleWiring;
+
+/** Header of a standard Argeo Suite application. */
+public class DefaultHeader implements CmsUiProvider {
+       public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title";
+       private Localized title = null;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
+               CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
+
+               parent.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, true)));
+
+               // TODO right to left
+               Composite lead = new Composite(parent, SWT.NONE);
+               CmsSwtUtils.style(lead, SuiteStyle.header);
+               lead.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false));
+               lead.setLayout(new GridLayout());
+               Label lbl = new Label(lead, SWT.NONE);
+//             String title = properties.get(TITLE_PROPERTY);
+//             // TODO expose the localized
+//             lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString()
+//                             : title);
+               lbl.setText(title.lead());
+               CmsSwtUtils.style(lbl, SuiteStyle.headerTitle);
+               lbl.setLayoutData(CmsSwtUtils.fillWidth());
+
+               Composite middle = new Composite(parent, SWT.NONE);
+               CmsSwtUtils.style(middle, SuiteStyle.header);
+               middle.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
+               middle.setLayout(new GridLayout());
+
+               Composite end = new Composite(parent, SWT.NONE);
+               CmsSwtUtils.style(end, SuiteStyle.header);
+               end.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, false));
+
+               if (!cmsView.isAnonymous()) {
+                       end.setLayout(new GridLayout(2, false));
+                       Label userL = new Label(end, SWT.NONE);
+                       CmsSwtUtils.style(userL, SuiteStyle.header);
+                       userL.setText(CurrentUser.getDisplayName());
+                       Button logoutB = new Button(end, SWT.FLAT);
+//                     CmsUiUtils.style(logoutB, SuiteStyle.header);
+                       logoutB.setImage(SuiteIcon.logout.getSmallIcon(theme));
+                       logoutB.addSelectionListener(new SelectionAdapter() {
+                               private static final long serialVersionUID = 7116760083964201233L;
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       cmsView.logout();
+                               }
+
+                       });
+               } else {
+                       end.setLayout(new GridLayout(1, false));
+                       // required in order to avoid wrong height after logout
+                       new Label(end, SWT.NONE).setText("");
+
+               }
+               return lbl;
+       }
+
+       public void init(BundleContext bundleContext, Map<String, String> properties) {
+               String titleStr = (String) properties.get(TITLE_PROPERTY);
+               if (titleStr != null) {
+                       if (titleStr.startsWith("%")) {
+                               title = new Localized() {
+
+                                       @Override
+                                       public String name() {
+                                               return titleStr;
+                                       }
+
+                                       @Override
+                                       public ClassLoader getL10nClassLoader() {
+                                               return bundleContext != null
+                                                               ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader()
+                                                               : getClass().getClassLoader();
+                                       }
+                               };
+                       } else {
+                               title = new Localized.Untranslated(titleStr);
+                       }
+               }
+       }
+
+       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+
+       }
+
+       public Localized getTitle() {
+               return title;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLeadPane.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLeadPane.java
new file mode 100644 (file)
index 0000000..5650e9c
--- /dev/null
@@ -0,0 +1,187 @@
+package org.argeo.app.ui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsView;
+import org.argeo.app.api.RankedObject;
+import org.argeo.app.core.SuiteUtils;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.Localized;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.wiring.BundleWiring;
+
+/** Side pane listing various perspectives. */
+public class DefaultLeadPane implements CmsUiProvider {
+       private final static CmsLog log = CmsLog.getLog(DefaultLeadPane.class);
+
+       public static enum Property {
+               defaultLayers, adminLayers;
+       }
+
+       private Map<String, RankedObject<SuiteLayer>> layers = Collections.synchronizedSortedMap(new TreeMap<>());
+       private List<String> defaultLayers;
+       private List<String> adminLayers = new ArrayList<>();
+
+       private ClassLoader l10nClassLoader;
+
+       @Override
+       public Control createUi(Composite parent, Node node) throws RepositoryException {
+               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
+               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               Composite appLayersC = new Composite(parent, SWT.NONE);
+               CmsSwtUtils.style(appLayersC, SuiteStyle.leadPane);
+               GridLayout layout = new GridLayout();
+               layout.verticalSpacing = 10;
+               layout.marginTop = 10;
+               layout.marginLeft = 10;
+               layout.marginRight = 10;
+               appLayersC.setLayout(layout);
+               appLayersC.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+
+               Composite adminLayersC;
+               if (!adminLayers.isEmpty()) {
+                       adminLayersC = new Composite(parent, SWT.NONE);
+                       CmsSwtUtils.style(adminLayersC, SuiteStyle.leadPane);
+                       GridLayout adminLayout = new GridLayout();
+                       adminLayout.verticalSpacing = 10;
+                       adminLayout.marginBottom = 10;
+                       adminLayout.marginLeft = 10;
+                       adminLayout.marginRight = 10;
+                       adminLayersC.setLayout(adminLayout);
+                       adminLayersC.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, false, true));
+               } else {
+                       adminLayersC = null;
+               }
+
+//             boolean isAdmin = cmsView.doAs(() -> CurrentUser.isInRole(NodeConstants.ROLE_USER_ADMIN));
+               Set<String> userRoles = cmsView.doAs(() -> CurrentUser.roles());
+               Button first = null;
+               layers: for (String layerDef : defaultLayers) {
+                       layerDef = layerDef.trim();
+                       if ("".equals(layerDef))
+                               continue layers;// skip empty lines
+                       String[] semiColArr = layerDef.split(";");
+                       String layerId = semiColArr[0];
+                       Set<String> layerRoles = SuiteUtils.extractRoles(semiColArr);
+                       if (layers.containsKey(layerId)) {
+                               if (!layerRoles.isEmpty()) {
+                                       Set<String> intersection = new HashSet<String>(layerRoles);
+                                       intersection.retainAll(userRoles);
+                                       if (intersection.isEmpty())
+                                               continue layers;// skip unauthorized layer
+                               }
+                               RankedObject<SuiteLayer> layerObj = layers.get(layerId);
+
+                               Localized title = null;
+                               if (!adminLayers.contains(layerId)) {
+                                       String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
+                                       if (titleStr != null) {
+                                               if (titleStr.startsWith("%")) {
+                                                       // LocaleUtils.local(titleStr, getClass().getClassLoader());
+                                                       title = () -> titleStr;
+                                               } else {
+                                                       title = new Localized.Untranslated(titleStr);
+                                               }
+                                       }
+                               }
+
+                               String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
+                               SuiteIcon icon = null;
+                               if (iconName != null)
+                                       icon = SuiteIcon.valueOf(iconName);
+
+                               Composite buttonParent;
+                               if (adminLayers.contains(layerId))
+                                       buttonParent = adminLayersC;
+                               else
+                                       buttonParent = appLayersC;
+                               Button b = SuiteUiUtils.createLayerButton(buttonParent, layerId, title, icon, l10nClassLoader);
+                               if (first == null)
+                                       first = b;
+                       }
+               }
+               return first;
+       }
+
+       public void init(BundleContext bundleContext, Map<String, Object> properties) {
+               l10nClassLoader = bundleContext != null ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader()
+                               : getClass().getClassLoader();
+
+               String[] defaultLayers = (String[]) properties.get(Property.defaultLayers.toString());
+               if (defaultLayers == null)
+                       throw new IllegalArgumentException("Default layers must be set.");
+               this.defaultLayers = Arrays.asList(defaultLayers);
+               if (log.isDebugEnabled())
+                       log.debug("Default layers: " + Arrays.asList(defaultLayers));
+               String[] adminLayers = (String[]) properties.get(Property.adminLayers.toString());
+               if (adminLayers != null) {
+                       this.adminLayers = Arrays.asList(adminLayers);
+                       if (log.isDebugEnabled())
+                               log.debug("Admin layers: " + Arrays.asList(adminLayers));
+               }
+       }
+
+       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+
+       }
+
+       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);
+                               }
+                       }
+               }
+       }
+
+//     protected Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon) {
+//             CmsTheme theme = CmsTheme.getCmsTheme(parent);
+//             Button button = new Button(parent, SWT.PUSH);
+//             CmsUiUtils.style(button, SuiteStyle.leadPane);
+//             if (icon != null)
+//                     button.setImage(icon.getBigIcon(theme));
+//             button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false));
+//             // button.setToolTipText(msg.lead());
+//             if (msg != null) {
+//                     Label lbl = new Label(parent, SWT.CENTER);
+//                     CmsUiUtils.style(lbl, SuiteStyle.leadPane);
+//                     // CmsUiUtils.markup(lbl);
+//                     ClassLoader l10nClassLoader = getClass().getClassLoader();
+//                     String txt = LocaleUtils.lead(msg, l10nClassLoader);
+////                   String txt = msg.lead();
+//                     lbl.setText(txt);
+//                     lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
+//             }
+//             CmsUiUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer);
+//             return button;
+//     }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLoginScreen.java b/org.argeo.app.ui/src/org/argeo/app/ui/DefaultLoginScreen.java
new file mode 100644 (file)
index 0000000..0624c48
--- /dev/null
@@ -0,0 +1,35 @@
+package org.argeo.app.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsView;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.auth.CmsLogin;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Provides a login screen. */
+public class DefaultLoginScreen implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
+               if (!cmsView.isAnonymous())
+                       throw new IllegalStateException(CurrentUser.getUsername() + " is already logged in");
+
+               parent.setLayout(new GridLayout());
+               Composite loginArea = new Composite(parent, SWT.NONE);
+               loginArea.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+               
+               CmsLogin cmsLogin = new CmsLogin(cmsView);
+               cmsLogin.createUi(loginArea);
+               return cmsLogin.getCredentialsBlock();
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/EventRecorder.java b/org.argeo.app.ui/src/org/argeo/app/ui/EventRecorder.java
new file mode 100644 (file)
index 0000000..0607952
--- /dev/null
@@ -0,0 +1,26 @@
+package org.argeo.app.ui;
+
+import org.argeo.api.cms.CmsLog;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+/** Record UI events. */
+public class EventRecorder implements EventHandler {
+       private final static CmsLog log = CmsLog.getLog(EventRecorder.class);
+
+       public void init() {
+
+       }
+
+       public void destroy() {
+
+       }
+
+       @Override
+       public void handleEvent(Event event) {
+               if (log.isTraceEnabled())
+                       log.trace(event);
+
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/RecentItems.java b/org.argeo.app.ui/src/org/argeo/app/ui/RecentItems.java
new file mode 100644 (file)
index 0000000..bad48b8
--- /dev/null
@@ -0,0 +1,365 @@
+package org.argeo.app.ui;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.core.XPathUtils;
+import org.argeo.app.ui.widgets.DelayedText;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.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 = CmsSwtUtils.getCmsTheme(parent);
+               parent.setLayout(new GridLayout());
+//             parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+               parent.setLayout(new GridLayout());
+
+//             Composite top = new Composite(parent, SWT.BORDER);
+//             CmsUiUtils.style(top, SuiteStyle.recentItems);
+//             top.setLayoutData(CmsUiUtils.fillWidth());
+//             top.setLayout(CmsUiUtils.noSpaceGridLayout(2));
+//             Label lbl = new Label(top, SWT.FLAT);
+//             lbl.setLayoutData(CmsUiUtils.fillWidth());
+//             lbl.setText(SuiteMsg.recentItems.lead());
+//             CmsUiUtils.style(lbl, SuiteStyle.recentItems);
+//
+//             ToolBar topToolBar = new ToolBar(top, SWT.NONE);
+//             ToolItem addItem = new ToolItem(topToolBar, SWT.FLAT);
+////           CmsUiUtils.style(addItem, SuiteStyle.recentItems);
+//             addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+
+               if (context == null)
+                       return null;
+               SingleEntityViewer entityViewer = new SingleEntityViewer(parent, SWT.NONE, context.getSession());
+               entityViewer.createUi();
+               entityViewer.getViewer().getTable().setLayoutData(CmsSwtUtils.fillAll());
+
+               Composite bottom = new Composite(parent, SWT.NONE);
+               bottom.setLayoutData(CmsSwtUtils.fillWidth());
+               bottom.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
+               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               deleteItem.setEnabled(false);
+//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
+               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
+               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+               entityViewer.getViewer().addDoubleClickListener(new IDoubleClickListener() {
+
+                       @Override
+                       public void doubleClick(DoubleClickEvent event) {
+                               Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
+                               if (node != null)
+                                       CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
+                                                       SuiteEvent.eventProperties(node));
+
+                       }
+               });
+               entityViewer.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
+                               if (node != null) {
+                                       CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
+                                                       SuiteEvent.eventProperties(node));
+                                       deleteItem.setEnabled(true);
+                               } else {
+                                       deleteItem.setEnabled(false);
+                               }
+                       }
+               });
+
+               return entityViewer.filterTxt;
+
+       }
+
+       public void init(Map<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.app.ui/src/org/argeo/app/ui/SuiteApp.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteApp.java
new file mode 100644 (file)
index 0000000..7070ed5
--- /dev/null
@@ -0,0 +1,637 @@
+package org.argeo.app.ui;
+
+import static org.argeo.api.cms.CmsView.CMS_VIEW_UID_PROPERTY;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.cms.CmsSession;
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.api.cms.CmsUi;
+import org.argeo.api.cms.CmsView;
+import org.argeo.app.api.EntityConstants;
+import org.argeo.app.api.EntityNames;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.api.RankedObject;
+import org.argeo.app.core.SuiteUtils;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.AbstractCmsApp;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.Localized;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.dialogs.CmsFeedback;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.Constants;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+import org.osgi.service.useradmin.User;
+
+/** The Argeo Suite App. */
+public class SuiteApp extends AbstractCmsApp implements EventHandler {
+       private final static CmsLog log = CmsLog.getLog(SuiteApp.class);
+
+       public final static String PUBLIC_BASE_PATH_PROPERTY = "publicBasePath";
+       public final static String DEFAULT_UI_NAME_PROPERTY = "defaultUiName";
+       public final static String DEFAULT_THEME_ID_PROPERTY = "defaultThemeId";
+       public final static String DEFAULT_LAYER_PROPERTY = "defaultLayer";
+       private final static String LOGIN = "login";
+       private final static String HOME_STATE = "~";
+
+       private String publicBasePath = null;
+
+       private String pidPrefix;
+       private String headerPid;
+       private String footerPid;
+       private String leadPanePid;
+       private String adminLeadPanePid;
+       private String loginScreenPid;
+
+       private String defaultLayerPid = "argeo.suite.ui.dashboardLayer";
+
+       private String defaultUiName = "app";
+       private String adminUiName = "admin";
+       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 Repository repository;
+
+
+       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);
+               if (properties.containsKey(DEFAULT_LAYER_PROPERTY))
+                       defaultLayerPid = LangUtils.get(properties, DEFAULT_LAYER_PROPERTY);
+               publicBasePath = LangUtils.get(properties, PUBLIC_BASE_PATH_PROPERTY);
+
+               if (properties.containsKey(Constants.SERVICE_PID)) {
+                       String servicePid = properties.get(Constants.SERVICE_PID).toString();
+                       if (servicePid.endsWith(".app")) {
+                               pidPrefix = servicePid.substring(0, servicePid.length() - "app".length());
+                       }
+               }
+
+               if (pidPrefix == null)
+                       throw new IllegalArgumentException("PID prefix must be set.");
+
+               headerPid = pidPrefix + "header";
+               footerPid = pidPrefix + "footer";
+               leadPanePid = pidPrefix + "leadPane";
+               adminLeadPanePid = pidPrefix + "adminLeadPane";
+               loginScreenPid = pidPrefix + "loginScreen";
+       }
+
+       public void destroy(Map<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);
+               uiNames.add(adminUiName);
+               return uiNames;
+       }
+
+       @Override
+       public CmsUi initUi(Object parent) {
+               Composite uiParent =(Composite) parent;
+               String uiName = uiParent.getData(UI_NAME_PROPERTY) != null ? uiParent.getData(UI_NAME_PROPERTY).toString() : null;
+               CmsView cmsView = CmsSwtUtils.getCmsView(uiParent);
+               if (cmsView == null)
+                       throw new IllegalStateException("No CMS view is registered.");
+               CmsTheme theme = getTheme(uiName);
+               if (theme != null)
+                       CmsSwtUtils.registerCmsTheme(uiParent.getShell(), theme);
+               SuiteUi argeoSuiteUi = new SuiteUi(uiParent, SWT.INHERIT_DEFAULT);
+               String uid = cmsView.getUid();
+               managedUis.put(uid, argeoSuiteUi);
+               argeoSuiteUi.addDisposeListener((e) -> {
+                       managedUis.remove(uid);
+                       if (log.isDebugEnabled())
+                               log.debug("Suite UI " + uid + " has been disposed.");
+               });
+               return argeoSuiteUi;
+       }
+
+       @Override
+       public String getThemeId(String uiName) {
+               return defaultThemeId;
+       }
+
+       @Override
+       public void refreshUi(CmsUi cmsUi, String state) {
+               try {
+                       Node context = null;
+                       SuiteUi ui = (SuiteUi) cmsUi;
+
+                       String uiName = Objects.toString(ui.getParent().getData(UI_NAME_PROPERTY), null);
+                       if (uiName == null)
+                               throw new IllegalStateException("UI name should not be null");
+                       CmsView cmsView = CmsSwtUtils.getCmsView(ui);
+                       CmsUiProvider headerUiProvider = findUiProvider(headerPid);
+                       CmsUiProvider footerUiProvider = findUiProvider(footerPid);
+                       CmsUiProvider leadPaneUiProvider;
+                       if (adminUiName.equals(uiName)) {
+                               leadPaneUiProvider = findUiProvider(adminLeadPanePid);
+                       } else {
+                               leadPaneUiProvider = findUiProvider(leadPanePid);
+                       }
+
+                       Localized appTitle = null;
+                       if (headerUiProvider instanceof DefaultHeader) {
+                               appTitle = ((DefaultHeader) headerUiProvider).getTitle();
+                       }
+                       ui.setTitle(appTitle);
+
+                       if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login
+                               ui.logout();
+                               if (headerUiProvider != null)
+                                       refreshPart(headerUiProvider, ui.getHeader(), context);
+                               ui.refreshBelowHeader(false);
+                               refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context);
+                               if (footerUiProvider != null)
+                                       refreshPart(footerUiProvider, ui.getFooter(), context);
+                               ui.layout(true, true);
+                               setState(ui, LOGIN);
+                       } else {
+                               if (LOGIN.equals(state))
+                                       state = null;
+                               CmsSession cmsSession = cmsView.getCmsSession();
+                               if (ui.getUserDir() == null) {
+                                       // FIXME NPE on CMSSession when logging in from anonymous
+                                       if (cmsSession == null || cmsView.isAnonymous()) {
+                                               assert publicBasePath != null;
+                                               ui.initSessions(getRepository(), publicBasePath);
+                                       } else {
+                                               Session adminSession = null;
+                                               try {
+                                                       adminSession = CmsJcrUtils.openDataAdminSession(getRepository(), null);
+                                                       Node userDir = SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
+                                                       ui.initSessions(getRepository(), userDir.getPath());
+                                               } finally {
+                                                       Jcr.logout(adminSession);
+                                               }
+                                       }
+                               }
+                               initLocale(cmsSession);
+                               context = stateToNode(ui, state);
+                               if (context == null)
+                                       context = ui.getUserDir();
+
+                               if (headerUiProvider != null)
+                                       refreshPart(headerUiProvider, ui.getHeader(), context);
+                               ui.refreshBelowHeader(true);
+                               for (String key : layersByPid.keySet()) {
+                                       SuiteLayer layer = layersByPid.get(key).get();
+                                       ui.addLayer(key, layer);
+                               }
+
+                               if (leadPaneUiProvider != null)
+                                       refreshPart(leadPaneUiProvider, ui.getLeadPane(), context);
+                               if (footerUiProvider != null)
+                                       refreshPart(footerUiProvider, ui.getFooter(), context);
+                               ui.layout(true, true);
+                               setState(ui, state != null ? state : defaultLayerPid);
+                       }
+               } catch (Exception e) {
+                       CmsFeedback.show("Unexpected exception", e);
+               }
+       }
+
+       private void initLocale(CmsSession cmsSession) {
+               if (cmsSession == null)
+                       return;
+               Locale locale = cmsSession.getLocale();
+               UiContext.setLocale(locale);
+               LocaleUtils.setThreadLocale(locale);
+
+       }
+
+       private void refreshPart(CmsUiProvider uiProvider, Composite part, Node context) {
+               CmsSwtUtils.clear(part);
+               uiProvider.createUiPart(part, context);
+       }
+
+       private CmsUiProvider findUiProvider(String pid) {
+               if (!uiProvidersByPid.containsKey(pid))
+                       return null;
+               return uiProvidersByPid.get(pid).get();
+       }
+
+       private SuiteLayer findLayer(String pid) {
+               if (!layersByPid.containsKey(pid))
+                       return null;
+               return layersByPid.get(pid).get();
+       }
+
+       private <T> 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 mixinType : context.getMixinNodeTypes()) {
+                               String mixinTypeName = mixinType.getName();
+                               if (byType.containsKey(mixinTypeName)) {
+                                       types.add(mixinTypeName);
+                               }
+                               for (NodeType superType : mixinType.getDeclaredSupertypes()) {
+                                       if (byType.containsKey(superType.getName())) {
+                                               types.add(superType.getName());
+                                       }
+                               }
+                       }
+                       // primary node type
+                       NodeType primaryType = context.getPrimaryNodeType();
+                       String primaryTypeName = primaryType.getName();
+                       if (byType.containsKey(primaryTypeName)) {
+                               types.add(primaryTypeName);
+                       }
+                       for (NodeType superType : primaryType.getDeclaredSupertypes()) {
+                               if (byType.containsKey(superType.getName())) {
+                                       types.add(superType.getName());
+                               }
+                       }
+                       // entity type
+                       if (context.isNodeType(EntityType.entity.get())) {
+                               if (context.hasProperty(EntityNames.ENTITY_TYPE)) {
+                                       String entityTypeName = context.getProperty(EntityNames.ENTITY_TYPE).getString();
+                                       if (byType.containsKey(entityTypeName)) {
+                                               types.add(entityTypeName);
+                                       }
+                               }
+                       }
+
+//                     if (context.getPath().equals("/")) {// root node
+//                             types.add("nt:folder");
+//                     }
+                       if (CmsJcrUtils.isUserHome(context) && byType.containsKey("nt:folder")) {// home node
+                               types.add("nt:folder");
+                       }
+
+                       if (types.size() == 0)
+                               throw new IllegalArgumentException("No type found for " + context + " (" + listTypes(context) + ")");
+                       String type = types.iterator().next();
+                       if (!byType.containsKey(type))
+                               throw new IllegalArgumentException("No component found for " + context + " with type " + type);
+                       return byType.get(type).get();
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException(e);
+               }
+       }
+
+       private static String listTypes(Node context) {
+               try {
+                       StringBuilder sb = new StringBuilder();
+                       sb.append(context.getPrimaryNodeType().getName());
+                       for (NodeType superType : context.getPrimaryNodeType().getDeclaredSupertypes()) {
+                               sb.append(' ');
+                               sb.append(superType.getName());
+                       }
+
+                       for (NodeType nodeType : context.getMixinNodeTypes()) {
+                               sb.append(' ');
+                               sb.append(nodeType.getName());
+                               if (nodeType.getName().equals(EntityType.local.get()))
+                                       sb.append('/').append(context.getProperty(EntityNames.ENTITY_TYPE).getString());
+                               for (NodeType superType : nodeType.getDeclaredSupertypes()) {
+                                       sb.append(' ');
+                                       sb.append(superType.getName());
+                               }
+                       }
+                       return sb.toString();
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+       }
+
+       @Override
+       public void setState(CmsUi cmsUi, String state) {
+               if (state == null)
+                       return;
+               if (!state.startsWith("/")) {
+                       if (cmsUi instanceof SuiteUi) {
+                               SuiteUi ui = (SuiteUi) cmsUi;
+                               if (LOGIN.equals(state)) {
+                                       String appTitle = "";
+                                       if (ui.getTitle() != null)
+                                               appTitle = ui.getTitle().lead();
+                                       ui.getCmsView().stateChanged(state, appTitle);
+                                       return;
+                               }
+                               Map<String, Object> properties = new HashMap<>();
+                               String layerId = HOME_STATE.equals(state) ? defaultLayerPid : state;
+                               properties.put(SuiteEvent.LAYER, layerId);
+                               properties.put(SuiteEvent.NODE_PATH, HOME_STATE);
+                               ui.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), properties);
+                       }
+                       return;
+               }
+               SuiteUi suiteUi = (SuiteUi) cmsUi;
+               Node node = stateToNode(suiteUi, state);
+               if (node == null) {
+                       suiteUi.getCmsView().navigateTo(HOME_STATE);
+               } else {
+                       suiteUi.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), SuiteEvent.eventProperties(node));
+                       suiteUi.getCmsView().sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(node));
+               }
+       }
+
+       // TODO move it to an internal package?
+       static String nodeToState(Node node) {
+               return '/' + Jcr.getWorkspaceName(node) + Jcr.getPath(node);
+       }
+
+       private Node stateToNode(SuiteUi suiteUi, String state) {
+               if (suiteUi == null)
+                       return null;
+               if (state == null || !state.startsWith("/"))
+                       return null;
+
+               String path = state.substring(1);
+               String workspace;
+               if (path.equals("")) {
+                       workspace = null;
+                       path = "/";
+               } else {
+                       int index = path.indexOf('/');
+                       if (index == 0) {
+                               log.error("Cannot interpret " + state);
+//                             cmsView.navigateTo("~");
+                               return null;
+                       } else if (index > 0) {
+                               workspace = path.substring(0, index);
+                               path = path.substring(index);
+                       } else {// index<0, assuming root node
+                               workspace = path;
+                               path = "/";
+                       }
+               }
+               Session session = suiteUi.getSession(workspace);
+               if (session == null)
+                       return null;
+               Node node = Jcr.getNode(session, path);
+               return node;
+       }
+
+       /*
+        * Events management
+        */
+
+       @Override
+       public void handleEvent(Event event) {
+
+               // Specific UI related events
+               SuiteUi ui = getRelatedUi(event);
+               if (ui == null)
+                       return;
+               try {
+                       String appTitle = "";
+                       if (ui.getTitle() != null)
+                               appTitle = ui.getTitle().lead() + " - ";
+
+//                     String currentLayerId = ui.getCurrentLayerId();
+//                     SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null;
+                       if (SuiteUiUtils.isTopic(event, SuiteEvent.refreshPart)) {
+                               Node node = getNode(ui, event);
+                               if (node == null)
+                                       return;
+                               CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
+                               SuiteLayer layer = findByType(layersByType, node);
+                               ui.switchToLayer(layer, node);
+                               ui.getCmsView().runAs(() -> layer.view(uiProvider, ui.getCurrentWorkArea(), node));
+                               ui.getCmsView().stateChanged(nodeToState(node), appTitle + Jcr.getTitle(node));
+                       } else if (SuiteUiUtils.isTopic(event, SuiteEvent.openNewPart)) {
+                               Node node = getNode(ui, event);
+                               if (node == null)
+                                       return;
+                               CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
+                               SuiteLayer layer = findByType(layersByType, node);
+                               ui.switchToLayer(layer, node);
+                               ui.getCmsView().runAs(() -> layer.open(uiProvider, ui.getCurrentWorkArea(), node));
+                               ui.getCmsView().stateChanged(nodeToState(node), appTitle + Jcr.getTitle(node));
+                       } else if (SuiteUiUtils.isTopic(event, SuiteEvent.switchLayer)) {
+                               String layerId = get(event, SuiteEvent.LAYER);
+                               if (layerId != null) {
+//                                     ui.switchToLayer(layerId, ui.getUserDir());
+                                       SuiteLayer suiteLayer = findLayer(layerId);
+                                       if (suiteLayer == null)
+                                               throw new IllegalArgumentException("No layer '" + layerId + "' available.");
+                                       Localized layerTitle = suiteLayer.getTitle();
+                                       // FIXME make sure we don't rebuild the work area twice
+                                       Composite workArea = ui.getCmsView().doAs(() -> ui.switchToLayer(layerId, ui.getUserDir()));
+                                       String title = null;
+                                       if (layerTitle != null)
+                                               title = layerTitle.lead();
+                                       Node nodeFromState = getNode(ui, event);
+                                       if (nodeFromState != null && nodeFromState.getPath().equals(ui.getUserDir().getPath())) {
+                                               // default layer view is forced
+                                               String state = defaultLayerPid.equals(layerId) ? "~" : layerId;
+                                               ui.getCmsView().stateChanged(state, appTitle + title);
+                                               suiteLayer.view(null, workArea, nodeFromState);
+                                       } else {
+                                               Node layerCurrentContext = suiteLayer.getCurrentContext(workArea);
+                                               if (layerCurrentContext != null) {
+                                                       // layer was already showing a context so we set the state to it
+                                                       ui.getCmsView().stateChanged(nodeToState(layerCurrentContext),
+                                                                       appTitle + Jcr.getTitle(layerCurrentContext));
+                                               } else {
+                                                       // no context was shown
+                                                       ui.getCmsView().stateChanged(layerId, appTitle + title);
+                                               }
+                                       }
+                               } else {
+                                       Node node = getNode(ui, event);
+                                       if (node != null) {
+                                               SuiteLayer layer = findByType(layersByType, node);
+                                               ui.getCmsView().runAs(() -> ui.switchToLayer(layer, node));
+                                       }
+                               }
+                       }
+               } catch (Exception e) {
+                       log.error("Cannot handle event " + event, e);
+//                     CmsView.getCmsView(ui).exception(e);
+               }
+
+       }
+
+       private Node getNode(SuiteUi ui, Event event) {
+               String nodePath = get(event, SuiteEvent.NODE_PATH);
+               if (nodePath != null && nodePath.equals(HOME_STATE))
+                       return ui.getUserDir();
+               String workspaceName = get(event, SuiteEvent.WORKSPACE);
+               Session session = ui.getSession(workspaceName);
+               Node node;
+               if (nodePath == null) {
+                       // look for a user
+                       String username = get(event, SuiteEvent.USERNAME);
+                       if (username == null)
+                               return null;
+                       User user = cmsUserManager.getUser(username);
+                       if (user == null)
+                               return null;
+                       LdapName userDn;
+                       try {
+                               userDn = new LdapName(user.getName());
+                       } catch (InvalidNameException e) {
+                               throw new IllegalArgumentException("Badly formatted username", e);
+                       }
+                       String userNodePath = SuiteUtils.getUserNodePath(userDn);
+                       if (Jcr.itemExists(session, userNodePath))
+                               node = Jcr.getNode(session, userNodePath);
+                       else {
+                               Session adminSession = null;
+                               try {
+                                       adminSession = CmsJcrUtils.openDataAdminSession(getRepository(), workspaceName);
+                                       SuiteUtils.getOrCreateUserNode(adminSession, userDn);
+                               } finally {
+                                       Jcr.logout(adminSession);
+                               }
+                               node = Jcr.getNode(session, userNodePath);
+                       }
+               } else {
+                       node = Jcr.getNode(session, nodePath);
+               }
+               return node;
+       }
+
+       private SuiteUi getRelatedUi(Event event) {
+               return managedUis.get(get(event, CMS_VIEW_UID_PROPERTY));
+       }
+
+       public static String get(Event event, String key) {
+               Object value = event.getProperty(key);
+               if (value == null)
+                       return null;
+//                     throw new IllegalArgumentException("Property " + key + " must be set");
+               return value.toString();
+
+       }
+
+       /*
+        * Dependency injection.
+        */
+
+       public void addUiProvider(CmsUiProvider uiProvider, Map<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;
+       }
+
+       public Repository getRepository() {
+               return repository;
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+       
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteEvent.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteEvent.java
new file mode 100644 (file)
index 0000000..6eaa607
--- /dev/null
@@ -0,0 +1,38 @@
+package org.argeo.app.ui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+
+import org.argeo.api.cms.CmsEvent;
+import org.argeo.jcr.Jcr;
+import org.osgi.service.useradmin.User;
+
+/** Events specific to Argeo Suite. */
+public enum SuiteEvent implements CmsEvent {
+       openNewPart, refreshPart, switchLayer;
+
+       public final static String LAYER = "layer";
+//     public final static String NODE_ID = "nodeId";
+       public final static String NODE_PATH = "path";
+       public final static String USERNAME = "username";
+       public final static String WORKSPACE = "workspace";
+
+       public String getTopicBase() {
+               return "argeo/suite/ui";
+       }
+
+       public static Map<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.app.ui/src/org/argeo/app/ui/SuiteIcon.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteIcon.java
new file mode 100644 (file)
index 0000000..bfc92c3
--- /dev/null
@@ -0,0 +1,16 @@
+package org.argeo.app.ui;
+
+import org.argeo.cms.swt.CmsIcon;
+
+/** Icon names used by Argeo Suite. */
+public enum SuiteIcon implements CmsIcon {
+       add, save, close, closeAll, search, delete, logout, dashboard,
+       // people
+       people, person, organisation,
+       // library
+       documents, document, folder,
+       // admin and settings
+       settings, user,
+       // misc
+       task, tag, location, inbox, map;
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteLayer.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteLayer.java
new file mode 100644 (file)
index 0000000..a92994f
--- /dev/null
@@ -0,0 +1,26 @@
+package org.argeo.app.ui;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.Localized;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.widgets.Composite;
+
+/** An UI layer for the main work area. */
+public interface SuiteLayer extends CmsUiProvider {
+       static enum Property {
+               title, icon, weights, startMaximized, singleTab, fixedEntryArea;
+       }
+
+       void view(CmsUiProvider uiProvider, Composite workArea, Node context);
+       
+       Node getCurrentContext(Composite workArea);
+
+       default void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
+               view(uiProvider, workArea, context);
+       }
+
+       default Localized getTitle() {
+               return null;
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteMsg.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteMsg.java
new file mode 100644 (file)
index 0000000..fae15df
--- /dev/null
@@ -0,0 +1,34 @@
+package org.argeo.app.ui;
+
+import org.argeo.cms.Localized;
+
+/** Localized messages. */
+public enum SuiteMsg implements Localized {
+       dashboard, people, documents, locations, recentItems,
+       // NewPersonWizard
+       firstName, lastName, salutation, email, personWizardWindowTitle, personWizardPageTitle,
+       // NewOrgWizard
+       orgWizardWindowTitle, orgWizardPageTitle, legalName, legalForm, vatId,
+       // ContextAddressComposite
+       chooseAnOrganisation, street, streetComplement, zipCode, city, state, country, geopoint,
+       // FilteredOrderableEntityTable
+       filterHelp,
+       // BankAccountComposite
+       accountHolder, bankName, currency, accountNumber, bankNumber, BIC, IBAN,
+       // EditJobDialog
+       position, chosenItem, department, isPrimary, searchAndChooseEntity,
+       // ContactListCTab (e4)
+       notes, addAContact, contactValue, linkedCompany,
+       // OrgAdminInfoCTab (e4)
+       paymentAccount,
+       // OrgEditor (e4)
+       orgDetails, orgActivityLog, team, orgAdmin,
+       // PersonEditor (e4)
+       personDetails, personActivityLog, personOrgs, personSecurity,
+       // PersonSecurityCTab (e4)
+       resetPassword,
+       // Generic
+       label, aCustomLabel, description, value, name, primary, add, save, pickup,
+       // Tag
+       confirmNewTag, cannotCreateTag;
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteStyle.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteStyle.java
new file mode 100644 (file)
index 0000000..7afd23c
--- /dev/null
@@ -0,0 +1,35 @@
+package org.argeo.app.ui;
+
+import org.argeo.api.cms.CmsStyle;
+
+/** Styles used by Argeo Suite work UI. */
+public enum SuiteStyle implements CmsStyle {
+       // header
+       header, headerTitle, headerMenu, headerMenuItem,
+       // footer
+       footer,
+       // recent items
+       recentItems,
+       // lead pane
+       leadPane, leadPaneItem, leadPaneSectionTitle, leadPaneSubSectionTitle,
+       // entry area
+       entryArea,
+       // group composite
+       titleContainer, titleLabel, subTitleLabel, formLine, formColumn, navigationBar, navigationTitle, navigationButton,
+       // forms elements
+       simpleLabel, simpleText, simpleInput,
+       // table
+       titleCell,
+       // layers
+       workArea,
+       // tabbed area
+       mainTabBody, mainTabSelected, mainTab,
+       // buttons
+       inlineButton;
+
+       @Override
+       public String getClassPrefix() {
+               return "argeo-suite";
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUi.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUi.java
new file mode 100644 (file)
index 0000000..b2e4385
--- /dev/null
@@ -0,0 +1,258 @@
+package org.argeo.app.ui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.cms.CmsUi;
+import org.argeo.api.cms.CmsView;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.Localized;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/** The view for the default ergonomics of Argeo Suite. */
+class SuiteUi extends Composite implements CmsUi {
+       private static final long serialVersionUID = 6207018859086689108L;
+       private final static CmsLog log = CmsLog.getLog(SuiteUi.class);
+
+       private Localized title;
+       private Composite header;
+       private Composite footer;
+       private Composite belowHeader;
+       private Composite leadPane;
+       private Composite sidePane;
+       private Composite dynamicArea;
+
+       private Session sysSession;
+       private Session homeSession;
+       private Node userDir;
+
+       private Map<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 = CmsSwtUtils.getCmsView(parent);
+               this.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+               header = new Composite(this, SWT.NONE);
+               header.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               CmsSwtUtils.style(header, SuiteStyle.header);
+               header.setLayoutData(CmsSwtUtils.fillWidth());
+
+               belowHeader = new Composite(this, SWT.NONE);
+               belowHeader.setLayoutData(CmsSwtUtils.fillAll());
+
+               footer = new Composite(this, SWT.NONE);
+               footer.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               CmsSwtUtils.style(footer, SuiteStyle.footer);
+               footer.setLayoutData(CmsSwtUtils.fillWidth());
+       }
+
+       public void refreshBelowHeader(boolean initApp) {
+               CmsSwtUtils.clear(belowHeader);
+               int style = getStyle();
+               if (initApp) {
+                       belowHeader.setLayout(CmsSwtUtils.noSpaceGridLayout(3));
+
+                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
+                               sidePane = new Composite(belowHeader, SWT.NONE);
+                               sidePane.setLayout(CmsSwtUtils.noSpaceGridLayout());
+                               sidePane.setLayoutData(CmsSwtUtils.fillHeight());
+                               dynamicArea = new Composite(belowHeader, SWT.NONE);
+                               leadPane = new Composite(belowHeader, SWT.NONE);
+                       } else {
+                               leadPane = new Composite(belowHeader, SWT.NONE);
+                               dynamicArea = new Composite(belowHeader, SWT.NONE);
+                               sidePane = new Composite(belowHeader, SWT.NONE);
+                               sidePane.setLayout(CmsSwtUtils.noSpaceGridLayout());
+                               sidePane.setLayoutData(CmsSwtUtils.fillHeight());
+                       }
+                       leadPane.setLayoutData(CmsSwtUtils.fillHeight());
+                       leadPane.setLayout(CmsSwtUtils.noSpaceGridLayout());
+                       CmsSwtUtils.style(leadPane, SuiteStyle.leadPane);
+
+                       dynamicArea.setLayoutData(CmsSwtUtils.fillAll());
+                       dynamicArea.setLayout(new FormLayout());
+
+               } else {
+                       belowHeader.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               }
+       }
+
+       /*
+        * LAYERS
+        */
+
+       Composite getCurrentWorkArea() {
+               if (currentLayerId == null)
+                       throw new IllegalStateException("No current layer");
+               return workAreas.get(currentLayerId);
+       }
+
+       String getCurrentLayerId() {
+               return currentLayerId;
+       }
+
+       private Composite getLayer(String id, Node context) {
+               if (!layers.containsKey(id))
+                       return null;
+               if (!workAreas.containsKey(id))
+                       initLayer(id, layers.get(id), context);
+               return workAreas.get(id);
+       }
+
+       Composite switchToLayer(String layerId, Node context) {
+               Composite current = null;
+               if (currentLayerId != null) {
+                       current = getCurrentWorkArea();
+                       if (currentLayerId.equals(layerId))
+                               return current;
+               }
+               if (context == null) {
+                       if (!cmsView.isAnonymous())
+                               context = userDir;
+               }
+               Composite toShow = getLayer(layerId, context);
+               if (toShow != null) {
+                       currentLayerId = layerId;
+                       if (!isDisposed()) {
+//                             getDisplay().syncExec(() -> {
+                               if (!toShow.isDisposed()) {
+                                       toShow.moveAbove(null);
+                               } else {
+                                       log.warn("Cannot show work area because it is disposed.");
+                                       toShow = initLayer(layerId, layers.get(layerId), context);
+                                       toShow.moveAbove(null);
+                               }
+                               dynamicArea.layout(true, true);
+//                             });
+                       }
+                       return toShow;
+               } else {
+                       return current;
+               }
+       }
+
+       Composite switchToLayer(SuiteLayer layer, Node context) {
+               // TODO make it more robust
+               for (String layerId : layers.keySet()) {
+                       SuiteLayer l = layers.get(layerId);
+                       if (layer == l) {
+                               return switchToLayer(layerId, context);
+                       }
+               }
+               throw new IllegalArgumentException("Layer is not registered.");
+       }
+
+       void addLayer(String id, SuiteLayer layer) {
+               layers.put(id, layer);
+       }
+
+       void removeLayer(String id) {
+               layers.remove(id);
+               if (workAreas.containsKey(id)) {
+                       Composite workArea = workAreas.remove(id);
+                       if (!workArea.isDisposed())
+                               workArea.dispose();
+               }
+       }
+
+       protected Composite initLayer(String id, SuiteLayer layer, Node context) {
+               Composite workArea = cmsView.doAs(() -> (Composite) layer.createUiPart(dynamicArea, context));
+               CmsSwtUtils.style(workArea, SuiteStyle.workArea);
+               workArea.setLayoutData(CmsSwtUtils.coverAll());
+               workAreas.put(id, workArea);
+               return workArea;
+       }
+
+       synchronized void logout() {
+               userDir = null;
+               Jcr.logout(sysSession);
+               Jcr.logout(homeSession);
+               currentLayerId = null;
+               workAreas.clear();
+       }
+
+       /*
+        * GETTERS / SETTERS
+        */
+
+       Composite getHeader() {
+               return header;
+       }
+
+       Composite getFooter() {
+               return footer;
+       }
+
+       Composite getLeadPane() {
+               return leadPane;
+       }
+
+       Composite getSidePane() {
+               return sidePane;
+       }
+
+       Composite getBelowHeader() {
+               return belowHeader;
+       }
+
+//     Session getSysSession() {
+//             return sysSession;
+//     }
+//
+       synchronized void initSessions(Repository repository, String userDirPath) throws RepositoryException {
+               this.sysSession = repository.login();
+               this.homeSession = repository.login(CmsConstants.HOME_WORKSPACE);
+               userDir = sysSession.getNode(userDirPath);
+               addDisposeListener((e) -> {
+                       Jcr.logout(sysSession);
+                       Jcr.logout(homeSession);
+               });
+       }
+
+       Node getUserDir() {
+               return userDir;
+       }
+
+       Session getSysSession() {
+               return sysSession;
+       }
+
+       Session getSession(String workspaceName) {
+               if (workspaceName == null)
+                       return sysSession;
+               if (CmsConstants.SYS_WORKSPACE.equals(workspaceName))
+                       return sysSession;
+               else if (CmsConstants.HOME_WORKSPACE.equals(workspaceName))
+                       return homeSession;
+               else
+                       throw new IllegalArgumentException("Unknown workspace " + workspaceName);
+       }
+
+       public CmsView getCmsView() {
+               return cmsView;
+       }
+
+       public Localized getTitle() {
+               return title;
+       }
+
+       public void setTitle(Localized title) {
+               this.title = title;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java b/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java
new file mode 100644 (file)
index 0000000..cad9bdd
--- /dev/null
@@ -0,0 +1,432 @@
+package org.argeo.app.ui;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.cms.CmsEditable;
+import org.argeo.api.cms.CmsEvent;
+import org.argeo.api.cms.CmsStyle;
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.api.cms.CmsView;
+import org.argeo.app.api.EntityNames;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.api.SuiteRole;
+import org.argeo.cms.LocaleUtils;
+import org.argeo.cms.Localized;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsIcon;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.dialogs.LightweightDialog;
+import org.argeo.cms.ui.util.CmsLink;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.event.Event;
+
+/** UI utilities related to the APAF project. */
+public class SuiteUiUtils {
+
+       /** Singleton. */
+       private SuiteUiUtils() {
+       }
+
+       /** creates a title bar composite with label and optional button */
+       public static void addTitleBar(Composite parent, String title, Boolean isEditable) {
+               Composite titleBar = new Composite(parent, SWT.NONE);
+               titleBar.setLayoutData(CmsSwtUtils.fillWidth());
+               CmsSwtUtils.style(titleBar, SuiteStyle.titleContainer);
+
+               titleBar.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(2, false)));
+               Label titleLbl = new Label(titleBar, SWT.NONE);
+               titleLbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
+               CmsSwtUtils.style(titleLbl, SuiteStyle.titleLabel);
+               titleLbl.setText(title);
+
+               if (isEditable) {
+                       Button editBtn = new Button(titleBar, SWT.PUSH);
+                       editBtn.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+                       CmsSwtUtils.style(editBtn, SuiteStyle.inlineButton);
+                       editBtn.setText("Edit");
+               }
+       }
+
+       public static Label addFormLabel(Composite parent, String label) {
+               Label lbl = new Label(parent, SWT.WRAP);
+               lbl.setText(label);
+               // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
+               CmsSwtUtils.style(lbl, SuiteStyle.simpleLabel);
+               return lbl;
+       }
+
+       public static Text addFormTextField(Composite parent, String text, String message) {
+               return addFormTextField(parent, text, message, SWT.NONE);
+       }
+
+       public static Text addFormTextField(Composite parent, String text, String message, int style) {
+               Text txt = new Text(parent, style);
+               if (text != null)
+                       txt.setText(text);
+               if (message != null)
+                       txt.setMessage(message);
+               txt.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
+               CmsSwtUtils.style(txt, SuiteStyle.simpleText);
+               return txt;
+       }
+
+       public static Text addFormInputField(Composite parent, String placeholder) {
+               Text txt = new Text(parent, SWT.BORDER);
+
+               GridData gridData = CmsSwtUtils.fillWidth();
+               txt.setLayoutData(gridData);
+
+               if (placeholder != null)
+                       txt.setText(placeholder);
+
+               CmsSwtUtils.style(txt, SuiteStyle.simpleInput);
+               return txt;
+       }
+
+       /** creates a single horizontal-block composite for key:value display */
+       public static Text addFormLine(Composite parent, String label, String text) {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(2, false));
+               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
+               addFormLabel(lineComposite, label);
+               Text txt = addFormTextField(lineComposite, text, null);
+               txt.setEditable(false);
+               txt.setLayoutData(CmsSwtUtils.fillWidth());
+               return txt;
+       }
+
+       public static Text addFormLine(Composite parent, String label, Node node, String property,
+                       CmsEditable cmsEditable) {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(2, false));
+               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
+               addFormLabel(lineComposite, label);
+               String text = Jcr.get(node, property);
+//             int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
+               Text txt = addFormTextField(lineComposite, text, null, SWT.WRAP);
+               if (cmsEditable != null && cmsEditable.isEditing()) {
+                       txt.addModifyListener((e) -> {
+                               Jcr.set(node, property, txt.getText());
+                               Jcr.save(node);
+                       });
+               } else {
+                       txt.setEditable(false);
+               }
+               txt.setLayoutData(CmsSwtUtils.fillWidth());
+               return txt;
+       }
+
+       public static Text addFormInput(Composite parent, String label, String placeholder) {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(2, false));
+               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
+               addFormLabel(lineComposite, label);
+               Text txt = addFormInputField(lineComposite, placeholder);
+               txt.setLayoutData(CmsSwtUtils.fillWidth());
+               return txt;
+       }
+
+       /**
+        * creates a single horizontal-block composite for key:value display, with
+        * offset value
+        */
+       public static Text addFormLine(Composite parent, String label, String text, Integer offset) {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(3, false));
+               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
+               Label offsetLbl = new Label(lineComposite, SWT.NONE);
+               GridData gridData = new GridData();
+               gridData.widthHint = offset;
+               offsetLbl.setLayoutData(gridData);
+               addFormLabel(lineComposite, label);
+               Text txt = addFormTextField(lineComposite, text, null);
+               txt.setLayoutData(CmsSwtUtils.fillWidth());
+               return txt;
+       }
+
+       /** creates a single vertical-block composite for key:value display */
+       public static Text addFormColumn(Composite parent, String label, String text) {
+//             Composite columnComposite = new Composite(parent, SWT.NONE);
+//             columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+//             columnComposite.setLayout(new GridLayout(1, false));
+               addFormLabel(parent, label);
+               Text txt = addFormTextField(parent, text, null);
+               txt.setEditable(false);
+               txt.setLayoutData(CmsSwtUtils.fillWidth());
+               return txt;
+       }
+
+       public static Text addFormColumn(Composite parent, String label, Node node, String property,
+                       CmsEditable cmsEditable) {
+//             Composite columnComposite = new Composite(parent, SWT.NONE);
+//             columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+//             columnComposite.setLayout(new GridLayout(1, false));
+               addFormLabel(parent, label);
+               String text = Jcr.get(node, property);
+//             int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
+               Text txt = addFormTextField(parent, text, null, SWT.WRAP);
+               if (cmsEditable != null && cmsEditable.isEditing()) {
+                       txt.addModifyListener((e) -> {
+                               Jcr.set(node, property, txt.getText());
+                               Jcr.save(node);
+                       });
+               } else {
+                       txt.setEditable(false);
+               }
+               txt.setLayoutData(CmsSwtUtils.fillWidth());
+               return txt;
+       }
+
+       public static Label createBoldLabel(Composite parent, Localized localized) {
+               Label label = new Label(parent, SWT.LEAD);
+               label.setText(localized.lead());
+               label.setFont(EclipseUiUtils.getBoldFont(parent));
+               label.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
+               return label;
+       }
+
+       public static Label addFormPicture(Composite parent, String label, Node fileNode) throws RepositoryException {
+               Composite lineComposite = new Composite(parent, SWT.NONE);
+               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+               lineComposite.setLayout(new GridLayout(2, true));
+               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
+               addFormLabel(lineComposite, label);
+
+               return addPicture(lineComposite, fileNode);
+       }
+
+       public static Label addPicture(Composite parent, Node fileNode) throws RepositoryException {
+               return addPicture(parent, fileNode, null);
+       }
+
+       public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth) throws RepositoryException {
+               return addPicture(parent, fileNode, maxWidth, null);
+       }
+
+       public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth, Node link)
+                       throws RepositoryException {
+               Node content = fileNode.getNode(Node.JCR_CONTENT);
+               // TODO move it deeper in the middleware.
+               if (!content.isNodeType(EntityType.box.get())) {
+                       if (content.getSession().hasPermission(content.getPath(), Session.ACTION_SET_PROPERTY)) {
+                               try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
+                                       ImageData imageData = new ImageData(in);
+                                       content.addMixin(EntityType.box.get());
+                                       content.setProperty(EntityNames.SVG_WIDTH, imageData.width);
+                                       content.setProperty(EntityNames.SVG_HEIGHT, imageData.height);
+                                       content.getSession().save();
+                               } catch (IOException e) {
+                                       throw new RuntimeException(e);
+                               }
+                       }
+               }
+
+               // TODO optimise
+               Long width;
+               Long height;
+               if (content.isNodeType(EntityType.box.get())) {
+                       width = content.getProperty(EntityNames.SVG_WIDTH).getLong();
+                       height = content.getProperty(EntityNames.SVG_HEIGHT).getLong();
+               } else {
+                       try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
+                               ImageData imageData = new ImageData(in);
+                               width = Long.valueOf(imageData.width);
+                               height = Long.valueOf(imageData.height);
+                       } catch (IOException e) {
+                               throw new RuntimeException(e);
+                       }
+               }
+
+               if (maxWidth != null && width > maxWidth) {
+                       Double ratio = maxWidth.doubleValue() / width.doubleValue();
+                       width = maxWidth.longValue();
+                       height = Math.round(ratio * height);
+               }
+               Label img = new Label(parent, SWT.NONE);
+               CmsSwtUtils.markup(img);
+               StringBuffer txt = new StringBuffer();
+               String target = toLink(link);
+               if (target != null)
+                       txt.append("<a href='").append(target).append("'>");
+               txt.append(CmsUiUtils.img(fileNode, width.toString(), height.toString()));
+               if (target != null)
+                       txt.append("</a>");
+               img.setText(txt.toString());
+               if (parent.getLayout() instanceof GridLayout) {
+                       GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+                       gd.widthHint = width.intValue();
+                       gd.heightHint = height.intValue();
+                       img.setLayoutData(gd);
+               }
+
+               if (target == null)
+                       img.addMouseListener(new MouseListener() {
+                               private static final long serialVersionUID = -1362242049325206168L;
+
+                               @Override
+                               public void mouseUp(MouseEvent e) {
+                               }
+
+                               @Override
+                               public void mouseDown(MouseEvent e) {
+                               }
+
+                               @Override
+                               public void mouseDoubleClick(MouseEvent e) {
+                                       LightweightDialog dialog = new LightweightDialog(img.getShell()) {
+
+                                               @Override
+                                               protected Control createDialogArea(Composite parent) {
+                                                       parent.setLayout(new GridLayout());
+                                                       ScrolledComposite scroll = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
+                                                       scroll.setLayoutData(CmsSwtUtils.fillAll());
+                                                       scroll.setLayout(CmsSwtUtils.noSpaceGridLayout());
+                                                       scroll.setExpandHorizontal(true);
+                                                       scroll.setExpandVertical(true);
+                                                       // scroll.setAlwaysShowScrollBars(true);
+
+                                                       Composite c = new Composite(scroll, SWT.NONE);
+                                                       scroll.setContent(c);
+                                                       c.setLayout(new GridLayout());
+                                                       c.setLayoutData(CmsSwtUtils.fillAll());
+                                                       Label bigImg = new Label(c, SWT.NONE);
+                                                       CmsSwtUtils.markup(bigImg);
+                                                       bigImg.setText(CmsUiUtils.img(fileNode, Jcr.get(content, EntityNames.SVG_WIDTH),
+                                                                       Jcr.get(content, EntityNames.SVG_HEIGHT)));
+                                                       bigImg.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+                                                       return bigImg;
+                                               }
+
+                                               @Override
+                                               protected Point getInitialSize() {
+                                                       Point shellSize = img.getShell().getSize();
+                                                       return new Point(shellSize.x - 100, shellSize.y - 100);
+                                               }
+
+                                       };
+                                       dialog.open();
+                               }
+                       });
+               return img;
+       }
+
+       public static String toLink(Node node) {
+                       return node != null ? "#" + CmsUiUtils.cleanPathForUrl(SuiteApp.nodeToState(node)) : null;
+       }
+
+       public static Control addLink(Composite parent, String label, Node node, CmsStyle style)
+                       throws RepositoryException {
+               String target = toLink(node);
+               CmsLink link = new CmsLink(label, target, style);
+               return link.createUi(parent, node);
+       }
+
+       public static Control addExternalLink(Composite parent, String label, String url, String plainCssAnchorClass,
+                       boolean newWindow) throws RepositoryException {
+               Label lbl = new Label(parent, SWT.NONE);
+               CmsSwtUtils.markup(lbl);
+               StringBuilder txt = new StringBuilder();
+               txt.append("<a class='" + plainCssAnchorClass + "'");
+               txt.append(" href='").append(url).append("'");
+               if (newWindow) {
+                       txt.append(" target='blank_'");
+               }
+               txt.append(">");
+               txt.append(label);
+               txt.append("</a>");
+               lbl.setText(txt.toString());
+               return lbl;
+       }
+
+       public static boolean isCoworker(CmsView cmsView) {
+               boolean coworker = cmsView.doAs(() -> CurrentUser.isInRole(SuiteRole.coworker.dn()));
+               return coworker;
+       }
+
+       public static boolean isTopic(Event event, CmsEvent cmsEvent) {
+               return event.getTopic().equals(cmsEvent.topic());
+       }
+
+       public static Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon,
+                       ClassLoader l10nClassLoader) {
+               CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
+               Button button = new Button(parent, SWT.PUSH);
+               CmsSwtUtils.style(button, SuiteStyle.leadPane);
+               if (icon != null)
+                       button.setImage(icon.getBigIcon(theme));
+               button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false));
+               // button.setToolTipText(msg.lead());
+               if (msg != null) {
+                       Label lbl = new Label(parent, SWT.CENTER);
+                       CmsSwtUtils.style(lbl, SuiteStyle.leadPane);
+                       String txt = LocaleUtils.lead(msg, l10nClassLoader);
+//                     String txt = msg.lead();
+                       lbl.setText(txt);
+                       lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
+               }
+               CmsSwtUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer);
+               return button;
+       }
+
+//     public static String createAndConfigureEntity(Shell shell, Session referenceSession, String mainMixin,
+//                     String... additionnalProps) {
+//
+//             Session tmpSession = null;
+//             Session mainSession = null;
+//             try {
+//                     // FIXME would not work if home is another physical workspace
+//                     tmpSession = referenceSession.getRepository().login(NodeConstants.HOME_WORKSPACE);
+//                     Node draftNode = null;
+//                     for (int i = 0; i < additionnalProps.length - 1; i += 2) {
+//                             draftNode.setProperty(additionnalProps[i], additionnalProps[i + 1]);
+//                     }
+//                     Wizard wizard = null;
+//                     CmsWizardDialog dialog = new CmsWizardDialog(shell, wizard);
+//                     // WizardDialog dialog = new WizardDialog(shell, wizard);
+//                     if (dialog.open() == Window.OK) {
+//                             String parentPath = null;// "/" + appService.getBaseRelPath(mainMixin);
+//                             // FIXME it should be possible to specify the workspace
+//                             mainSession = referenceSession.getRepository().login();
+//                             Node parent = mainSession.getNode(parentPath);
+//                             Node task = null;// appService.publishEntity(parent, mainMixin, draftNode);
+////                           task = appService.saveEntity(task, false);
+//                             referenceSession.refresh(true);
+//                             return task.getPath();
+//                     }
+//                     return null;
+//             } catch (RepositoryException e1) {
+//                     throw new JcrException(
+//                                     "Unable to create " + mainMixin + " entity with session " + referenceSession.toString(), e1);
+//             } finally {
+//                     JcrUtils.logoutQuietly(tmpSession);
+//                     JcrUtils.logoutQuietly(mainSession);
+//             }
+//     }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/TermsEntryArea.java b/org.argeo.app.ui/src/org/argeo/app/ui/TermsEntryArea.java
new file mode 100644 (file)
index 0000000..97d8c1f
--- /dev/null
@@ -0,0 +1,24 @@
+package org.argeo.app.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Entry area for managing th etypologies. */
+public class TermsEntryArea implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               parent.setLayout(new GridLayout());
+               Label lbl = new Label(parent, SWT.NONE);
+               lbl.setText("Typologies");
+               return lbl;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonPage.java b/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonPage.java
new file mode 100644 (file)
index 0000000..380330f
--- /dev/null
@@ -0,0 +1,72 @@
+package org.argeo.app.ui.dialogs;
+
+import org.argeo.app.ui.SuiteMsg;
+import org.argeo.app.ui.SuiteUiUtils;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+public class NewPersonPage extends WizardPage {
+       private static final long serialVersionUID = -944349994177526468L;
+       protected Text lastNameTxt;
+       protected Text firstNameTxt;
+       protected Text emailTxt;
+
+       protected NewPersonPage(String pageName) {
+               super(pageName);
+               setTitle(SuiteMsg.personWizardPageTitle.lead());
+       }
+
+       @Override
+       public void createControl(Composite parent) {
+               parent.setLayout(new GridLayout(2, false));
+
+               // FirstName
+               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+               firstNameTxt = new Text(parent, SWT.BORDER);
+               firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+               // LastName
+               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+               lastNameTxt = new Text(parent, SWT.BORDER);
+               lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+               SuiteUiUtils.createBoldLabel(parent, SuiteMsg.email);
+               emailTxt = new Text(parent, SWT.BORDER);
+               emailTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+               ModifyListener ml = new ModifyListener() {
+                       private static final long serialVersionUID = -1628130380128946886L;
+
+                       @Override
+                       public void modifyText(ModifyEvent event) {
+                               getContainer().updateButtons();
+                       }
+               };
+
+               firstNameTxt.addModifyListener(ml);
+               lastNameTxt.addModifyListener(ml);
+               emailTxt.addModifyListener(ml);
+
+               // Don't forget this.
+               setControl(firstNameTxt);
+               firstNameTxt.setFocus();
+
+       }
+
+//     public void updateNode(Node node, PeopleService peopleService, ResourcesService resourcesService) {
+//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_LAST_NAME, PropertyType.STRING, lastNameTxt.getText());
+//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_FIRST_NAME, PropertyType.STRING,
+//                             firstNameTxt.getText());
+//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_DISPLAY_NAME, PropertyType.STRING,
+//                             firstNameTxt.getText() + " " + lastNameTxt.getText());
+//             String email = emailTxt.getText();
+//             ConnectJcrUtils.setJcrProperty(node, PeopleNames.PEOPLE_PRIMARY_EMAIL, PropertyType.STRING, email);
+//             PeopleJcrUtils.createEmail(resourcesService, peopleService, node, email, true, null, null);
+//     }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonWizard.java b/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewPersonWizard.java
new file mode 100644 (file)
index 0000000..ee9f5b9
--- /dev/null
@@ -0,0 +1,151 @@
+package org.argeo.app.ui.dialogs;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
+
+import javax.jcr.Node;
+
+import org.argeo.app.ui.SuiteMsg;
+import org.argeo.app.ui.SuiteUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/** Ask first & last name. Update the passed node on finish */
+public class NewPersonWizard extends Wizard {
+       // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
+
+       // Context
+       private Node person;
+
+       // This page widgets
+       protected Text lastNameTxt;
+       protected Text firstNameTxt;
+       // private Button useDistinctDisplayNameBtn;
+       // private Text displayNameTxt;
+
+       public NewPersonWizard(Node person) {
+               this.person = person;
+       }
+
+       @Override
+       public void addPages() {
+               try {
+                       MainInfoPage page = new MainInfoPage("Main page");
+                       addPage(page);
+               } catch (Exception e) {
+                       throw new RuntimeException("Cannot add page to wizard", e);
+               }
+               setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
+       }
+
+       /**
+        * Called when the user click on 'Finish' in the wizard. The task is then
+        * created and the corresponding session saved.
+        */
+       @Override
+       public boolean performFinish() {
+               String lastName = lastNameTxt.getText();
+               String firstName = firstNameTxt.getText();
+               // String displayName = displayNameTxt.getText();
+               // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
+               if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
+                       MessageDialog.openError(getShell(), "Non-valid information",
+                                       "Please enter at least a name that is not empty.");
+                       return false;
+               } else {
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
+//                     String fullName = firstName + " " + lastName;
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
+                       return true;
+               }
+       }
+
+       @Override
+       public boolean performCancel() {
+               return true;
+       }
+
+       @Override
+       public boolean canFinish() {
+               String lastName = lastNameTxt.getText();
+               String firstName = firstNameTxt.getText();
+               if (isEmpty(lastName) && isEmpty(firstName)) {
+                       return false;
+               } else
+                       return true;
+       }
+
+       protected class MainInfoPage extends WizardPage {
+               private static final long serialVersionUID = 1L;
+
+               public MainInfoPage(String pageName) {
+                       super(pageName);
+                       setTitle(SuiteMsg.personWizardPageTitle.lead());
+                       // setMessage("Please enter a last name and/or a first name.");
+               }
+
+               public void createControl(Composite parent) {
+                       parent.setLayout(new GridLayout(2, false));
+
+                       // FirstName
+                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+                       firstNameTxt = new Text(parent, SWT.BORDER);
+                       // firstNameTxt.setMessage("a first name");
+                       firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       // LastName
+                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+                       lastNameTxt = new Text(parent, SWT.BORDER);
+                       // lastNameTxt.setMessage("a last name");
+                       lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       // Display Name
+                       // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
+                       // useDistinctDisplayNameBtn.setText("Define a disting display name");
+                       // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
+                       // true, false, 2, 1));
+                       //
+                       // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
+                       // displayNameTxt = new Text(parent, SWT.BORDER);
+                       // displayNameTxt.setMessage("an optional display name");
+                       // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
+                       // false));
+                       // displayNameTxt.setEnabled(false);
+                       //
+                       // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
+                       // private static final long serialVersionUID = 1L;
+                       //
+                       // @Override
+                       // public void widgetSelected(SelectionEvent e) {
+                       // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
+                       // }
+                       // });
+
+                       ModifyListener ml = new ModifyListener() {
+                               private static final long serialVersionUID = -1628130380128946886L;
+
+                               @Override
+                               public void modifyText(ModifyEvent event) {
+                                       getContainer().updateButtons();
+                               }
+                       };
+
+                       firstNameTxt.addModifyListener(ml);
+                       lastNameTxt.addModifyListener(ml);
+                       // displayNameTxt.addModifyListener(ml);
+
+                       // Don't forget this.
+                       setControl(firstNameTxt);
+                       firstNameTxt.setFocus();
+               }
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewUserWizard.java b/org.argeo.app.ui/src/org/argeo/app/ui/dialogs/NewUserWizard.java
new file mode 100644 (file)
index 0000000..2071872
--- /dev/null
@@ -0,0 +1,151 @@
+package org.argeo.app.ui.dialogs;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
+
+import javax.jcr.Node;
+
+import org.argeo.app.ui.SuiteMsg;
+import org.argeo.app.ui.SuiteUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/** Ask first & last name. Update the passed node on finish */
+public class NewUserWizard extends Wizard {
+       // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
+
+       // Context
+       private Node person;
+
+       // This page widgets
+       protected Text lastNameTxt;
+       protected Text firstNameTxt;
+       // private Button useDistinctDisplayNameBtn;
+       // private Text displayNameTxt;
+
+       public NewUserWizard(Node person) {
+               this.person = person;
+       }
+
+       @Override
+       public void addPages() {
+               try {
+                       MainInfoPage page = new MainInfoPage("Main page");
+                       addPage(page);
+               } catch (Exception e) {
+                       throw new RuntimeException("Cannot add page to wizard", e);
+               }
+               setWindowTitle(SuiteMsg.personWizardWindowTitle.lead());
+       }
+
+       /**
+        * Called when the user click on 'Finish' in the wizard. The task is then
+        * created and the corresponding session saved.
+        */
+       @Override
+       public boolean performFinish() {
+               String lastName = lastNameTxt.getText();
+               String firstName = firstNameTxt.getText();
+               // String displayName = displayNameTxt.getText();
+               // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
+               if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
+                       MessageDialog.openError(getShell(), "Non-valid information",
+                                       "Please enter at least a name that is not empty.");
+                       return false;
+               } else {
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
+//                     String fullName = firstName + " " + lastName;
+//                     ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
+                       return true;
+               }
+       }
+
+       @Override
+       public boolean performCancel() {
+               return true;
+       }
+
+       @Override
+       public boolean canFinish() {
+               String lastName = lastNameTxt.getText();
+               String firstName = firstNameTxt.getText();
+               if (isEmpty(lastName) && isEmpty(firstName)) {
+                       return false;
+               } else
+                       return true;
+       }
+
+       protected class MainInfoPage extends WizardPage {
+               private static final long serialVersionUID = 1L;
+
+               public MainInfoPage(String pageName) {
+                       super(pageName);
+                       setTitle(SuiteMsg.personWizardPageTitle.lead());
+                       // setMessage("Please enter a last name and/or a first name.");
+               }
+
+               public void createControl(Composite parent) {
+                       parent.setLayout(new GridLayout(2, false));
+
+                       // FirstName
+                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+                       firstNameTxt = new Text(parent, SWT.BORDER);
+                       // firstNameTxt.setMessage("a first name");
+                       firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       // LastName
+                       SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+                       lastNameTxt = new Text(parent, SWT.BORDER);
+                       // lastNameTxt.setMessage("a last name");
+                       lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       // Display Name
+                       // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
+                       // useDistinctDisplayNameBtn.setText("Define a disting display name");
+                       // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
+                       // true, false, 2, 1));
+                       //
+                       // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
+                       // displayNameTxt = new Text(parent, SWT.BORDER);
+                       // displayNameTxt.setMessage("an optional display name");
+                       // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
+                       // false));
+                       // displayNameTxt.setEnabled(false);
+                       //
+                       // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
+                       // private static final long serialVersionUID = 1L;
+                       //
+                       // @Override
+                       // public void widgetSelected(SelectionEvent e) {
+                       // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
+                       // }
+                       // });
+
+                       ModifyListener ml = new ModifyListener() {
+                               private static final long serialVersionUID = -1628130380128946886L;
+
+                               @Override
+                               public void modifyText(ModifyEvent event) {
+                                       getContainer().updateButtons();
+                               }
+                       };
+
+                       firstNameTxt.addModifyListener(ml);
+                       lastNameTxt.addModifyListener(ml);
+                       // displayNameTxt.addModifyListener(ml);
+
+                       // Don't forget this.
+                       setControl(firstNameTxt);
+                       firstNameTxt.setFocus();
+               }
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/AbstractDbkViewer.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/AbstractDbkViewer.java
new file mode 100644 (file)
index 0000000..5012805
--- /dev/null
@@ -0,0 +1,1034 @@
+package org.argeo.app.ui.docbook;
+
+import static org.argeo.app.docbook.DbkType.para;
+import static org.argeo.app.docbook.DbkUtils.addDbk;
+import static org.argeo.app.docbook.DbkUtils.isDbk;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Observer;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.cms.Cms2DSize;
+import org.argeo.api.cms.CmsEditable;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.app.docbook.DbkAttr;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.app.docbook.DbkUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.viewers.AbstractPageViewer;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.viewers.NodePart;
+import org.argeo.cms.ui.viewers.PropertyPart;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.cms.ui.viewers.SectionPart;
+import org.argeo.cms.ui.widgets.EditableText;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.fileupload.FileDetails;
+import org.eclipse.rap.fileupload.FileUploadEvent;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadListener;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Base class for text viewers and editors. */
+public abstract class AbstractDbkViewer extends AbstractPageViewer implements KeyListener, Observer {
+       private static final long serialVersionUID = -2401274679492339668L;
+       private final static CmsLog log = CmsLog.getLog(AbstractDbkViewer.class);
+
+       private final Section mainSection;
+
+       private TextInterpreter textInterpreter = new DbkTextInterpreter();
+       private DbkImageManager imageManager;
+
+       private FileUploadListener fileUploadListener;
+       private DbkContextMenu styledTools;
+
+       private final boolean flat;
+
+       private boolean showMainTitle = true;
+
+       private Integer maxMediaWidth = null;
+       private String defaultSectionStyle;
+
+       protected AbstractDbkViewer(Section parent, int style, CmsEditable cmsEditable) {
+               super(parent, style, cmsEditable);
+//             CmsView cmsView = CmsView.getCmsView(parent);
+//             imageManager = cmsView.getImageManager();
+               flat = SWT.FLAT == (style & SWT.FLAT);
+
+               if (getCmsEditable().canEdit()) {
+                       fileUploadListener = new FUL();
+                       styledTools = new DbkContextMenu(this, parent.getShell());
+               }
+               this.mainSection = parent;
+               Node baseFolder = Jcr.getParent(mainSection.getNode());
+               imageManager = new DbkImageManager(baseFolder);
+               initModelIfNeeded(mainSection.getNode());
+               // layout(this.mainSection);
+       }
+
+       @Override
+       public Control getControl() {
+               return mainSection;
+       }
+
+       protected void refresh(Control control) throws RepositoryException {
+               if (!(control instanceof Section))
+                       return;
+               long begin = System.currentTimeMillis();
+               Section section = (Section) control;
+               if (section instanceof TextSection) {
+                       CmsSwtUtils.clear(section);
+                       Node node = section.getNode();
+                       TextSection textSection = (TextSection) section;
+                       String style = node.hasProperty(DbkAttr.role.name()) ? node.getProperty(DbkAttr.role.name()).getString()
+                                       : getDefaultSectionStyle();
+                       if (style != null)
+                               CmsSwtUtils.style(textSection, style);
+
+                       // Title
+                       Node titleNode = null;
+                       // We give priority to ./title vs ./info/title, like the DocBook XSL
+                       if (node.hasNode(DbkType.title.get())) {
+                               titleNode = node.getNode(DbkType.title.get());
+                       } else if (node.hasNode(DbkType.info.get() + '/' + DbkType.title.get())) {
+                               titleNode = node.getNode(DbkType.info.get() + '/' + DbkType.title.get());
+                       }
+
+                       if (titleNode != null) {
+                               boolean showTitle = getMainSection() == section ? showMainTitle : true;
+                               if (showTitle) {
+                                       if (section.getHeader() == null)
+                                               section.createHeader();
+                                       DbkSectionTitle title = newSectionTitle(textSection, titleNode);
+                                       title.setLayoutData(CmsSwtUtils.fillWidth());
+                                       updateContent(title);
+                               }
+                       }
+
+                       // content
+                       for (NodeIterator ni = node.getNodes(); ni.hasNext();) {
+                               Node child = ni.nextNode();
+                               SectionPart sectionPart = null;
+                               if (isDbk(child, DbkType.mediaobject)) {
+                                       if (child.hasNode(DbkType.imageobject.get())) {
+                                               sectionPart = newImg(textSection, child);
+                                       } else if (child.hasNode(DbkType.videoobject.get())) {
+                                               sectionPart = newVideo(textSection, child);
+                                       } else {
+                                               throw new IllegalArgumentException("Unsupported media object " + child);
+                                       }
+                               } else if (isDbk(child, DbkType.info)) {
+                                       // TODO enrich UI based on info
+                               } else if (isDbk(child, DbkType.title)) {
+                                       // already managed
+                               } else if (isDbk(child, para)) {
+                                       sectionPart = newParagraph(textSection, child);
+                               } else if (isDbk(child, DbkType.section)) {
+                                       sectionPart = newSectionPart(textSection, child);
+//                                     if (sectionPart == null)
+//                                             throw new IllegalArgumentException("Unsupported node " + child);
+                                       // TODO list node types in exception
+                               } else {
+                                       throw new IllegalArgumentException("Unsupported node type for " + child);
+                               }
+                               if (sectionPart != null && sectionPart instanceof Control)
+                                       ((Control) sectionPart).setLayoutData(CmsSwtUtils.fillWidth());
+                       }
+
+//                     if (!flat)
+                       for (NodeIterator ni = section.getNode().getNodes(DbkType.section.get()); ni.hasNext();) {
+                               Node child = ni.nextNode();
+                               if (isDbk(child, DbkType.section)) {
+                                       TextSection newSection = newTextSection(section, child);
+                                       newSection.setLayoutData(CmsSwtUtils.fillWidth());
+                                       refresh(newSection);
+                               }
+                       }
+               } else {
+                       for (Section s : section.getSubSections().values())
+                               refresh(s);
+               }
+               // section.layout(true, true);
+               long duration = System.currentTimeMillis() - begin;
+//             System.out.println(duration + " ms - " + DbkUtils.getTitle(section.getNode()));
+       }
+
+       /** To be overridden in order to provide additional SectionPart types */
+       protected TextSection newTextSection(Section section, Node node) {
+               return new TextSection(section, SWT.NONE, node);
+       }
+
+       /** To be overridden in order to provide additional SectionPart types */
+       protected SectionPart newSectionPart(TextSection textSection, Node node) {
+               return null;
+       }
+
+       // CRUD
+       protected Paragraph newParagraph(TextSection parent, Node node) throws RepositoryException {
+               Paragraph paragraph = new Paragraph(parent, parent.getStyle(), node);
+               updateContent(paragraph);
+               paragraph.setLayoutData(CmsSwtUtils.fillWidth());
+               paragraph.setMouseListener(getMouseListener());
+               paragraph.setFocusListener(getFocusListener());
+               return paragraph;
+       }
+
+       protected DbkImg newImg(TextSection parent, Node node) {
+               try {
+                       DbkImg img = new DbkImg(parent, parent.getStyle(), node, imageManager);
+                       GridData imgGd;
+                       if (maxMediaWidth != null) {
+                               imgGd = new GridData(SWT.CENTER, SWT.FILL, false, false);
+                               imgGd.widthHint = maxMediaWidth;
+                               img.setPreferredSize(new Cms2DSize(maxMediaWidth, 0));
+                       } else {
+                               imgGd = CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT);
+                       }
+                       img.setLayoutData(imgGd);
+                       updateContent(img);
+                       img.setMouseListener(getMouseListener());
+                       img.setFocusListener(getFocusListener());
+                       return img;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot add new image " + node, e);
+               }
+       }
+
+       protected DbkVideo newVideo(TextSection parent, Node node) {
+               try {
+                       DbkVideo video = new DbkVideo(parent, getCmsEditable().canEdit() ? SWT.NONE : SWT.READ_ONLY, node);
+                       GridData gd;
+                       if (maxMediaWidth != null) {
+                               gd = new GridData(SWT.CENTER, SWT.FILL, false, false);
+                               // TODO, manage size
+//                             gd.widthHint = maxMediaWidth;
+//                             gd.heightHint = (int) (gd.heightHint * 0.5625);
+                       } else {
+                               gd = new GridData(SWT.CENTER, SWT.FILL, false, false);
+//                             gd.widthHint = video.getWidth();
+//                             gd.heightHint = video.getHeight();
+                       }
+                       video.setLayoutData(gd);
+                       updateContent(video);
+                       return video;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot add new image " + node, e);
+               }
+       }
+
+       protected DbkSectionTitle newSectionTitle(TextSection parent, Node titleNode) throws RepositoryException {
+               int style = parent.getStyle();
+               Composite titleParent = newSectionHeader(parent);
+               if (parent.isTitleReadOnly())
+                       style = style | SWT.READ_ONLY;
+               DbkSectionTitle title = new DbkSectionTitle(titleParent, style, titleNode);
+               updateContent(title);
+               title.setMouseListener(getMouseListener());
+               title.setFocusListener(getFocusListener());
+               return title;
+       }
+
+       /**
+        * To be overridden in order to provide additional processing at the section
+        * level.
+        * 
+        * @return the parent to use for the {@link DbkSectionTitle}, by default
+        *         {@link Section#getHeader()}
+        */
+       protected Composite newSectionHeader(TextSection section) {
+               return section.getHeader();
+       }
+
+       protected DbkSectionTitle prepareSectionTitle(Section newSection, String titleText) throws RepositoryException {
+               Node sectionNode = newSection.getNode();
+               Node titleNode = DbkUtils.getOrAddDbk(sectionNode, DbkType.title);
+               getTextInterpreter().write(titleNode, titleText);
+               if (newSection.getHeader() == null)
+                       newSection.createHeader();
+               DbkSectionTitle sectionTitle = newSectionTitle((TextSection) newSection, sectionNode);
+               return sectionTitle;
+       }
+
+       protected void updateContent(EditablePart part) throws RepositoryException {
+               if (part instanceof SectionPart) {
+                       SectionPart sectionPart = (SectionPart) part;
+                       Node partNode = sectionPart.getNode();
+
+                       if (part instanceof StyledControl && (sectionPart.getSection() instanceof TextSection)) {
+                               TextSection section = (TextSection) sectionPart.getSection();
+                               StyledControl styledControl = (StyledControl) part;
+                               if (isDbk(partNode, para)) {
+                                       String style = partNode.hasProperty(DbkAttr.role.name())
+                                                       ? partNode.getProperty(DbkAttr.role.name()).getString()
+                                                       : section.getDefaultTextStyle();
+                                       styledControl.setStyle(style);
+                               }
+                       }
+                       // use control AFTER setting style, since it may have been reset
+
+                       if (part instanceof EditableText) {
+                               EditableText paragraph = (EditableText) part;
+                               if (paragraph == getEdited())
+                                       paragraph.setText(textInterpreter.raw(partNode));
+                               else
+                                       paragraph.setText(textInterpreter.readSimpleHtml(partNode));
+                       } else if (part instanceof DbkImg) {
+                               DbkImg editableImage = (DbkImg) part;
+                               // imageManager.load(partNode, part.getControl(),
+                               // editableImage.getPreferredImageSize());
+                       } else if (part instanceof DbkVideo) {
+                               DbkVideo video = (DbkVideo) part;
+                               video.load(part.getControl());
+                       }
+               } else if (part instanceof DbkSectionTitle) {
+                       DbkSectionTitle title = (DbkSectionTitle) part;
+                       title.setStyle(title.getSection().getTitleStyle());
+                       // use control AFTER setting style
+                       if (title == getEdited())
+                               title.setText(textInterpreter.read(title.getNode()));
+                       else
+                               title.setText(textInterpreter.readSimpleHtml(title.getNode()));
+               }
+       }
+
+       // OVERRIDDEN FROM PARENT VIEWER
+       @Override
+       protected void save(EditablePart part) throws RepositoryException {
+               if (part instanceof EditableText) {
+                       EditableText et = (EditableText) part;
+                       if (!et.getEditable())
+                               return;
+                       String text = ((Text) et.getControl()).getText();
+
+                       // String[] lines = text.split("[\r\n]+");
+                       String[] lines = { text };
+                       assert lines.length != 0;
+                       saveLine(part, lines[0]);
+                       if (lines.length > 1) {
+                               ArrayList<Control> toLayout = new ArrayList<Control>();
+                               if (part instanceof Paragraph) {
+                                       Paragraph currentParagraph = (Paragraph) et;
+                                       Section section = currentParagraph.getSection();
+                                       Node sectionNode = section.getNode();
+                                       Node currentParagraphN = currentParagraph.getNode();
+                                       for (int i = 1; i < lines.length; i++) {
+                                               Node newNode = addDbk(sectionNode, para);
+                                               // newNode.addMixin(CmsTypes.CMS_STYLED);
+                                               saveLine(newNode, lines[i]);
+                                               // second node was create as last, if it is not the next
+                                               // one, it
+                                               // means there are some in between and we can take the
+                                               // one at
+                                               // index+1 for the re-order
+                                               if (newNode.getIndex() > currentParagraphN.getIndex() + 1) {
+                                                       sectionNode.orderBefore(p(newNode.getIndex()), p(currentParagraphN.getIndex() + 1));
+                                               }
+                                               Paragraph newParagraph = newParagraph((TextSection) section, newNode);
+                                               newParagraph.moveBelow(currentParagraph);
+                                               toLayout.add(newParagraph);
+
+                                               currentParagraph = newParagraph;
+                                               currentParagraphN = newNode;
+                                       }
+                               }
+                               // TODO or rather return the created paragraphs?
+                               layout(toLayout.toArray(new Control[toLayout.size()]));
+                       }
+                       persistChanges(et.getNode());
+               }
+       }
+
+       protected void saveLine(EditablePart part, String line) {
+               if (part instanceof NodePart) {
+                       saveLine(((NodePart) part).getNode(), line);
+               } else if (part instanceof PropertyPart) {
+                       saveLine(((PropertyPart) part).getProperty(), line);
+               } else {
+                       throw new IllegalArgumentException("Unsupported part " + part);
+               }
+       }
+
+       protected void saveLine(Item item, String line) {
+               line = line.trim();
+               textInterpreter.write(item, line);
+       }
+
+       @Override
+       protected void prepare(EditablePart part, Object caretPosition) {
+               Control control = part.getControl();
+               if (control instanceof Text) {
+                       Text text = (Text) control;
+                       if (caretPosition != null)
+                               if (caretPosition instanceof Integer)
+                                       text.setSelection((Integer) caretPosition);
+                               else if (caretPosition instanceof Point) {
+//                                     layout(text);
+//                                     // TODO find a way to position the caret at the right place
+//                                     Point clickLocation = (Point) caretPosition;
+//                                     Point withinText = text.toControl(clickLocation);
+//                                     Rectangle bounds = text.getBounds();
+//                                     int width = bounds.width;
+//                                     int height = bounds.height;
+//                                     int textLength = text.getText().length();
+//                                     float area = width * height;
+//                                     float proportion = withinText.y * width + withinText.x;
+//                                     int pos = (int) (textLength * (proportion / area));
+//                                     text.setSelection(pos);
+                               }
+                       text.setData(RWT.ACTIVE_KEYS, new String[] { "BACKSPACE", "ESC", "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT",
+                                       "ALT+ARROW_RIGHT", "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", "ENTER", "DELETE" });
+                       text.setData(RWT.CANCEL_KEYS, new String[] { "RETURN", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
+                       text.addKeyListener(this);
+               } else if (part instanceof DbkImg) {
+                       ((DbkImg) part).setFileUploadListener(fileUploadListener);
+               }
+       }
+
+       // REQUIRED BY CONTEXT MENU
+       void setParagraphStyle(Paragraph paragraph, String style) {
+               try {
+                       Node paragraphNode = paragraph.getNode();
+                       if (style == null) {// default
+                               if (paragraphNode.hasProperty(DbkAttr.role.name()))
+                                       paragraphNode.getProperty(DbkAttr.role.name()).remove();
+                       } else {
+                               paragraphNode.setProperty(DbkAttr.role.name(), style);
+                       }
+                       persistChanges(paragraphNode);
+                       updateContent(paragraph);
+                       layoutPage();
+               } catch (RepositoryException e1) {
+                       throw new JcrException("Cannot set style " + style + " on " + paragraph, e1);
+               }
+       }
+
+       SectionPart insertPart(Section section, Node node) {
+               try {
+                       refresh(section);
+                       layoutPage();
+                       for (Control control : section.getChildren()) {
+                               if (control instanceof SectionPart) {
+                                       SectionPart sectionPart = (SectionPart) control;
+                                       Node partNode = sectionPart.getNode();
+                                       if (partNode.getPath().equals(node.getPath()))
+                                               return sectionPart;
+                               }
+                       }
+                       throw new IllegalStateException("New section part " + node + "not found");
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot insert part " + node + " in section " + section.getNode(), e);
+               }
+       }
+
+       void addParagraph(SectionPart partBefore, String txt) {
+               Section section = partBefore.getSection();
+               SectionPart nextSectionPart = section.nextSectionPart(partBefore);
+               Node newNode = addDbk(section.getNode(), para);
+               textInterpreter.write(newNode, txt != null ? txt : "");
+               if (nextSectionPart != null) {
+                       try {
+                               Node nextNode = nextSectionPart.getNode();
+                               section.getNode().orderBefore(Jcr.getIndexedName(newNode), Jcr.getIndexedName(nextNode));
+                       } catch (RepositoryException e) {
+                               throw new JcrException("Cannot order " + newNode + " before " + nextSectionPart.getNode(), e);
+                       }
+               }
+               Jcr.save(newNode);
+               Paragraph paragraph = (Paragraph) insertPart(partBefore.getSection(), newNode);
+               edit(paragraph, 0);
+       }
+
+       void deletePart(SectionPart sectionPart) {
+               try {
+                       Node node = sectionPart.getNode();
+                       Session session = node.getSession();
+                       if (sectionPart instanceof DbkImg) {
+                               if (!isDbk(node, DbkType.mediaobject))
+                                       throw new IllegalArgumentException("Node " + node + " is not a media object.");
+                       }
+                       node.remove();
+                       session.save();
+                       if (sectionPart instanceof Control)
+                               ((Control) sectionPart).dispose();
+                       layoutPage();
+               } catch (RepositoryException e1) {
+                       throw new JcrException("Cannot delete " + sectionPart, e1);
+               }
+       }
+
+       void deleteSection(Section section) {
+               try {
+                       Node node = section.getNode();
+                       Session session = node.getSession();
+                       node.remove();
+                       session.save();
+                       section.dispose();
+                       layoutPage();
+               } catch (RepositoryException e1) {
+                       throw new JcrException("Cannot delete " + section, e1);
+               }
+       }
+
+       String getRawParagraphText(Paragraph paragraph) {
+               return textInterpreter.raw(paragraph.getNode());
+       }
+
+       // COMMANDS
+       protected void splitEdit() {
+               checkEdited();
+               try {
+                       if (getEdited() instanceof Paragraph) {
+                               Paragraph paragraph = (Paragraph) getEdited();
+                               Text text = (Text) paragraph.getControl();
+                               int caretPosition = text.getCaretPosition();
+                               String txt = text.getText();
+                               String first = txt.substring(0, caretPosition);
+                               String second = txt.substring(caretPosition);
+                               Node firstNode = paragraph.getNode();
+                               Node sectionNode = firstNode.getParent();
+
+                               // FIXME set content the DocBook way
+                               // firstNode.setProperty(CMS_CONTENT, first);
+                               Node secondNode = addDbk(sectionNode, para);
+                               // secondNode.addMixin(CmsTypes.CMS_STYLED);
+
+                               // second node was create as last, if it is not the next one, it
+                               // means there are some in between and we can take the one at
+                               // index+1 for the re-order
+                               if (secondNode.getIndex() > firstNode.getIndex() + 1) {
+                                       sectionNode.orderBefore(p(secondNode.getIndex()), p(firstNode.getIndex() + 1));
+                               }
+
+                               // if we die in between, at least we still have the whole text
+                               // in the first node
+                               try {
+                                       textInterpreter.write(secondNode, second);
+                                       textInterpreter.write(firstNode, first);
+                               } catch (Exception e) {
+                                       // so that no additional nodes are created:
+                                       JcrUtils.discardUnderlyingSessionQuietly(firstNode);
+                                       throw e;
+                               }
+
+                               persistChanges(firstNode);
+
+                               Paragraph secondParagraph = paragraphSplitted(paragraph, secondNode);
+                               edit(secondParagraph, 0);
+                       } else if (getEdited() instanceof DbkSectionTitle) {
+                               DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited();
+                               Text text = (Text) sectionTitle.getControl();
+                               String txt = text.getText();
+                               int caretPosition = text.getCaretPosition();
+                               Section section = sectionTitle.getSection();
+                               Node sectionNode = section.getNode();
+                               Node paragraphNode = addDbk(sectionNode, para);
+                               // paragraphNode.addMixin(CmsTypes.CMS_STYLED);
+
+                               textInterpreter.write(paragraphNode, txt.substring(caretPosition));
+                               textInterpreter.write(sectionNode.getNode(DbkType.title.get()), txt.substring(0, caretPosition));
+                               sectionNode.orderBefore(p(paragraphNode.getIndex()), p(1));
+                               persistChanges(sectionNode);
+
+                               Paragraph paragraph = sectionTitleSplitted(sectionTitle, paragraphNode);
+                               // section.layout();
+                               edit(paragraph, 0);
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot split " + getEdited(), e);
+               }
+       }
+
+       protected void mergeWithPrevious() {
+               checkEdited();
+               try {
+                       Paragraph paragraph = (Paragraph) getEdited();
+                       Text text = (Text) paragraph.getControl();
+                       String txt = text.getText();
+                       Node paragraphNode = paragraph.getNode();
+                       if (paragraphNode.getIndex() == 1)
+                               return;// do nothing
+                       Node sectionNode = paragraphNode.getParent();
+                       Node previousNode = sectionNode.getNode(p(paragraphNode.getIndex() - 1));
+                       String previousTxt = textInterpreter.read(previousNode);
+                       textInterpreter.write(previousNode, previousTxt + txt);
+                       paragraphNode.remove();
+                       persistChanges(sectionNode);
+
+                       Paragraph previousParagraph = paragraphMergedWithPrevious(paragraph, previousNode);
+                       edit(previousParagraph, previousTxt.length());
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot stop editing", e);
+               }
+       }
+
+       protected void mergeWithNext() {
+               checkEdited();
+               try {
+                       Paragraph paragraph = (Paragraph) getEdited();
+                       Text text = (Text) paragraph.getControl();
+                       String txt = text.getText();
+                       Node paragraphNode = paragraph.getNode();
+                       Node sectionNode = paragraphNode.getParent();
+                       NodeIterator paragraphNodes = sectionNode.getNodes(DbkType.para.get());
+                       long size = paragraphNodes.getSize();
+                       if (paragraphNode.getIndex() == size)
+                               return;// do nothing
+                       Node nextNode = sectionNode.getNode(p(paragraphNode.getIndex() + 1));
+                       String nextTxt = textInterpreter.read(nextNode);
+                       textInterpreter.write(paragraphNode, txt + nextTxt);
+
+                       Section section = paragraph.getSection();
+                       Paragraph removed = (Paragraph) section.getSectionPart(nextNode.getIdentifier());
+
+                       nextNode.remove();
+                       persistChanges(sectionNode);
+
+                       paragraphMergedWithNext(paragraph, removed);
+                       edit(paragraph, txt.length());
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot stop editing", e);
+               }
+       }
+
+       protected synchronized void upload(EditablePart part) {
+               try {
+                       if (part instanceof SectionPart) {
+                               SectionPart sectionPart = (SectionPart) part;
+                               Node partNode = sectionPart.getNode();
+                               int partIndex = partNode.getIndex();
+                               Section section = sectionPart.getSection();
+                               Node sectionNode = section.getNode();
+
+                               if (part instanceof Paragraph) {
+                                       // FIXME adapt to DocBook
+//                                     Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE);
+//                                     newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
+//                                     JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]);
+//                                     if (partIndex < newNode.getIndex() - 1) {
+//                                             // was not last
+//                                             sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1));
+//                                     }
+//                                     // sectionNode.orderBefore(p(partNode.getIndex()),
+//                                     // p(newNode.getIndex()));
+//                                     persistChanges(sectionNode);
+//                                     DbkImg img = newImg((TextSection) section, newNode);
+//                                     edit(img, null);
+//                                     layout(img.getControl());
+                               } else if (part instanceof DbkImg) {
+                                       if (getEdited() == part)
+                                               return;
+                                       edit(part, null);
+                                       layoutPage();
+                               }
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot upload", e);
+               }
+       }
+
+       protected void deepen() {
+               if (flat)
+                       return;
+               checkEdited();
+               try {
+                       if (getEdited() instanceof Paragraph) {
+                               Paragraph paragraph = (Paragraph) getEdited();
+                               Text text = (Text) paragraph.getControl();
+                               String txt = text.getText();
+                               Node paragraphNode = paragraph.getNode();
+                               Section section = paragraph.getSection();
+                               Node sectionNode = section.getNode();
+                               // main title
+                               if (section == mainSection && section instanceof TextSection && paragraphNode.getIndex() == 1
+                                               && !sectionNode.hasNode(DbkType.title.get())) {
+                                       DbkSectionTitle sectionTitle = prepareSectionTitle(section, txt);
+                                       edit(sectionTitle, 0);
+                                       return;
+                               }
+                               Node newSectionNode = addDbk(sectionNode, DbkType.section);
+                               // newSectionNode.addMixin(NodeType.MIX_TITLE);
+                               sectionNode.orderBefore(h(newSectionNode.getIndex()), h(1));
+
+                               int paragraphIndex = paragraphNode.getIndex();
+                               String sectionPath = sectionNode.getPath();
+                               String newSectionPath = newSectionNode.getPath();
+                               while (sectionNode.hasNode(p(paragraphIndex + 1))) {
+                                       Node parag = sectionNode.getNode(p(paragraphIndex + 1));
+                                       sectionNode.getSession().move(sectionPath + '/' + p(paragraphIndex + 1),
+                                                       newSectionPath + '/' + DbkType.para.get());
+                                       SectionPart sp = section.getSectionPart(parag.getIdentifier());
+                                       if (sp instanceof Control)
+                                               ((Control) sp).dispose();
+                               }
+                               // create title
+                               Node titleNode = DbkUtils.addDbk(newSectionNode, DbkType.title);
+                               // newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE);
+                               getTextInterpreter().write(titleNode, txt);
+
+                               TextSection newSection = new TextSection(section, section.getStyle(), newSectionNode);
+                               newSection.setLayoutData(CmsSwtUtils.fillWidth());
+                               newSection.moveBelow(paragraph);
+
+                               // dispose
+                               paragraphNode.remove();
+                               paragraph.dispose();
+
+                               refresh(newSection);
+                               newSection.getParent().layout();
+                               layout(newSection);
+                               persistChanges(sectionNode);
+                       } else if (getEdited() instanceof DbkSectionTitle) {
+                               DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited();
+                               Section section = sectionTitle.getSection();
+                               Section parentSection = section.getParentSection();
+                               if (parentSection == null)
+                                       return;// cannot deepen main section
+                               Node sectionN = section.getNode();
+                               Node parentSectionN = parentSection.getNode();
+                               if (sectionN.getIndex() == 1)
+                                       return;// cannot deepen first section
+                               Node previousSectionN = parentSectionN.getNode(h(sectionN.getIndex() - 1));
+                               NodeIterator subSections = previousSectionN.getNodes(DbkType.section.get());
+                               int subsectionsCount = (int) subSections.getSize();
+                               previousSectionN.getSession().move(sectionN.getPath(),
+                                               previousSectionN.getPath() + "/" + h(subsectionsCount + 1));
+                               section.dispose();
+                               TextSection newSection = new TextSection(section, section.getStyle(), sectionN);
+                               refresh(newSection);
+                               persistChanges(previousSectionN);
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot deepen " + getEdited(), e);
+               }
+       }
+
+       protected void undeepen() {
+               if (flat)
+                       return;
+               checkEdited();
+               try {
+                       if (getEdited() instanceof Paragraph) {
+                               upload(getEdited());
+                       } else if (getEdited() instanceof DbkSectionTitle) {
+                               DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited();
+                               Section section = sectionTitle.getSection();
+                               Node sectionNode = section.getNode();
+                               Section parentSection = section.getParentSection();
+                               if (parentSection == null)
+                                       return;// cannot undeepen main section
+
+                               // choose in which section to merge
+                               Section mergedSection;
+                               if (sectionNode.getIndex() == 1)
+                                       mergedSection = section.getParentSection();
+                               else {
+                                       Map<String, Section> parentSubsections = parentSection.getSubSections();
+                                       ArrayList<Section> lst = new ArrayList<Section>(parentSubsections.values());
+                                       mergedSection = lst.get(sectionNode.getIndex() - 1);
+                               }
+                               Node mergedNode = mergedSection.getNode();
+                               boolean mergedHasSubSections = mergedNode.hasNode(DbkType.section.get());
+
+                               // title as paragraph
+                               Node newParagrapheNode = addDbk(mergedNode, para);
+                               // newParagrapheNode.addMixin(CmsTypes.CMS_STYLED);
+                               if (mergedHasSubSections)
+                                       mergedNode.orderBefore(p(newParagrapheNode.getIndex()), h(1));
+                               String txt = getTextInterpreter().read(sectionNode.getNode(DbkType.title.get()));
+                               getTextInterpreter().write(newParagrapheNode, txt);
+                               // move
+                               NodeIterator paragraphs = sectionNode.getNodes(para.get());
+                               while (paragraphs.hasNext()) {
+                                       Node p = paragraphs.nextNode();
+                                       SectionPart sp = section.getSectionPart(p.getIdentifier());
+                                       if (sp instanceof Control)
+                                               ((Control) sp).dispose();
+                                       mergedNode.getSession().move(p.getPath(), mergedNode.getPath() + '/' + para.get());
+                                       if (mergedHasSubSections)
+                                               mergedNode.orderBefore(p(p.getIndex()), h(1));
+                               }
+
+                               Iterator<Section> subsections = section.getSubSections().values().iterator();
+                               // NodeIterator sections = sectionNode.getNodes(CMS_H);
+                               while (subsections.hasNext()) {
+                                       Section subsection = subsections.next();
+                                       Node s = subsection.getNode();
+                                       mergedNode.getSession().move(s.getPath(), mergedNode.getPath() + '/' + DbkType.section.get());
+                                       subsection.dispose();
+                               }
+
+                               // remove section
+                               section.getNode().remove();
+                               section.dispose();
+
+                               refresh(mergedSection);
+                               mergedSection.getParent().layout();
+                               layout(mergedSection);
+                               persistChanges(mergedNode);
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot undeepen " + getEdited(), e);
+               }
+       }
+
+       // UI CHANGES
+       protected Paragraph paragraphSplitted(Paragraph paragraph, Node newNode) throws RepositoryException {
+               Section section = paragraph.getSection();
+               updateContent(paragraph);
+               Paragraph newParagraph = newParagraph((TextSection) section, newNode);
+               newParagraph.setLayoutData(CmsSwtUtils.fillWidth());
+               newParagraph.moveBelow(paragraph);
+               layout(paragraph.getControl(), newParagraph.getControl());
+               return newParagraph;
+       }
+
+       protected Paragraph sectionTitleSplitted(DbkSectionTitle sectionTitle, Node newNode) throws RepositoryException {
+               updateContent(sectionTitle);
+               Paragraph newParagraph = newParagraph(sectionTitle.getSection(), newNode);
+               // we assume beforeFirst is not null since there was a sectionTitle
+               newParagraph.moveBelow(sectionTitle.getSection().getHeader());
+               layout(sectionTitle.getControl(), newParagraph.getControl());
+               return newParagraph;
+       }
+
+       protected Paragraph paragraphMergedWithPrevious(Paragraph removed, Node remaining) throws RepositoryException {
+               Section section = removed.getSection();
+               removed.dispose();
+
+               Paragraph paragraph = (Paragraph) section.getSectionPart(remaining.getIdentifier());
+               updateContent(paragraph);
+               layout(paragraph.getControl());
+               return paragraph;
+       }
+
+       protected void paragraphMergedWithNext(Paragraph remaining, Paragraph removed) throws RepositoryException {
+               removed.dispose();
+               updateContent(remaining);
+               layout(remaining.getControl());
+       }
+
+       // UTILITIES
+       protected String p(Integer index) {
+               StringBuilder sb = new StringBuilder(6);
+               sb.append(para.get()).append('[').append(index).append(']');
+               return sb.toString();
+       }
+
+       protected String h(Integer index) {
+               StringBuilder sb = new StringBuilder(5);
+               sb.append(DbkType.section.get()).append('[').append(index).append(']');
+               return sb.toString();
+       }
+
+       // GETTERS / SETTERS
+       public Section getMainSection() {
+               return mainSection;
+       }
+
+       public boolean isFlat() {
+               return flat;
+       }
+
+       public TextInterpreter getTextInterpreter() {
+               return textInterpreter;
+       }
+
+       // KEY LISTENER
+       @Override
+       public void keyPressed(KeyEvent ke) {
+               if (log.isTraceEnabled())
+                       log.trace(ke);
+
+               if (getEdited() == null)
+                       return;
+               boolean altPressed = (ke.stateMask & SWT.ALT) != 0;
+               boolean shiftPressed = (ke.stateMask & SWT.SHIFT) != 0;
+               boolean ctrlPressed = (ke.stateMask & SWT.CTRL) != 0;
+
+               try {
+                       // Common
+                       if (ke.keyCode == SWT.ESC) {
+//                             cancelEdit();
+                               saveEdit();
+                       } else if (ke.character == '\r') {
+                               if (!shiftPressed)
+                                       splitEdit();
+                       } else if (ke.character == 'z') {
+                               if (ctrlPressed)
+                                       cancelEdit();
+                       } else if (ke.character == 'S') {
+                               if (ctrlPressed)
+                                       saveEdit();
+                       } else if (ke.character == '\t') {
+                               if (!shiftPressed) {
+                                       deepen();
+                               } else if (shiftPressed) {
+                                       undeepen();
+                               }
+                       } else {
+                               if (getEdited() instanceof Paragraph) {
+                                       Paragraph paragraph = (Paragraph) getEdited();
+                                       Section section = paragraph.getSection();
+                                       if (altPressed && ke.keyCode == SWT.ARROW_RIGHT) {
+                                               edit(section.nextSectionPart(paragraph), 0);
+                                       } else if (altPressed && ke.keyCode == SWT.ARROW_LEFT) {
+                                               edit(section.previousSectionPart(paragraph), 0);
+                                       } else if (ke.character == SWT.BS) {
+                                               Text text = (Text) paragraph.getControl();
+                                               int caretPosition = text.getCaretPosition();
+                                               if (caretPosition == 0) {
+                                                       mergeWithPrevious();
+                                               }
+                                       } else if (ke.character == SWT.DEL) {
+                                               Text text = (Text) paragraph.getControl();
+                                               int caretPosition = text.getCaretPosition();
+                                               int charcount = text.getCharCount();
+                                               if (caretPosition == charcount) {
+                                                       mergeWithNext();
+                                               }
+                                       }
+                               }
+                       }
+               } catch (Exception e) {
+                       ke.doit = false;
+                       notifyEditionException(e);
+               }
+       }
+
+       @Override
+       public void keyReleased(KeyEvent e) {
+       }
+
+       // MOUSE LISTENER
+       @Override
+       protected MouseListener createMouseListener() {
+               return new ML();
+       }
+
+       private class ML extends MouseAdapter {
+               private static final long serialVersionUID = 8526890859876770905L;
+
+               @Override
+               public void mouseDoubleClick(MouseEvent e) {
+                       if (e.button == 1) {
+                               Control source = (Control) e.getSource();
+                               EditablePart composite = findDataParent(source);
+                               Point point = new Point(e.x, e.y);
+                               if (composite instanceof DbkImg) {
+                                       if (getCmsEditable().canEdit()) {
+                                               if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg)) {
+                                                       if (source == mainSection)
+                                                               return;
+                                                       EditablePart part = findDataParent(source);
+                                                       upload(part);
+                                               } else {
+                                                       getCmsEditable().startEditing();
+                                               }
+                                       }
+                               } else if (source instanceof Label) {
+                                       Label lbl = (Label) source;
+                                       Rectangle bounds = lbl.getBounds();
+                                       float width = bounds.width;
+                                       float height = bounds.height;
+                                       float textLength = lbl.getText().length();
+                                       float area = width * height;
+                                       float charArea = area / textLength;
+                                       float lines = textLength / width;
+                                       float proportion = point.y * width + point.x;
+                                       int pos = (int) (textLength * (proportion / area));
+                                       // TODO refine it
+                                       edit(composite, (Integer) pos);
+                               } else {
+                                       edit(composite, source.toDisplay(point));
+                               }
+                       }
+               }
+
+               @Override
+               public void mouseDown(MouseEvent e) {
+                       if (getCmsEditable().isEditing()) {
+                               if (e.button == 3) {
+                                       EditablePart composite = findDataParent((Control) e.getSource());
+                                       if (styledTools != null) {
+                                               List<String> styles = getAvailableStyles(composite);
+                                               styledTools.show(composite, new Point(e.x, e.y), styles);
+                                       }
+                               }
+                       }
+               }
+
+               @Override
+               public void mouseUp(MouseEvent e) {
+               }
+       }
+
+       protected List<String> getAvailableStyles(EditablePart editablePart) {
+               return new ArrayList<>();
+       }
+
+       public void setMaxMediaWidth(Integer maxMediaWidth) {
+               this.maxMediaWidth = maxMediaWidth;
+       }
+
+       public void setShowMainTitle(boolean showMainTitle) {
+               this.showMainTitle = showMainTitle;
+       }
+
+       public String getDefaultSectionStyle() {
+               return defaultSectionStyle;
+       }
+
+       public void setDefaultSectionStyle(String defaultSectionStyle) {
+               this.defaultSectionStyle = defaultSectionStyle;
+       }
+
+       // FILE UPLOAD LISTENER
+       private class FUL implements FileUploadListener {
+               public void uploadProgress(FileUploadEvent event) {
+                       // TODO Monitor upload progress
+               }
+
+               public void uploadFailed(FileUploadEvent event) {
+                       throw new RuntimeException("Upload failed " + event, event.getException());
+               }
+
+               public void uploadFinished(FileUploadEvent event) {
+                       for (FileDetails file : event.getFileDetails()) {
+                               if (log.isDebugEnabled())
+                                       log.debug("Received: " + file.getFileName());
+                       }
+                       mainSection.getDisplay().syncExec(new Runnable() {
+                               @Override
+                               public void run() {
+                                       saveEdit();
+                               }
+                       });
+                       FileUploadHandler uploadHandler = (FileUploadHandler) event.getSource();
+                       uploadHandler.dispose();
+               }
+       }
+}
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/CustomDbkEditor.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/CustomDbkEditor.java
new file mode 100644 (file)
index 0000000..16845ae
--- /dev/null
@@ -0,0 +1,23 @@
+package org.argeo.app.ui.docbook;
+
+import javax.jcr.Node;
+
+import org.argeo.api.cms.CmsEditable;
+import org.argeo.cms.ui.viewers.Section;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Manages hardcoded sections as an arbitrary hierarchy under the main section,
+ * which contains no text and no title.
+ */
+public class CustomDbkEditor extends AbstractDbkViewer {
+       private static final long serialVersionUID = 656302500183820802L;
+
+       public CustomDbkEditor(Composite parent, int style, Node textNode, CmsEditable cmsEditable) {
+               this(new Section(parent, style, textNode), style, cmsEditable);
+       }
+
+       public CustomDbkEditor(Section parent, int style, CmsEditable cmsEditable) {
+               super(parent, style, cmsEditable);
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkContextMenu.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkContextMenu.java
new file mode 100644 (file)
index 0000000..cf45ef9
--- /dev/null
@@ -0,0 +1,230 @@
+package org.argeo.app.ui.docbook;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.api.cms.CmsEditable;
+import org.argeo.app.docbook.DbkMsg;
+import org.argeo.app.docbook.DbkUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.MouseDown;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.viewers.NodePart;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.cms.ui.viewers.SectionPart;
+import org.argeo.cms.ui.widgets.EditableText;
+import org.argeo.cms.ui.widgets.Img;
+import org.argeo.jcr.Jcr;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/** Dialog to edit a text part. */
+class DbkContextMenu {
+       private final AbstractDbkViewer textViewer;
+
+       private Shell shell;
+
+       DbkContextMenu(AbstractDbkViewer textViewer, Shell parentShell) {
+//             shell = new Shell(display, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+               shell = new Shell(parentShell, SWT.BORDER);
+//             super(display, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+               this.textViewer = textViewer;
+               shell.setLayout(new GridLayout());
+               // shell.setData(RWT.CUSTOM_VARIANT, TEXT_STYLED_TOOLS_DIALOG);
+
+               shell.addShellListener(new ToolsShellListener());
+       }
+
+       void show(EditablePart editablePart, Point location, List<String> availableStyles) {
+               if (shell.isVisible())
+                       shell.setVisible(false);
+               CmsSwtUtils.clear(shell);
+               Composite parent = shell;
+               CmsEditable cmsEditable = textViewer.getCmsEditable();
+//             if (availableStyles.isEmpty())
+//                     return;
+
+               if (editablePart instanceof Paragraph) {
+                       Paragraph paragraph = (Paragraph) editablePart;
+                       deletePartB(parent, DbkMsg.deleteParagraph.lead(), paragraph);
+                       insertMediaB(parent,  paragraph);
+
+               } else if (editablePart instanceof Img) {
+                       Img img = (Img) editablePart;
+                       deletePartB(parent, DbkMsg.deleteMedia.lead(), img);
+                       insertMediaB(parent, img);
+                       insertParagraphB(parent, DbkMsg.insertParagraph.lead(), img);
+
+               } else if (editablePart instanceof DbkSectionTitle) {
+                       DbkSectionTitle sectionTitle = (DbkSectionTitle) editablePart;
+                       TextSection section = sectionTitle.getSection();
+                       if (!section.isTitleReadOnly()) {
+                               Label deleteB = new Label(shell, SWT.NONE);
+                               deleteB.setText(DbkMsg.deleteSection.lead());
+                               deleteB.addMouseListener((MouseDown) (e) -> {
+                                       textViewer.deleteSection(section);
+                                       hide();
+                               });
+                       }
+                       insertMediaB(parent,  sectionTitle.getSection(), sectionTitle);
+               }
+
+               StyledToolMouseListener stml = new StyledToolMouseListener(editablePart);
+               List<StyleButton> styleButtons = new ArrayList<DbkContextMenu.StyleButton>();
+               if (cmsEditable.isEditing()) {
+                       for (String style : availableStyles) {
+                               StyleButton styleButton = new StyleButton(shell, SWT.WRAP);
+                               if (!"".equals(style))
+                                       styleButton.setStyle(style);
+                               else
+                                       styleButton.setStyle(null);
+                               styleButton.setMouseListener(stml);
+                               styleButtons.add(styleButton);
+                       }
+               } else if (cmsEditable.canEdit()) {
+                       // Edit
+//                     Label editButton = new Label(shell, SWT.NONE);
+//                     editButton.setText("Edit");
+//                     editButton.addMouseListener(stml);
+               }
+
+               if (editablePart instanceof Paragraph) {
+                       final int size = 32;
+                       String text = textViewer.getRawParagraphText((Paragraph) editablePart);
+                       String textToShow = text.length() > size ? text.substring(0, size - 3) + "..." : text;
+                       for (StyleButton styleButton : styleButtons) {
+                               styleButton.setText((styleButton.style == null ? "default" : styleButton.style) + " : " + textToShow);
+                       }
+               }
+
+               shell.pack();
+               shell.layout();
+               if (editablePart instanceof Control) {
+                       int height = shell.getSize().y;
+                       int parentShellHeight = shell.getShell().getSize().y;
+                       if ((location.y + height) < parentShellHeight) {
+                               shell.setLocation(((Control) editablePart).toDisplay(location.x, location.y));
+                       } else {
+                               shell.setLocation(((Control) editablePart).toDisplay(location.x, location.y - parentShellHeight));
+                       }
+               }
+
+               if (shell.getChildren().length != 0)
+                       shell.open();
+       }
+
+       void hide() {
+               shell.setVisible(false);
+       }
+
+       protected void insertMediaB(Composite parent, SectionPart sectionPart) {
+               insertMediaB(parent,  sectionPart.getSection(), sectionPart);
+       }
+
+       protected void insertMediaB(Composite parent, Section section, NodePart nodePart) {
+               Label insertPictureB = new Label(parent, SWT.NONE);
+               insertPictureB.setText(DbkMsg.insertPicture.lead());
+               insertPictureB.addMouseListener((MouseDown) (e) -> {
+                       Node newNode = DbkUtils.insertImageAfter(nodePart.getNode());
+                       Jcr.save(newNode);
+                       textViewer.insertPart(section, newNode);
+                       hide();
+               });
+               Label insertVideoB = new Label(parent, SWT.NONE);
+               insertVideoB.setText(DbkMsg.insertVideo.lead());
+               insertVideoB.addMouseListener((MouseDown) (e) -> {
+                       Node newNode = DbkUtils.insertVideoAfter(nodePart.getNode());
+                       Jcr.save(newNode);
+                       textViewer.insertPart(section, newNode);
+                       hide();
+               });
+
+       }
+
+       protected void insertParagraphB(Composite parent, String msg, SectionPart sectionPart) {
+               Label insertMediaB = new Label(parent, SWT.NONE);
+               insertMediaB.setText(msg);
+               insertMediaB.addMouseListener((MouseDown) (e) -> {
+                       textViewer.addParagraph(sectionPart, null);
+                       hide();
+               });
+       }
+
+       protected void deletePartB(Composite parent, String msg, SectionPart sectionPart) {
+               Label deleteB = new Label(shell, SWT.NONE);
+               deleteB.setText(msg);
+               deleteB.addMouseListener((MouseDown) (e) -> {
+                       textViewer.deletePart(sectionPart);
+                       hide();
+               });
+       }
+
+       class StyleButton extends EditableText {
+               private static final long serialVersionUID = 7731102609123946115L;
+
+               String style;
+
+               public StyleButton(Composite parent, int style) {
+                       super(parent, style);
+               }
+
+               @Override
+               public void setStyle(String style) {
+                       this.style = style;
+                       super.setStyle(style);
+               }
+
+//             private Label label;
+//
+//             public StyleButton(Composite parent, int swtStyle) {
+//                     super(parent, SWT.NONE);
+//                     setLayout(new GridLayout());
+//                     label = new Label(this, swtStyle);
+//             }
+//
+//             public Label getLabel() {
+//                     return label;
+//             }
+
+       }
+
+       class StyledToolMouseListener extends MouseAdapter {
+               private static final long serialVersionUID = 8516297091549329043L;
+               private EditablePart editablePart;
+
+               public StyledToolMouseListener(EditablePart editablePart) {
+                       super();
+                       this.editablePart = editablePart;
+               }
+
+               @Override
+               public void mouseDown(MouseEvent e) {
+                       // TODO make it more robust.
+                       Label sb = (Label) e.getSource();
+                       Object style = sb.getData(RWT.CUSTOM_VARIANT);
+                       textViewer.setParagraphStyle((Paragraph) editablePart, style == null ? null : style.toString());
+                       hide();
+               }
+       }
+
+       class ToolsShellListener extends org.eclipse.swt.events.ShellAdapter {
+               private static final long serialVersionUID = 8432350564023247241L;
+
+               @Override
+               public void shellDeactivated(ShellEvent e) {
+                       hide();
+               }
+
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImageManager.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImageManager.java
new file mode 100644 (file)
index 0000000..32bbdd9
--- /dev/null
@@ -0,0 +1,175 @@
+package org.argeo.app.ui.docbook;
+
+import static javax.jcr.Node.JCR_CONTENT;
+import static javax.jcr.Property.JCR_DATA;
+import static javax.jcr.nodetype.NodeType.NT_FILE;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.api.cms.Cms2DSize;
+import org.argeo.api.cms.CmsImageManager;
+import org.argeo.app.api.EntityNames;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.docbook.DbkAttr;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.app.docbook.DbkUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.util.DefaultImageManager;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.swt.graphics.ImageData;
+
+/** Add DocBook images support to {@link CmsImageManager}. */
+public class DbkImageManager extends DefaultImageManager {
+       private Node baseFolder = null;
+
+       public DbkImageManager(Node baseFolder) {
+               this.baseFolder = baseFolder;
+       }
+
+       Node getImageDataNode(Node mediaObjectNode) {
+               try {
+                       if (mediaObjectNode.hasNode(DbkType.imageobject.get())) {
+                               Node imageDataNode = mediaObjectNode.getNode(DbkType.imageobject.get())
+                                               .getNode(DbkType.imagedata.get());
+                               return imageDataNode;
+                       } else {
+                               throw new IllegalStateException("No image data found for " + mediaObjectNode);
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+       }
+
+       @Override
+       public Binary getImageBinary(Node node) {
+               Node fileNode = null;
+               if (DbkUtils.isDbk(node, DbkType.mediaobject)) {
+                       Node imageDataNode = getImageDataNode(node);
+                       fileNode = getFileNode(imageDataNode);
+               }
+               try {
+                       if (node.isNodeType(NT_FILE)) {
+                               fileNode = node;
+                       }
+                       if (fileNode != null) {
+                               return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();
+                       } else {
+                               return null;
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+       }
+
+       public Cms2DSize getImageSize(Node mediaObjectNode) {
+               Node imageDataNode = getImageDataNode(mediaObjectNode);
+               Node fileNode = getFileNode(imageDataNode);
+               if (fileNode == null)
+                       return new Cms2DSize(0, 0);
+               try {
+                       Cms2DSize intrinsicSize;
+                       if (fileNode.hasProperty(EntityNames.SVG_WIDTH) && fileNode.hasProperty(EntityNames.SVG_HEIGHT)) {
+                               int width = (int) fileNode.getProperty(EntityNames.SVG_WIDTH).getLong();
+                               int height = (int) fileNode.getProperty(EntityNames.SVG_HEIGHT).getLong();
+                               intrinsicSize = new Cms2DSize(width, height);
+                       } else {
+                               try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
+                                       ImageData id = new ImageData(in);
+                                       intrinsicSize = updateSize(fileNode, id);
+                               } catch (IOException e) {
+                                       throw new RuntimeException("Cannot load file " + fileNode, e);
+                               }
+                       }
+                       // TODO interpret image data infos
+                       return intrinsicSize;
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+       }
+
+       protected Cms2DSize updateSize(Node fileNode, ImageData id) throws RepositoryException {
+               fileNode.addMixin(EntityType.box.get());
+               fileNode.setProperty(EntityNames.SVG_WIDTH, id.width);
+               fileNode.setProperty(EntityNames.SVG_HEIGHT, id.height);
+               return new Cms2DSize(id.width, id.height);
+       }
+
+       @Override
+       protected void processNewImageFile(Node mediaObjectNode, Node fileNode, ImageData id)
+                       throws RepositoryException, IOException {
+               Node imageDataNode = getImageDataNode(mediaObjectNode);
+               updateSize(fileNode, id);
+               String filePath = fileNode.getPath();
+               String relPath = filePath.substring(baseFolder.getPath().length() + 1);
+               imageDataNode.setProperty(DbkAttr.fileref.name(), relPath);
+       }
+
+       @Override
+       public String getImageUrl(Node mediaObjectNode) {
+               Node imageDataNode = getImageDataNode(mediaObjectNode);
+               // TODO factorise
+               String fileref = null;
+               try {
+                       if (imageDataNode.hasProperty(DbkAttr.fileref.name()))
+                               fileref = imageDataNode.getProperty(DbkAttr.fileref.name()).getString();
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+               if (fileref == null)
+                       return null;
+               URI fileUri;
+               try {
+                       // FIXME it messes up with the '/'
+                       fileUri = new URI(URLEncoder.encode(fileref, StandardCharsets.UTF_8.toString()));
+               } catch (URISyntaxException | UnsupportedEncodingException e) {
+                       throw new IllegalArgumentException("File ref in " + imageDataNode + " is badly formatted", e);
+               }
+               if (fileUri.getScheme() != null)
+                       return fileUri.toString();
+               // local
+               Node fileNode = getFileNode(imageDataNode);
+               String url = CmsUiUtils.getDataPathForUrl(fileNode);
+               return url;
+       }
+
+       protected Node getFileNode(Node imageDataNode) {
+               // FIXME make URL use case more robust
+               try {
+                       String fileref = null;
+                       if (imageDataNode.hasProperty(DbkAttr.fileref.name()))
+                               fileref = imageDataNode.getProperty(DbkAttr.fileref.name()).getString();
+                       if (fileref == null)
+                               return null;
+                       Node fileNode;
+                       if (fileref.startsWith("/"))
+                               fileNode = baseFolder.getSession().getNode(fileref);
+                       else
+                               fileNode = baseFolder.getNode(fileref);
+                       return fileNode;
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+       }
+
+       protected Node getMediaFolder() {
+               try {
+                       // TODO check edition status
+                       Node mediaFolder = JcrUtils.getOrAdd(baseFolder, EntityNames.MEDIA, NodeType.NT_FOLDER);
+                       return mediaFolder;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get media folder", e);
+               }
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImg.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkImg.java
new file mode 100644 (file)
index 0000000..ca9b388
--- /dev/null
@@ -0,0 +1,70 @@
+package org.argeo.app.ui.docbook;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.widgets.Img;
+import org.eclipse.rap.fileupload.FileUploadEvent;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadListener;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** DocBook specific image area. */
+public class DbkImg extends Img {
+       private static final long serialVersionUID = -6150996708899219074L;
+
+       public DbkImg(Composite parent, int swtStyle, Node imgNode, DbkImageManager imageManager)
+                       throws RepositoryException {
+               super(parent, swtStyle, imgNode, imageManager);
+       }
+
+       @Override
+       protected Node getUploadFolder() {
+               Node mediaFolder = ((DbkImageManager) getImageManager()).getMediaFolder();
+               return mediaFolder;
+       }
+
+       @Override
+       protected String getUploadName() {
+               return null;
+       }
+
+       @Override
+       protected void setContainerLayoutData(Composite composite) {
+               composite.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+       }
+
+       @Override
+       protected void setControlLayoutData(Control control) {
+               control.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+       }
+
+       @Override
+       protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) {
+               FileUploadHandler fileUploadHandler = super.prepareUpload(receiver);
+               fileUploadHandler.addUploadListener(new FileUploadListener() {
+
+                       @Override
+                       public void uploadProgress(FileUploadEvent event) {
+                               // TODO Auto-generated method stub
+
+                       }
+
+                       @Override
+                       public void uploadFinished(FileUploadEvent event) {
+                       }
+
+                       @Override
+                       public void uploadFailed(FileUploadEvent event) {
+                               // TODO Auto-generated method stub
+
+                       }
+               });
+               return fileUploadHandler;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkSectionTitle.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkSectionTitle.java
new file mode 100644 (file)
index 0000000..b537333
--- /dev/null
@@ -0,0 +1,30 @@
+package org.argeo.app.ui.docbook;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.viewers.NodePart;
+import org.argeo.cms.ui.widgets.EditableText;
+import org.eclipse.swt.widgets.Composite;
+
+/** The title of a section, based on an XML text node. */
+public class DbkSectionTitle extends EditableText implements EditablePart, NodePart {
+       private static final long serialVersionUID = -1787983154946583171L;
+
+       private final TextSection section;
+
+       public DbkSectionTitle(Composite parent, int swtStyle, Node titleNode) throws RepositoryException {
+               super(parent, swtStyle, titleNode);
+               section = (TextSection) TextSection.findSection(this);
+       }
+
+       public TextSection getSection() {
+               return section;
+       }
+
+       @Override
+       public Node getItem() throws RepositoryException {
+               return getNode();
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkTextInterpreter.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkTextInterpreter.java
new file mode 100644 (file)
index 0000000..ff12348
--- /dev/null
@@ -0,0 +1,283 @@
+package org.argeo.app.ui.docbook;
+
+import static org.argeo.app.docbook.DbkType.para;
+import static org.argeo.app.docbook.DbkType.title;
+import static org.argeo.app.docbook.DbkUtils.isDbk;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.app.docbook.DbkAttr;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+
+/** Based on HTML with a few Wiki-like shortcuts. */
+public class DbkTextInterpreter implements TextInterpreter {
+       private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+
+       private String linkCssClass = DbkType.link.name();
+
+       @Override
+       public void write(Item item, String content) {
+               try {
+                       if (item instanceof Node) {
+                               Node node = (Node) item;
+                               if (isDbk(node, para) || isDbk(node, title)) {
+                                       String raw = convertToStorage(node, content);
+                                       validateBeforeStoring(raw);
+
+                                       String jcrUuid = node.getIdentifier();
+//                                     if (node.hasProperty(Property.JCR_UUID))
+//                                             jcrUuid = node.getProperty(Property.JCR_UUID).getString();
+//                                     else {
+//                                             // TODO use time based
+//                                             jcrUuid = UUID.randomUUID().toString();
+//                                             node.setProperty(Property.JCR_UUID, jcrUuid);
+//                                             node.getSession().save();
+//                                     }
+
+                                       StringBuilder namespaces = new StringBuilder();
+                                       namespaces.append(" xmlns:dbk=\"http://docbook.org/ns/docbook\"");
+                                       namespaces.append(" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\"");
+                                       namespaces.append(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
+                                       raw = "<" + node.getName() + " jcr:uuid=\"" + jcrUuid + "\"" + namespaces + ">" + raw + "</"
+                                                       + node.getName() + ">";
+//                                     System.out.println(raw);
+                                       try (InputStream in = new ByteArrayInputStream(raw.getBytes(StandardCharsets.UTF_8))) {
+                                               node.getSession().importXML(node.getParent().getPath(), in,
+                                                               ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+                                               // node.getSession().save();
+                                       } catch (IOException e) {
+                                               throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
+                                       }
+
+//                                     try {
+//                                             DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+//                                             Document document;
+//                                             try (Reader in = new StringReader(raw)) {
+//                                                     document = documentBuilder.parse(new InputSource(in));
+//                                             }
+//                                             NodeList nl = document.getChildNodes();
+//                                             for (int i = 0; i < nl.getLength(); i++) {
+//                                                     org.w3c.dom.Node n = nl.item(i);
+//                                                     if (node instanceof Text) {
+//
+//                                                     }
+//                                             }
+//                                     } catch (ParserConfigurationException | SAXException | IOException e) {
+//                                             throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
+//                                     }
+
+//                                     Node jcrText;
+//                                     if (!node.hasNode(Jcr.JCR_XMLTEXT))
+//                                             jcrText = node.addNode(Jcr.JCR_XMLTEXT, JcrxType.JCRX_XMLTEXT);
+//                                     else
+//                                             jcrText = node.getNode(Jcr.JCR_XMLTEXT);
+//                                     jcrText.setProperty(Jcr.JCR_XMLCHARACTERS, raw);
+                               } else {
+                                       throw new IllegalArgumentException("Don't know how to interpret " + node);
+                               }
+                       } else {// property
+                               Property property = (Property) item;
+                               property.setValue(content);
+                       }
+                       // item.getSession().save();
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot set content on " + item, e);
+               }
+       }
+
+       @Override
+       public String read(Item item) {
+               try {
+                       String raw = raw(item);
+                       return convertFromStorage(item, raw);
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get " + item + " for edit", e);
+               }
+       }
+
+       @Override
+       public String raw(Item item) {
+               try {
+                       item.getSession().refresh(true);
+                       if (item instanceof Node) {
+                               Node node = (Node) item;
+                               if (isDbk(node, para) || isDbk(node, title)) {
+                                       StringBuilder sb = new StringBuilder();
+                                       readXml(node, sb);
+//                                     NodeIterator nit = node.getNodes();
+//                                     while (nit.hasNext()) {
+//                                             Node child = nit.nextNode();
+//                                             if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
+//                                                     Node jcrText = node.getNode(Jcr.JCR_XMLTEXT);
+//                                                     String txt = jcrText.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
+//                                                     // TODO make it more robust
+//                                                     // txt = txt.replace("\n", "").replace("\t", "");
+//                                                     txt = txt.replace("\t", "  ");
+//                                                     sb.append(txt);
+//                                             } else {
+//                                                     try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+//                                                             child.getSession().exportDocumentView(child.getPath(), out, true, false);
+//                                                             sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
+//                                                     } catch (IOException e) {
+//                                                             throw new IllegalStateException("Cannot export " + child, e);
+//                                                     }
+//                                             }
+//                                     }
+                                       return sb.toString();
+                               } else {
+                                       throw new IllegalArgumentException("Don't know how to interpret " + node);
+                               }
+                       } else {// property
+                               Property property = (Property) item;
+                               return property.getString();
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get " + item + " content", e);
+               }
+       }
+
+       private void readXml(Node node, StringBuilder sb) throws RepositoryException {
+               NodeIterator nit = node.getNodes();
+               while (nit.hasNext()) {
+                       Node child = nit.nextNode();
+                       if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
+                               String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
+                               // TODO make it more robust
+                               // txt = txt.replace("\n", "").replace("\t", "");
+                               txt = txt.replace("\t", "  ");
+                               sb.append(txt);
+                       } else {
+                               sb.append('<').append(child.getName());
+                               PropertyIterator pit = child.getProperties();
+                               properties: while (pit.hasNext()) {
+                                       Property p = pit.nextProperty();
+                                       if (p.getName().startsWith("jcr:"))
+                                               continue properties;
+                                       sb.append(' ').append(p.getName()).append("=\"").append(p.getString()).append('\"');
+                               }
+                               sb.append('>');
+                               readXml(child, sb);
+//                             try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+//                                     child.getSession().exportDocumentView(child.getPath(), out, true, false);
+//                                     sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
+//                             } catch (IOException e) {
+//                                     throw new IllegalStateException("Cannot export " + child, e);
+//                             }
+                               sb.append("</").append(child.getName()).append('>');
+                       }
+               }
+       }
+
+       private void readAsSimpleHtml(Node node, StringBuilder sb) throws RepositoryException {
+               NodeIterator nit = node.getNodes();
+               while (nit.hasNext()) {
+                       Node child = nit.nextNode();
+                       if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
+                               String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
+                               // TODO make it more robust
+                               // txt = txt.replace("\n", "").replace("\t", "");
+                               txt = txt.replace("\t", "  ");
+                               String html = textToSimpleHtml(txt);
+                               sb.append(html);
+                       } else if (child.getName().equals(DbkType.link.get())) {
+                               if (child.hasProperty(DbkAttr.XLINK_HREF)) {
+                                       String href = child.getProperty(DbkAttr.XLINK_HREF).getString();
+                                       // TODO deal with other forbidden XML characters?
+                                       href = href.replace("&", "&amp;");
+                                       sb.append("<a class='" + linkCssClass + "' href='").append(href).append("'>");
+                                       readAsSimpleHtml(child, sb);
+                                       sb.append("</a>");
+                               }
+                       } else {
+                               // ignore
+                       }
+               }
+       }
+
+       private String textToSimpleHtml(String raw) {
+               // FIXME the saved data should be corrected instead.
+               if (raw.indexOf('&') >= 0) {
+                       raw = raw.replace("&", "&amp;");
+               }
+               if (raw.indexOf('<') >= 0) {
+                       raw = raw.replace("<", "&lt;");
+               }
+               if (raw.indexOf('>') >= 0) {
+                       raw = raw.replace(">", "&gt;");
+               }
+               if (raw.indexOf('\"') >= 0) {
+                       raw = raw.replace("\"", "&quot;");
+               }
+               if (raw.indexOf('\'') >= 0) {
+                       raw = raw.replace("\'", "&apos;");
+               }
+//             raw = "<span style='text-align:justify'>" + raw + "</span>";
+               if (raw.length() == 0)
+                       return raw;
+               try (StringReader reader = new StringReader(raw)) {
+                       List<String> lines = IOUtils.readLines(reader);
+                       if (lines.size() == 1)
+                               return lines.get(0);
+                       StringBuilder sb = new StringBuilder(raw.length() + lines.size() * BR_LENGTH);
+                       for (int i = 0; i < lines.size(); i++) {
+                               if (i != 0)
+                                       sb.append("<br/>");
+                               sb.append(lines.get(i));
+                       }
+                       return sb.toString();
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       final static int BR_LENGTH = "<br/>".length();
+
+       public String readSimpleHtml(Item item) {
+               try {
+                       StringBuilder sb = new StringBuilder();
+//                     sb.append("<div style='text-align: justify;'>");
+                       readAsSimpleHtml((Node) item, sb);
+//                     sb.append("</div>");
+//                     System.out.println(sb);
+                       return sb.toString();
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot convert " + item + " to simple HTML", e);
+               }
+       }
+
+       // EXTENSIBILITY
+       /**
+        * To be overridden, in order to make sure that only valid strings are being
+        * stored.
+        */
+       protected void validateBeforeStoring(String raw) {
+       }
+
+       /** To be overridden, in order to support additional formatting. */
+       protected String convertToStorage(Item item, String content) throws RepositoryException {
+               return content;
+
+       }
+
+       /** To be overridden, in order to support additional formatting. */
+       protected String convertFromStorage(Item item, String content) throws RepositoryException {
+               return content;
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkVideo.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkVideo.java
new file mode 100644 (file)
index 0000000..c8aee51
--- /dev/null
@@ -0,0 +1,227 @@
+package org.argeo.app.ui.docbook;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.app.docbook.DbkAttr;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.app.docbook.DbkUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.Selected;
+import org.argeo.cms.ui.viewers.NodePart;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.cms.ui.viewers.SectionPart;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.argeo.util.naming.NamingUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+public class DbkVideo extends StyledControl implements SectionPart, NodePart {
+       private static final long serialVersionUID = -8753232181570351880L;
+       private Section section;
+
+       private int width = 640;
+       private int height = 360;
+
+       private boolean editable;
+
+       public DbkVideo(Composite parent, int style, Node node) {
+               this(Section.findSection(parent), parent, style, node);
+       }
+
+       DbkVideo(Section section, Composite parent, int style, Node node) {
+               super(parent, style, node);
+               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
+               this.section = section;
+               setStyle(DbkType.videoobject.name());
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               Node mediaobject = getNode();
+               Composite wrapper = new Composite(box, SWT.NONE);
+               wrapper.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+               Composite browserC = new Composite(wrapper, SWT.NONE);
+               browserC.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               GridData gd = new GridData(SWT.CENTER, SWT.FILL, true, true);
+               gd.widthHint = getWidth();
+               gd.heightHint = getHeight();
+               browserC.setLayoutData(gd);
+//             wrapper.setLayoutData(CmsUiUtils.fillAll());
+               Browser browser = new Browser(browserC, SWT.NONE);
+
+               if (editable) {
+                       Composite editor = new Composite(wrapper, SWT.BORDER);
+                       editor.setLayout(new GridLayout(3, false));
+                       editor.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+                       String fileref = DbkUtils.getMediaFileref(mediaobject);
+                       Text text = new Text(editor, SWT.SINGLE);
+                       if (fileref != null)
+                               text.setText(fileref);
+                       else
+                               text.setMessage("Embed URL of the video");
+                       text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+                       Button updateB = new Button(editor, SWT.FLAT);
+                       updateB.setText("Update");
+                       updateB.addSelectionListener(new Selected() {
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       try {
+                                               Node videodata = mediaobject.getNode(DbkType.videoobject.get())
+                                                               .getNode(DbkType.videodata.get());
+                                               String txt = text.getText();
+                                               URI uri;
+                                               try {
+                                                       uri = new URI(txt);
+                                               } catch (URISyntaxException e1) {
+                                                       text.setText("");
+                                                       text.setMessage("Invalid URL");
+                                                       return;
+                                               }
+
+                                               // Transform watch URL in embed
+                                               // YouTube
+                                               String videoId = null;
+                                               if ("www.youtube.com".equals(uri.getHost()) || "youtube.com".equals(uri.getHost())
+                                                               || "youtu.be".equals(uri.getHost())) {
+                                                       if ("www.youtube.com".equals(uri.getHost()) || "youtube.com".equals(uri.getHost())) {
+                                                               if ("/watch".equals(uri.getPath())) {
+                                                                       Map<String, List<String>> map = NamingUtils.queryToMap(uri);
+                                                                       videoId = map.get("v").get(0);
+                                                               }
+                                                       } else if ("youtu.be".equals(uri.getHost())) {
+                                                               videoId = uri.getPath().substring(1);
+                                                       }
+                                                       if (videoId != null) {
+                                                               try {
+                                                                       uri = new URI("https://www.youtube.com/embed/" + videoId);
+                                                                       text.setText(uri.toString());
+                                                               } catch (URISyntaxException e1) {
+                                                                       throw new IllegalStateException(e1);
+                                                               }
+                                                       }
+                                               }
+
+                                               // Vimeo
+                                               if ("vimeo.com".equals(uri.getHost())) {
+                                                       videoId = uri.getPath().substring(1);
+                                                       if (videoId != null) {
+                                                               try {
+                                                                       uri = new URI("https://player.vimeo.com/video/" + videoId);
+                                                                       text.setText(uri.toString());
+                                                               } catch (URISyntaxException e1) {
+                                                                       throw new IllegalStateException(e1);
+                                                               }
+                                                       }
+                                               }
+
+                                               videodata.setProperty(DbkAttr.fileref.name(), uri.toString());
+                                               // TODO better integrate it in the edition lifecycle
+                                               videodata.getSession().save();
+                                               load(browser);
+                                       } catch (RepositoryException e1) {
+                                               throw new JcrException("Cannot update " + mediaobject, e1);
+                                       }
+
+                               }
+                       });
+
+                       Button deleteB = new Button(editor, SWT.FLAT);
+                       deleteB.setText("Delete");
+                       deleteB.addSelectionListener(new Selected() {
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       try {
+                                               mediaobject.remove();
+                                               mediaobject.getSession().save();
+                                               dispose();
+                                               getSection().getParent().layout(true, true);
+                                       } catch (RepositoryException e1) {
+                                               throw new JcrException("Cannot update " + mediaobject, e1);
+                                       }
+
+                               }
+                       });
+               }
+
+               // TODO caption
+               return browser;
+       }
+
+       public void load(Control control) {
+               try {
+                       if (control instanceof Browser) {
+                               Browser browser = (Browser) control;
+                               getNode().getSession();
+                               String fileref = DbkUtils.getMediaFileref(getNode());
+                               if (fileref != null) {
+                                       // TODO manage self-hosted videos
+                                       // TODO for YouTube videos, check whether the URL starts with
+                                       // https://www.youtube.com/embed/ and not https://www.youtube.com/watch?v=
+                                       StringBuilder html = new StringBuilder();
+                                       html.append(
+                                                       "<iframe frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"true\"");
+                                       // TODO make size configurable
+                                       html.append("width=\"").append(width).append("\" height=\"").append(height).append("\" ");
+                                       html.append("src=\"").append(fileref).append("\" ");
+                                       html.append("/>");
+                                       browser.setText(html.toString());
+                               }
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot retrieve src for video " + getNode(), e);
+               }
+       }
+
+       @Override
+       protected void setContainerLayoutData(Composite composite) {
+               composite.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, true));
+       }
+
+       @Override
+       protected void setControlLayoutData(Control control) {
+               control.setLayoutData(CmsSwtUtils.fillAll());
+       }
+
+       @Override
+       public Item getItem() throws RepositoryException {
+               return getNode();
+       }
+
+       @Override
+       public String getPartId() {
+               return getNodeId();
+       }
+
+       @Override
+       public Section getSection() {
+               return section;
+       }
+
+       public int getWidth() {
+               return width;
+       }
+
+       public int getHeight() {
+               return height;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DocumentPage.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DocumentPage.java
new file mode 100644 (file)
index 0000000..8aba8b7
--- /dev/null
@@ -0,0 +1,62 @@
+package org.argeo.app.ui.docbook;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.api.cms.CmsEditable;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsLink;
+import org.argeo.cms.ui.viewers.JcrVersionCmsEditable;
+import org.argeo.cms.ui.widgets.ScrolledPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Display the text of the context, and provide an editor if the user can edit.
+ */
+public class DocumentPage implements CmsUiProvider {
+       public final static String WWW = "www";
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+
+               ScrolledPage page = new ScrolledPage(parent, SWT.NONE);
+               page.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               GridData textGd = CmsSwtUtils.fillAll();
+               page.setLayoutData(textGd);
+
+               if (context.isNodeType(DbkType.article.get())) {
+                       CmsEditable cmsEditable = new JcrVersionCmsEditable(context);
+                       if (cmsEditable.canEdit())
+                               new TextEditorHeader(cmsEditable, parent, SWT.NONE).setLayoutData(CmsSwtUtils.fillWidth());
+                       if (!cmsEditable.isEditing())
+                               cmsEditable.startEditing();
+                       new DocumentTextEditor(page, SWT.FLAT, context, cmsEditable);
+               } else {
+                       parent.setBackgroundMode(SWT.INHERIT_NONE);
+                       if (context.getSession().hasPermission(context.getPath(), Session.ACTION_ADD_NODE)) {
+//                             new DocumentTextEditor(page, SWT.FLAT, indexNode, cmsEditable);
+//                             textGd.heightHint = 400;
+
+                               for (NodeIterator ni = context.getNodes(); ni.hasNext();) {
+                                       Node textNode = ni.nextNode();
+                                       if (textNode.isNodeType(NodeType.NT_FOLDER))
+                                               new CmsLink(textNode.getName() + "/", textNode.getPath()).createUi(parent, textNode);
+                               }
+                               for (NodeIterator ni = context.getNodes(); ni.hasNext();) {
+                                       Node textNode = ni.nextNode();
+                                       if (textNode.isNodeType(DbkType.article.get()) && !textNode.getName().equals(WWW))
+                                               new CmsLink(textNode.getName(), textNode.getPath()).createUi(parent, textNode);
+                               }
+                       }
+               }
+               return page;
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DocumentTextEditor.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DocumentTextEditor.java
new file mode 100644 (file)
index 0000000..8f3a10c
--- /dev/null
@@ -0,0 +1,37 @@
+package org.argeo.app.ui.docbook;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsEditable;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.app.docbook.DbkUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.widgets.Composite;
+
+/** Text editor where sections and subsections can be managed by the user. */
+public class DocumentTextEditor extends AbstractDbkViewer {
+       private static final long serialVersionUID = 6049661610883342325L;
+
+       public DocumentTextEditor(Composite parent, int style, Node textNode, CmsEditable cmsEditable) {
+               super(new TextSection(parent, style, textNode), style, cmsEditable);
+//             refresh();
+               getMainSection().setLayoutData(CmsSwtUtils.fillWidth());
+       }
+
+       @Override
+       protected void initModel(Node textNode) throws RepositoryException {
+               if (isFlat()) {
+                       DbkUtils.addParagraph(textNode, "");
+               }
+//             else
+//                     textNode.setProperty(DocBookNames.DBK_TITLE, textNode.getName());
+       }
+
+       @Override
+       protected Boolean isModelInitialized(Node textNode) throws RepositoryException {
+               return textNode.hasNode(DbkType.title.get()) || textNode.hasNode(DbkType.para.get())
+                               || (!isFlat() && textNode.hasNode(DbkType.section.get()));
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/Paragraph.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/Paragraph.java
new file mode 100644 (file)
index 0000000..ef23d96
--- /dev/null
@@ -0,0 +1,51 @@
+package org.argeo.app.ui.docbook;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.app.docbook.DbkType;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.viewers.SectionPart;
+import org.argeo.cms.ui.widgets.EditableText;
+import org.argeo.cms.ui.widgets.TextStyles;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/** An editable paragraph. */
+public class Paragraph extends EditableText implements SectionPart {
+       private static final long serialVersionUID = 3746457776229542887L;
+
+       private final TextSection section;
+
+       public Paragraph(TextSection section, int style, Node node) throws RepositoryException {
+               super(section, style, node);
+               this.section = section;
+               CmsSwtUtils.style(this, DbkType.para.name());
+       }
+
+       public TextSection getSection() {
+               return section;
+       }
+
+       @Override
+       protected Label createLabel(Composite box, String style) {
+               Label lbl = super.createLabel(box, style);
+               CmsSwtUtils.disableMarkupValidation(lbl);
+               return lbl;
+       }
+
+       @Override
+       public String getPartId() {
+               return getNodeId();
+       }
+
+       @Override
+       public Node getItem() throws RepositoryException {
+               return getNode();
+       }
+
+       @Override
+       public String toString() {
+               return "Paragraph #" + getPartId();
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextEditorHeader.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextEditorHeader.java
new file mode 100644 (file)
index 0000000..31251aa
--- /dev/null
@@ -0,0 +1,91 @@
+package org.argeo.app.ui.docbook;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import org.argeo.api.cms.CmsEditable;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.widgets.TextStyles;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+
+/** Adds editing capabilities to a page editing text */
+public class TextEditorHeader implements SelectionListener, Observer {
+       private static final long serialVersionUID = 4186756396045701253L;
+
+       private final CmsEditable cmsEditable;
+       private Button publish;
+
+       private Composite parent;
+       private Composite display;
+       private Object layoutData;
+
+       public TextEditorHeader(CmsEditable cmsEditable, Composite parent, int style) {
+               this.cmsEditable = cmsEditable;
+               this.parent = parent;
+               if (this.cmsEditable instanceof Observable)
+                       ((Observable) this.cmsEditable).addObserver(this);
+               refresh();
+       }
+
+       protected void refresh() {
+               if (display != null && !display.isDisposed())
+                       display.dispose();
+               display = null;
+               publish = null;
+               if (cmsEditable.isEditing()) {
+                       display = new Composite(parent, SWT.NONE);
+                       // display.setBackgroundMode(SWT.INHERIT_NONE);
+                       display.setLayoutData(layoutData);
+                       display.setLayout(CmsSwtUtils.noSpaceGridLayout());
+                       CmsSwtUtils.style(display, TextStyles.TEXT_EDITOR_HEADER);
+                       publish = new Button(display, SWT.FLAT | SWT.PUSH);
+                       publish.setText(getPublishButtonLabel());
+                       CmsSwtUtils.style(publish, TextStyles.TEXT_EDITOR_HEADER);
+                       publish.addSelectionListener(this);
+                       display.moveAbove(null);
+               }
+               parent.layout();
+       }
+
+       private String getPublishButtonLabel() {
+               if (cmsEditable.isEditing())
+                       return "Publish";
+               else
+                       return "Edit";
+       }
+
+       @Override
+       public void widgetSelected(SelectionEvent e) {
+               if (e.getSource() == publish) {
+                       if (cmsEditable.isEditing()) {
+                               cmsEditable.stopEditing();
+                       } else {
+                               cmsEditable.startEditing();
+                       }
+                       // publish.setText(getPublishButtonLabel());
+               }
+       }
+
+       @Override
+       public void widgetDefaultSelected(SelectionEvent e) {
+       }
+
+       @Override
+       public void update(Observable o, Object arg) {
+               if (o == cmsEditable) {
+                       // publish.setText(getPublishButtonLabel());
+                       refresh();
+               }
+       }
+
+       public void setLayoutData(Object layoutData) {
+               this.layoutData = layoutData;
+               if (display != null && !display.isDisposed())
+                       display.setLayoutData(layoutData);
+       }
+
+}
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextInterpreter.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextInterpreter.java
new file mode 100644 (file)
index 0000000..9da2f6f
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.app.ui.docbook;
+
+import javax.jcr.Item;
+
+/** Convert from/to data layer to/from presentation layer. */
+public interface TextInterpreter {
+       String raw(Item item);
+
+       String read(Item item);
+
+       String readSimpleHtml(Item item);
+
+       void write(Item item, String content);
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextSection.java b/org.argeo.app.ui/src/org/argeo/app/ui/docbook/TextSection.java
new file mode 100644 (file)
index 0000000..3967834
--- /dev/null
@@ -0,0 +1,82 @@
+package org.argeo.app.ui.docbook;
+
+import javax.jcr.Node;
+
+import org.argeo.app.docbook.DbkType;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.cms.ui.widgets.TextStyles;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** An editable section. */
+public class TextSection extends Section {
+       private static final long serialVersionUID = -8625209546243220689L;
+       private String defaultTextStyle = DbkType.para.name();
+       private String titleStyle;
+
+       private final boolean flat;
+
+       private boolean titleReadOnly = false;
+
+       private final int level;
+
+       public TextSection(Composite parent, int style, Node node) {
+               this(parent, findSection(parent), style, node);
+       }
+
+       public TextSection(TextSection section, int style, Node node) {
+               this(section, section.getParentSection(), style, node);
+       }
+
+       private TextSection(Composite parent, Section parentSection, int style, Node node) {
+               super(parent, parentSection, style, node);
+               flat = SWT.FLAT == (style & SWT.FLAT);
+               if (parentSection instanceof TextSection) {
+                       level = ((TextSection) parentSection).getLevel() + 1;
+               } else {
+                       level = 0;
+               }
+               CmsSwtUtils.style(this, DbkType.section.name());
+       }
+
+       public String getDefaultTextStyle() {
+               return defaultTextStyle;
+       }
+
+       public boolean isFlat() {
+               return flat;
+       }
+
+       /** The level of this section, similar to h1, h2, etc. in HTML. */
+       public int getLevel() {
+               return level;
+       }
+
+       public String getTitleStyle() {
+               if (titleStyle != null)
+                       return titleStyle;
+               // TODO make base H styles configurable
+//             Integer relativeDepth = getRelativeDepth();
+//             System.out.println("Level: " + getLevel());
+               return "h" + (getLevel() + 1);
+       }
+
+       public void setDefaultTextStyle(String defaultTextStyle) {
+               this.defaultTextStyle = defaultTextStyle;
+       }
+
+       public void setTitleStyle(String titleStyle) {
+               this.titleStyle = titleStyle;
+       }
+
+       public boolean isTitleReadOnly() {
+               return titleReadOnly;
+       }
+
+       public void setTitleReadOnly(boolean titleReadOnly) {
+               this.titleReadOnly = titleReadOnly;
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/forms/AbstractTermsPart.java b/org.argeo.app.ui/src/org/argeo/app/ui/forms/AbstractTermsPart.java
new file mode 100644 (file)
index 0000000..0ce2ed1
--- /dev/null
@@ -0,0 +1,131 @@
+package org.argeo.app.ui.forms;
+
+import javax.jcr.Item;
+
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.app.api.Term;
+import org.argeo.app.api.TermsManager;
+import org.argeo.app.api.Typology;
+import org.argeo.cms.Localized;
+import org.argeo.cms.swt.CmsIcon;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+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 Typology typology;
+
+       private 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);
+               if (item == null)
+                       throw new IllegalArgumentException("Item cannot be null");
+               this.termsManager = termsManager;
+               this.typology = termsManager.getTypology(typology);
+               this.theme = CmsSwtUtils.getCmsTheme(parent);
+               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
+               highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
+       }
+
+       public boolean isEditable() {
+               return editable;
+       }
+
+       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(Term term) {
+               if (term instanceof Localized)
+                       return ((Localized) term).lead();
+               else
+                       return term.getName();
+
+       }
+
+       protected abstract void refresh(ContextOverlay contextArea, String filter, Text txt);
+
+       protected boolean isTermSelectable(Term term) {
+               return true;
+       }
+
+       protected void processTermListLabel(Term term, Label label) {
+
+       }
+
+       protected void setControlLayoutData(Control control) {
+               control.setLayoutData(CmsSwtUtils.fillAll());
+       }
+
+       protected void setContainerLayoutData(Composite composite) {
+               composite.setLayoutData(CmsSwtUtils.fillAll());
+       }
+
+       //
+       // 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.app.ui/src/org/argeo/app/ui/forms/MultiTermsPart.java b/org.argeo.app.ui/src/org/argeo/app/ui/forms/MultiTermsPart.java
new file mode 100644 (file)
index 0000000..4a56b41
--- /dev/null
@@ -0,0 +1,206 @@
+package org.argeo.app.ui.forms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Item;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.app.api.Term;
+import org.argeo.app.api.TermsManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.MouseDoubleClick;
+import org.argeo.cms.swt.MouseDown;
+import org.argeo.cms.swt.Selected;
+import org.argeo.cms.ui.forms.FormStyle;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+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;
+       private final static CmsLog log = CmsLog.getLog(MultiTermsPart.class);
+
+       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);
+
+               boolean vertical = SWT.VERTICAL == (getStyle() & SWT.VERTICAL);
+               RowLayout rl = new RowLayout(vertical ? SWT.VERTICAL : SWT.HORIZONTAL);
+               rl = CmsSwtUtils.noMarginsRowLayout(rl);
+//             rl.wrap = true;
+//             rl.justify = true;
+               placeholder.setLayout(rl);
+               List<Term> currentValue = getValue();
+               if (currentValue != null && !currentValue.isEmpty()) {
+                       for (Term value : currentValue) {
+                               Composite block = new Composite(placeholder, SWT.NONE);
+                               block.setLayout(CmsSwtUtils.noSpaceGridLayout(3));
+                               Label lbl = new Label(block, SWT.NONE);
+                               String display = getTermLabel(value);
+                               lbl.setText(display);
+                               CmsSwtUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
+                               processTermListLabel(value, lbl);
+                               if (isEditable())
+                                       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<Term> curr = getValue();
+                                               List<Term> newValue = new ArrayList<>();
+                                               for (Term v : curr) {
+                                                       if (!v.equals(value))
+                                                               newValue.add(v);
+                                               }
+                                               setValue(newValue);
+                                               block.dispose();
+                                               layout(true, true);
+                                       });
+
+                               }
+                       }
+               } else {// empty
+                       if (isEditable() && !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(CmsSwtUtils.noSpaceGridLayout(3));
+
+                       createHighlight(block);
+
+                       Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
+                       txt.setLayoutData(CmsSwtUtils.fillWidth());
+//                     txt.setMessage("[new]");
+
+                       CmsSwtUtils.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) {
+               CmsSwtUtils.clear(contextArea);
+               List<? extends Term> terms = termsManager.listAllTerms(typology.getId());
+               List<Term> currentValue = getValue();
+               terms: for (Term 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<Term> newValue = new ArrayList<>();
+                                       List<Term> curr = getValue();
+                                       if (currentValue != null)
+                                               newValue.addAll(curr);
+                                       newValue.add(term);
+                                       setValue(newValue);
+                                       contextArea.hide();
+                                       stopEditing();
+                               });
+               }
+               contextArea.show();
+       }
+
+       protected List<Term> getValue() {
+               String property = typology.getId();
+               List<String> curr = Jcr.getMultiple(getNode(), property);
+               List<Term> res = new ArrayList<>();
+               if (curr != null)
+                       terms: for (String str : curr) {
+                               Term term = termsManager.getTerm(str);
+                               if (term == null) {
+                                       log.warn("Ignoring term " + str + " for " + getNode() + ", as it was not found.");
+                                       continue terms;
+                               }
+                               res.add(term);
+                       }
+               return res;
+       }
+
+       protected void setValue(List<Term> value) {
+               String property = typology.getId();
+               List<String> ids = new ArrayList<>();
+               for (Term term : value) {
+                       ids.add(term.getId());
+               }
+               Jcr.set(getNode(), property, ids);
+               Jcr.save(getNode());
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/forms/SingleTermPart.java b/org.argeo.app.ui/src/org/argeo/app/ui/forms/SingleTermPart.java
new file mode 100644 (file)
index 0000000..4a5aa8d
--- /dev/null
@@ -0,0 +1,159 @@
+package org.argeo.app.ui.forms;
+
+import java.util.List;
+
+import javax.jcr.Item;
+
+import org.argeo.app.api.Term;
+import org.argeo.app.api.TermsManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.MouseDoubleClick;
+import org.argeo.cms.swt.MouseDown;
+import org.argeo.cms.swt.Selected;
+import org.argeo.cms.ui.forms.FormStyle;
+import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.ui.widgets.ContextOverlay;
+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(CmsSwtUtils.noSpaceGridLayout(3));
+
+                       createHighlight(block);
+
+                       Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
+                       CmsSwtUtils.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) -> {
+                               setValue(null);
+                               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(CmsSwtUtils.noSpaceGridLayout(2));
+                       Term currentValue = getValue();
+                       if (currentValue != null) {
+                               Label lbl = new Label(block, SWT.SINGLE);
+                               String display = getTermLabel(currentValue);
+                               lbl.setText(display);
+                               CmsSwtUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
+                               processTermListLabel(currentValue, lbl);
+                               if (isEditable()) {
+                                       lbl.addMouseListener((MouseDoubleClick) (e) -> {
+                                               startEditing();
+                                       });
+                               }
+                       } else {
+                               if (isEditable()) {
+                                       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) {
+               CmsSwtUtils.clear(contextArea);
+               List<? extends Term> terms = termsManager.listAllTerms(typology.getId());
+               terms: for (Term 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) -> {
+                                       setValue(term);
+                                       contextArea.hide();
+                                       stopEditing();
+                               });
+               }
+               contextArea.show();
+               // txt.setFocus();
+       }
+
+       protected Term getValue() {
+               String property = typology.getId();
+               String id = Jcr.get(getNode(), property);
+               Term term = termsManager.getTerm(id);
+
+               return term;
+       }
+
+       protected void setValue(Term value) {
+               String property = typology.getId();
+               Jcr.set(getNode(), property, value != null ? value.getId() : null);
+               Jcr.save(getNode());
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/library/ContentEntryArea.java b/org.argeo.app.ui/src/org/argeo/app/ui/library/ContentEntryArea.java
new file mode 100644 (file)
index 0000000..af31ac5
--- /dev/null
@@ -0,0 +1,169 @@
+package org.argeo.app.ui.library;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.query.Query;
+
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.ui.SuiteEvent;
+import org.argeo.app.ui.SuiteIcon;
+import org.argeo.app.ui.widgets.TreeOrSearchArea;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+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.ITreeContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+public class ContentEntryArea implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
+
+               parent.setLayout(new GridLayout());
+               Ui ui = new Ui(parent, SWT.NONE);
+               ui.setLayoutData(CmsSwtUtils.fillAll());
+
+               TreeViewerColumn nameCol = new TreeViewerColumn(ui.getTreeViewer(), SWT.NONE);
+               nameCol.getColumn().setWidth(400);
+               nameCol.setLabelProvider(new ColumnLabelProvider() {
+
+                       @Override
+                       public String getText(Object element) {
+                               Node node = (Node) element;
+                               return Jcr.getTitle(node);
+                       }
+
+                       @Override
+                       public Image getImage(Object element) {
+                               Node node = (Node) element;
+                               Image icon;
+                               if (Jcr.isNodeType(node, NodeType.NT_FOLDER)) {
+                                       icon = SuiteIcon.folder.getSmallIcon(theme);
+                               } else if (Jcr.isNodeType(node, NodeType.NT_FILE)) {
+                                       // TODO check recognized document types
+                                       icon = SuiteIcon.document.getSmallIcon(theme);
+                               } else if (Jcr.isNodeType(node, EntityType.document.get())) {
+                                       icon = SuiteIcon.document.getSmallIcon(theme);
+                               } else {
+                                       if (!isLeaf(node))
+                                               icon = SuiteIcon.folder.getSmallIcon(theme);
+                                       else
+                                               icon = null;
+                               }
+                               return icon;
+                       }
+
+               });
+
+               ui.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
+
+                       @Override
+                       public void doubleClick(DoubleClickEvent event) {
+                               Node user = (Node) ui.getTreeViewer().getStructuredSelection().getFirstElement();
+                               if (user != null) {
+                                       CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
+                                                       SuiteEvent.eventProperties(user));
+                               }
+
+                       }
+               });
+               ui.getTreeViewer().addSelectionChangedListener(new ISelectionChangedListener() {
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               Node user = (Node) ui.getTreeViewer().getStructuredSelection().getFirstElement();
+                               if (user != null) {
+                                       CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
+                                                       SuiteEvent.eventProperties(user));
+                               }
+                       }
+               });
+
+               ui.getTreeViewer().setContentProvider(new SpacesContentProvider());
+               ui.getTreeViewer().setInput(context.getSession());
+               return ui;
+       }
+
+       protected boolean isLeaf(Node node) {
+               return Jcr.isNodeType(node, EntityType.entity.get()) || Jcr.isNodeType(node, EntityType.document.get())
+                               || Jcr.isNodeType(node, NodeType.NT_FILE);
+       }
+
+       class Ui extends TreeOrSearchArea {
+
+               public Ui(Composite parent, int style) {
+                       super(parent, style);
+               }
+
+       }
+
+       class SpacesContentProvider implements ITreeContentProvider {
+
+               @Override
+               public Object[] getElements(Object inputElement) {
+                       Session session = (Session) inputElement;
+                       try {
+                               Query query = session.getWorkspace().getQueryManager()
+                                               .createQuery("SELECT * FROM [" + EntityType.space.get() + "]", Query.JCR_SQL2);
+                               NodeIterator spacesIt = query.execute().getNodes();
+                               SortedMap<String, Node> map = new TreeMap<>();
+                               while (spacesIt.hasNext()) {
+                                       Node space = spacesIt.nextNode();
+                                       String path = space.getPath();
+                                       map.put(path, space);
+                               }
+                               return map.values().toArray();
+                       } catch (RepositoryException e) {
+                               throw new JcrException(e);
+                       }
+               }
+
+               @Override
+               public Object[] getChildren(Object parentElement) {
+                       Node parent = (Node) parentElement;
+                       if (isLeaf(parent))
+                               return null;
+                       return Jcr.getNodes(parent).toArray();
+               }
+
+               @Override
+               public Object getParent(Object element) {
+                       Node node = (Node) element;
+                       return Jcr.getParent(node);
+               }
+
+               @Override
+               public boolean hasChildren(Object element) {
+                       Node node = (Node) element;
+                       return !isLeaf(node);
+               }
+
+               @Override
+               public void dispose() {
+               }
+
+               @Override
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+               }
+
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsContextMenu.java b/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsContextMenu.java
new file mode 100644 (file)
index 0000000..82a21c1
--- /dev/null
@@ -0,0 +1,177 @@
+package org.argeo.app.ui.library;
+
+import static org.argeo.app.ui.library.DocumentsUiService.ACTION_ID_BOOKMARK_FOLDER;
+import static org.argeo.app.ui.library.DocumentsUiService.ACTION_ID_CREATE_FOLDER;
+import static org.argeo.app.ui.library.DocumentsUiService.ACTION_ID_DELETE;
+import static org.argeo.app.ui.library.DocumentsUiService.ACTION_ID_DOWNLOAD_FOLDER;
+import static org.argeo.app.ui.library.DocumentsUiService.ACTION_ID_RENAME;
+import static org.argeo.app.ui.library.DocumentsUiService.ACTION_ID_SHARE_FOLDER;
+import static org.argeo.app.ui.library.DocumentsUiService.ACTION_ID_UPLOAD_FILE;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.argeo.app.ui.widgets.AbstractConnectContextMenu;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+
+/** Generic popup context menu to manage NIO Path in a Viewer. */
+public class DocumentsContextMenu extends AbstractConnectContextMenu {
+       // Local context
+       private final DocumentsFolderComposite browser;
+       private final DocumentsUiService uiService;
+//     private final Repository repository;
+
+       private final static String[] DEFAULT_ACTIONS = { ACTION_ID_CREATE_FOLDER, ACTION_ID_BOOKMARK_FOLDER,
+                       ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_RENAME,
+                       ACTION_ID_DELETE };
+
+       private Path currFolderPath;
+
+       public DocumentsContextMenu(DocumentsFolderComposite browser,
+                       DocumentsUiService documentsUiService) {
+               super(browser.getDisplay(), DEFAULT_ACTIONS);
+               this.browser = browser;
+               this.uiService = documentsUiService;
+//             this.repository = repository;
+
+               createControl();
+       }
+
+       public void setCurrFolderPath(Path currFolderPath) {
+               this.currFolderPath = currFolderPath;
+       }
+
+       protected boolean aboutToShow(Control source, Point location, IStructuredSelection selection) {
+               boolean emptySel = true;
+               boolean multiSel = false;
+               boolean isFolder = true;
+               if (selection != null && !selection.isEmpty()) {
+                       emptySel = false;
+                       multiSel = selection.size() > 1;
+                       if (!multiSel && selection.getFirstElement() instanceof Path) {
+                               isFolder = Files.isDirectory((Path) selection.getFirstElement());
+                       }
+               }
+               if (emptySel) {
+                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_BOOKMARK_FOLDER);
+                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_RENAME, ACTION_ID_DELETE
+                               );
+               } else if (multiSel) {
+                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_DELETE,
+                                       ACTION_ID_BOOKMARK_FOLDER);
+                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_RENAME);
+               } else if (isFolder) {
+                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_RENAME, ACTION_ID_DELETE,
+                                       ACTION_ID_BOOKMARK_FOLDER);
+                       setVisible(false, 
+                                       // to be implemented
+                                       ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER);
+               } else {
+                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_RENAME,
+                                       ACTION_ID_DELETE);
+                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_BOOKMARK_FOLDER);
+               }
+               return true;
+       }
+
+       public void show(Control source, Point location, IStructuredSelection selection, Path currFolderPath) {
+               // TODO find a better way to retrieve the parent path (cannot be deduced
+               // from table content because it will fail on an empty folder)
+               this.currFolderPath = currFolderPath;
+               super.show(source, location, selection);
+
+       }
+
+       @Override
+       protected boolean performAction(String actionId) {
+               switch (actionId) {
+               case ACTION_ID_CREATE_FOLDER:
+                       createFolder();
+                       break;
+               case ACTION_ID_BOOKMARK_FOLDER:
+                       bookmarkFolder();
+                       break;
+               case ACTION_ID_RENAME:
+                       renameItem();
+                       break;
+               case ACTION_ID_DELETE:
+                       deleteItems();
+                       break;
+//             case ACTION_ID_OPEN:
+//                     openFile();
+//                     break;
+               case ACTION_ID_UPLOAD_FILE:
+                       uploadFiles();
+                       break;
+               default:
+                       throw new IllegalArgumentException("Unimplemented action " + actionId);
+                       // case ACTION_ID_SHARE_FOLDER:
+                       // return "Share Folder";
+                       // case ACTION_ID_DOWNLOAD_FOLDER:
+                       // return "Download as zip archive";
+               }
+               browser.setFocus();
+               return false;
+       }
+
+       @Override
+       protected String getLabel(String actionId) {
+               return uiService.getLabel(actionId);
+       }
+
+       private void openFile() {
+               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
+               if (selection.isEmpty() || selection.size() > 1)
+                       // Should never happen
+                       return;
+               Path toOpenPath = ((Path) selection.getFirstElement());
+               uiService.openFile(toOpenPath);
+       }
+
+       private void deleteItems() {
+               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
+               if (selection.isEmpty())
+                       return;
+               else if (uiService.deleteItems(getParentShell(), selection))
+                       browser.refresh();
+       }
+
+       private void renameItem() {
+               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
+               if (selection.isEmpty() || selection.size() > 1)
+                       // Should never happen
+                       return;
+               Path toRenamePath = ((Path) selection.getFirstElement());
+               if (uiService.renameItem(getParentShell(), currFolderPath, toRenamePath))
+                       browser.refresh();
+       }
+
+       private void createFolder() {
+               if (uiService.createFolder(getParentShell(), currFolderPath))
+                       browser.refresh();
+       }
+
+       private void bookmarkFolder() {
+               Path toBookmarkPath = null;
+               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
+               if (selection.isEmpty())
+                       toBookmarkPath = currFolderPath;
+               else if (selection.size() > 1)
+                       toBookmarkPath = currFolderPath;
+               else if (selection.size() == 1) {
+                       Path currSelected = ((Path) selection.getFirstElement());
+                       if (Files.isDirectory(currSelected))
+                               toBookmarkPath = currSelected;
+                       else
+                               return;
+               }
+               //uiService.bookmarkFolder(toBookmarkPath, repository, null);
+       }
+
+       private void uploadFiles() {
+               if (uiService.uploadFiles(getParentShell(), currFolderPath))
+                       browser.refresh();
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFileComposite.java b/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFileComposite.java
new file mode 100644 (file)
index 0000000..d4b70bb
--- /dev/null
@@ -0,0 +1,118 @@
+package org.argeo.app.ui.library;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.spi.FileSystemProvider;
+
+import javax.jcr.Node;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.fs.CmsFsUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.fs.FsUiUtils;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * Default Documents file composite: a sashForm with a browser in the middle and
+ * meta data at right hand side.
+ */
+public class DocumentsFileComposite extends Composite {
+       private static final long serialVersionUID = -7567632342889241793L;
+
+       private final static CmsLog log = CmsLog.getLog(DocumentsFileComposite.class);
+
+       private final Node currentBaseContext;
+
+       // UI Parts for the browser
+       private Composite rightPannelCmp;
+
+       public DocumentsFileComposite(Composite parent, int style, Node context, FileSystemProvider fsp) {
+               super(parent, style);
+               this.currentBaseContext = context;
+               this.setLayout(EclipseUiUtils.noSpaceGridLayout());
+               SashForm form = new SashForm(this, SWT.HORIZONTAL);
+
+               Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
+               createDisplay(centerCmp);
+
+               rightPannelCmp = new Composite(form, SWT.NO_FOCUS);
+
+               Path path = CmsFsUtils.getPath(fsp, context);
+               setOverviewInput(path);
+               form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               form.setWeights(new int[] { 55, 20 });
+       }
+
+       private void createDisplay(final Composite parent) {
+               parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+               Browser browser = new Browser(parent, SWT.NONE);
+               // browser.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true,
+               // true));
+               browser.setLayoutData(EclipseUiUtils.fillAll());
+               // FIXME make it more robust
+               String url = CmsUiUtils.getDataUrl(currentBaseContext, UiContext.getHttpRequest());
+               // FIXME issue with the redirection to https
+               if (url.startsWith("http://") && !url.startsWith("http://localhost"))
+                       url = "https://" + url.substring("http://".length(), url.length());
+               if (log.isTraceEnabled())
+                       log.debug("Trying to display " + url);
+               browser.setUrl(url);
+               browser.layout(true, true);
+       }
+
+       /**
+        * Recreates the content of the box that displays information about the current
+        * selected Path.
+        */
+       private void setOverviewInput(Path path) {
+               try {
+                       EclipseUiUtils.clear(rightPannelCmp);
+                       rightPannelCmp.setLayout(new GridLayout());
+                       if (path != null) {
+                               // if (isImg(context)) {
+                               // EditableImage image = new Img(parent, RIGHT, context,
+                               // imageWidth);
+                               // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
+                               // true, false,
+                               // 2, 1));
+                               // }
+
+                               Label contextL = new Label(rightPannelCmp, SWT.NONE);
+                               contextL.setText(path.getFileName().toString());
+                               contextL.setFont(EclipseUiUtils.getBoldFont(rightPannelCmp));
+                               addProperty(rightPannelCmp, "Last modified", Files.getLastModifiedTime(path).toString());
+                               // addProperty(rightPannelCmp, "Owner",
+                               // Files.getOwner(path).getName());
+                               if (Files.isDirectory(path)) {
+                                       addProperty(rightPannelCmp, "Type", "Folder");
+                               } else {
+                                       String mimeType = Files.probeContentType(path);
+                                       if (EclipseUiUtils.isEmpty(mimeType))
+                                               mimeType = "<i>Unknown</i>";
+                                       addProperty(rightPannelCmp, "Type", mimeType);
+                                       addProperty(rightPannelCmp, "Size", FsUiUtils.humanReadableByteCount(Files.size(path), false));
+                               }
+                       }
+                       rightPannelCmp.layout(true, true);
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot display details for " + path.toString(), e);
+               }
+       }
+
+       // Simplify UI implementation
+       private void addProperty(Composite parent, String propName, String value) {
+               Label propLbl = new Label(parent, SWT.NONE);
+               // propLbl.setText(ConnectUtils.replaceAmpersand(propName + ": " + value));
+               propLbl.setText(value);
+               // CmsUiUtils.markup(propLbl);
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFolderComposite.java b/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFolderComposite.java
new file mode 100644 (file)
index 0000000..58ceed6
--- /dev/null
@@ -0,0 +1,454 @@
+package org.argeo.app.ui.library;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.fs.FileDrop;
+import org.argeo.cms.ui.fs.FsStyles;
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider;
+import org.argeo.eclipse.ui.fs.FsTableViewer;
+import org.argeo.eclipse.ui.fs.FsUiConstants;
+import org.argeo.eclipse.ui.fs.FsUiUtils;
+import org.argeo.eclipse.ui.fs.NioFileLabelProvider;
+import org.argeo.eclipse.ui.fs.ParentDir;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Default Documents folder composite: a sashForm layout with a simple table in
+ * the middle and an overview at right hand side.
+ */
+public class DocumentsFolderComposite extends Composite {
+       private final static CmsLog log = CmsLog.getLog(DocumentsFolderComposite.class);
+       private static final long serialVersionUID = -40347919096946585L;
+
+       private final Node currentBaseContext;
+
+       private final DocumentsUiService documentUiService = new DocumentsUiService();
+
+       // UI Parts for the browser
+       private Composite filterCmp;
+       private Composite breadCrumbCmp;
+       private Text filterTxt;
+       private FsTableViewer directoryDisplayViewer;
+       private Composite rightPanelCmp;
+
+       private DocumentsContextMenu contextMenu;
+       private DateFormat dateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm");
+
+       // Local context
+       private Path initialPath;
+       private Path currentFolder;
+
+       public DocumentsFolderComposite(Composite parent, int style, Node context) {
+               super(parent, style);
+               this.currentBaseContext = context;
+
+               this.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+               SashForm form = new SashForm(this, SWT.HORIZONTAL);
+
+               Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
+               createDisplay(centerCmp);
+
+               rightPanelCmp = new Composite(form, SWT.NO_FOCUS);
+
+               form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               form.setWeights(new int[] { 55, 20 });
+       }
+
+       public void populate(Path path) {
+               initialPath = path;
+               directoryDisplayViewer.setInitialPath(initialPath);
+               setInput(path);
+       }
+
+       void refresh() {
+               modifyFilter(false);
+       }
+
+       private void createDisplay(final Composite parent) {
+               parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+               // top filter
+               filterCmp = new Composite(parent, SWT.NO_FOCUS);
+               filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
+               RowLayout rl = new RowLayout(SWT.HORIZONTAL);
+               rl.wrap = true;
+               rl.center = true;
+               filterCmp.setLayout(rl);
+               // addFilterPanel(filterCmp);
+
+               // Main display
+               directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
+               List<ColumnDefinition> colDefs = new ArrayList<>();
+               colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), " Name", 250));
+               colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100));
+//             colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 150));
+               colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
+                               "Last modified", 400));
+               final Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
+               table.setLayoutData(EclipseUiUtils.fillAll());
+
+               directoryDisplayViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+                       @Override
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+                               Path selected = null;
+                               if (selection.isEmpty())
+                                       setSelected(null);
+                               else {
+                                       Object o = selection.getFirstElement();
+                                       if (o instanceof Path)
+                                               selected = (Path) o;
+                                       else if (o instanceof ParentDir)
+                                               selected = ((ParentDir) o).getPath();
+                               }
+                               if (selected != null) {
+                                       // TODO manage multiple selection
+                                       setSelected(selected);
+                               }
+                       }
+               });
+
+               directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
+                       @Override
+                       public void doubleClick(DoubleClickEvent event) {
+                               IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+                               Path selected = null;
+                               if (!selection.isEmpty()) {
+                                       Object o = selection.getFirstElement();
+                                       if (o instanceof Path)
+                                               selected = (Path) o;
+                                       else if (o instanceof ParentDir)
+                                               selected = ((ParentDir) o).getPath();
+                               }
+                               if (selected != null) {
+                                       if (Files.isDirectory(selected))
+                                               setInput(selected);
+                                       else
+                                               externalNavigateTo(selected);
+                               }
+                       }
+               });
+
+               // The context menu
+               contextMenu = new DocumentsContextMenu(this,  documentUiService);
+
+               table.addMouseListener(new MouseAdapter() {
+                       private static final long serialVersionUID = 6737579410648595940L;
+
+                       @Override
+                       public void mouseDown(MouseEvent e) {
+                               if (e.button == 3) {
+                                       // contextMenu.setCurrFolderPath(currDisplayedFolder);
+                                       contextMenu.show(table, new Point(e.x, e.y),
+                                                       (IStructuredSelection) directoryDisplayViewer.getSelection(), currentFolder);
+                               }
+                       }
+               });
+
+               FileDrop fileDrop = new FileDrop() {
+
+                       @Override
+                       protected void processFileUpload(InputStream in, String fileName, String contetnType) throws IOException {
+                               Path file = currentFolder.resolve(fileName);
+                               Files.copy(in, file);
+                               refresh();
+                       }
+               };
+               fileDrop.createDropTarget(directoryDisplayViewer.getTable());
+       }
+
+       /**
+        * Overwrite to enable single sourcing between workbench and CMS navigation
+        */
+       protected void externalNavigateTo(Path path) {
+
+       }
+
+       private void addPathElementBtn(Path path) {
+               Button elemBtn = new Button(breadCrumbCmp, SWT.PUSH);
+               String nameStr;
+               if (path.toString().equals("/"))
+                       nameStr = "[jcr:root]";
+               else
+                       nameStr = path.getFileName().toString();
+//             elemBtn.setText(nameStr + " >> ");
+               elemBtn.setText(nameStr);
+               CmsSwtUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN);
+               elemBtn.addSelectionListener(new SelectionAdapter() {
+                       private static final long serialVersionUID = -4103695476023480651L;
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               setInput(path);
+                       }
+               });
+       }
+
+       public void setInput(Path path) {
+               if (path.equals(currentFolder))
+                       return;
+               // below initial path
+               if (!initialPath.equals(path) && initialPath.startsWith(path))
+                       return;
+               currentFolder = path;
+
+               Path diff = initialPath.relativize(currentFolder);
+
+               for (Control child : filterCmp.getChildren())
+                       if (!child.equals(filterTxt))
+                               child.dispose();
+
+               // Bread crumbs
+               breadCrumbCmp = new Composite(filterCmp, SWT.NO_FOCUS);
+               CmsSwtUtils.style(breadCrumbCmp, FsStyles.BREAD_CRUMB_BTN);
+               RowLayout breadCrumbLayout = new RowLayout();
+               breadCrumbLayout.spacing = 0;
+               breadCrumbLayout.marginTop = 0;
+               breadCrumbLayout.marginBottom = 0;
+               breadCrumbLayout.marginRight = 0;
+               breadCrumbLayout.marginLeft = 0;
+               breadCrumbCmp.setLayout(breadCrumbLayout);
+               addPathElementBtn(initialPath);
+               Path currTarget = initialPath;
+               if (!diff.toString().equals(""))
+                       for (Path pathElem : diff) {
+                               currTarget = currTarget.resolve(pathElem);
+                               addPathElementBtn(currTarget);
+                       }
+
+               if (filterTxt != null) {
+                       filterTxt.setText("");
+                       filterTxt.moveBelow(null);
+               } else {
+                       modifyFilter(false);
+               }
+               setSelected(null);
+               filterCmp.getParent().layout(true, true);
+       }
+
+       private void setSelected(Path path) {
+               if (path == null)
+                       setOverviewInput(currentFolder);
+               else
+                       setOverviewInput(path);
+       }
+
+       public Viewer getViewer() {
+               return directoryDisplayViewer;
+       }
+
+       /**
+        * Recreates the content of the box that displays information about the current
+        * selected Path.
+        */
+       private void setOverviewInput(Path path) {
+               try {
+                       EclipseUiUtils.clear(rightPanelCmp);
+                       rightPanelCmp.setLayout(new GridLayout());
+                       if (path != null) {
+                               // if (isImg(context)) {
+                               // EditableImage image = new Img(parent, RIGHT, context,
+                               // imageWidth);
+                               // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
+                               // true, false,
+                               // 2, 1));
+                               // }
+
+                               Label contextL = new Label(rightPanelCmp, SWT.NONE);
+                               contextL.setText(path.getFileName().toString());
+                               contextL.setFont(EclipseUiUtils.getBoldFont(rightPanelCmp));
+                               FileTime lastModified = Files.getLastModifiedTime(path);
+                               if (lastModified.toMillis() != 0)
+                                       try {
+                                               String lastModifiedStr = dateFormat.format(new Date(lastModified.toMillis()));
+                                               addProperty(rightPanelCmp, "Last modified", lastModifiedStr);
+                                       } catch (Exception e) {
+                                               log.error("Workarounded issue while getting last update date for " + path, e);
+                                               addProperty(rightPanelCmp, "Last modified", "-");
+                                       }
+                               // addProperty(rightPannelCmp, "Owner",
+                               // Files.getOwner(path).getName());
+                               if (Files.isDirectory(path)) {
+                                       addProperty(rightPanelCmp, "Type", "Folder");
+                               } else {
+                                       String mimeType = Files.probeContentType(path);
+                                       if (EclipseUiUtils.isEmpty(mimeType))
+                                               mimeType = "<i>Unknown</i>";
+                                       addProperty(rightPanelCmp, "Type", mimeType);
+                                       addProperty(rightPanelCmp, "Size", FsUiUtils.humanReadableByteCount(Files.size(path), false));
+                               }
+
+                               // read all attributes
+//                             Map<String, Object> attrs = Files.readAttributes(path, "*");
+//                             for (String attr : attrs.keySet()) {
+//                                     Object value = attrs.get(attr);
+//                                     String str;
+//                                     if (value instanceof Calendar) {
+//                                             str = dateFormat.format(((Calendar) value).getTime());
+//                                     } else {
+//                                             str = value.toString();
+//                                     }
+//                                     addProperty(rightPanelCmp, attr, str);
+//
+//                             }
+                       }
+                       rightPanelCmp.layout(true, true);
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot display details for " + path.toString(), e);
+               }
+       }
+
+       private void addFilterPanel(Composite parent) {
+               // parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
+               // false)));
+
+               filterTxt = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL);
+               filterTxt.setMessage("Search current folder");
+               filterTxt.setLayoutData(new RowData(250, SWT.DEFAULT));
+               filterTxt.addModifyListener(new ModifyListener() {
+                       private static final long serialVersionUID = 1L;
+
+                       public void modifyText(ModifyEvent event) {
+                               modifyFilter(false);
+                       }
+               });
+               filterTxt.addKeyListener(new KeyListener() {
+                       private static final long serialVersionUID = 2533535233583035527L;
+
+                       @Override
+                       public void keyReleased(KeyEvent e) {
+                       }
+
+                       @Override
+                       public void keyPressed(KeyEvent e) {
+                               // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
+                               // // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
+                               // FilterEntitiesVirtualTable currTable = null;
+                               // if (currEdited != null) {
+                               // FilterEntitiesVirtualTable table =
+                               // browserCols.get(currEdited);
+                               // if (table != null && !table.isDisposed())
+                               // currTable = table;
+                               // }
+                               //
+                               // if (e.keyCode == SWT.ARROW_DOWN)
+                               // currTable.setFocus();
+                               // else if (e.keyCode == SWT.BS) {
+                               // if (filterTxt.getText().equals("")
+                               // && !(currEdited.getNameCount() == 1 ||
+                               // currEdited.equals(initialPath))) {
+                               // Path oldEdited = currEdited;
+                               // Path parentPath = currEdited.getParent();
+                               // setEdited(parentPath);
+                               // if (browserCols.containsKey(parentPath))
+                               // browserCols.get(parentPath).setSelected(oldEdited);
+                               // filterTxt.setFocus();
+                               // e.doit = false;
+                               // }
+                               // } else if (e.keyCode == SWT.TAB && !shiftPressed) {
+                               // Path uniqueChild = getOnlyChild(currEdited,
+                               // filterTxt.getText());
+                               // if (uniqueChild != null) {
+                               // // Highlight the unique chosen child
+                               // currTable.setSelected(uniqueChild);
+                               // setEdited(uniqueChild);
+                               // }
+                               // filterTxt.setFocus();
+                               // e.doit = false;
+                               // }
+                       }
+               });
+       }
+
+       // private Path getOnlyChild(Path parent, String filter) {
+       // try (DirectoryStream<Path> stream =
+       // Files.newDirectoryStream(currDisplayedFolder, filter + "*")) {
+       // Path uniqueChild = null;
+       // boolean moreThanOne = false;
+       // loop: for (Path entry : stream) {
+       // if (uniqueChild == null) {
+       // uniqueChild = entry;
+       // } else {
+       // moreThanOne = true;
+       // break loop;
+       // }
+       // }
+       // if (!moreThanOne)
+       // return uniqueChild;
+       // return null;
+       // } catch (IOException ioe) {
+       // throw new DocumentsException(
+       // "Unable to determine unique child existence and get it under " + parent +
+       // " with filter " + filter,
+       // ioe);
+       // }
+       // }
+
+       private void modifyFilter(boolean fromOutside) {
+               if (!fromOutside)
+                       if (currentFolder != null) {
+                               String filter;
+                               if (filterTxt != null)
+                                       filter = filterTxt.getText() + "*";
+                               else
+                                       filter = "*";
+                               directoryDisplayViewer.setInput(currentFolder, filter);
+                       }
+       }
+
+       // Simplify UI implementation
+       private void addProperty(Composite parent, String propName, String value) {
+               Label propLbl = new Label(parent, SWT.NONE);
+               //propLbl.setText(ConnectUtils.replaceAmpersand(propName + ": " + value));
+               propLbl.setText(value);
+               //CmsUiUtils.markup(propLbl);
+       }
+
+       public Path getCurrentFolder() {
+               return currentFolder;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFolderUiProvider.java b/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsFolderUiProvider.java
new file mode 100644 (file)
index 0000000..781b862
--- /dev/null
@@ -0,0 +1,44 @@
+package org.argeo.app.ui.library;
+
+import java.nio.file.Path;
+import java.nio.file.spi.FileSystemProvider;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsView;
+import org.argeo.app.ui.SuiteEvent;
+import org.argeo.cms.fs.CmsFsUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** UI provider of a document folder. */
+public class DocumentsFolderUiProvider implements CmsUiProvider {
+       private FileSystemProvider nodeFileSystemProvider;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
+               DocumentsFolderComposite dfc = new DocumentsFolderComposite(parent, SWT.NONE, context) {
+
+                       @Override
+                       protected void externalNavigateTo(Path path) {
+                               Node folderNode = cmsView.doAs(() -> CmsFsUtils.getNode(Jcr.getSession(context).getRepository(), path));
+                               parent.addDisposeListener((e1) -> Jcr.logout(folderNode));
+                               cmsView.sendEvent(SuiteEvent.openNewPart.topic(), SuiteEvent.eventProperties(folderNode));
+                       }
+               };
+               dfc.setLayoutData(CmsSwtUtils.fillAll());
+               dfc.populate(cmsView.doAs(() -> CmsFsUtils.getPath(nodeFileSystemProvider, context)));
+               return dfc;
+       }
+
+       public void setNodeFileSystemProvider(FileSystemProvider nodeFileSystemProvider) {
+               this.nodeFileSystemProvider = nodeFileSystemProvider;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsTreeUiProvider.java b/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsTreeUiProvider.java
new file mode 100644 (file)
index 0000000..1c82396
--- /dev/null
@@ -0,0 +1,80 @@
+package org.argeo.app.ui.library;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.spi.FileSystemProvider;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsView;
+import org.argeo.app.ui.SuiteEvent;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.fs.CmsFsUtils;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.eclipse.ui.fs.FsTreeViewer;
+import org.argeo.jcr.Jcr;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Tree view of a user root folders. */
+public class DocumentsTreeUiProvider implements CmsUiProvider {
+       private FileSystemProvider nodeFileSystemProvider;
+       private Repository repository;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               parent.setLayout(new GridLayout());
+               FsTreeViewer fsTreeViewer = new FsTreeViewer(parent, SWT.NONE);
+               fsTreeViewer.configureDefaultSingleColumnTable(500);
+               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
+               Node homeNode = CmsJcrUtils.getUserHome(cmsView.doAs(() -> Jcr.login(repository, CmsConstants.HOME_WORKSPACE)));
+               parent.addDisposeListener((e1) -> Jcr.logout(homeNode));
+               Path homePath = CmsFsUtils.getPath(nodeFileSystemProvider, homeNode);
+               fsTreeViewer.addSelectionChangedListener((e) -> {
+                       IStructuredSelection selection = (IStructuredSelection) fsTreeViewer.getSelection();
+                       if (selection.isEmpty())
+                               return;
+                       else {
+                               Path newSelected = (Path) selection.getFirstElement();
+                               if (Files.isDirectory(newSelected)) {
+                                       Node folderNode = cmsView.doAs(() -> CmsFsUtils.getNode(repository, newSelected));
+                                       parent.addDisposeListener((e1) -> Jcr.logout(folderNode));
+                                       cmsView.sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(folderNode));
+                               }
+                       }
+               });
+               fsTreeViewer.addDoubleClickListener((e) -> {
+                       IStructuredSelection selection = (IStructuredSelection) fsTreeViewer.getSelection();
+                       if (selection.isEmpty())
+                               return;
+                       else {
+                               Path newSelected = (Path) selection.getFirstElement();
+                               if (Files.isDirectory(newSelected)) {
+                                       Node folderNode = cmsView.doAs(() -> CmsFsUtils.getNode(repository, newSelected));
+                                       parent.addDisposeListener((e1) -> Jcr.logout(folderNode));
+                                       cmsView.sendEvent(SuiteEvent.openNewPart.topic(), SuiteEvent.eventProperties(folderNode));
+                               }
+                       }
+               });
+               fsTreeViewer.setPathsInput(homePath);
+               fsTreeViewer.getControl().setLayoutData(CmsSwtUtils.fillAll());
+               fsTreeViewer.getControl().getParent().layout(true, true);
+               return fsTreeViewer.getControl();
+       }
+
+       public void setNodeFileSystemProvider(FileSystemProvider nodeFileSystemProvider) {
+               this.nodeFileSystemProvider = nodeFileSystemProvider;
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsUiService.java b/org.argeo.app.ui/src/org/argeo/app/ui/library/DocumentsUiService.java
new file mode 100644 (file)
index 0000000..6cbe4ae
--- /dev/null
@@ -0,0 +1,308 @@
+package org.argeo.app.ui.library;
+
+import static org.argeo.cms.swt.dialogs.CmsMessageDialog.openConfirm;
+import static org.argeo.cms.swt.dialogs.CmsMessageDialog.openError;
+import static org.argeo.cms.swt.dialogs.SingleValueDialog.ask;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.nio.file.DirectoryNotEmptyException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.swt.dialogs.CmsFeedback;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+
+public class DocumentsUiService {
+       private final static CmsLog log = CmsLog.getLog(DocumentsUiService.class);
+
+       // Default known actions
+       public final static String ACTION_ID_CREATE_FOLDER = "createFolder";
+       public final static String ACTION_ID_BOOKMARK_FOLDER = "bookmarkFolder";
+       public final static String ACTION_ID_SHARE_FOLDER = "shareFolder";
+       public final static String ACTION_ID_DOWNLOAD_FOLDER = "downloadFolder";
+       public final static String ACTION_ID_RENAME = "rename";
+       public final static String ACTION_ID_DELETE = "delete";
+       public final static String ACTION_ID_UPLOAD_FILE = "uploadFiles";
+       // public final static String ACTION_ID_OPEN = "open";
+       public final static String ACTION_ID_DELETE_BOOKMARK = "deleteBookmark";
+       public final static String ACTION_ID_RENAME_BOOKMARK = "renameBookmark";
+
+       public String getLabel(String actionId) {
+               switch (actionId) {
+               case ACTION_ID_CREATE_FOLDER:
+                       return "Create Folder";
+               case ACTION_ID_BOOKMARK_FOLDER:
+                       return "Bookmark Folder";
+               case ACTION_ID_SHARE_FOLDER:
+                       return "Share Folder";
+               case ACTION_ID_DOWNLOAD_FOLDER:
+                       return "Download as zip archive";
+               case ACTION_ID_RENAME:
+                       return "Rename";
+               case ACTION_ID_DELETE:
+                       return "Delete";
+               case ACTION_ID_UPLOAD_FILE:
+                       return "Upload Files";
+//             case ACTION_ID_OPEN:
+//                     return "Open";
+               case ACTION_ID_DELETE_BOOKMARK:
+                       return "Delete bookmark";
+               case ACTION_ID_RENAME_BOOKMARK:
+                       return "Rename bookmark";
+               default:
+                       throw new IllegalArgumentException("Unknown action ID " + actionId);
+               }
+       }
+
+       public void openFile(Path toOpenPath) {
+               try {
+                       String name = toOpenPath.getFileName().toString();
+                       File tmpFile = File.createTempFile("tmp", name);
+                       tmpFile.deleteOnExit();
+                       try (OutputStream os = new FileOutputStream(tmpFile)) {
+                               Files.copy(toOpenPath, os);
+                       } catch (IOException e) {
+                               throw new IllegalStateException("Cannot open copy " + name + " to tmpFile.", e);
+                       }
+                       String uri = Paths.get(tmpFile.getAbsolutePath()).toUri().toString();
+                       Map<String, String> params = new HashMap<String, String>();
+//                     params.put(OpenFile.PARAM_FILE_NAME, name);
+//                     params.put(OpenFile.PARAM_FILE_URI, uri);
+                       // FIXME open file without a command
+                       // CommandUtils.callCommand(OpenFile.ID, params);
+               } catch (IOException e1) {
+                       throw new IllegalStateException("Cannot create tmp copy of " + toOpenPath, e1);
+               }
+       }
+
+       public boolean deleteItems(Shell shell, IStructuredSelection selection) {
+               if (selection.isEmpty())
+                       return false;
+
+               StringBuilder builder = new StringBuilder();
+               @SuppressWarnings("unchecked")
+               Iterator<Object> iterator = selection.iterator();
+               List<Path> paths = new ArrayList<>();
+
+               while (iterator.hasNext()) {
+                       Path path = (Path) iterator.next();
+                       builder.append(path.getFileName() + ", ");
+                       paths.add(path);
+               }
+               String msg = "You are about to delete following elements: " + builder.substring(0, builder.length() - 2)
+                               + ". Are you sure?";
+               if (openConfirm(msg)) {
+                       for (Path path : paths) {
+                               try {
+                                       // recursively delete directory and its content
+                                       Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+                                               @Override
+                                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                                                       Files.delete(file);
+                                                       return FileVisitResult.CONTINUE;
+                                               }
+
+                                               @Override
+                                               public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                                                       Files.delete(dir);
+                                                       return FileVisitResult.CONTINUE;
+                                               }
+                                       });
+                               } catch (DirectoryNotEmptyException e) {
+                                       String errMsg = path.getFileName() + " cannot be deleted: directory is not empty.";
+                                       openError( errMsg);
+                                       throw new IllegalArgumentException("Cannot delete path " + path, e);
+                               } catch (IOException e) {
+                                       String errMsg = e.toString();
+                                       openError(errMsg);
+                                       throw new IllegalArgumentException("Cannot delete path " + path, e);
+                               }
+                       }
+                       return true;
+               }
+               return false;
+       }
+
+       public boolean renameItem(Shell shell, Path parentFolderPath, Path toRenamePath) {
+               String msg = "Enter a new name:";
+               String name = ask( msg, toRenamePath.getFileName().toString());
+               // TODO enhance check of name validity
+               if (EclipseUiUtils.notEmpty(name)) {
+                       try {
+                               Path child = parentFolderPath.resolve(name);
+                               if (Files.exists(child)) {
+                                       String errMsg = "An object named " + name + " already exists at " + parentFolderPath.toString()
+                                                       + ", please provide another name";
+                                       openError( errMsg);
+                                       throw new IllegalArgumentException(errMsg);
+                               } else {
+                                       Files.move(toRenamePath, child);
+                                       return true;
+                               }
+                       } catch (IOException e) {
+                               throw new IllegalStateException("Cannot rename " + name + " at " + parentFolderPath.toString(), e);
+                       }
+               }
+               return false;
+       }
+
+       public boolean createFolder(Shell shell, Path currFolderPath) {
+               String msg = "Enter a name:";
+               String name = ask( msg);
+               // TODO enhance check of name validity
+               if (EclipseUiUtils.notEmpty(name)) {
+                       name = name.trim();
+                       try {
+                               Path child = currFolderPath.resolve(name);
+                               if (Files.exists(child)) {
+                                       String errMsg = "A folder named " + name + " already exists at " + currFolderPath.toString()
+                                                       + ", cannot create";
+                                       openError(errMsg);
+                                       throw new IllegalArgumentException(errMsg);
+                               } else {
+                                       Files.createDirectories(child);
+                                       return true;
+                               }
+                       } catch (IOException e) {
+                               throw new IllegalStateException("Cannot create folder " + name + " at " + currFolderPath.toString(), e);
+                       }
+               }
+               return false;
+       }
+
+//     public void bookmarkFolder(Path toBookmarkPath, Repository repository, DocumentsService documentsService) {
+//             String msg = "Provide a name:";
+//             String name = SingleQuestion.ask("Create bookmark", msg, toBookmarkPath.getFileName().toString());
+//             if (EclipseUiUtils.notEmpty(name))
+//                     documentsService.createFolderBookmark(toBookmarkPath, name, repository);
+//     }
+
+       public boolean uploadFiles(Shell shell, Path currFolderPath) {
+//             shell = Display.getCurrent().getActiveShell();// ignore argument
+               try {
+                       FileDialog dialog = new FileDialog(shell, SWT.MULTI);
+                       dialog.setText("Choose one or more files to upload");
+
+                       if (EclipseUiUtils.notEmpty(dialog.open())) {
+                               String[] names = dialog.getFileNames();
+                               // Workaround small differences between RAP and RCP
+                               // 1. returned names are absolute path on RAP and
+                               // relative in RCP
+                               // 2. in RCP we must use getFilterPath that does not
+                               // exists on RAP
+                               Method filterMethod = null;
+                               Path parPath = null;
+                               try {
+                                       filterMethod = dialog.getClass().getDeclaredMethod("getFilterPath");
+                                       String filterPath = (String) filterMethod.invoke(dialog);
+                                       parPath = Paths.get(filterPath);
+                               } catch (NoSuchMethodException nsme) { // RAP
+                               }
+                               if (names.length == 0)
+                                       return false;
+                               else {
+                                       loop: for (String name : names) {
+                                               Path tmpPath = Paths.get(name);
+                                               if (parPath != null)
+                                                       tmpPath = parPath.resolve(tmpPath);
+                                               if (Files.exists(tmpPath)) {
+                                                       URI uri = tmpPath.toUri();
+                                                       String uriStr = uri.toString();
+
+                                                       if (Files.isDirectory(tmpPath)) {
+                                                               openError(
+                                                                               "Upload of directories in the system is not yet implemented");
+                                                               continue loop;
+                                                       }
+                                                       Path targetPath = currFolderPath.resolve(tmpPath.getFileName().toString());
+                                                       try (InputStream in = new FileInputStream(tmpPath.toFile())) {
+                                                               Files.copy(in, targetPath);
+                                                               Files.delete(tmpPath);
+                                                       }
+                                                       if (log.isDebugEnabled())
+                                                               log.debug("copied uploaded file " + uriStr + " to " + targetPath.toString());
+                                               } else {
+                                                       String msg = "Cannot copy tmp file from " + tmpPath.toString();
+                                                       if (parPath != null)
+                                                               msg += "\nPlease remember that file upload fails when choosing files from the \"Recently Used\" bookmarks on some OS";
+                                                       openError( msg);
+                                                       continue loop;
+                                               }
+                                       }
+                                       return true;
+                               }
+                       }
+               } catch (Exception e) {
+                       CmsFeedback.show("Cannot import files to " + currFolderPath,e);
+               }
+               return false;
+       }
+
+//     public boolean deleteBookmark(Shell shell, IStructuredSelection selection, Node bookmarkParent) {
+//             if (selection.isEmpty())
+//                     return false;
+//
+//             StringBuilder builder = new StringBuilder();
+//             @SuppressWarnings("unchecked")
+//             Iterator<Object> iterator = selection.iterator();
+//             List<Node> nodes = new ArrayList<>();
+//
+//             while (iterator.hasNext()) {
+//                     Node node = (Node) iterator.next();
+//                     builder.append(Jcr.get(node, Property.JCR_TITLE) + ", ");
+//                     nodes.add(node);
+//             }
+//             String msg = "You are about to delete following bookmark: " + builder.substring(0, builder.length() - 2)
+//                             + ". Are you sure?";
+//             if (MessageDialog.openConfirm(shell, "Confirm deletion", msg)) {
+//                     Session session = Jcr.session(bookmarkParent);
+//                     try {
+//                             if (session.hasPendingChanges())
+//                                     throw new DocumentsException("Cannot remove bookmarks, session is not clean");
+//                             for (Node path : nodes)
+//                                     path.remove();
+//                             bookmarkParent.getSession().save();
+//                             return true;
+//                     } catch (RepositoryException e) {
+//                             JcrUtils.discardQuietly(session);
+//                             throw new DocumentsException("Cannot delete bookmarks " + builder.toString(), e);
+//                     }
+//             }
+//             return false;
+//     }
+
+//     public boolean renameBookmark(IStructuredSelection selection) {
+//             if (selection.isEmpty() || selection.size() > 1)
+//                     return false;
+//             Node toRename = (Node) selection.getFirstElement();
+//             String msg = "Please provide a new name.";
+//             String name = SingleQuestion.ask("Rename bookmark", msg, ConnectJcrUtils.get(toRename, Property.JCR_TITLE));
+//             if (EclipseUiUtils.notEmpty(name)
+//                             && ConnectJcrUtils.setJcrProperty(toRename, Property.JCR_TITLE, PropertyType.STRING, name)) {
+//                     ConnectJcrUtils.saveIfNecessary(toRename);
+//                     return true;
+//             }
+//             return false;
+//     }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OLMap.java b/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OLMap.java
new file mode 100644 (file)
index 0000000..1301325
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.app.ui.openlayers;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+public class OLMap extends Composite {
+       private Label div;
+
+       public OLMap(Composite parent, int style) {
+               super(parent, style);
+               setLayout(CmsSwtUtils.noSpaceGridLayout());
+               div = new Label(this, SWT.NONE);
+               CmsSwtUtils.markup(div);
+               CmsSwtUtils.disableMarkupValidation(div);
+               div.setText("<div id='map'></div>");
+               div.setLayoutData(CmsSwtUtils.fillAll());
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OpenLayersMap.java b/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OpenLayersMap.java
new file mode 100644 (file)
index 0000000..d755e8b
--- /dev/null
@@ -0,0 +1,300 @@
+package org.argeo.app.ui.openlayers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.api.cms.CmsView;
+import org.argeo.app.api.EntityNames;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.ui.SuiteEvent;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.BrowserFunction;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/** Display a map. */
+public class OpenLayersMap extends Composite {
+       private static final long serialVersionUID = 1055893020490283622L;
+
+       private final static CmsLog log = CmsLog.getLog(OpenLayersMap.class);
+
+       private Browser browser;
+       private boolean renderCompleted = false;
+
+       private Double centerLng = null, centerLat = null;
+       private Integer zoom = null;
+       private String vectorSource = null;
+       private String gpxSource = null;
+
+       private String vectorSourceStyle;
+
+       private List<String> geoJsonSources = new ArrayList<>();
+       private Map<String, String> vectorSources = new HashMap<>();
+       private Map<String, String> layerStyles = new HashMap<>();
+
+       private CmsView cmsView;
+
+       public OpenLayersMap(Composite parent, int style, URL mapHtml) {
+               super(parent, style);
+               cmsView = CmsSwtUtils.getCmsView(parent);
+               setLayout(new GridLayout());
+
+               browser = new Browser(this, SWT.BORDER);
+               browser.setLayoutData(CmsSwtUtils.fillAll());
+               String html;
+               try (InputStream in = mapHtml.openStream()) {
+                       html = IOUtils.toString(in, StandardCharsets.UTF_8);
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+               new RenderCompleted(browser, "renderCompleted");
+               new OnFeatureSelect(browser, "onFeatureSelect");
+               new OnFeatureUnselect(browser, "onFeatureUnselect");
+               new OnFeatureClick(browser, "onFeatureClick");
+               browser.setText(html);
+       }
+
+       public void setCenter(Double lng, Double lat) {
+               if (isRenderCompleted())
+                       browser.evaluate("map.getView().setCenter(ol.proj.fromLonLat([" + lng + ", " + lat + "]))");
+               this.centerLat = lat;
+               this.centerLng = lng;
+       }
+
+       public synchronized void setRenderCompleted(boolean renderCompleted) {
+               this.renderCompleted = renderCompleted;
+               notifyAll();
+       }
+
+       public synchronized boolean isRenderCompleted() {
+               return renderCompleted;
+       }
+
+       @Override
+       public synchronized void dispose() {
+               long timeout = 500;
+               long begin = System.currentTimeMillis();
+               while (!isRenderCompleted() && ((System.currentTimeMillis() - begin) < timeout)) {
+                       try {
+                               wait(50);
+                       } catch (InterruptedException e) {
+                               // silent
+                       }
+               }
+               super.dispose();
+       }
+
+       public void setZoom(int zoom) {
+               if (isRenderCompleted())
+                       browser.evaluate("map.getView().setZoom(" + zoom + ")");
+               this.zoom = zoom;
+       }
+
+       protected String asVectorSource(List<Node> geoPoints) throws RepositoryException {
+               boolean first = true;
+               StringBuffer sb = new StringBuffer("new ol.source.Vector({ features: [");
+               for (int i = 0; i < geoPoints.size(); i++) {
+                       Node node = geoPoints.get(i);
+                       if (node.isNodeType(EntityType.geopoint.get())) {
+                               if (first)
+                                       first = false;
+                               else
+                                       sb.append(",");
+                               Double lng = node.getProperty(EntityNames.GEO_LONG).getDouble();
+                               Double lat = node.getProperty(EntityNames.GEO_LAT).getDouble();
+                               sb.append("new ol.Feature({ geometry:");
+                               sb.append("new ol.geom.Point(ol.proj.fromLonLat([");
+                               sb.append(lng).append(',').append(lat);
+                               sb.append("]))");
+                               sb.append(",path:\"").append(node.getPath()).append("\"");
+                               sb.append(",name:\"").append(node.getName()).append("\"");
+                               String entityType = null;
+                               if (node.isNodeType(EntityType.local.get())) {
+                                       entityType = node.getProperty(EntityNames.ENTITY_TYPE).getString();
+                                       sb.append(", type:'").append(entityType).append("'");
+                               }
+                               sb.append("})");
+                       }
+               }
+               sb.append("]");
+               sb.append(" })");
+               return sb.toString();
+       }
+
+       public void addPoints(List<Node> geoPoints) throws RepositoryException {
+               this.vectorSource = asVectorSource(geoPoints);
+               if (log.isTraceEnabled())
+                       log.trace("Vector source: " + vectorSource);
+               renderVectorSource();
+       }
+
+       public void addPoints(String layerName, List<Node> geoPoints, String style) throws RepositoryException {
+               this.vectorSources.put(layerName, asVectorSource(geoPoints));
+               if (style != null) {
+                       layerStyles.put(layerName, style);
+               }
+               renderVectorSources();
+       }
+
+       protected void renderVectorSource() {
+               if (vectorSource == null)
+                       return;
+               if (isRenderCompleted()) {
+//                     String style = ", style: new ol.style.Style({  image: new ol.style.Icon({ src: '/pkg/org.djapps.on.openheritage.ui/map_oc.png' }) })";
+                       String style = vectorSourceStyle != null ? ", style: " + vectorSourceStyle : "";
+//                     String style = "";
+                       String toEvaluate = "map.addLayer(new ol.layer.Vector({ source: " + vectorSource + style + "}));";
+//                     System.out.println(toEvaluate);
+                       browser.execute(toEvaluate);
+               }
+       }
+
+       protected void renderVectorSources() {
+               if (vectorSources.isEmpty())
+                       return;
+               if (isRenderCompleted()) {
+                       StringBuilder toExecute = new StringBuilder();
+                       for (String name : vectorSources.keySet()) {
+                               String style = layerStyles.containsKey(name) ? ", style: " + layerStyles.get(name) : "";
+                               String toEvaluate = "map.addLayer(new ol.layer.Vector({ source: " + vectorSources.get(name) + style
+                                               + ",name: '" + name + "'}));";
+                               toExecute.append(toEvaluate);
+                       }
+                       System.out.println(toExecute);
+                       browser.execute(toExecute.toString());
+               }
+       }
+
+       public void addPoint(Double lng, Double lat) {
+               this.vectorSource = "new ol.source.Vector({ features: [ new ol.Feature({ geometry:"
+                               + " new ol.geom.Point(ol.proj.fromLonLat([" + lng + ", " + lat + "])) }) ] })";
+//             if (renderCompleted) {
+//                     browser.evaluate(
+//                                     "map.addLayer(new ol.layer.Vector({ source: new ol.source.Vector({ features: [ new ol.Feature({ geometry:"
+//                                                     + " new ol.geom.Point(ol.proj.fromLonLat([" + lng + ", " + lat + "])) }) ] }) }));");
+//             }
+               renderVectorSource();
+       }
+
+       public void addGpx(String path) {
+               this.gpxSource = "new ol.source.Vector({ url: '" + path + "', format: new ol.format.GPX() })";
+               renderGpxSource();
+       }
+
+       protected void renderGpxSource() {
+               if (gpxSource == null)
+                       return;
+               if (isRenderCompleted())
+                       browser.evaluate("map.addLayer(new ol.layer.Vector({ source: " + gpxSource + "}));");
+       }
+
+       public void addGeoJson(String path) {
+               String geoJsonSource = "new ol.source.Vector({ url: '" + path + "', format: new ol.format.GeoJSON() })";
+               geoJsonSources.add(geoJsonSource);
+               renderGeoJsonSources();
+       }
+
+       protected void renderGeoJsonSources() {
+               if (geoJsonSources.isEmpty())
+                       return;
+               if (isRenderCompleted()) {
+                       for (String geoJson : geoJsonSources) {
+                               browser.evaluate("map.addLayer(new ol.layer.Vector({ source: " + geoJson + "}));");
+                       }
+               }
+       }
+
+       public void setVectorSourceStyle(String vectorSourceStyle) {
+               this.vectorSourceStyle = vectorSourceStyle;
+       }
+
+       private class RenderCompleted extends BrowserFunction {
+
+               RenderCompleted(Browser browser, String name) {
+                       super(browser, name);
+               }
+
+               @Override
+               public Object function(Object[] arguments) {
+                       try {
+                               if (!isRenderCompleted()) {
+                                       setRenderCompleted(true);
+                                       if (zoom != null)
+                                               setZoom(zoom);
+                                       if (centerLat != null && centerLng != null) {
+                                               setCenter(centerLng, centerLat);
+                                       }
+                                       if (!geoJsonSources.isEmpty())
+                                               renderGeoJsonSources();
+                                       if (gpxSource != null)
+                                               renderGpxSource();
+                                       if (vectorSource != null)
+                                               renderVectorSource();
+                                       if (!vectorSources.isEmpty())
+                                               renderVectorSources();
+                               }
+                               return null;
+                       } catch (Exception e) {
+                               log.error("Cannot render map", e);
+                               return null;
+                       }
+               }
+       }
+
+       private class OnFeatureSelect extends BrowserFunction {
+
+               OnFeatureSelect(Browser browser, String name) {
+                       super(browser, name);
+               }
+
+               @Override
+               public Object function(Object[] arguments) {
+                       if (arguments.length == 0)
+                               return null;
+                       String path = arguments[0].toString();
+                       Map<String, Object> properties = new HashMap<>();
+                       properties.put(SuiteEvent.NODE_PATH, path);
+                       properties.put(SuiteEvent.WORKSPACE, CmsConstants.SYS_WORKSPACE);
+                       cmsView.sendEvent(SuiteEvent.refreshPart.topic(), properties);
+                       return null;
+               }
+       }
+
+       private class OnFeatureUnselect extends BrowserFunction {
+
+               OnFeatureUnselect(Browser browser, String name) {
+                       super(browser, name);
+               }
+
+               @Override
+               public Object function(Object[] arguments) {
+                       return null;
+               }
+       }
+
+       private class OnFeatureClick extends BrowserFunction {
+
+               OnFeatureClick(Browser browser, String name) {
+                       super(browser, name);
+               }
+
+               @Override
+               public Object function(Object[] arguments) {
+                       return null;
+               }
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OverviewMap.java b/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OverviewMap.java
new file mode 100644 (file)
index 0000000..dbb3119
--- /dev/null
@@ -0,0 +1,66 @@
+package org.argeo.app.ui.openlayers;
+
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.query.Query;
+
+import org.argeo.app.api.EntityType;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Displays an overview map. */
+public class OverviewMap implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               parent.setLayout(new GridLayout());
+               refreshUi(parent, context);
+
+               try {
+                       String[] nodeTypes = { EntityType.geopoint.get() };
+                       context.getSession().getWorkspace().getObservationManager().addEventListener(new EventListener() {
+
+                               @Override
+                               public void onEvent(EventIterator events) {
+                                       if (!parent.isDisposed())
+                                               parent.getDisplay().asyncExec(() -> {
+                                                       try {
+                                                               refreshUi(parent, context);
+                                                       } catch (RepositoryException e) {
+                                                               throw new JcrException(e);
+                                                       }
+                                               });
+                               }
+                       }, 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);
+               }
+
+               return parent;
+       }
+
+       protected void refreshUi(Composite parent, Node context) throws RepositoryException {
+               CmsSwtUtils.clear(parent);
+               Query query = context.getSession().getWorkspace().getQueryManager()
+                               .createQuery("SELECT * FROM [" + EntityType.geopoint.get() + "]", Query.JCR_SQL2);
+               List<Node> geoPoints = JcrUtils.nodeIteratorToList(query.execute().getNodes());
+               OpenLayersMap map = new OpenLayersMap(parent, SWT.NONE, getClass().getResource("map-osm.html"));
+               map.setLayoutData(CmsSwtUtils.fillAll());
+
+               // apafMap.setZoom(7);
+               // apafMap.setCenter(-2.472, 8.010);
+               map.addPoints(geoPoints);
+       }
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/map-osm.html b/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/map-osm.html
new file mode 100644 (file)
index 0000000..157d708
--- /dev/null
@@ -0,0 +1,41 @@
+<html lang="en">
+<head>
+<link rel="stylesheet"
+       href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css"
+       type="text/css">
+<style>
+</style>
+<script
+       src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script>
+</head>
+<body>
+       <div id="map" class="map"></div>
+       <script type="text/javascript">
+       // default OSM
+       var source_OSM = new ol.source.OSM();
+       
+       var map = new ol.Map({
+                       target : 'map',
+                       layers : [ new ol.layer.Tile({
+                               source : source_OSM
+                       }) ],
+                       view : new ol.View({
+                               center : ol.proj.fromLonLat([ 34, 34 ]),
+                               zoom : 4
+                       })
+               });
+               map.on('rendercomplete', e => {
+                       console.log('Render completed.');
+                       renderCompleted();
+               });
+               var select = new ol.interaction.Select();
+               map.addInteraction(select);
+           select.on('select',function (e) {
+               if(e.selected.length>0){
+                               console.log('Feature selected: '+e.selected[0].get('path'));
+                       onFeatureSelect(e.selected[0].get('path'));
+               }
+           });
+       </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/map.js b/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/map.js
new file mode 100644 (file)
index 0000000..68489fb
--- /dev/null
@@ -0,0 +1,11 @@
+var map = new ol.Map({
+       target : 'map',
+       layers : [ new ol.layer.Tile({
+               source : new ol.source.OSM()
+       }) ],
+       view : new ol.View({
+               center : ol.proj.fromLonLat([ 34, 34 ]),
+               zoom : 4
+       })
+});
+               
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/people/PeopleEntryArea.java b/org.argeo.app.ui/src/org/argeo/app/ui/people/PeopleEntryArea.java
new file mode 100644 (file)
index 0000000..7e9fa6a
--- /dev/null
@@ -0,0 +1,183 @@
+package org.argeo.app.ui.people;
+
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.app.api.SuiteRole;
+import org.argeo.app.ui.SuiteEvent;
+import org.argeo.app.ui.SuiteIcon;
+import org.argeo.app.ui.dialogs.NewUserWizard;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.Selected;
+import org.argeo.cms.swt.dialogs.CmsWizardDialog;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.util.naming.LdapAttrs;
+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 PeopleEntryArea implements CmsUiProvider {
+
+       private CmsUserManager cmsUserManager;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsTheme theme = CmsSwtUtils.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(CmsSwtUtils.fillWidth());
+               bottom.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
+               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               deleteItem.setEnabled(false);
+//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
+               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
+               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+               usersViewer.addDoubleClickListener(new IDoubleClickListener() {
+
+                       @Override
+                       public void doubleClick(DoubleClickEvent event) {
+                               User user = (User) usersViewer.getStructuredSelection().getFirstElement();
+                               if (user != null) {
+//                                     Node userNode = getOrCreateUserNode(user, context);
+                                       CmsSwtUtils.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);
+                                       CmsSwtUtils.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(CmsSwtUtils.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.app.ui/src/org/argeo/app/ui/people/PersonUiProvider.java b/org.argeo.app.ui/src/org/argeo/app/ui/people/PersonUiProvider.java
new file mode 100644 (file)
index 0000000..24b0893
--- /dev/null
@@ -0,0 +1,88 @@
+package org.argeo.app.ui.people;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.app.ui.SuiteMsg;
+import org.argeo.app.ui.SuiteUiUtils;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.util.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 PersonUiProvider 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(CmsSwtUtils.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(CmsSwtUtils.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.app.ui/src/org/argeo/app/ui/people/SuiteUserUiProvider.java b/org.argeo.app.ui/src/org/argeo/app/ui/people/SuiteUserUiProvider.java
new file mode 100644 (file)
index 0000000..6cec22d
--- /dev/null
@@ -0,0 +1,88 @@
+package org.argeo.app.ui.people;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.app.ui.SuiteMsg;
+import org.argeo.app.ui.SuiteUiUtils;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.util.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(CmsSwtUtils.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(CmsSwtUtils.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.app.ui/src/org/argeo/app/ui/people/SuiteUsersEntryArea.java b/org.argeo.app.ui/src/org/argeo/app/ui/people/SuiteUsersEntryArea.java
new file mode 100644 (file)
index 0000000..c6a49b6
--- /dev/null
@@ -0,0 +1,183 @@
+package org.argeo.app.ui.people;
+
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.app.api.SuiteRole;
+import org.argeo.app.ui.SuiteEvent;
+import org.argeo.app.ui.SuiteIcon;
+import org.argeo.app.ui.dialogs.NewUserWizard;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.Selected;
+import org.argeo.cms.swt.dialogs.CmsWizardDialog;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.util.naming.LdapAttrs;
+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 SuiteUsersEntryArea implements CmsUiProvider {
+
+       private CmsUserManager cmsUserManager;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsTheme theme = CmsSwtUtils.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(CmsSwtUtils.fillWidth());
+               bottom.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
+               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               deleteItem.setEnabled(false);
+//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
+               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
+               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
+               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
+               usersViewer.addDoubleClickListener(new IDoubleClickListener() {
+
+                       @Override
+                       public void doubleClick(DoubleClickEvent event) {
+                               User user = (User) usersViewer.getStructuredSelection().getFirstElement();
+                               if (user != null) {
+//                                     Node userNode = getOrCreateUserNode(user, context);
+                                       CmsSwtUtils.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);
+                                       CmsSwtUtils.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(CmsSwtUtils.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.app.ui/src/org/argeo/app/ui/publish/DocumentUiProvider.java b/org.argeo.app.ui/src/org/argeo/app/ui/publish/DocumentUiProvider.java
new file mode 100644 (file)
index 0000000..3829583
--- /dev/null
@@ -0,0 +1,60 @@
+package org.argeo.app.ui.publish;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.api.cms.CmsEditable;
+import org.argeo.api.cms.CmsView;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.app.ui.docbook.AbstractDbkViewer;
+import org.argeo.app.ui.docbook.DocumentTextEditor;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsLink;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.JcrVersionCmsEditable;
+import org.argeo.cms.ui.widgets.ScrolledPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+public class DocumentUiProvider implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
+               CmsEditable cmsEditable = new JcrVersionCmsEditable(context);
+               if (context.hasNode(DbkType.article.get())) {
+                       Node textNode = context.getNode(DbkType.article.get());
+                       // Title
+                       parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+                       CmsLink toHtml = new CmsLink("To HTML", "/html/dbk" + context.getPath()+"/index.html");
+                       toHtml.createUiPart(parent, context);
+
+                       ScrolledPage page = new ScrolledPage(parent, SWT.NONE);
+                       page.setLayoutData(CmsSwtUtils.fillAll());
+                       page.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+                       cmsView.runAs(() -> {
+                               AbstractDbkViewer dbkEditor = new DocumentTextEditor(page, SWT.NONE, textNode, cmsEditable);
+                               dbkEditor.refresh();
+                       });
+                       return page;
+
+               } else if (context.isNodeType(NodeType.NT_FILE)) {
+                       String fileName = context.getName();
+                       if (fileName.endsWith(".pdf")) {
+                               Browser browser = new Browser(parent, SWT.NONE);
+                               String dataPath = CmsUiUtils.getDataPath(context);
+                               browser.setUrl(dataPath);
+                               browser.setLayoutData(CmsSwtUtils.fillAll());
+                               return browser;
+                       }
+               }
+               return null;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/publish/PublishingApp.java b/org.argeo.app.ui/src/org/argeo/app/ui/publish/PublishingApp.java
new file mode 100644 (file)
index 0000000..d57706c
--- /dev/null
@@ -0,0 +1,133 @@
+package org.argeo.app.ui.publish;
+
+import static org.argeo.app.ui.SuiteApp.DEFAULT_THEME_ID_PROPERTY;
+import static org.argeo.app.ui.SuiteApp.DEFAULT_UI_NAME_PROPERTY;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+
+import org.argeo.api.cms.CmsApp;
+import org.argeo.api.cms.CmsUi;
+import org.argeo.app.ui.SuiteApp;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.AbstractCmsApp;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.jcr.Jcr;
+import org.argeo.util.LangUtils;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.Constants;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+/**
+ * A {@link CmsApp} dedicated to publishing, typically a public or internal web
+ * site.
+ */
+public class PublishingApp extends AbstractCmsApp implements EventHandler {
+       private final static CmsLog log = CmsLog.getLog(PublishingApp.class);
+
+       private String pid;
+       private String defaultThemeId;
+       private String defaultUiName = "";
+
+       private String publicBasePath = null;
+
+       private CmsUiProvider landingPage;
+       private CmsUiProvider defaultProvider = new DocumentUiProvider();
+
+       private Repository repository;
+
+       public void init(Map<String, String> properties) {
+               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, SuiteApp.PUBLIC_BASE_PATH_PROPERTY);
+               pid = properties.get(Constants.SERVICE_PID);
+
+               if (log.isDebugEnabled())
+                       log.info("Publishing App " + pid + " started");
+       }
+
+       public void destroy(Map<String, String> properties) {
+               if (log.isDebugEnabled())
+                       log.info("Publishing App " + pid + " stopped");
+
+       }
+
+       @Override
+       public Set<String> getUiNames() {
+               Set<String> uiNames = new HashSet<>();
+               uiNames.add(defaultUiName);
+               return uiNames;
+       }
+
+       @Override
+       public CmsUi initUi(Object uiParent) {
+               Composite parent = (Composite) uiParent;
+//             Session adminSession = NodeUtils.openDataAdminSession(getRepository(), null);
+               Session session = Jcr.login(getRepository(), null);
+               parent.setLayout(new GridLayout());
+               Node indexNode = Jcr.getNode(session, publicBasePath + "/index");
+//             try {
+//                     indexNode = JcrUtils.getOrAdd(Jcr.getRootNode(adminSession), DocumentPage.WWW, DbkType.article.get());
+//                     adminSession.save();
+//             } catch (RepositoryException e) {
+//                     throw new IllegalStateException(e);
+//             }
+
+               Control page;
+               if (landingPage != null) {
+                       page = landingPage.createUiPart(parent, indexNode);
+               } else {
+                       page = defaultProvider.createUiPart(parent, indexNode);
+               }
+               return (CmsUi) page;
+       }
+
+       @Override
+       public void refreshUi(CmsUi cmsUi, String state) {
+               Composite parent = (Composite) cmsUi;
+               parent.setLayout(new GridLayout());
+               if (landingPage != null)
+                       landingPage.createUiPart(parent, null);
+               else
+                       defaultProvider.createUiPart(parent, null);
+       }
+
+       @Override
+       public void setState(CmsUi cmsUi, String state) {
+
+       }
+
+       @Override
+       protected String getThemeId(String uiName) {
+               return defaultThemeId;
+       }
+
+       public void setLandingPage(CmsUiProvider landingPage) {
+               this.landingPage = landingPage;
+       }
+
+       @Override
+       public void handleEvent(Event event) {
+               // TODO listen to some events
+
+       }
+
+       public Repository getRepository() {
+               return repository;
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/publish/PublishingStyle.java b/org.argeo.app.ui/src/org/argeo/app/ui/publish/PublishingStyle.java
new file mode 100644 (file)
index 0000000..c2c8231
--- /dev/null
@@ -0,0 +1,23 @@
+package org.argeo.app.ui.publish;
+
+import org.argeo.api.cms.CmsStyle;
+
+/** Publishing styles. */
+public enum PublishingStyle implements CmsStyle {
+       // general
+       page, coverTitle, coverSubTitle, coverTagline, bannerLine1, bannerLine2,
+       // meta data
+       tag, menu,
+       // text style
+       title, subTitle, chapo, para, sectionTitle, subSectionTitle,
+       // links
+       internalLink,
+       // composite style
+       framed, line;
+
+       @Override
+       public String getClassPrefix() {
+               return "argeo-publishing";
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/widgets/AbstractConnectContextMenu.java b/org.argeo.app.ui/src/org/argeo/app/ui/widgets/AbstractConnectContextMenu.java
new file mode 100644 (file)
index 0000000..7824691
--- /dev/null
@@ -0,0 +1,133 @@
+package org.argeo.app.ui.widgets;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+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());
+                       CmsSwtUtils.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.app.ui/src/org/argeo/app/ui/widgets/ConnectAbstractDropDown.java b/org.argeo.app.ui/src/org/argeo/app/ui/widgets/ConnectAbstractDropDown.java
new file mode 100644 (file)
index 0000000..d1f1a29
--- /dev/null
@@ -0,0 +1,194 @@
+package org.argeo.app.ui.widgets;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+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)
+                       CmsSwtUtils.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.app.ui/src/org/argeo/app/ui/widgets/DelayedText.java b/org.argeo.app.ui/src/org/argeo/app/ui/widgets/DelayedText.java
new file mode 100644 (file)
index 0000000..3b58776
--- /dev/null
@@ -0,0 +1,127 @@
+package org.argeo.app.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/org.argeo.app.ui/src/org/argeo/app/ui/widgets/TabbedArea.java b/org.argeo.app.ui/src/org/argeo/app/ui/widgets/TabbedArea.java
new file mode 100644 (file)
index 0000000..c214207
--- /dev/null
@@ -0,0 +1,256 @@
+package org.argeo.app.ui.widgets;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.Selected;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** Manages {@link Section} in a tab-like structure. */
+public class TabbedArea extends Composite {
+       private static final long serialVersionUID = 8659669229482033444L;
+
+       private Composite headers;
+       private Composite body;
+
+       private List<Section> sections = new ArrayList<>();
+
+       private Node previousNode;
+       private CmsUiProvider previousUiProvider;
+       private CmsUiProvider currentUiProvider;
+
+       private String tabStyle;
+       private String tabSelectedStyle;
+       private String bodyStyle;
+       private Image closeIcon;
+
+       private StackLayout stackLayout;
+
+       private boolean singleTab = false;
+
+       public TabbedArea(Composite parent, int style) {
+               super(parent, SWT.NONE);
+               CmsSwtUtils.style(parent, bodyStyle);
+
+               setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+               // TODO manage tabs at bottom or sides
+               headers = new Composite(this, SWT.NONE);
+               headers.setLayoutData(CmsSwtUtils.fillWidth());
+               body = new Composite(this, SWT.NONE);
+               body.setLayoutData(CmsSwtUtils.fillAll());
+               // body.setLayout(new FormLayout());
+               stackLayout = new StackLayout();
+               body.setLayout(stackLayout);
+               emptyState();
+       }
+
+       protected void refreshTabHeaders() {
+               int tabCount = sections.size() > 0 ? sections.size() : 1;
+               for (Control tab : headers.getChildren())
+                       tab.dispose();
+
+               headers.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(tabCount, true)));
+
+               if (sections.size() == 0) {
+                       Composite emptyHeader = new Composite(headers, SWT.NONE);
+                       emptyHeader.setLayoutData(CmsSwtUtils.fillAll());
+                       emptyHeader.setLayout(new GridLayout());
+                       Label lbl = new Label(emptyHeader, SWT.NONE);
+                       lbl.setText("");
+                       lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
+
+               }
+
+               Section currentSection = getCurrentSection();
+               for (Section section : sections) {
+                       boolean selected = section == currentSection;
+                       Composite sectionHeader = section.createHeader(headers);
+                       CmsSwtUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle);
+                       int headerColumns = singleTab ? 1 : 2;
+                       sectionHeader.setLayout(new GridLayout(headerColumns, false));
+                       sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout(headerColumns));
+                       Button title = new Button(sectionHeader, SWT.FLAT);
+                       CmsSwtUtils.style(title, selected ? tabSelectedStyle : tabStyle);
+                       title.setLayoutData(CmsSwtUtils.fillWidth());
+                       title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode())));
+                       Node node = section.getNode();
+                       String titleStr = Jcr.getTitle(node);
+                       // TODO internationalize
+                       title.setText(titleStr);
+                       if (!singleTab) {
+                               ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
+                               ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT);
+                               if (closeIcon != null)
+                                       closeItem.setImage(closeIcon);
+                               else
+                                       closeItem.setText("X");
+                               CmsSwtUtils.style(closeItem, selected ? tabSelectedStyle : tabStyle);
+                               closeItem.addSelectionListener((Selected) (e) -> closeTab(section));
+                       }
+               }
+
+       }
+
+       public void view(CmsUiProvider uiProvider, Node context) {
+               if (body.isDisposed())
+                       return;
+               int index = tabIndex(context);
+               if (index >= 0) {
+                       showTab(index);
+                       previousNode = context;
+                       previousUiProvider = uiProvider;
+                       return;
+               }
+               Section section = (Section) body.getChildren()[0];
+               previousNode = section.getNode();
+               if (previousNode == null) {// empty state
+                       previousNode = context;
+                       previousUiProvider = uiProvider;
+               } else {
+                       previousUiProvider = currentUiProvider;
+               }
+               currentUiProvider = uiProvider;
+               section.setNode(context);
+               // section.setLayoutData(CmsUiUtils.coverAll());
+               build(section, uiProvider, context);
+               if (sections.size() == 0)
+                       sections.add(section);
+               refreshTabHeaders();
+               index = tabIndex(context);
+               showTab(index);
+               layout(true, true);
+       }
+
+       public void open(CmsUiProvider uiProvider, Node context) {
+               if (singleTab)
+                       throw new UnsupportedOperationException("Open is not supported in single tab mode.");
+
+               if (previousNode != null && Jcr.getIdentifier(previousNode).equals(Jcr.getIdentifier(context))) {
+                       // does nothing
+                       return;
+               }
+               if (sections.size() == 0)
+                       CmsSwtUtils.clear(body);
+               Section currentSection = getCurrentSection();
+               int currentIndex = sections.indexOf(currentSection);
+               Section previousSection = new Section(body, SWT.NONE, context);
+               build(previousSection, previousUiProvider, previousNode);
+               // previousSection.setLayoutData(CmsUiUtils.coverAll());
+               int index = currentIndex + 1;
+               sections.add(index, previousSection);
+               showTab(index);
+               refreshTabHeaders();
+               layout(true, true);
+       }
+
+       public void showTab(int index) {
+               Section sectionToShow = sections.get(index);
+               // sectionToShow.moveAbove(null);
+               stackLayout.topControl = sectionToShow;
+               refreshTabHeaders();
+               layout(true, true);
+       }
+
+       protected void build(Section section, CmsUiProvider uiProvider, Node context) {
+               for (Control child : section.getChildren())
+                       child.dispose();
+               CmsSwtUtils.style(section, bodyStyle);
+               section.setNode(context);
+               uiProvider.createUiPart(section, context);
+
+       }
+
+       private int tabIndex(Node node) {
+               for (int i = 0; i < sections.size(); i++) {
+                       Section section = sections.get(i);
+                       if (Jcr.getIdentifier(section.getNode()).equals(Jcr.getIdentifier(node)))
+                               return i;
+               }
+               return -1;
+       }
+
+       public void closeTab(Section section) {
+               int currentIndex = sections.indexOf(section);
+               int nextIndex = currentIndex == 0 ? 0 : currentIndex - 1;
+               sections.remove(section);
+               section.dispose();
+               if (sections.size() == 0) {
+                       emptyState();
+                       refreshTabHeaders();
+                       layout(true, true);
+                       return;
+               }
+               refreshTabHeaders();
+               showTab(nextIndex);
+       }
+       
+       public void closeAllTabs() {
+               for(Section section:sections) {
+                       section.dispose();                      
+               }
+               sections.clear();
+               emptyState();
+               refreshTabHeaders();
+               layout(true, true);
+       }
+
+       protected void emptyState() {
+               new Section(body, SWT.NONE, null);
+               refreshTabHeaders();
+       }
+
+       public Composite getCurrent() {
+               return getCurrentSection();
+       }
+
+       protected Section getCurrentSection() {
+               return (Section) stackLayout.topControl;
+       }
+
+       public Node getCurrentContext() {
+               Section section = getCurrentSection();
+               if (section != null) {
+                       return section.getNode();
+               } else {
+                       return null;
+               }
+       }
+
+       public void setTabStyle(String tabStyle) {
+               this.tabStyle = tabStyle;
+       }
+
+       public void setTabSelectedStyle(String tabSelectedStyle) {
+               this.tabSelectedStyle = tabSelectedStyle;
+       }
+
+       public void setBodyStyle(String bodyStyle) {
+               this.bodyStyle = bodyStyle;
+       }
+
+       public void setCloseIcon(Image closeIcon) {
+               this.closeIcon = closeIcon;
+       }
+
+       public void setSingleTab(boolean singleTab) {
+               this.singleTab = singleTab;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/widgets/TreeOrSearchArea.java b/org.argeo.app.ui/src/org/argeo/app/ui/widgets/TreeOrSearchArea.java
new file mode 100644 (file)
index 0000000..2b8f54e
--- /dev/null
@@ -0,0 +1,74 @@
+package org.argeo.app.ui.widgets;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Displays a tree by default, which becomes a list if the search text field is
+ * used.
+ */
+public class TreeOrSearchArea extends Composite {
+       private static final long serialVersionUID = -1302546480076719532L;
+
+       private Text searchT;
+       private StackLayout bodyLayout;
+
+       private TreeViewer treeViewer;
+       private TreeViewer searchResultsViewer;
+
+       public TreeOrSearchArea(Composite parent, int style) {
+               super(parent, style);
+               createUi(this);
+       }
+
+       protected void createUi(Composite parent) {
+               parent.setLayout(new GridLayout());
+               Composite searchC = new Composite(parent, SWT.NONE);
+               searchC.setLayout(new GridLayout());
+               searchC.setLayoutData(CmsSwtUtils.fillWidth());
+               createSearchUi(searchC);
+
+               Composite bodyC = new Composite(parent, SWT.NONE);
+               bodyC.setLayoutData(CmsSwtUtils.fillAll());
+               bodyLayout = new StackLayout();
+               bodyC.setLayout(bodyLayout);
+               Composite treeC = new Composite(bodyC, SWT.NONE);
+               createTreeUi(treeC);
+               Composite searchResultsC = new Composite(bodyC, SWT.NONE);
+               createSearchResultsUi(searchResultsC);
+
+               bodyLayout.topControl = treeC;
+       }
+
+       protected void createSearchUi(Composite parent) {
+               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               searchT = new Text(parent, SWT.MULTI | SWT.BORDER);
+               searchT.setLayoutData(CmsSwtUtils.fillWidth());
+       }
+
+       protected void createTreeUi(Composite parent) {
+               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               treeViewer = new TreeViewer(parent);
+               treeViewer.getTree().setLayoutData(CmsSwtUtils.fillAll());
+       }
+
+       protected void createSearchResultsUi(Composite parent) {
+               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               searchResultsViewer = new TreeViewer(parent);
+               searchResultsViewer.getTree().setLayoutData(CmsSwtUtils.fillAll());
+       }
+
+       public TreeViewer getTreeViewer() {
+               return treeViewer;
+       }
+
+       public TreeViewer getSearchResultsViewer() {
+               return searchResultsViewer;
+       }
+
+}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java
deleted file mode 100644 (file)
index c9e2183..0000000
+++ /dev/null
@@ -1,1034 +0,0 @@
-package org.argeo.docbook.ui;
-
-import static org.argeo.docbook.DbkType.para;
-import static org.argeo.docbook.DbkUtils.addDbk;
-import static org.argeo.docbook.DbkUtils.isDbk;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Observer;
-
-import javax.jcr.Item;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.cms.Cms2DSize;
-import org.argeo.api.cms.CmsEditable;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.viewers.AbstractPageViewer;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.viewers.NodePart;
-import org.argeo.cms.ui.viewers.PropertyPart;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.cms.ui.viewers.SectionPart;
-import org.argeo.cms.ui.widgets.EditableText;
-import org.argeo.cms.ui.widgets.StyledControl;
-import org.argeo.docbook.DbkAttr;
-import org.argeo.docbook.DbkType;
-import org.argeo.docbook.DbkUtils;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.fileupload.FileDetails;
-import org.eclipse.rap.fileupload.FileUploadEvent;
-import org.eclipse.rap.fileupload.FileUploadHandler;
-import org.eclipse.rap.fileupload.FileUploadListener;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Base class for text viewers and editors. */
-public abstract class AbstractDbkViewer extends AbstractPageViewer implements KeyListener, Observer {
-       private static final long serialVersionUID = -2401274679492339668L;
-       private final static CmsLog log = CmsLog.getLog(AbstractDbkViewer.class);
-
-       private final Section mainSection;
-
-       private TextInterpreter textInterpreter = new DbkTextInterpreter();
-       private DbkImageManager imageManager;
-
-       private FileUploadListener fileUploadListener;
-       private DbkContextMenu styledTools;
-
-       private final boolean flat;
-
-       private boolean showMainTitle = true;
-
-       private Integer maxMediaWidth = null;
-       private String defaultSectionStyle;
-
-       protected AbstractDbkViewer(Section parent, int style, CmsEditable cmsEditable) {
-               super(parent, style, cmsEditable);
-//             CmsView cmsView = CmsView.getCmsView(parent);
-//             imageManager = cmsView.getImageManager();
-               flat = SWT.FLAT == (style & SWT.FLAT);
-
-               if (getCmsEditable().canEdit()) {
-                       fileUploadListener = new FUL();
-                       styledTools = new DbkContextMenu(this, parent.getShell());
-               }
-               this.mainSection = parent;
-               Node baseFolder = Jcr.getParent(mainSection.getNode());
-               imageManager = new DbkImageManager(baseFolder);
-               initModelIfNeeded(mainSection.getNode());
-               // layout(this.mainSection);
-       }
-
-       @Override
-       public Control getControl() {
-               return mainSection;
-       }
-
-       protected void refresh(Control control) throws RepositoryException {
-               if (!(control instanceof Section))
-                       return;
-               long begin = System.currentTimeMillis();
-               Section section = (Section) control;
-               if (section instanceof TextSection) {
-                       CmsSwtUtils.clear(section);
-                       Node node = section.getNode();
-                       TextSection textSection = (TextSection) section;
-                       String style = node.hasProperty(DbkAttr.role.name()) ? node.getProperty(DbkAttr.role.name()).getString()
-                                       : getDefaultSectionStyle();
-                       if (style != null)
-                               CmsSwtUtils.style(textSection, style);
-
-                       // Title
-                       Node titleNode = null;
-                       // We give priority to ./title vs ./info/title, like the DocBook XSL
-                       if (node.hasNode(DbkType.title.get())) {
-                               titleNode = node.getNode(DbkType.title.get());
-                       } else if (node.hasNode(DbkType.info.get() + '/' + DbkType.title.get())) {
-                               titleNode = node.getNode(DbkType.info.get() + '/' + DbkType.title.get());
-                       }
-
-                       if (titleNode != null) {
-                               boolean showTitle = getMainSection() == section ? showMainTitle : true;
-                               if (showTitle) {
-                                       if (section.getHeader() == null)
-                                               section.createHeader();
-                                       DbkSectionTitle title = newSectionTitle(textSection, titleNode);
-                                       title.setLayoutData(CmsSwtUtils.fillWidth());
-                                       updateContent(title);
-                               }
-                       }
-
-                       // content
-                       for (NodeIterator ni = node.getNodes(); ni.hasNext();) {
-                               Node child = ni.nextNode();
-                               SectionPart sectionPart = null;
-                               if (isDbk(child, DbkType.mediaobject)) {
-                                       if (child.hasNode(DbkType.imageobject.get())) {
-                                               sectionPart = newImg(textSection, child);
-                                       } else if (child.hasNode(DbkType.videoobject.get())) {
-                                               sectionPart = newVideo(textSection, child);
-                                       } else {
-                                               throw new IllegalArgumentException("Unsupported media object " + child);
-                                       }
-                               } else if (isDbk(child, DbkType.info)) {
-                                       // TODO enrich UI based on info
-                               } else if (isDbk(child, DbkType.title)) {
-                                       // already managed
-                               } else if (isDbk(child, para)) {
-                                       sectionPart = newParagraph(textSection, child);
-                               } else if (isDbk(child, DbkType.section)) {
-                                       sectionPart = newSectionPart(textSection, child);
-//                                     if (sectionPart == null)
-//                                             throw new IllegalArgumentException("Unsupported node " + child);
-                                       // TODO list node types in exception
-                               } else {
-                                       throw new IllegalArgumentException("Unsupported node type for " + child);
-                               }
-                               if (sectionPart != null && sectionPart instanceof Control)
-                                       ((Control) sectionPart).setLayoutData(CmsSwtUtils.fillWidth());
-                       }
-
-//                     if (!flat)
-                       for (NodeIterator ni = section.getNode().getNodes(DbkType.section.get()); ni.hasNext();) {
-                               Node child = ni.nextNode();
-                               if (isDbk(child, DbkType.section)) {
-                                       TextSection newSection = newTextSection(section, child);
-                                       newSection.setLayoutData(CmsSwtUtils.fillWidth());
-                                       refresh(newSection);
-                               }
-                       }
-               } else {
-                       for (Section s : section.getSubSections().values())
-                               refresh(s);
-               }
-               // section.layout(true, true);
-               long duration = System.currentTimeMillis() - begin;
-//             System.out.println(duration + " ms - " + DbkUtils.getTitle(section.getNode()));
-       }
-
-       /** To be overridden in order to provide additional SectionPart types */
-       protected TextSection newTextSection(Section section, Node node) {
-               return new TextSection(section, SWT.NONE, node);
-       }
-
-       /** To be overridden in order to provide additional SectionPart types */
-       protected SectionPart newSectionPart(TextSection textSection, Node node) {
-               return null;
-       }
-
-       // CRUD
-       protected Paragraph newParagraph(TextSection parent, Node node) throws RepositoryException {
-               Paragraph paragraph = new Paragraph(parent, parent.getStyle(), node);
-               updateContent(paragraph);
-               paragraph.setLayoutData(CmsSwtUtils.fillWidth());
-               paragraph.setMouseListener(getMouseListener());
-               paragraph.setFocusListener(getFocusListener());
-               return paragraph;
-       }
-
-       protected DbkImg newImg(TextSection parent, Node node) {
-               try {
-                       DbkImg img = new DbkImg(parent, parent.getStyle(), node, imageManager);
-                       GridData imgGd;
-                       if (maxMediaWidth != null) {
-                               imgGd = new GridData(SWT.CENTER, SWT.FILL, false, false);
-                               imgGd.widthHint = maxMediaWidth;
-                               img.setPreferredSize(new Cms2DSize(maxMediaWidth, 0));
-                       } else {
-                               imgGd = CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT);
-                       }
-                       img.setLayoutData(imgGd);
-                       updateContent(img);
-                       img.setMouseListener(getMouseListener());
-                       img.setFocusListener(getFocusListener());
-                       return img;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot add new image " + node, e);
-               }
-       }
-
-       protected DbkVideo newVideo(TextSection parent, Node node) {
-               try {
-                       DbkVideo video = new DbkVideo(parent, getCmsEditable().canEdit() ? SWT.NONE : SWT.READ_ONLY, node);
-                       GridData gd;
-                       if (maxMediaWidth != null) {
-                               gd = new GridData(SWT.CENTER, SWT.FILL, false, false);
-                               // TODO, manage size
-//                             gd.widthHint = maxMediaWidth;
-//                             gd.heightHint = (int) (gd.heightHint * 0.5625);
-                       } else {
-                               gd = new GridData(SWT.CENTER, SWT.FILL, false, false);
-//                             gd.widthHint = video.getWidth();
-//                             gd.heightHint = video.getHeight();
-                       }
-                       video.setLayoutData(gd);
-                       updateContent(video);
-                       return video;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot add new image " + node, e);
-               }
-       }
-
-       protected DbkSectionTitle newSectionTitle(TextSection parent, Node titleNode) throws RepositoryException {
-               int style = parent.getStyle();
-               Composite titleParent = newSectionHeader(parent);
-               if (parent.isTitleReadOnly())
-                       style = style | SWT.READ_ONLY;
-               DbkSectionTitle title = new DbkSectionTitle(titleParent, style, titleNode);
-               updateContent(title);
-               title.setMouseListener(getMouseListener());
-               title.setFocusListener(getFocusListener());
-               return title;
-       }
-
-       /**
-        * To be overridden in order to provide additional processing at the section
-        * level.
-        * 
-        * @return the parent to use for the {@link DbkSectionTitle}, by default
-        *         {@link Section#getHeader()}
-        */
-       protected Composite newSectionHeader(TextSection section) {
-               return section.getHeader();
-       }
-
-       protected DbkSectionTitle prepareSectionTitle(Section newSection, String titleText) throws RepositoryException {
-               Node sectionNode = newSection.getNode();
-               Node titleNode = DbkUtils.getOrAddDbk(sectionNode, DbkType.title);
-               getTextInterpreter().write(titleNode, titleText);
-               if (newSection.getHeader() == null)
-                       newSection.createHeader();
-               DbkSectionTitle sectionTitle = newSectionTitle((TextSection) newSection, sectionNode);
-               return sectionTitle;
-       }
-
-       protected void updateContent(EditablePart part) throws RepositoryException {
-               if (part instanceof SectionPart) {
-                       SectionPart sectionPart = (SectionPart) part;
-                       Node partNode = sectionPart.getNode();
-
-                       if (part instanceof StyledControl && (sectionPart.getSection() instanceof TextSection)) {
-                               TextSection section = (TextSection) sectionPart.getSection();
-                               StyledControl styledControl = (StyledControl) part;
-                               if (isDbk(partNode, para)) {
-                                       String style = partNode.hasProperty(DbkAttr.role.name())
-                                                       ? partNode.getProperty(DbkAttr.role.name()).getString()
-                                                       : section.getDefaultTextStyle();
-                                       styledControl.setStyle(style);
-                               }
-                       }
-                       // use control AFTER setting style, since it may have been reset
-
-                       if (part instanceof EditableText) {
-                               EditableText paragraph = (EditableText) part;
-                               if (paragraph == getEdited())
-                                       paragraph.setText(textInterpreter.raw(partNode));
-                               else
-                                       paragraph.setText(textInterpreter.readSimpleHtml(partNode));
-                       } else if (part instanceof DbkImg) {
-                               DbkImg editableImage = (DbkImg) part;
-                               // imageManager.load(partNode, part.getControl(),
-                               // editableImage.getPreferredImageSize());
-                       } else if (part instanceof DbkVideo) {
-                               DbkVideo video = (DbkVideo) part;
-                               video.load(part.getControl());
-                       }
-               } else if (part instanceof DbkSectionTitle) {
-                       DbkSectionTitle title = (DbkSectionTitle) part;
-                       title.setStyle(title.getSection().getTitleStyle());
-                       // use control AFTER setting style
-                       if (title == getEdited())
-                               title.setText(textInterpreter.read(title.getNode()));
-                       else
-                               title.setText(textInterpreter.readSimpleHtml(title.getNode()));
-               }
-       }
-
-       // OVERRIDDEN FROM PARENT VIEWER
-       @Override
-       protected void save(EditablePart part) throws RepositoryException {
-               if (part instanceof EditableText) {
-                       EditableText et = (EditableText) part;
-                       if (!et.getEditable())
-                               return;
-                       String text = ((Text) et.getControl()).getText();
-
-                       // String[] lines = text.split("[\r\n]+");
-                       String[] lines = { text };
-                       assert lines.length != 0;
-                       saveLine(part, lines[0]);
-                       if (lines.length > 1) {
-                               ArrayList<Control> toLayout = new ArrayList<Control>();
-                               if (part instanceof Paragraph) {
-                                       Paragraph currentParagraph = (Paragraph) et;
-                                       Section section = currentParagraph.getSection();
-                                       Node sectionNode = section.getNode();
-                                       Node currentParagraphN = currentParagraph.getNode();
-                                       for (int i = 1; i < lines.length; i++) {
-                                               Node newNode = addDbk(sectionNode, para);
-                                               // newNode.addMixin(CmsTypes.CMS_STYLED);
-                                               saveLine(newNode, lines[i]);
-                                               // second node was create as last, if it is not the next
-                                               // one, it
-                                               // means there are some in between and we can take the
-                                               // one at
-                                               // index+1 for the re-order
-                                               if (newNode.getIndex() > currentParagraphN.getIndex() + 1) {
-                                                       sectionNode.orderBefore(p(newNode.getIndex()), p(currentParagraphN.getIndex() + 1));
-                                               }
-                                               Paragraph newParagraph = newParagraph((TextSection) section, newNode);
-                                               newParagraph.moveBelow(currentParagraph);
-                                               toLayout.add(newParagraph);
-
-                                               currentParagraph = newParagraph;
-                                               currentParagraphN = newNode;
-                                       }
-                               }
-                               // TODO or rather return the created paragraphs?
-                               layout(toLayout.toArray(new Control[toLayout.size()]));
-                       }
-                       persistChanges(et.getNode());
-               }
-       }
-
-       protected void saveLine(EditablePart part, String line) {
-               if (part instanceof NodePart) {
-                       saveLine(((NodePart) part).getNode(), line);
-               } else if (part instanceof PropertyPart) {
-                       saveLine(((PropertyPart) part).getProperty(), line);
-               } else {
-                       throw new IllegalArgumentException("Unsupported part " + part);
-               }
-       }
-
-       protected void saveLine(Item item, String line) {
-               line = line.trim();
-               textInterpreter.write(item, line);
-       }
-
-       @Override
-       protected void prepare(EditablePart part, Object caretPosition) {
-               Control control = part.getControl();
-               if (control instanceof Text) {
-                       Text text = (Text) control;
-                       if (caretPosition != null)
-                               if (caretPosition instanceof Integer)
-                                       text.setSelection((Integer) caretPosition);
-                               else if (caretPosition instanceof Point) {
-//                                     layout(text);
-//                                     // TODO find a way to position the caret at the right place
-//                                     Point clickLocation = (Point) caretPosition;
-//                                     Point withinText = text.toControl(clickLocation);
-//                                     Rectangle bounds = text.getBounds();
-//                                     int width = bounds.width;
-//                                     int height = bounds.height;
-//                                     int textLength = text.getText().length();
-//                                     float area = width * height;
-//                                     float proportion = withinText.y * width + withinText.x;
-//                                     int pos = (int) (textLength * (proportion / area));
-//                                     text.setSelection(pos);
-                               }
-                       text.setData(RWT.ACTIVE_KEYS, new String[] { "BACKSPACE", "ESC", "TAB", "SHIFT+TAB", "ALT+ARROW_LEFT",
-                                       "ALT+ARROW_RIGHT", "ALT+ARROW_UP", "ALT+ARROW_DOWN", "RETURN", "CTRL+RETURN", "ENTER", "DELETE" });
-                       text.setData(RWT.CANCEL_KEYS, new String[] { "RETURN", "ALT+ARROW_LEFT", "ALT+ARROW_RIGHT" });
-                       text.addKeyListener(this);
-               } else if (part instanceof DbkImg) {
-                       ((DbkImg) part).setFileUploadListener(fileUploadListener);
-               }
-       }
-
-       // REQUIRED BY CONTEXT MENU
-       void setParagraphStyle(Paragraph paragraph, String style) {
-               try {
-                       Node paragraphNode = paragraph.getNode();
-                       if (style == null) {// default
-                               if (paragraphNode.hasProperty(DbkAttr.role.name()))
-                                       paragraphNode.getProperty(DbkAttr.role.name()).remove();
-                       } else {
-                               paragraphNode.setProperty(DbkAttr.role.name(), style);
-                       }
-                       persistChanges(paragraphNode);
-                       updateContent(paragraph);
-                       layoutPage();
-               } catch (RepositoryException e1) {
-                       throw new JcrException("Cannot set style " + style + " on " + paragraph, e1);
-               }
-       }
-
-       SectionPart insertPart(Section section, Node node) {
-               try {
-                       refresh(section);
-                       layoutPage();
-                       for (Control control : section.getChildren()) {
-                               if (control instanceof SectionPart) {
-                                       SectionPart sectionPart = (SectionPart) control;
-                                       Node partNode = sectionPart.getNode();
-                                       if (partNode.getPath().equals(node.getPath()))
-                                               return sectionPart;
-                               }
-                       }
-                       throw new IllegalStateException("New section part " + node + "not found");
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot insert part " + node + " in section " + section.getNode(), e);
-               }
-       }
-
-       void addParagraph(SectionPart partBefore, String txt) {
-               Section section = partBefore.getSection();
-               SectionPart nextSectionPart = section.nextSectionPart(partBefore);
-               Node newNode = addDbk(section.getNode(), para);
-               textInterpreter.write(newNode, txt != null ? txt : "");
-               if (nextSectionPart != null) {
-                       try {
-                               Node nextNode = nextSectionPart.getNode();
-                               section.getNode().orderBefore(Jcr.getIndexedName(newNode), Jcr.getIndexedName(nextNode));
-                       } catch (RepositoryException e) {
-                               throw new JcrException("Cannot order " + newNode + " before " + nextSectionPart.getNode(), e);
-                       }
-               }
-               Jcr.save(newNode);
-               Paragraph paragraph = (Paragraph) insertPart(partBefore.getSection(), newNode);
-               edit(paragraph, 0);
-       }
-
-       void deletePart(SectionPart sectionPart) {
-               try {
-                       Node node = sectionPart.getNode();
-                       Session session = node.getSession();
-                       if (sectionPart instanceof DbkImg) {
-                               if (!isDbk(node, DbkType.mediaobject))
-                                       throw new IllegalArgumentException("Node " + node + " is not a media object.");
-                       }
-                       node.remove();
-                       session.save();
-                       if (sectionPart instanceof Control)
-                               ((Control) sectionPart).dispose();
-                       layoutPage();
-               } catch (RepositoryException e1) {
-                       throw new JcrException("Cannot delete " + sectionPart, e1);
-               }
-       }
-
-       void deleteSection(Section section) {
-               try {
-                       Node node = section.getNode();
-                       Session session = node.getSession();
-                       node.remove();
-                       session.save();
-                       section.dispose();
-                       layoutPage();
-               } catch (RepositoryException e1) {
-                       throw new JcrException("Cannot delete " + section, e1);
-               }
-       }
-
-       String getRawParagraphText(Paragraph paragraph) {
-               return textInterpreter.raw(paragraph.getNode());
-       }
-
-       // COMMANDS
-       protected void splitEdit() {
-               checkEdited();
-               try {
-                       if (getEdited() instanceof Paragraph) {
-                               Paragraph paragraph = (Paragraph) getEdited();
-                               Text text = (Text) paragraph.getControl();
-                               int caretPosition = text.getCaretPosition();
-                               String txt = text.getText();
-                               String first = txt.substring(0, caretPosition);
-                               String second = txt.substring(caretPosition);
-                               Node firstNode = paragraph.getNode();
-                               Node sectionNode = firstNode.getParent();
-
-                               // FIXME set content the DocBook way
-                               // firstNode.setProperty(CMS_CONTENT, first);
-                               Node secondNode = addDbk(sectionNode, para);
-                               // secondNode.addMixin(CmsTypes.CMS_STYLED);
-
-                               // second node was create as last, if it is not the next one, it
-                               // means there are some in between and we can take the one at
-                               // index+1 for the re-order
-                               if (secondNode.getIndex() > firstNode.getIndex() + 1) {
-                                       sectionNode.orderBefore(p(secondNode.getIndex()), p(firstNode.getIndex() + 1));
-                               }
-
-                               // if we die in between, at least we still have the whole text
-                               // in the first node
-                               try {
-                                       textInterpreter.write(secondNode, second);
-                                       textInterpreter.write(firstNode, first);
-                               } catch (Exception e) {
-                                       // so that no additional nodes are created:
-                                       JcrUtils.discardUnderlyingSessionQuietly(firstNode);
-                                       throw e;
-                               }
-
-                               persistChanges(firstNode);
-
-                               Paragraph secondParagraph = paragraphSplitted(paragraph, secondNode);
-                               edit(secondParagraph, 0);
-                       } else if (getEdited() instanceof DbkSectionTitle) {
-                               DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited();
-                               Text text = (Text) sectionTitle.getControl();
-                               String txt = text.getText();
-                               int caretPosition = text.getCaretPosition();
-                               Section section = sectionTitle.getSection();
-                               Node sectionNode = section.getNode();
-                               Node paragraphNode = addDbk(sectionNode, para);
-                               // paragraphNode.addMixin(CmsTypes.CMS_STYLED);
-
-                               textInterpreter.write(paragraphNode, txt.substring(caretPosition));
-                               textInterpreter.write(sectionNode.getNode(DbkType.title.get()), txt.substring(0, caretPosition));
-                               sectionNode.orderBefore(p(paragraphNode.getIndex()), p(1));
-                               persistChanges(sectionNode);
-
-                               Paragraph paragraph = sectionTitleSplitted(sectionTitle, paragraphNode);
-                               // section.layout();
-                               edit(paragraph, 0);
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot split " + getEdited(), e);
-               }
-       }
-
-       protected void mergeWithPrevious() {
-               checkEdited();
-               try {
-                       Paragraph paragraph = (Paragraph) getEdited();
-                       Text text = (Text) paragraph.getControl();
-                       String txt = text.getText();
-                       Node paragraphNode = paragraph.getNode();
-                       if (paragraphNode.getIndex() == 1)
-                               return;// do nothing
-                       Node sectionNode = paragraphNode.getParent();
-                       Node previousNode = sectionNode.getNode(p(paragraphNode.getIndex() - 1));
-                       String previousTxt = textInterpreter.read(previousNode);
-                       textInterpreter.write(previousNode, previousTxt + txt);
-                       paragraphNode.remove();
-                       persistChanges(sectionNode);
-
-                       Paragraph previousParagraph = paragraphMergedWithPrevious(paragraph, previousNode);
-                       edit(previousParagraph, previousTxt.length());
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot stop editing", e);
-               }
-       }
-
-       protected void mergeWithNext() {
-               checkEdited();
-               try {
-                       Paragraph paragraph = (Paragraph) getEdited();
-                       Text text = (Text) paragraph.getControl();
-                       String txt = text.getText();
-                       Node paragraphNode = paragraph.getNode();
-                       Node sectionNode = paragraphNode.getParent();
-                       NodeIterator paragraphNodes = sectionNode.getNodes(DbkType.para.get());
-                       long size = paragraphNodes.getSize();
-                       if (paragraphNode.getIndex() == size)
-                               return;// do nothing
-                       Node nextNode = sectionNode.getNode(p(paragraphNode.getIndex() + 1));
-                       String nextTxt = textInterpreter.read(nextNode);
-                       textInterpreter.write(paragraphNode, txt + nextTxt);
-
-                       Section section = paragraph.getSection();
-                       Paragraph removed = (Paragraph) section.getSectionPart(nextNode.getIdentifier());
-
-                       nextNode.remove();
-                       persistChanges(sectionNode);
-
-                       paragraphMergedWithNext(paragraph, removed);
-                       edit(paragraph, txt.length());
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot stop editing", e);
-               }
-       }
-
-       protected synchronized void upload(EditablePart part) {
-               try {
-                       if (part instanceof SectionPart) {
-                               SectionPart sectionPart = (SectionPart) part;
-                               Node partNode = sectionPart.getNode();
-                               int partIndex = partNode.getIndex();
-                               Section section = sectionPart.getSection();
-                               Node sectionNode = section.getNode();
-
-                               if (part instanceof Paragraph) {
-                                       // FIXME adapt to DocBook
-//                                     Node newNode = sectionNode.addNode(DocBookNames.DBK_MEDIAOBJECT, NodeType.NT_FILE);
-//                                     newNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
-//                                     JcrUtils.copyBytesAsFile(sectionNode, p(newNode.getIndex()), new byte[0]);
-//                                     if (partIndex < newNode.getIndex() - 1) {
-//                                             // was not last
-//                                             sectionNode.orderBefore(p(newNode.getIndex()), p(partIndex - 1));
-//                                     }
-//                                     // sectionNode.orderBefore(p(partNode.getIndex()),
-//                                     // p(newNode.getIndex()));
-//                                     persistChanges(sectionNode);
-//                                     DbkImg img = newImg((TextSection) section, newNode);
-//                                     edit(img, null);
-//                                     layout(img.getControl());
-                               } else if (part instanceof DbkImg) {
-                                       if (getEdited() == part)
-                                               return;
-                                       edit(part, null);
-                                       layoutPage();
-                               }
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot upload", e);
-               }
-       }
-
-       protected void deepen() {
-               if (flat)
-                       return;
-               checkEdited();
-               try {
-                       if (getEdited() instanceof Paragraph) {
-                               Paragraph paragraph = (Paragraph) getEdited();
-                               Text text = (Text) paragraph.getControl();
-                               String txt = text.getText();
-                               Node paragraphNode = paragraph.getNode();
-                               Section section = paragraph.getSection();
-                               Node sectionNode = section.getNode();
-                               // main title
-                               if (section == mainSection && section instanceof TextSection && paragraphNode.getIndex() == 1
-                                               && !sectionNode.hasNode(DbkType.title.get())) {
-                                       DbkSectionTitle sectionTitle = prepareSectionTitle(section, txt);
-                                       edit(sectionTitle, 0);
-                                       return;
-                               }
-                               Node newSectionNode = addDbk(sectionNode, DbkType.section);
-                               // newSectionNode.addMixin(NodeType.MIX_TITLE);
-                               sectionNode.orderBefore(h(newSectionNode.getIndex()), h(1));
-
-                               int paragraphIndex = paragraphNode.getIndex();
-                               String sectionPath = sectionNode.getPath();
-                               String newSectionPath = newSectionNode.getPath();
-                               while (sectionNode.hasNode(p(paragraphIndex + 1))) {
-                                       Node parag = sectionNode.getNode(p(paragraphIndex + 1));
-                                       sectionNode.getSession().move(sectionPath + '/' + p(paragraphIndex + 1),
-                                                       newSectionPath + '/' + DbkType.para.get());
-                                       SectionPart sp = section.getSectionPart(parag.getIdentifier());
-                                       if (sp instanceof Control)
-                                               ((Control) sp).dispose();
-                               }
-                               // create title
-                               Node titleNode = DbkUtils.addDbk(newSectionNode, DbkType.title);
-                               // newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE);
-                               getTextInterpreter().write(titleNode, txt);
-
-                               TextSection newSection = new TextSection(section, section.getStyle(), newSectionNode);
-                               newSection.setLayoutData(CmsSwtUtils.fillWidth());
-                               newSection.moveBelow(paragraph);
-
-                               // dispose
-                               paragraphNode.remove();
-                               paragraph.dispose();
-
-                               refresh(newSection);
-                               newSection.getParent().layout();
-                               layout(newSection);
-                               persistChanges(sectionNode);
-                       } else if (getEdited() instanceof DbkSectionTitle) {
-                               DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited();
-                               Section section = sectionTitle.getSection();
-                               Section parentSection = section.getParentSection();
-                               if (parentSection == null)
-                                       return;// cannot deepen main section
-                               Node sectionN = section.getNode();
-                               Node parentSectionN = parentSection.getNode();
-                               if (sectionN.getIndex() == 1)
-                                       return;// cannot deepen first section
-                               Node previousSectionN = parentSectionN.getNode(h(sectionN.getIndex() - 1));
-                               NodeIterator subSections = previousSectionN.getNodes(DbkType.section.get());
-                               int subsectionsCount = (int) subSections.getSize();
-                               previousSectionN.getSession().move(sectionN.getPath(),
-                                               previousSectionN.getPath() + "/" + h(subsectionsCount + 1));
-                               section.dispose();
-                               TextSection newSection = new TextSection(section, section.getStyle(), sectionN);
-                               refresh(newSection);
-                               persistChanges(previousSectionN);
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot deepen " + getEdited(), e);
-               }
-       }
-
-       protected void undeepen() {
-               if (flat)
-                       return;
-               checkEdited();
-               try {
-                       if (getEdited() instanceof Paragraph) {
-                               upload(getEdited());
-                       } else if (getEdited() instanceof DbkSectionTitle) {
-                               DbkSectionTitle sectionTitle = (DbkSectionTitle) getEdited();
-                               Section section = sectionTitle.getSection();
-                               Node sectionNode = section.getNode();
-                               Section parentSection = section.getParentSection();
-                               if (parentSection == null)
-                                       return;// cannot undeepen main section
-
-                               // choose in which section to merge
-                               Section mergedSection;
-                               if (sectionNode.getIndex() == 1)
-                                       mergedSection = section.getParentSection();
-                               else {
-                                       Map<String, Section> parentSubsections = parentSection.getSubSections();
-                                       ArrayList<Section> lst = new ArrayList<Section>(parentSubsections.values());
-                                       mergedSection = lst.get(sectionNode.getIndex() - 1);
-                               }
-                               Node mergedNode = mergedSection.getNode();
-                               boolean mergedHasSubSections = mergedNode.hasNode(DbkType.section.get());
-
-                               // title as paragraph
-                               Node newParagrapheNode = addDbk(mergedNode, para);
-                               // newParagrapheNode.addMixin(CmsTypes.CMS_STYLED);
-                               if (mergedHasSubSections)
-                                       mergedNode.orderBefore(p(newParagrapheNode.getIndex()), h(1));
-                               String txt = getTextInterpreter().read(sectionNode.getNode(DbkType.title.get()));
-                               getTextInterpreter().write(newParagrapheNode, txt);
-                               // move
-                               NodeIterator paragraphs = sectionNode.getNodes(para.get());
-                               while (paragraphs.hasNext()) {
-                                       Node p = paragraphs.nextNode();
-                                       SectionPart sp = section.getSectionPart(p.getIdentifier());
-                                       if (sp instanceof Control)
-                                               ((Control) sp).dispose();
-                                       mergedNode.getSession().move(p.getPath(), mergedNode.getPath() + '/' + para.get());
-                                       if (mergedHasSubSections)
-                                               mergedNode.orderBefore(p(p.getIndex()), h(1));
-                               }
-
-                               Iterator<Section> subsections = section.getSubSections().values().iterator();
-                               // NodeIterator sections = sectionNode.getNodes(CMS_H);
-                               while (subsections.hasNext()) {
-                                       Section subsection = subsections.next();
-                                       Node s = subsection.getNode();
-                                       mergedNode.getSession().move(s.getPath(), mergedNode.getPath() + '/' + DbkType.section.get());
-                                       subsection.dispose();
-                               }
-
-                               // remove section
-                               section.getNode().remove();
-                               section.dispose();
-
-                               refresh(mergedSection);
-                               mergedSection.getParent().layout();
-                               layout(mergedSection);
-                               persistChanges(mergedNode);
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot undeepen " + getEdited(), e);
-               }
-       }
-
-       // UI CHANGES
-       protected Paragraph paragraphSplitted(Paragraph paragraph, Node newNode) throws RepositoryException {
-               Section section = paragraph.getSection();
-               updateContent(paragraph);
-               Paragraph newParagraph = newParagraph((TextSection) section, newNode);
-               newParagraph.setLayoutData(CmsSwtUtils.fillWidth());
-               newParagraph.moveBelow(paragraph);
-               layout(paragraph.getControl(), newParagraph.getControl());
-               return newParagraph;
-       }
-
-       protected Paragraph sectionTitleSplitted(DbkSectionTitle sectionTitle, Node newNode) throws RepositoryException {
-               updateContent(sectionTitle);
-               Paragraph newParagraph = newParagraph(sectionTitle.getSection(), newNode);
-               // we assume beforeFirst is not null since there was a sectionTitle
-               newParagraph.moveBelow(sectionTitle.getSection().getHeader());
-               layout(sectionTitle.getControl(), newParagraph.getControl());
-               return newParagraph;
-       }
-
-       protected Paragraph paragraphMergedWithPrevious(Paragraph removed, Node remaining) throws RepositoryException {
-               Section section = removed.getSection();
-               removed.dispose();
-
-               Paragraph paragraph = (Paragraph) section.getSectionPart(remaining.getIdentifier());
-               updateContent(paragraph);
-               layout(paragraph.getControl());
-               return paragraph;
-       }
-
-       protected void paragraphMergedWithNext(Paragraph remaining, Paragraph removed) throws RepositoryException {
-               removed.dispose();
-               updateContent(remaining);
-               layout(remaining.getControl());
-       }
-
-       // UTILITIES
-       protected String p(Integer index) {
-               StringBuilder sb = new StringBuilder(6);
-               sb.append(para.get()).append('[').append(index).append(']');
-               return sb.toString();
-       }
-
-       protected String h(Integer index) {
-               StringBuilder sb = new StringBuilder(5);
-               sb.append(DbkType.section.get()).append('[').append(index).append(']');
-               return sb.toString();
-       }
-
-       // GETTERS / SETTERS
-       public Section getMainSection() {
-               return mainSection;
-       }
-
-       public boolean isFlat() {
-               return flat;
-       }
-
-       public TextInterpreter getTextInterpreter() {
-               return textInterpreter;
-       }
-
-       // KEY LISTENER
-       @Override
-       public void keyPressed(KeyEvent ke) {
-               if (log.isTraceEnabled())
-                       log.trace(ke);
-
-               if (getEdited() == null)
-                       return;
-               boolean altPressed = (ke.stateMask & SWT.ALT) != 0;
-               boolean shiftPressed = (ke.stateMask & SWT.SHIFT) != 0;
-               boolean ctrlPressed = (ke.stateMask & SWT.CTRL) != 0;
-
-               try {
-                       // Common
-                       if (ke.keyCode == SWT.ESC) {
-//                             cancelEdit();
-                               saveEdit();
-                       } else if (ke.character == '\r') {
-                               if (!shiftPressed)
-                                       splitEdit();
-                       } else if (ke.character == 'z') {
-                               if (ctrlPressed)
-                                       cancelEdit();
-                       } else if (ke.character == 'S') {
-                               if (ctrlPressed)
-                                       saveEdit();
-                       } else if (ke.character == '\t') {
-                               if (!shiftPressed) {
-                                       deepen();
-                               } else if (shiftPressed) {
-                                       undeepen();
-                               }
-                       } else {
-                               if (getEdited() instanceof Paragraph) {
-                                       Paragraph paragraph = (Paragraph) getEdited();
-                                       Section section = paragraph.getSection();
-                                       if (altPressed && ke.keyCode == SWT.ARROW_RIGHT) {
-                                               edit(section.nextSectionPart(paragraph), 0);
-                                       } else if (altPressed && ke.keyCode == SWT.ARROW_LEFT) {
-                                               edit(section.previousSectionPart(paragraph), 0);
-                                       } else if (ke.character == SWT.BS) {
-                                               Text text = (Text) paragraph.getControl();
-                                               int caretPosition = text.getCaretPosition();
-                                               if (caretPosition == 0) {
-                                                       mergeWithPrevious();
-                                               }
-                                       } else if (ke.character == SWT.DEL) {
-                                               Text text = (Text) paragraph.getControl();
-                                               int caretPosition = text.getCaretPosition();
-                                               int charcount = text.getCharCount();
-                                               if (caretPosition == charcount) {
-                                                       mergeWithNext();
-                                               }
-                                       }
-                               }
-                       }
-               } catch (Exception e) {
-                       ke.doit = false;
-                       notifyEditionException(e);
-               }
-       }
-
-       @Override
-       public void keyReleased(KeyEvent e) {
-       }
-
-       // MOUSE LISTENER
-       @Override
-       protected MouseListener createMouseListener() {
-               return new ML();
-       }
-
-       private class ML extends MouseAdapter {
-               private static final long serialVersionUID = 8526890859876770905L;
-
-               @Override
-               public void mouseDoubleClick(MouseEvent e) {
-                       if (e.button == 1) {
-                               Control source = (Control) e.getSource();
-                               EditablePart composite = findDataParent(source);
-                               Point point = new Point(e.x, e.y);
-                               if (composite instanceof DbkImg) {
-                                       if (getCmsEditable().canEdit()) {
-                                               if (getCmsEditable().isEditing() && !(getEdited() instanceof DbkImg)) {
-                                                       if (source == mainSection)
-                                                               return;
-                                                       EditablePart part = findDataParent(source);
-                                                       upload(part);
-                                               } else {
-                                                       getCmsEditable().startEditing();
-                                               }
-                                       }
-                               } else if (source instanceof Label) {
-                                       Label lbl = (Label) source;
-                                       Rectangle bounds = lbl.getBounds();
-                                       float width = bounds.width;
-                                       float height = bounds.height;
-                                       float textLength = lbl.getText().length();
-                                       float area = width * height;
-                                       float charArea = area / textLength;
-                                       float lines = textLength / width;
-                                       float proportion = point.y * width + point.x;
-                                       int pos = (int) (textLength * (proportion / area));
-                                       // TODO refine it
-                                       edit(composite, (Integer) pos);
-                               } else {
-                                       edit(composite, source.toDisplay(point));
-                               }
-                       }
-               }
-
-               @Override
-               public void mouseDown(MouseEvent e) {
-                       if (getCmsEditable().isEditing()) {
-                               if (e.button == 3) {
-                                       EditablePart composite = findDataParent((Control) e.getSource());
-                                       if (styledTools != null) {
-                                               List<String> styles = getAvailableStyles(composite);
-                                               styledTools.show(composite, new Point(e.x, e.y), styles);
-                                       }
-                               }
-                       }
-               }
-
-               @Override
-               public void mouseUp(MouseEvent e) {
-               }
-       }
-
-       protected List<String> getAvailableStyles(EditablePart editablePart) {
-               return new ArrayList<>();
-       }
-
-       public void setMaxMediaWidth(Integer maxMediaWidth) {
-               this.maxMediaWidth = maxMediaWidth;
-       }
-
-       public void setShowMainTitle(boolean showMainTitle) {
-               this.showMainTitle = showMainTitle;
-       }
-
-       public String getDefaultSectionStyle() {
-               return defaultSectionStyle;
-       }
-
-       public void setDefaultSectionStyle(String defaultSectionStyle) {
-               this.defaultSectionStyle = defaultSectionStyle;
-       }
-
-       // FILE UPLOAD LISTENER
-       private class FUL implements FileUploadListener {
-               public void uploadProgress(FileUploadEvent event) {
-                       // TODO Monitor upload progress
-               }
-
-               public void uploadFailed(FileUploadEvent event) {
-                       throw new RuntimeException("Upload failed " + event, event.getException());
-               }
-
-               public void uploadFinished(FileUploadEvent event) {
-                       for (FileDetails file : event.getFileDetails()) {
-                               if (log.isDebugEnabled())
-                                       log.debug("Received: " + file.getFileName());
-                       }
-                       mainSection.getDisplay().syncExec(new Runnable() {
-                               @Override
-                               public void run() {
-                                       saveEdit();
-                               }
-                       });
-                       FileUploadHandler uploadHandler = (FileUploadHandler) event.getSource();
-                       uploadHandler.dispose();
-               }
-       }
-}
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/CustomDbkEditor.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/CustomDbkEditor.java
deleted file mode 100644 (file)
index 94c9825..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.argeo.docbook.ui;
-
-import javax.jcr.Node;
-
-import org.argeo.api.cms.CmsEditable;
-import org.argeo.cms.ui.viewers.Section;
-import org.eclipse.swt.widgets.Composite;
-
-/**
- * Manages hardcoded sections as an arbitrary hierarchy under the main section,
- * which contains no text and no title.
- */
-public class CustomDbkEditor extends AbstractDbkViewer {
-       private static final long serialVersionUID = 656302500183820802L;
-
-       public CustomDbkEditor(Composite parent, int style, Node textNode, CmsEditable cmsEditable) {
-               this(new Section(parent, style, textNode), style, cmsEditable);
-       }
-
-       public CustomDbkEditor(Section parent, int style, CmsEditable cmsEditable) {
-               super(parent, style, cmsEditable);
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkContextMenu.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkContextMenu.java
deleted file mode 100644 (file)
index 778f7c8..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-package org.argeo.docbook.ui;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-
-import org.argeo.api.cms.CmsEditable;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.MouseDown;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.viewers.NodePart;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.cms.ui.viewers.SectionPart;
-import org.argeo.cms.ui.widgets.EditableText;
-import org.argeo.cms.ui.widgets.Img;
-import org.argeo.docbook.DbkMsg;
-import org.argeo.docbook.DbkUtils;
-import org.argeo.jcr.Jcr;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-
-/** Dialog to edit a text part. */
-class DbkContextMenu {
-       private final AbstractDbkViewer textViewer;
-
-       private Shell shell;
-
-       DbkContextMenu(AbstractDbkViewer textViewer, Shell parentShell) {
-//             shell = new Shell(display, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-               shell = new Shell(parentShell, SWT.BORDER);
-//             super(display, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-               this.textViewer = textViewer;
-               shell.setLayout(new GridLayout());
-               // shell.setData(RWT.CUSTOM_VARIANT, TEXT_STYLED_TOOLS_DIALOG);
-
-               shell.addShellListener(new ToolsShellListener());
-       }
-
-       void show(EditablePart editablePart, Point location, List<String> availableStyles) {
-               if (shell.isVisible())
-                       shell.setVisible(false);
-               CmsSwtUtils.clear(shell);
-               Composite parent = shell;
-               CmsEditable cmsEditable = textViewer.getCmsEditable();
-//             if (availableStyles.isEmpty())
-//                     return;
-
-               if (editablePart instanceof Paragraph) {
-                       Paragraph paragraph = (Paragraph) editablePart;
-                       deletePartB(parent, DbkMsg.deleteParagraph.lead(), paragraph);
-                       insertMediaB(parent,  paragraph);
-
-               } else if (editablePart instanceof Img) {
-                       Img img = (Img) editablePart;
-                       deletePartB(parent, DbkMsg.deleteMedia.lead(), img);
-                       insertMediaB(parent, img);
-                       insertParagraphB(parent, DbkMsg.insertParagraph.lead(), img);
-
-               } else if (editablePart instanceof DbkSectionTitle) {
-                       DbkSectionTitle sectionTitle = (DbkSectionTitle) editablePart;
-                       TextSection section = sectionTitle.getSection();
-                       if (!section.isTitleReadOnly()) {
-                               Label deleteB = new Label(shell, SWT.NONE);
-                               deleteB.setText(DbkMsg.deleteSection.lead());
-                               deleteB.addMouseListener((MouseDown) (e) -> {
-                                       textViewer.deleteSection(section);
-                                       hide();
-                               });
-                       }
-                       insertMediaB(parent,  sectionTitle.getSection(), sectionTitle);
-               }
-
-               StyledToolMouseListener stml = new StyledToolMouseListener(editablePart);
-               List<StyleButton> styleButtons = new ArrayList<DbkContextMenu.StyleButton>();
-               if (cmsEditable.isEditing()) {
-                       for (String style : availableStyles) {
-                               StyleButton styleButton = new StyleButton(shell, SWT.WRAP);
-                               if (!"".equals(style))
-                                       styleButton.setStyle(style);
-                               else
-                                       styleButton.setStyle(null);
-                               styleButton.setMouseListener(stml);
-                               styleButtons.add(styleButton);
-                       }
-               } else if (cmsEditable.canEdit()) {
-                       // Edit
-//                     Label editButton = new Label(shell, SWT.NONE);
-//                     editButton.setText("Edit");
-//                     editButton.addMouseListener(stml);
-               }
-
-               if (editablePart instanceof Paragraph) {
-                       final int size = 32;
-                       String text = textViewer.getRawParagraphText((Paragraph) editablePart);
-                       String textToShow = text.length() > size ? text.substring(0, size - 3) + "..." : text;
-                       for (StyleButton styleButton : styleButtons) {
-                               styleButton.setText((styleButton.style == null ? "default" : styleButton.style) + " : " + textToShow);
-                       }
-               }
-
-               shell.pack();
-               shell.layout();
-               if (editablePart instanceof Control) {
-                       int height = shell.getSize().y;
-                       int parentShellHeight = shell.getShell().getSize().y;
-                       if ((location.y + height) < parentShellHeight) {
-                               shell.setLocation(((Control) editablePart).toDisplay(location.x, location.y));
-                       } else {
-                               shell.setLocation(((Control) editablePart).toDisplay(location.x, location.y - parentShellHeight));
-                       }
-               }
-
-               if (shell.getChildren().length != 0)
-                       shell.open();
-       }
-
-       void hide() {
-               shell.setVisible(false);
-       }
-
-       protected void insertMediaB(Composite parent, SectionPart sectionPart) {
-               insertMediaB(parent,  sectionPart.getSection(), sectionPart);
-       }
-
-       protected void insertMediaB(Composite parent, Section section, NodePart nodePart) {
-               Label insertPictureB = new Label(parent, SWT.NONE);
-               insertPictureB.setText(DbkMsg.insertPicture.lead());
-               insertPictureB.addMouseListener((MouseDown) (e) -> {
-                       Node newNode = DbkUtils.insertImageAfter(nodePart.getNode());
-                       Jcr.save(newNode);
-                       textViewer.insertPart(section, newNode);
-                       hide();
-               });
-               Label insertVideoB = new Label(parent, SWT.NONE);
-               insertVideoB.setText(DbkMsg.insertVideo.lead());
-               insertVideoB.addMouseListener((MouseDown) (e) -> {
-                       Node newNode = DbkUtils.insertVideoAfter(nodePart.getNode());
-                       Jcr.save(newNode);
-                       textViewer.insertPart(section, newNode);
-                       hide();
-               });
-
-       }
-
-       protected void insertParagraphB(Composite parent, String msg, SectionPart sectionPart) {
-               Label insertMediaB = new Label(parent, SWT.NONE);
-               insertMediaB.setText(msg);
-               insertMediaB.addMouseListener((MouseDown) (e) -> {
-                       textViewer.addParagraph(sectionPart, null);
-                       hide();
-               });
-       }
-
-       protected void deletePartB(Composite parent, String msg, SectionPart sectionPart) {
-               Label deleteB = new Label(shell, SWT.NONE);
-               deleteB.setText(msg);
-               deleteB.addMouseListener((MouseDown) (e) -> {
-                       textViewer.deletePart(sectionPart);
-                       hide();
-               });
-       }
-
-       class StyleButton extends EditableText {
-               private static final long serialVersionUID = 7731102609123946115L;
-
-               String style;
-
-               public StyleButton(Composite parent, int style) {
-                       super(parent, style);
-               }
-
-               @Override
-               public void setStyle(String style) {
-                       this.style = style;
-                       super.setStyle(style);
-               }
-
-//             private Label label;
-//
-//             public StyleButton(Composite parent, int swtStyle) {
-//                     super(parent, SWT.NONE);
-//                     setLayout(new GridLayout());
-//                     label = new Label(this, swtStyle);
-//             }
-//
-//             public Label getLabel() {
-//                     return label;
-//             }
-
-       }
-
-       class StyledToolMouseListener extends MouseAdapter {
-               private static final long serialVersionUID = 8516297091549329043L;
-               private EditablePart editablePart;
-
-               public StyledToolMouseListener(EditablePart editablePart) {
-                       super();
-                       this.editablePart = editablePart;
-               }
-
-               @Override
-               public void mouseDown(MouseEvent e) {
-                       // TODO make it more robust.
-                       Label sb = (Label) e.getSource();
-                       Object style = sb.getData(RWT.CUSTOM_VARIANT);
-                       textViewer.setParagraphStyle((Paragraph) editablePart, style == null ? null : style.toString());
-                       hide();
-               }
-       }
-
-       class ToolsShellListener extends org.eclipse.swt.events.ShellAdapter {
-               private static final long serialVersionUID = 8432350564023247241L;
-
-               @Override
-               public void shellDeactivated(ShellEvent e) {
-                       hide();
-               }
-
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkImageManager.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkImageManager.java
deleted file mode 100644 (file)
index 63f17d2..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-package org.argeo.docbook.ui;
-
-import static javax.jcr.Node.JCR_CONTENT;
-import static javax.jcr.Property.JCR_DATA;
-import static javax.jcr.nodetype.NodeType.NT_FILE;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-
-import javax.jcr.Binary;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
-import org.argeo.api.cms.Cms2DSize;
-import org.argeo.api.cms.CmsImageManager;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.util.DefaultImageManager;
-import org.argeo.docbook.DbkAttr;
-import org.argeo.docbook.DbkType;
-import org.argeo.docbook.DbkUtils;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.swt.graphics.ImageData;
-
-/** Add DocBook images support to {@link CmsImageManager}. */
-public class DbkImageManager extends DefaultImageManager {
-       private Node baseFolder = null;
-
-       public DbkImageManager(Node baseFolder) {
-               this.baseFolder = baseFolder;
-       }
-
-       Node getImageDataNode(Node mediaObjectNode) {
-               try {
-                       if (mediaObjectNode.hasNode(DbkType.imageobject.get())) {
-                               Node imageDataNode = mediaObjectNode.getNode(DbkType.imageobject.get())
-                                               .getNode(DbkType.imagedata.get());
-                               return imageDataNode;
-                       } else {
-                               throw new IllegalStateException("No image data found for " + mediaObjectNode);
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-       }
-
-       @Override
-       public Binary getImageBinary(Node node) {
-               Node fileNode = null;
-               if (DbkUtils.isDbk(node, DbkType.mediaobject)) {
-                       Node imageDataNode = getImageDataNode(node);
-                       fileNode = getFileNode(imageDataNode);
-               }
-               try {
-                       if (node.isNodeType(NT_FILE)) {
-                               fileNode = node;
-                       }
-                       if (fileNode != null) {
-                               return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();
-                       } else {
-                               return null;
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-       }
-
-       public Cms2DSize getImageSize(Node mediaObjectNode) {
-               Node imageDataNode = getImageDataNode(mediaObjectNode);
-               Node fileNode = getFileNode(imageDataNode);
-               if (fileNode == null)
-                       return new Cms2DSize(0, 0);
-               try {
-                       Cms2DSize intrinsicSize;
-                       if (fileNode.hasProperty(EntityNames.SVG_WIDTH) && fileNode.hasProperty(EntityNames.SVG_HEIGHT)) {
-                               int width = (int) fileNode.getProperty(EntityNames.SVG_WIDTH).getLong();
-                               int height = (int) fileNode.getProperty(EntityNames.SVG_HEIGHT).getLong();
-                               intrinsicSize = new Cms2DSize(width, height);
-                       } else {
-                               try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
-                                       ImageData id = new ImageData(in);
-                                       intrinsicSize = updateSize(fileNode, id);
-                               } catch (IOException e) {
-                                       throw new RuntimeException("Cannot load file " + fileNode, e);
-                               }
-                       }
-                       // TODO interpret image data infos
-                       return intrinsicSize;
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-       }
-
-       protected Cms2DSize updateSize(Node fileNode, ImageData id) throws RepositoryException {
-               fileNode.addMixin(EntityType.box.get());
-               fileNode.setProperty(EntityNames.SVG_WIDTH, id.width);
-               fileNode.setProperty(EntityNames.SVG_HEIGHT, id.height);
-               return new Cms2DSize(id.width, id.height);
-       }
-
-       @Override
-       protected void processNewImageFile(Node mediaObjectNode, Node fileNode, ImageData id)
-                       throws RepositoryException, IOException {
-               Node imageDataNode = getImageDataNode(mediaObjectNode);
-               updateSize(fileNode, id);
-               String filePath = fileNode.getPath();
-               String relPath = filePath.substring(baseFolder.getPath().length() + 1);
-               imageDataNode.setProperty(DbkAttr.fileref.name(), relPath);
-       }
-
-       @Override
-       public String getImageUrl(Node mediaObjectNode) {
-               Node imageDataNode = getImageDataNode(mediaObjectNode);
-               // TODO factorise
-               String fileref = null;
-               try {
-                       if (imageDataNode.hasProperty(DbkAttr.fileref.name()))
-                               fileref = imageDataNode.getProperty(DbkAttr.fileref.name()).getString();
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-               if (fileref == null)
-                       return null;
-               URI fileUri;
-               try {
-                       // FIXME it messes up with the '/'
-                       fileUri = new URI(URLEncoder.encode(fileref, StandardCharsets.UTF_8.toString()));
-               } catch (URISyntaxException | UnsupportedEncodingException e) {
-                       throw new IllegalArgumentException("File ref in " + imageDataNode + " is badly formatted", e);
-               }
-               if (fileUri.getScheme() != null)
-                       return fileUri.toString();
-               // local
-               Node fileNode = getFileNode(imageDataNode);
-               String url = CmsUiUtils.getDataPathForUrl(fileNode);
-               return url;
-       }
-
-       protected Node getFileNode(Node imageDataNode) {
-               // FIXME make URL use case more robust
-               try {
-                       String fileref = null;
-                       if (imageDataNode.hasProperty(DbkAttr.fileref.name()))
-                               fileref = imageDataNode.getProperty(DbkAttr.fileref.name()).getString();
-                       if (fileref == null)
-                               return null;
-                       Node fileNode;
-                       if (fileref.startsWith("/"))
-                               fileNode = baseFolder.getSession().getNode(fileref);
-                       else
-                               fileNode = baseFolder.getNode(fileref);
-                       return fileNode;
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-       }
-
-       protected Node getMediaFolder() {
-               try {
-                       // TODO check edition status
-                       Node mediaFolder = JcrUtils.getOrAdd(baseFolder, EntityNames.MEDIA, NodeType.NT_FOLDER);
-                       return mediaFolder;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get media folder", e);
-               }
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkImg.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkImg.java
deleted file mode 100644 (file)
index f48c626..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.argeo.docbook.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.widgets.Img;
-import org.eclipse.rap.fileupload.FileUploadEvent;
-import org.eclipse.rap.fileupload.FileUploadHandler;
-import org.eclipse.rap.fileupload.FileUploadListener;
-import org.eclipse.rap.fileupload.FileUploadReceiver;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** DocBook specific image area. */
-public class DbkImg extends Img {
-       private static final long serialVersionUID = -6150996708899219074L;
-
-       public DbkImg(Composite parent, int swtStyle, Node imgNode, DbkImageManager imageManager)
-                       throws RepositoryException {
-               super(parent, swtStyle, imgNode, imageManager);
-       }
-
-       @Override
-       protected Node getUploadFolder() {
-               Node mediaFolder = ((DbkImageManager) getImageManager()).getMediaFolder();
-               return mediaFolder;
-       }
-
-       @Override
-       protected String getUploadName() {
-               return null;
-       }
-
-       @Override
-       protected void setContainerLayoutData(Composite composite) {
-               composite.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
-       }
-
-       @Override
-       protected void setControlLayoutData(Control control) {
-               control.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
-       }
-
-       @Override
-       protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) {
-               FileUploadHandler fileUploadHandler = super.prepareUpload(receiver);
-               fileUploadHandler.addUploadListener(new FileUploadListener() {
-
-                       @Override
-                       public void uploadProgress(FileUploadEvent event) {
-                               // TODO Auto-generated method stub
-
-                       }
-
-                       @Override
-                       public void uploadFinished(FileUploadEvent event) {
-                       }
-
-                       @Override
-                       public void uploadFailed(FileUploadEvent event) {
-                               // TODO Auto-generated method stub
-
-                       }
-               });
-               return fileUploadHandler;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkSectionTitle.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkSectionTitle.java
deleted file mode 100644 (file)
index 92fd2b8..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.argeo.docbook.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.viewers.NodePart;
-import org.argeo.cms.ui.widgets.EditableText;
-import org.eclipse.swt.widgets.Composite;
-
-/** The title of a section, based on an XML text node. */
-public class DbkSectionTitle extends EditableText implements EditablePart, NodePart {
-       private static final long serialVersionUID = -1787983154946583171L;
-
-       private final TextSection section;
-
-       public DbkSectionTitle(Composite parent, int swtStyle, Node titleNode) throws RepositoryException {
-               super(parent, swtStyle, titleNode);
-               section = (TextSection) TextSection.findSection(this);
-       }
-
-       public TextSection getSection() {
-               return section;
-       }
-
-       @Override
-       public Node getItem() throws RepositoryException {
-               return getNode();
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkTextInterpreter.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkTextInterpreter.java
deleted file mode 100644 (file)
index c853535..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-package org.argeo.docbook.ui;
-
-import static org.argeo.docbook.DbkType.para;
-import static org.argeo.docbook.DbkType.title;
-import static org.argeo.docbook.DbkUtils.isDbk;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.Item;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.RepositoryException;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.docbook.DbkAttr;
-import org.argeo.docbook.DbkType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-
-/** Based on HTML with a few Wiki-like shortcuts. */
-public class DbkTextInterpreter implements TextInterpreter {
-       private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
-
-       private String linkCssClass = DbkType.link.name();
-
-       @Override
-       public void write(Item item, String content) {
-               try {
-                       if (item instanceof Node) {
-                               Node node = (Node) item;
-                               if (isDbk(node, para) || isDbk(node, title)) {
-                                       String raw = convertToStorage(node, content);
-                                       validateBeforeStoring(raw);
-
-                                       String jcrUuid = node.getIdentifier();
-//                                     if (node.hasProperty(Property.JCR_UUID))
-//                                             jcrUuid = node.getProperty(Property.JCR_UUID).getString();
-//                                     else {
-//                                             // TODO use time based
-//                                             jcrUuid = UUID.randomUUID().toString();
-//                                             node.setProperty(Property.JCR_UUID, jcrUuid);
-//                                             node.getSession().save();
-//                                     }
-
-                                       StringBuilder namespaces = new StringBuilder();
-                                       namespaces.append(" xmlns:dbk=\"http://docbook.org/ns/docbook\"");
-                                       namespaces.append(" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\"");
-                                       namespaces.append(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
-                                       raw = "<" + node.getName() + " jcr:uuid=\"" + jcrUuid + "\"" + namespaces + ">" + raw + "</"
-                                                       + node.getName() + ">";
-//                                     System.out.println(raw);
-                                       try (InputStream in = new ByteArrayInputStream(raw.getBytes(StandardCharsets.UTF_8))) {
-                                               node.getSession().importXML(node.getParent().getPath(), in,
-                                                               ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-                                               // node.getSession().save();
-                                       } catch (IOException e) {
-                                               throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
-                                       }
-
-//                                     try {
-//                                             DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
-//                                             Document document;
-//                                             try (Reader in = new StringReader(raw)) {
-//                                                     document = documentBuilder.parse(new InputSource(in));
-//                                             }
-//                                             NodeList nl = document.getChildNodes();
-//                                             for (int i = 0; i < nl.getLength(); i++) {
-//                                                     org.w3c.dom.Node n = nl.item(i);
-//                                                     if (node instanceof Text) {
-//
-//                                                     }
-//                                             }
-//                                     } catch (ParserConfigurationException | SAXException | IOException e) {
-//                                             throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
-//                                     }
-
-//                                     Node jcrText;
-//                                     if (!node.hasNode(Jcr.JCR_XMLTEXT))
-//                                             jcrText = node.addNode(Jcr.JCR_XMLTEXT, JcrxType.JCRX_XMLTEXT);
-//                                     else
-//                                             jcrText = node.getNode(Jcr.JCR_XMLTEXT);
-//                                     jcrText.setProperty(Jcr.JCR_XMLCHARACTERS, raw);
-                               } else {
-                                       throw new IllegalArgumentException("Don't know how to interpret " + node);
-                               }
-                       } else {// property
-                               Property property = (Property) item;
-                               property.setValue(content);
-                       }
-                       // item.getSession().save();
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot set content on " + item, e);
-               }
-       }
-
-       @Override
-       public String read(Item item) {
-               try {
-                       String raw = raw(item);
-                       return convertFromStorage(item, raw);
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get " + item + " for edit", e);
-               }
-       }
-
-       @Override
-       public String raw(Item item) {
-               try {
-                       item.getSession().refresh(true);
-                       if (item instanceof Node) {
-                               Node node = (Node) item;
-                               if (isDbk(node, para) || isDbk(node, title)) {
-                                       StringBuilder sb = new StringBuilder();
-                                       readXml(node, sb);
-//                                     NodeIterator nit = node.getNodes();
-//                                     while (nit.hasNext()) {
-//                                             Node child = nit.nextNode();
-//                                             if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
-//                                                     Node jcrText = node.getNode(Jcr.JCR_XMLTEXT);
-//                                                     String txt = jcrText.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
-//                                                     // TODO make it more robust
-//                                                     // txt = txt.replace("\n", "").replace("\t", "");
-//                                                     txt = txt.replace("\t", "  ");
-//                                                     sb.append(txt);
-//                                             } else {
-//                                                     try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-//                                                             child.getSession().exportDocumentView(child.getPath(), out, true, false);
-//                                                             sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
-//                                                     } catch (IOException e) {
-//                                                             throw new IllegalStateException("Cannot export " + child, e);
-//                                                     }
-//                                             }
-//                                     }
-                                       return sb.toString();
-                               } else {
-                                       throw new IllegalArgumentException("Don't know how to interpret " + node);
-                               }
-                       } else {// property
-                               Property property = (Property) item;
-                               return property.getString();
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get " + item + " content", e);
-               }
-       }
-
-       private void readXml(Node node, StringBuilder sb) throws RepositoryException {
-               NodeIterator nit = node.getNodes();
-               while (nit.hasNext()) {
-                       Node child = nit.nextNode();
-                       if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
-                               String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
-                               // TODO make it more robust
-                               // txt = txt.replace("\n", "").replace("\t", "");
-                               txt = txt.replace("\t", "  ");
-                               sb.append(txt);
-                       } else {
-                               sb.append('<').append(child.getName());
-                               PropertyIterator pit = child.getProperties();
-                               properties: while (pit.hasNext()) {
-                                       Property p = pit.nextProperty();
-                                       if (p.getName().startsWith("jcr:"))
-                                               continue properties;
-                                       sb.append(' ').append(p.getName()).append("=\"").append(p.getString()).append('\"');
-                               }
-                               sb.append('>');
-                               readXml(child, sb);
-//                             try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-//                                     child.getSession().exportDocumentView(child.getPath(), out, true, false);
-//                                     sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
-//                             } catch (IOException e) {
-//                                     throw new IllegalStateException("Cannot export " + child, e);
-//                             }
-                               sb.append("</").append(child.getName()).append('>');
-                       }
-               }
-       }
-
-       private void readAsSimpleHtml(Node node, StringBuilder sb) throws RepositoryException {
-               NodeIterator nit = node.getNodes();
-               while (nit.hasNext()) {
-                       Node child = nit.nextNode();
-                       if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
-                               String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
-                               // TODO make it more robust
-                               // txt = txt.replace("\n", "").replace("\t", "");
-                               txt = txt.replace("\t", "  ");
-                               String html = textToSimpleHtml(txt);
-                               sb.append(html);
-                       } else if (child.getName().equals(DbkType.link.get())) {
-                               if (child.hasProperty(DbkAttr.XLINK_HREF)) {
-                                       String href = child.getProperty(DbkAttr.XLINK_HREF).getString();
-                                       // TODO deal with other forbidden XML characters?
-                                       href = href.replace("&", "&amp;");
-                                       sb.append("<a class='" + linkCssClass + "' href='").append(href).append("'>");
-                                       readAsSimpleHtml(child, sb);
-                                       sb.append("</a>");
-                               }
-                       } else {
-                               // ignore
-                       }
-               }
-       }
-
-       private String textToSimpleHtml(String raw) {
-               // FIXME the saved data should be corrected instead.
-               if (raw.indexOf('&') >= 0) {
-                       raw = raw.replace("&", "&amp;");
-               }
-               if (raw.indexOf('<') >= 0) {
-                       raw = raw.replace("<", "&lt;");
-               }
-               if (raw.indexOf('>') >= 0) {
-                       raw = raw.replace(">", "&gt;");
-               }
-               if (raw.indexOf('\"') >= 0) {
-                       raw = raw.replace("\"", "&quot;");
-               }
-               if (raw.indexOf('\'') >= 0) {
-                       raw = raw.replace("\'", "&apos;");
-               }
-//             raw = "<span style='text-align:justify'>" + raw + "</span>";
-               if (raw.length() == 0)
-                       return raw;
-               try (StringReader reader = new StringReader(raw)) {
-                       List<String> lines = IOUtils.readLines(reader);
-                       if (lines.size() == 1)
-                               return lines.get(0);
-                       StringBuilder sb = new StringBuilder(raw.length() + lines.size() * BR_LENGTH);
-                       for (int i = 0; i < lines.size(); i++) {
-                               if (i != 0)
-                                       sb.append("<br/>");
-                               sb.append(lines.get(i));
-                       }
-                       return sb.toString();
-               } catch (IOException e) {
-                       throw new RuntimeException(e);
-               }
-       }
-
-       final static int BR_LENGTH = "<br/>".length();
-
-       public String readSimpleHtml(Item item) {
-               try {
-                       StringBuilder sb = new StringBuilder();
-//                     sb.append("<div style='text-align: justify;'>");
-                       readAsSimpleHtml((Node) item, sb);
-//                     sb.append("</div>");
-//                     System.out.println(sb);
-                       return sb.toString();
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot convert " + item + " to simple HTML", e);
-               }
-       }
-
-       // EXTENSIBILITY
-       /**
-        * To be overridden, in order to make sure that only valid strings are being
-        * stored.
-        */
-       protected void validateBeforeStoring(String raw) {
-       }
-
-       /** To be overridden, in order to support additional formatting. */
-       protected String convertToStorage(Item item, String content) throws RepositoryException {
-               return content;
-
-       }
-
-       /** To be overridden, in order to support additional formatting. */
-       protected String convertFromStorage(Item item, String content) throws RepositoryException {
-               return content;
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkVideo.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/DbkVideo.java
deleted file mode 100644 (file)
index ed7976a..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-package org.argeo.docbook.ui;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Item;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.Selected;
-import org.argeo.cms.ui.viewers.NodePart;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.cms.ui.viewers.SectionPart;
-import org.argeo.cms.ui.widgets.StyledControl;
-import org.argeo.docbook.DbkAttr;
-import org.argeo.docbook.DbkType;
-import org.argeo.docbook.DbkUtils;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.argeo.util.naming.NamingUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.browser.Browser;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Text;
-
-public class DbkVideo extends StyledControl implements SectionPart, NodePart {
-       private static final long serialVersionUID = -8753232181570351880L;
-       private Section section;
-
-       private int width = 640;
-       private int height = 360;
-
-       private boolean editable;
-
-       public DbkVideo(Composite parent, int style, Node node) {
-               this(Section.findSection(parent), parent, style, node);
-       }
-
-       DbkVideo(Section section, Composite parent, int style, Node node) {
-               super(parent, style, node);
-               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
-               this.section = section;
-               setStyle(DbkType.videoobject.name());
-       }
-
-       @Override
-       protected Control createControl(Composite box, String style) {
-               Node mediaobject = getNode();
-               Composite wrapper = new Composite(box, SWT.NONE);
-               wrapper.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               Composite browserC = new Composite(wrapper, SWT.NONE);
-               browserC.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               GridData gd = new GridData(SWT.CENTER, SWT.FILL, true, true);
-               gd.widthHint = getWidth();
-               gd.heightHint = getHeight();
-               browserC.setLayoutData(gd);
-//             wrapper.setLayoutData(CmsUiUtils.fillAll());
-               Browser browser = new Browser(browserC, SWT.NONE);
-
-               if (editable) {
-                       Composite editor = new Composite(wrapper, SWT.BORDER);
-                       editor.setLayout(new GridLayout(3, false));
-                       editor.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-                       String fileref = DbkUtils.getMediaFileref(mediaobject);
-                       Text text = new Text(editor, SWT.SINGLE);
-                       if (fileref != null)
-                               text.setText(fileref);
-                       else
-                               text.setMessage("Embed URL of the video");
-                       text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-                       Button updateB = new Button(editor, SWT.FLAT);
-                       updateB.setText("Update");
-                       updateB.addSelectionListener(new Selected() {
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       try {
-                                               Node videodata = mediaobject.getNode(DbkType.videoobject.get())
-                                                               .getNode(DbkType.videodata.get());
-                                               String txt = text.getText();
-                                               URI uri;
-                                               try {
-                                                       uri = new URI(txt);
-                                               } catch (URISyntaxException e1) {
-                                                       text.setText("");
-                                                       text.setMessage("Invalid URL");
-                                                       return;
-                                               }
-
-                                               // Transform watch URL in embed
-                                               // YouTube
-                                               String videoId = null;
-                                               if ("www.youtube.com".equals(uri.getHost()) || "youtube.com".equals(uri.getHost())
-                                                               || "youtu.be".equals(uri.getHost())) {
-                                                       if ("www.youtube.com".equals(uri.getHost()) || "youtube.com".equals(uri.getHost())) {
-                                                               if ("/watch".equals(uri.getPath())) {
-                                                                       Map<String, List<String>> map = NamingUtils.queryToMap(uri);
-                                                                       videoId = map.get("v").get(0);
-                                                               }
-                                                       } else if ("youtu.be".equals(uri.getHost())) {
-                                                               videoId = uri.getPath().substring(1);
-                                                       }
-                                                       if (videoId != null) {
-                                                               try {
-                                                                       uri = new URI("https://www.youtube.com/embed/" + videoId);
-                                                                       text.setText(uri.toString());
-                                                               } catch (URISyntaxException e1) {
-                                                                       throw new IllegalStateException(e1);
-                                                               }
-                                                       }
-                                               }
-
-                                               // Vimeo
-                                               if ("vimeo.com".equals(uri.getHost())) {
-                                                       videoId = uri.getPath().substring(1);
-                                                       if (videoId != null) {
-                                                               try {
-                                                                       uri = new URI("https://player.vimeo.com/video/" + videoId);
-                                                                       text.setText(uri.toString());
-                                                               } catch (URISyntaxException e1) {
-                                                                       throw new IllegalStateException(e1);
-                                                               }
-                                                       }
-                                               }
-
-                                               videodata.setProperty(DbkAttr.fileref.name(), uri.toString());
-                                               // TODO better integrate it in the edition lifecycle
-                                               videodata.getSession().save();
-                                               load(browser);
-                                       } catch (RepositoryException e1) {
-                                               throw new JcrException("Cannot update " + mediaobject, e1);
-                                       }
-
-                               }
-                       });
-
-                       Button deleteB = new Button(editor, SWT.FLAT);
-                       deleteB.setText("Delete");
-                       deleteB.addSelectionListener(new Selected() {
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       try {
-                                               mediaobject.remove();
-                                               mediaobject.getSession().save();
-                                               dispose();
-                                               getSection().getParent().layout(true, true);
-                                       } catch (RepositoryException e1) {
-                                               throw new JcrException("Cannot update " + mediaobject, e1);
-                                       }
-
-                               }
-                       });
-               }
-
-               // TODO caption
-               return browser;
-       }
-
-       public void load(Control control) {
-               try {
-                       if (control instanceof Browser) {
-                               Browser browser = (Browser) control;
-                               getNode().getSession();
-                               String fileref = DbkUtils.getMediaFileref(getNode());
-                               if (fileref != null) {
-                                       // TODO manage self-hosted videos
-                                       // TODO for YouTube videos, check whether the URL starts with
-                                       // https://www.youtube.com/embed/ and not https://www.youtube.com/watch?v=
-                                       StringBuilder html = new StringBuilder();
-                                       html.append(
-                                                       "<iframe frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"true\"");
-                                       // TODO make size configurable
-                                       html.append("width=\"").append(width).append("\" height=\"").append(height).append("\" ");
-                                       html.append("src=\"").append(fileref).append("\" ");
-                                       html.append("/>");
-                                       browser.setText(html.toString());
-                               }
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot retrieve src for video " + getNode(), e);
-               }
-       }
-
-       @Override
-       protected void setContainerLayoutData(Composite composite) {
-               composite.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, true));
-       }
-
-       @Override
-       protected void setControlLayoutData(Control control) {
-               control.setLayoutData(CmsSwtUtils.fillAll());
-       }
-
-       @Override
-       public Item getItem() throws RepositoryException {
-               return getNode();
-       }
-
-       @Override
-       public String getPartId() {
-               return getNodeId();
-       }
-
-       @Override
-       public Section getSection() {
-               return section;
-       }
-
-       public int getWidth() {
-               return width;
-       }
-
-       public int getHeight() {
-               return height;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/DocumentPage.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/DocumentPage.java
deleted file mode 100644 (file)
index f568611..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.argeo.docbook.ui;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-
-import org.argeo.api.cms.CmsEditable;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsLink;
-import org.argeo.cms.ui.viewers.JcrVersionCmsEditable;
-import org.argeo.cms.ui.widgets.ScrolledPage;
-import org.argeo.docbook.DbkType;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/**
- * Display the text of the context, and provide an editor if the user can edit.
- */
-public class DocumentPage implements CmsUiProvider {
-       public final static String WWW = "www";
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-
-               ScrolledPage page = new ScrolledPage(parent, SWT.NONE);
-               page.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               GridData textGd = CmsSwtUtils.fillAll();
-               page.setLayoutData(textGd);
-
-               if (context.isNodeType(DbkType.article.get())) {
-                       CmsEditable cmsEditable = new JcrVersionCmsEditable(context);
-                       if (cmsEditable.canEdit())
-                               new TextEditorHeader(cmsEditable, parent, SWT.NONE).setLayoutData(CmsSwtUtils.fillWidth());
-                       if (!cmsEditable.isEditing())
-                               cmsEditable.startEditing();
-                       new DocumentTextEditor(page, SWT.FLAT, context, cmsEditable);
-               } else {
-                       parent.setBackgroundMode(SWT.INHERIT_NONE);
-                       if (context.getSession().hasPermission(context.getPath(), Session.ACTION_ADD_NODE)) {
-//                             new DocumentTextEditor(page, SWT.FLAT, indexNode, cmsEditable);
-//                             textGd.heightHint = 400;
-
-                               for (NodeIterator ni = context.getNodes(); ni.hasNext();) {
-                                       Node textNode = ni.nextNode();
-                                       if (textNode.isNodeType(NodeType.NT_FOLDER))
-                                               new CmsLink(textNode.getName() + "/", textNode.getPath()).createUi(parent, textNode);
-                               }
-                               for (NodeIterator ni = context.getNodes(); ni.hasNext();) {
-                                       Node textNode = ni.nextNode();
-                                       if (textNode.isNodeType(DbkType.article.get()) && !textNode.getName().equals(WWW))
-                                               new CmsLink(textNode.getName(), textNode.getPath()).createUi(parent, textNode);
-                               }
-                       }
-               }
-               return page;
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/DocumentTextEditor.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/DocumentTextEditor.java
deleted file mode 100644 (file)
index 9ffef2b..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.argeo.docbook.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsEditable;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.docbook.DbkUtils;
-import org.argeo.docbook.DbkType;
-import org.eclipse.swt.widgets.Composite;
-
-/** Text editor where sections and subsections can be managed by the user. */
-public class DocumentTextEditor extends AbstractDbkViewer {
-       private static final long serialVersionUID = 6049661610883342325L;
-
-       public DocumentTextEditor(Composite parent, int style, Node textNode, CmsEditable cmsEditable) {
-               super(new TextSection(parent, style, textNode), style, cmsEditable);
-//             refresh();
-               getMainSection().setLayoutData(CmsSwtUtils.fillWidth());
-       }
-
-       @Override
-       protected void initModel(Node textNode) throws RepositoryException {
-               if (isFlat()) {
-                       DbkUtils.addParagraph(textNode, "");
-               }
-//             else
-//                     textNode.setProperty(DocBookNames.DBK_TITLE, textNode.getName());
-       }
-
-       @Override
-       protected Boolean isModelInitialized(Node textNode) throws RepositoryException {
-               return textNode.hasNode(DbkType.title.get()) || textNode.hasNode(DbkType.para.get())
-                               || (!isFlat() && textNode.hasNode(DbkType.section.get()));
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/Paragraph.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/Paragraph.java
deleted file mode 100644 (file)
index 7314029..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.argeo.docbook.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.viewers.SectionPart;
-import org.argeo.cms.ui.widgets.EditableText;
-import org.argeo.cms.ui.widgets.TextStyles;
-import org.argeo.docbook.DbkType;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-
-/** An editable paragraph. */
-public class Paragraph extends EditableText implements SectionPart {
-       private static final long serialVersionUID = 3746457776229542887L;
-
-       private final TextSection section;
-
-       public Paragraph(TextSection section, int style, Node node) throws RepositoryException {
-               super(section, style, node);
-               this.section = section;
-               CmsSwtUtils.style(this, DbkType.para.name());
-       }
-
-       public TextSection getSection() {
-               return section;
-       }
-
-       @Override
-       protected Label createLabel(Composite box, String style) {
-               Label lbl = super.createLabel(box, style);
-               CmsSwtUtils.disableMarkupValidation(lbl);
-               return lbl;
-       }
-
-       @Override
-       public String getPartId() {
-               return getNodeId();
-       }
-
-       @Override
-       public Node getItem() throws RepositoryException {
-               return getNode();
-       }
-
-       @Override
-       public String toString() {
-               return "Paragraph #" + getPartId();
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/TextEditorHeader.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/TextEditorHeader.java
deleted file mode 100644 (file)
index b430de0..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.argeo.docbook.ui;
-
-import java.util.Observable;
-import java.util.Observer;
-
-import org.argeo.api.cms.CmsEditable;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.widgets.TextStyles;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-
-/** Adds editing capabilities to a page editing text */
-public class TextEditorHeader implements SelectionListener, Observer {
-       private static final long serialVersionUID = 4186756396045701253L;
-
-       private final CmsEditable cmsEditable;
-       private Button publish;
-
-       private Composite parent;
-       private Composite display;
-       private Object layoutData;
-
-       public TextEditorHeader(CmsEditable cmsEditable, Composite parent, int style) {
-               this.cmsEditable = cmsEditable;
-               this.parent = parent;
-               if (this.cmsEditable instanceof Observable)
-                       ((Observable) this.cmsEditable).addObserver(this);
-               refresh();
-       }
-
-       protected void refresh() {
-               if (display != null && !display.isDisposed())
-                       display.dispose();
-               display = null;
-               publish = null;
-               if (cmsEditable.isEditing()) {
-                       display = new Composite(parent, SWT.NONE);
-                       // display.setBackgroundMode(SWT.INHERIT_NONE);
-                       display.setLayoutData(layoutData);
-                       display.setLayout(CmsSwtUtils.noSpaceGridLayout());
-                       CmsSwtUtils.style(display, TextStyles.TEXT_EDITOR_HEADER);
-                       publish = new Button(display, SWT.FLAT | SWT.PUSH);
-                       publish.setText(getPublishButtonLabel());
-                       CmsSwtUtils.style(publish, TextStyles.TEXT_EDITOR_HEADER);
-                       publish.addSelectionListener(this);
-                       display.moveAbove(null);
-               }
-               parent.layout();
-       }
-
-       private String getPublishButtonLabel() {
-               if (cmsEditable.isEditing())
-                       return "Publish";
-               else
-                       return "Edit";
-       }
-
-       @Override
-       public void widgetSelected(SelectionEvent e) {
-               if (e.getSource() == publish) {
-                       if (cmsEditable.isEditing()) {
-                               cmsEditable.stopEditing();
-                       } else {
-                               cmsEditable.startEditing();
-                       }
-                       // publish.setText(getPublishButtonLabel());
-               }
-       }
-
-       @Override
-       public void widgetDefaultSelected(SelectionEvent e) {
-       }
-
-       @Override
-       public void update(Observable o, Object arg) {
-               if (o == cmsEditable) {
-                       // publish.setText(getPublishButtonLabel());
-                       refresh();
-               }
-       }
-
-       public void setLayoutData(Object layoutData) {
-               this.layoutData = layoutData;
-               if (display != null && !display.isDisposed())
-                       display.setLayoutData(layoutData);
-       }
-
-}
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/TextInterpreter.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/TextInterpreter.java
deleted file mode 100644 (file)
index 785d71e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.argeo.docbook.ui;
-
-import javax.jcr.Item;
-
-/** Convert from/to data layer to/from presentation layer. */
-public interface TextInterpreter {
-       String raw(Item item);
-
-       String read(Item item);
-
-       String readSimpleHtml(Item item);
-
-       void write(Item item, String content);
-}
diff --git a/org.argeo.app.ui/src/org/argeo/docbook/ui/TextSection.java b/org.argeo.app.ui/src/org/argeo/docbook/ui/TextSection.java
deleted file mode 100644 (file)
index b8c82d7..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.argeo.docbook.ui;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.cms.ui.widgets.TextStyles;
-import org.argeo.docbook.DbkType;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** An editable section. */
-public class TextSection extends Section {
-       private static final long serialVersionUID = -8625209546243220689L;
-       private String defaultTextStyle = DbkType.para.name();
-       private String titleStyle;
-
-       private final boolean flat;
-
-       private boolean titleReadOnly = false;
-
-       private final int level;
-
-       public TextSection(Composite parent, int style, Node node) {
-               this(parent, findSection(parent), style, node);
-       }
-
-       public TextSection(TextSection section, int style, Node node) {
-               this(section, section.getParentSection(), style, node);
-       }
-
-       private TextSection(Composite parent, Section parentSection, int style, Node node) {
-               super(parent, parentSection, style, node);
-               flat = SWT.FLAT == (style & SWT.FLAT);
-               if (parentSection instanceof TextSection) {
-                       level = ((TextSection) parentSection).getLevel() + 1;
-               } else {
-                       level = 0;
-               }
-               CmsSwtUtils.style(this, DbkType.section.name());
-       }
-
-       public String getDefaultTextStyle() {
-               return defaultTextStyle;
-       }
-
-       public boolean isFlat() {
-               return flat;
-       }
-
-       /** The level of this section, similar to h1, h2, etc. in HTML. */
-       public int getLevel() {
-               return level;
-       }
-
-       public String getTitleStyle() {
-               if (titleStyle != null)
-                       return titleStyle;
-               // TODO make base H styles configurable
-//             Integer relativeDepth = getRelativeDepth();
-//             System.out.println("Level: " + getLevel());
-               return "h" + (getLevel() + 1);
-       }
-
-       public void setDefaultTextStyle(String defaultTextStyle) {
-               this.defaultTextStyle = defaultTextStyle;
-       }
-
-       public void setTitleStyle(String titleStyle) {
-               this.titleStyle = titleStyle;
-       }
-
-       public boolean isTitleReadOnly() {
-               return titleReadOnly;
-       }
-
-       public void setTitleReadOnly(boolean titleReadOnly) {
-               this.titleReadOnly = titleReadOnly;
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java b/org.argeo.app.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java
deleted file mode 100644 (file)
index 973ceb2..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-package org.argeo.entity.ui.forms;
-
-import javax.jcr.Item;
-
-import org.argeo.api.cms.CmsTheme;
-import org.argeo.cms.Localized;
-import org.argeo.cms.swt.CmsIcon;
-import org.argeo.cms.swt.CmsSwtUtils;
-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.Term;
-import org.argeo.entity.TermsManager;
-import org.argeo.entity.Typology;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-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 Typology typology;
-
-       private 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);
-               if (item == null)
-                       throw new IllegalArgumentException("Item cannot be null");
-               this.termsManager = termsManager;
-               this.typology = termsManager.getTypology(typology);
-               this.theme = CmsSwtUtils.getCmsTheme(parent);
-               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
-               highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
-       }
-
-       public boolean isEditable() {
-               return editable;
-       }
-
-       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(Term term) {
-               if (term instanceof Localized)
-                       return ((Localized) term).lead();
-               else
-                       return term.getName();
-
-       }
-
-       protected abstract void refresh(ContextOverlay contextArea, String filter, Text txt);
-
-       protected boolean isTermSelectable(Term term) {
-               return true;
-       }
-
-       protected void processTermListLabel(Term term, Label label) {
-
-       }
-
-       protected void setControlLayoutData(Control control) {
-               control.setLayoutData(CmsSwtUtils.fillAll());
-       }
-
-       protected void setContainerLayoutData(Composite composite) {
-               composite.setLayoutData(CmsSwtUtils.fillAll());
-       }
-
-       //
-       // 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.app.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java b/org.argeo.app.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java
deleted file mode 100644 (file)
index e75a916..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-package org.argeo.entity.ui.forms;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Item;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.MouseDoubleClick;
-import org.argeo.cms.swt.MouseDown;
-import org.argeo.cms.swt.Selected;
-import org.argeo.cms.ui.forms.FormStyle;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.widgets.ContextOverlay;
-import org.argeo.entity.Term;
-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;
-       private final static CmsLog log = CmsLog.getLog(MultiTermsPart.class);
-
-       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);
-
-               boolean vertical = SWT.VERTICAL == (getStyle() & SWT.VERTICAL);
-               RowLayout rl = new RowLayout(vertical ? SWT.VERTICAL : SWT.HORIZONTAL);
-               rl = CmsSwtUtils.noMarginsRowLayout(rl);
-//             rl.wrap = true;
-//             rl.justify = true;
-               placeholder.setLayout(rl);
-               List<Term> currentValue = getValue();
-               if (currentValue != null && !currentValue.isEmpty()) {
-                       for (Term value : currentValue) {
-                               Composite block = new Composite(placeholder, SWT.NONE);
-                               block.setLayout(CmsSwtUtils.noSpaceGridLayout(3));
-                               Label lbl = new Label(block, SWT.NONE);
-                               String display = getTermLabel(value);
-                               lbl.setText(display);
-                               CmsSwtUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
-                               processTermListLabel(value, lbl);
-                               if (isEditable())
-                                       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<Term> curr = getValue();
-                                               List<Term> newValue = new ArrayList<>();
-                                               for (Term v : curr) {
-                                                       if (!v.equals(value))
-                                                               newValue.add(v);
-                                               }
-                                               setValue(newValue);
-                                               block.dispose();
-                                               layout(true, true);
-                                       });
-
-                               }
-                       }
-               } else {// empty
-                       if (isEditable() && !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(CmsSwtUtils.noSpaceGridLayout(3));
-
-                       createHighlight(block);
-
-                       Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
-                       txt.setLayoutData(CmsSwtUtils.fillWidth());
-//                     txt.setMessage("[new]");
-
-                       CmsSwtUtils.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) {
-               CmsSwtUtils.clear(contextArea);
-               List<? extends Term> terms = termsManager.listAllTerms(typology.getId());
-               List<Term> currentValue = getValue();
-               terms: for (Term 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<Term> newValue = new ArrayList<>();
-                                       List<Term> curr = getValue();
-                                       if (currentValue != null)
-                                               newValue.addAll(curr);
-                                       newValue.add(term);
-                                       setValue(newValue);
-                                       contextArea.hide();
-                                       stopEditing();
-                               });
-               }
-               contextArea.show();
-       }
-
-       protected List<Term> getValue() {
-               String property = typology.getId();
-               List<String> curr = Jcr.getMultiple(getNode(), property);
-               List<Term> res = new ArrayList<>();
-               if (curr != null)
-                       terms: for (String str : curr) {
-                               Term term = termsManager.getTerm(str);
-                               if (term == null) {
-                                       log.warn("Ignoring term " + str + " for " + getNode() + ", as it was not found.");
-                                       continue terms;
-                               }
-                               res.add(term);
-                       }
-               return res;
-       }
-
-       protected void setValue(List<Term> value) {
-               String property = typology.getId();
-               List<String> ids = new ArrayList<>();
-               for (Term term : value) {
-                       ids.add(term.getId());
-               }
-               Jcr.set(getNode(), property, ids);
-               Jcr.save(getNode());
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java b/org.argeo.app.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java
deleted file mode 100644 (file)
index da23819..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-package org.argeo.entity.ui.forms;
-
-import java.util.List;
-
-import javax.jcr.Item;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.MouseDoubleClick;
-import org.argeo.cms.swt.MouseDown;
-import org.argeo.cms.swt.Selected;
-import org.argeo.cms.ui.forms.FormStyle;
-import org.argeo.cms.ui.viewers.EditablePart;
-import org.argeo.cms.ui.widgets.ContextOverlay;
-import org.argeo.entity.Term;
-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(CmsSwtUtils.noSpaceGridLayout(3));
-
-                       createHighlight(block);
-
-                       Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
-                       CmsSwtUtils.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) -> {
-                               setValue(null);
-                               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(CmsSwtUtils.noSpaceGridLayout(2));
-                       Term currentValue = getValue();
-                       if (currentValue != null) {
-                               Label lbl = new Label(block, SWT.SINGLE);
-                               String display = getTermLabel(currentValue);
-                               lbl.setText(display);
-                               CmsSwtUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
-                               processTermListLabel(currentValue, lbl);
-                               if (isEditable()) {
-                                       lbl.addMouseListener((MouseDoubleClick) (e) -> {
-                                               startEditing();
-                                       });
-                               }
-                       } else {
-                               if (isEditable()) {
-                                       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) {
-               CmsSwtUtils.clear(contextArea);
-               List<? extends Term> terms = termsManager.listAllTerms(typology.getId());
-               terms: for (Term 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) -> {
-                                       setValue(term);
-                                       contextArea.hide();
-                                       stopEditing();
-                               });
-               }
-               contextArea.show();
-               // txt.setFocus();
-       }
-
-       protected Term getValue() {
-               String property = typology.getId();
-               String id = Jcr.get(getNode(), property);
-               Term term = termsManager.getTerm(id);
-
-               return term;
-       }
-
-       protected void setValue(Term value) {
-               String property = typology.getId();
-               Jcr.set(getNode(), property, value != null ? value.getId() : null);
-               Jcr.save(getNode());
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/library/ui/ContentEntryArea.java b/org.argeo.app.ui/src/org/argeo/library/ui/ContentEntryArea.java
deleted file mode 100644 (file)
index d633fed..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-package org.argeo.library.ui;
-
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.query.Query;
-
-import org.argeo.api.cms.CmsTheme;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.argeo.suite.ui.SuiteEvent;
-import org.argeo.suite.ui.SuiteIcon;
-import org.argeo.suite.ui.widgets.TreeOrSearchArea;
-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.ITreeContentProvider;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TreeViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-public class ContentEntryArea implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
-
-               parent.setLayout(new GridLayout());
-               Ui ui = new Ui(parent, SWT.NONE);
-               ui.setLayoutData(CmsSwtUtils.fillAll());
-
-               TreeViewerColumn nameCol = new TreeViewerColumn(ui.getTreeViewer(), SWT.NONE);
-               nameCol.getColumn().setWidth(400);
-               nameCol.setLabelProvider(new ColumnLabelProvider() {
-
-                       @Override
-                       public String getText(Object element) {
-                               Node node = (Node) element;
-                               return Jcr.getTitle(node);
-                       }
-
-                       @Override
-                       public Image getImage(Object element) {
-                               Node node = (Node) element;
-                               Image icon;
-                               if (Jcr.isNodeType(node, NodeType.NT_FOLDER)) {
-                                       icon = SuiteIcon.folder.getSmallIcon(theme);
-                               } else if (Jcr.isNodeType(node, NodeType.NT_FILE)) {
-                                       // TODO check recognized document types
-                                       icon = SuiteIcon.document.getSmallIcon(theme);
-                               } else if (Jcr.isNodeType(node, EntityType.document.get())) {
-                                       icon = SuiteIcon.document.getSmallIcon(theme);
-                               } else {
-                                       if (!isLeaf(node))
-                                               icon = SuiteIcon.folder.getSmallIcon(theme);
-                                       else
-                                               icon = null;
-                               }
-                               return icon;
-                       }
-
-               });
-
-               ui.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
-
-                       @Override
-                       public void doubleClick(DoubleClickEvent event) {
-                               Node user = (Node) ui.getTreeViewer().getStructuredSelection().getFirstElement();
-                               if (user != null) {
-                                       CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
-                                                       SuiteEvent.eventProperties(user));
-                               }
-
-                       }
-               });
-               ui.getTreeViewer().addSelectionChangedListener(new ISelectionChangedListener() {
-                       public void selectionChanged(SelectionChangedEvent event) {
-                               Node user = (Node) ui.getTreeViewer().getStructuredSelection().getFirstElement();
-                               if (user != null) {
-                                       CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
-                                                       SuiteEvent.eventProperties(user));
-                               }
-                       }
-               });
-
-               ui.getTreeViewer().setContentProvider(new SpacesContentProvider());
-               ui.getTreeViewer().setInput(context.getSession());
-               return ui;
-       }
-
-       protected boolean isLeaf(Node node) {
-               return Jcr.isNodeType(node, EntityType.entity.get()) || Jcr.isNodeType(node, EntityType.document.get())
-                               || Jcr.isNodeType(node, NodeType.NT_FILE);
-       }
-
-       class Ui extends TreeOrSearchArea {
-
-               public Ui(Composite parent, int style) {
-                       super(parent, style);
-               }
-
-       }
-
-       class SpacesContentProvider implements ITreeContentProvider {
-
-               @Override
-               public Object[] getElements(Object inputElement) {
-                       Session session = (Session) inputElement;
-                       try {
-                               Query query = session.getWorkspace().getQueryManager()
-                                               .createQuery("SELECT * FROM [" + EntityType.space.get() + "]", Query.JCR_SQL2);
-                               NodeIterator spacesIt = query.execute().getNodes();
-                               SortedMap<String, Node> map = new TreeMap<>();
-                               while (spacesIt.hasNext()) {
-                                       Node space = spacesIt.nextNode();
-                                       String path = space.getPath();
-                                       map.put(path, space);
-                               }
-                               return map.values().toArray();
-                       } catch (RepositoryException e) {
-                               throw new JcrException(e);
-                       }
-               }
-
-               @Override
-               public Object[] getChildren(Object parentElement) {
-                       Node parent = (Node) parentElement;
-                       if (isLeaf(parent))
-                               return null;
-                       return Jcr.getNodes(parent).toArray();
-               }
-
-               @Override
-               public Object getParent(Object element) {
-                       Node node = (Node) element;
-                       return Jcr.getParent(node);
-               }
-
-               @Override
-               public boolean hasChildren(Object element) {
-                       Node node = (Node) element;
-                       return !isLeaf(node);
-               }
-
-               @Override
-               public void dispose() {
-               }
-
-               @Override
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               }
-
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsContextMenu.java b/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsContextMenu.java
deleted file mode 100644 (file)
index 03de251..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-package org.argeo.library.ui;
-
-import static org.argeo.library.ui.DocumentsUiService.ACTION_ID_BOOKMARK_FOLDER;
-import static org.argeo.library.ui.DocumentsUiService.ACTION_ID_CREATE_FOLDER;
-import static org.argeo.library.ui.DocumentsUiService.ACTION_ID_DELETE;
-import static org.argeo.library.ui.DocumentsUiService.ACTION_ID_DOWNLOAD_FOLDER;
-import static org.argeo.library.ui.DocumentsUiService.ACTION_ID_RENAME;
-import static org.argeo.library.ui.DocumentsUiService.ACTION_ID_SHARE_FOLDER;
-import static org.argeo.library.ui.DocumentsUiService.ACTION_ID_UPLOAD_FILE;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import org.argeo.suite.ui.widgets.AbstractConnectContextMenu;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Control;
-
-/** Generic popup context menu to manage NIO Path in a Viewer. */
-public class DocumentsContextMenu extends AbstractConnectContextMenu {
-       // Local context
-       private final DocumentsFolderComposite browser;
-       private final DocumentsUiService uiService;
-//     private final Repository repository;
-
-       private final static String[] DEFAULT_ACTIONS = { ACTION_ID_CREATE_FOLDER, ACTION_ID_BOOKMARK_FOLDER,
-                       ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_RENAME,
-                       ACTION_ID_DELETE };
-
-       private Path currFolderPath;
-
-       public DocumentsContextMenu(DocumentsFolderComposite browser,
-                       DocumentsUiService documentsUiService) {
-               super(browser.getDisplay(), DEFAULT_ACTIONS);
-               this.browser = browser;
-               this.uiService = documentsUiService;
-//             this.repository = repository;
-
-               createControl();
-       }
-
-       public void setCurrFolderPath(Path currFolderPath) {
-               this.currFolderPath = currFolderPath;
-       }
-
-       protected boolean aboutToShow(Control source, Point location, IStructuredSelection selection) {
-               boolean emptySel = true;
-               boolean multiSel = false;
-               boolean isFolder = true;
-               if (selection != null && !selection.isEmpty()) {
-                       emptySel = false;
-                       multiSel = selection.size() > 1;
-                       if (!multiSel && selection.getFirstElement() instanceof Path) {
-                               isFolder = Files.isDirectory((Path) selection.getFirstElement());
-                       }
-               }
-               if (emptySel) {
-                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_BOOKMARK_FOLDER);
-                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_RENAME, ACTION_ID_DELETE
-                               );
-               } else if (multiSel) {
-                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_DELETE,
-                                       ACTION_ID_BOOKMARK_FOLDER);
-                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_RENAME);
-               } else if (isFolder) {
-                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_RENAME, ACTION_ID_DELETE,
-                                       ACTION_ID_BOOKMARK_FOLDER);
-                       setVisible(false, 
-                                       // to be implemented
-                                       ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER);
-               } else {
-                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_RENAME,
-                                       ACTION_ID_DELETE);
-                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_BOOKMARK_FOLDER);
-               }
-               return true;
-       }
-
-       public void show(Control source, Point location, IStructuredSelection selection, Path currFolderPath) {
-               // TODO find a better way to retrieve the parent path (cannot be deduced
-               // from table content because it will fail on an empty folder)
-               this.currFolderPath = currFolderPath;
-               super.show(source, location, selection);
-
-       }
-
-       @Override
-       protected boolean performAction(String actionId) {
-               switch (actionId) {
-               case ACTION_ID_CREATE_FOLDER:
-                       createFolder();
-                       break;
-               case ACTION_ID_BOOKMARK_FOLDER:
-                       bookmarkFolder();
-                       break;
-               case ACTION_ID_RENAME:
-                       renameItem();
-                       break;
-               case ACTION_ID_DELETE:
-                       deleteItems();
-                       break;
-//             case ACTION_ID_OPEN:
-//                     openFile();
-//                     break;
-               case ACTION_ID_UPLOAD_FILE:
-                       uploadFiles();
-                       break;
-               default:
-                       throw new IllegalArgumentException("Unimplemented action " + actionId);
-                       // case ACTION_ID_SHARE_FOLDER:
-                       // return "Share Folder";
-                       // case ACTION_ID_DOWNLOAD_FOLDER:
-                       // return "Download as zip archive";
-               }
-               browser.setFocus();
-               return false;
-       }
-
-       @Override
-       protected String getLabel(String actionId) {
-               return uiService.getLabel(actionId);
-       }
-
-       private void openFile() {
-               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
-               if (selection.isEmpty() || selection.size() > 1)
-                       // Should never happen
-                       return;
-               Path toOpenPath = ((Path) selection.getFirstElement());
-               uiService.openFile(toOpenPath);
-       }
-
-       private void deleteItems() {
-               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
-               if (selection.isEmpty())
-                       return;
-               else if (uiService.deleteItems(getParentShell(), selection))
-                       browser.refresh();
-       }
-
-       private void renameItem() {
-               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
-               if (selection.isEmpty() || selection.size() > 1)
-                       // Should never happen
-                       return;
-               Path toRenamePath = ((Path) selection.getFirstElement());
-               if (uiService.renameItem(getParentShell(), currFolderPath, toRenamePath))
-                       browser.refresh();
-       }
-
-       private void createFolder() {
-               if (uiService.createFolder(getParentShell(), currFolderPath))
-                       browser.refresh();
-       }
-
-       private void bookmarkFolder() {
-               Path toBookmarkPath = null;
-               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
-               if (selection.isEmpty())
-                       toBookmarkPath = currFolderPath;
-               else if (selection.size() > 1)
-                       toBookmarkPath = currFolderPath;
-               else if (selection.size() == 1) {
-                       Path currSelected = ((Path) selection.getFirstElement());
-                       if (Files.isDirectory(currSelected))
-                               toBookmarkPath = currSelected;
-                       else
-                               return;
-               }
-               //uiService.bookmarkFolder(toBookmarkPath, repository, null);
-       }
-
-       private void uploadFiles() {
-               if (uiService.uploadFiles(getParentShell(), currFolderPath))
-                       browser.refresh();
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFileComposite.java b/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFileComposite.java
deleted file mode 100644 (file)
index c9f4889..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.argeo.library.ui;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.spi.FileSystemProvider;
-
-import javax.jcr.Node;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.fs.CmsFsUtils;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.fs.FsUiUtils;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.browser.Browser;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-
-/**
- * Default Documents file composite: a sashForm with a browser in the middle and
- * meta data at right hand side.
- */
-public class DocumentsFileComposite extends Composite {
-       private static final long serialVersionUID = -7567632342889241793L;
-
-       private final static CmsLog log = CmsLog.getLog(DocumentsFileComposite.class);
-
-       private final Node currentBaseContext;
-
-       // UI Parts for the browser
-       private Composite rightPannelCmp;
-
-       public DocumentsFileComposite(Composite parent, int style, Node context, FileSystemProvider fsp) {
-               super(parent, style);
-               this.currentBaseContext = context;
-               this.setLayout(EclipseUiUtils.noSpaceGridLayout());
-               SashForm form = new SashForm(this, SWT.HORIZONTAL);
-
-               Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
-               createDisplay(centerCmp);
-
-               rightPannelCmp = new Composite(form, SWT.NO_FOCUS);
-
-               Path path = CmsFsUtils.getPath(fsp, context);
-               setOverviewInput(path);
-               form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               form.setWeights(new int[] { 55, 20 });
-       }
-
-       private void createDisplay(final Composite parent) {
-               parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
-               Browser browser = new Browser(parent, SWT.NONE);
-               // browser.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true,
-               // true));
-               browser.setLayoutData(EclipseUiUtils.fillAll());
-               // FIXME make it more robust
-               String url = CmsUiUtils.getDataUrl(currentBaseContext, UiContext.getHttpRequest());
-               // FIXME issue with the redirection to https
-               if (url.startsWith("http://") && !url.startsWith("http://localhost"))
-                       url = "https://" + url.substring("http://".length(), url.length());
-               if (log.isTraceEnabled())
-                       log.debug("Trying to display " + url);
-               browser.setUrl(url);
-               browser.layout(true, true);
-       }
-
-       /**
-        * Recreates the content of the box that displays information about the current
-        * selected Path.
-        */
-       private void setOverviewInput(Path path) {
-               try {
-                       EclipseUiUtils.clear(rightPannelCmp);
-                       rightPannelCmp.setLayout(new GridLayout());
-                       if (path != null) {
-                               // if (isImg(context)) {
-                               // EditableImage image = new Img(parent, RIGHT, context,
-                               // imageWidth);
-                               // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
-                               // true, false,
-                               // 2, 1));
-                               // }
-
-                               Label contextL = new Label(rightPannelCmp, SWT.NONE);
-                               contextL.setText(path.getFileName().toString());
-                               contextL.setFont(EclipseUiUtils.getBoldFont(rightPannelCmp));
-                               addProperty(rightPannelCmp, "Last modified", Files.getLastModifiedTime(path).toString());
-                               // addProperty(rightPannelCmp, "Owner",
-                               // Files.getOwner(path).getName());
-                               if (Files.isDirectory(path)) {
-                                       addProperty(rightPannelCmp, "Type", "Folder");
-                               } else {
-                                       String mimeType = Files.probeContentType(path);
-                                       if (EclipseUiUtils.isEmpty(mimeType))
-                                               mimeType = "<i>Unknown</i>";
-                                       addProperty(rightPannelCmp, "Type", mimeType);
-                                       addProperty(rightPannelCmp, "Size", FsUiUtils.humanReadableByteCount(Files.size(path), false));
-                               }
-                       }
-                       rightPannelCmp.layout(true, true);
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot display details for " + path.toString(), e);
-               }
-       }
-
-       // Simplify UI implementation
-       private void addProperty(Composite parent, String propName, String value) {
-               Label propLbl = new Label(parent, SWT.NONE);
-               // propLbl.setText(ConnectUtils.replaceAmpersand(propName + ": " + value));
-               propLbl.setText(value);
-               // CmsUiUtils.markup(propLbl);
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFolderComposite.java b/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFolderComposite.java
deleted file mode 100644 (file)
index b9709e6..0000000
+++ /dev/null
@@ -1,454 +0,0 @@
-package org.argeo.library.ui;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.attribute.FileTime;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import javax.jcr.Node;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.fs.FileDrop;
-import org.argeo.cms.ui.fs.FsStyles;
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider;
-import org.argeo.eclipse.ui.fs.FsTableViewer;
-import org.argeo.eclipse.ui.fs.FsUiConstants;
-import org.argeo.eclipse.ui.fs.FsUiUtils;
-import org.argeo.eclipse.ui.fs.NioFileLabelProvider;
-import org.argeo.eclipse.ui.fs.ParentDir;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowData;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Default Documents folder composite: a sashForm layout with a simple table in
- * the middle and an overview at right hand side.
- */
-public class DocumentsFolderComposite extends Composite {
-       private final static CmsLog log = CmsLog.getLog(DocumentsFolderComposite.class);
-       private static final long serialVersionUID = -40347919096946585L;
-
-       private final Node currentBaseContext;
-
-       private final DocumentsUiService documentUiService = new DocumentsUiService();
-
-       // UI Parts for the browser
-       private Composite filterCmp;
-       private Composite breadCrumbCmp;
-       private Text filterTxt;
-       private FsTableViewer directoryDisplayViewer;
-       private Composite rightPanelCmp;
-
-       private DocumentsContextMenu contextMenu;
-       private DateFormat dateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm");
-
-       // Local context
-       private Path initialPath;
-       private Path currentFolder;
-
-       public DocumentsFolderComposite(Composite parent, int style, Node context) {
-               super(parent, style);
-               this.currentBaseContext = context;
-
-               this.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
-               SashForm form = new SashForm(this, SWT.HORIZONTAL);
-
-               Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
-               createDisplay(centerCmp);
-
-               rightPanelCmp = new Composite(form, SWT.NO_FOCUS);
-
-               form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               form.setWeights(new int[] { 55, 20 });
-       }
-
-       public void populate(Path path) {
-               initialPath = path;
-               directoryDisplayViewer.setInitialPath(initialPath);
-               setInput(path);
-       }
-
-       void refresh() {
-               modifyFilter(false);
-       }
-
-       private void createDisplay(final Composite parent) {
-               parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
-               // top filter
-               filterCmp = new Composite(parent, SWT.NO_FOCUS);
-               filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
-               RowLayout rl = new RowLayout(SWT.HORIZONTAL);
-               rl.wrap = true;
-               rl.center = true;
-               filterCmp.setLayout(rl);
-               // addFilterPanel(filterCmp);
-
-               // Main display
-               directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
-               List<ColumnDefinition> colDefs = new ArrayList<>();
-               colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), " Name", 250));
-               colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100));
-//             colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 150));
-               colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
-                               "Last modified", 400));
-               final Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
-               table.setLayoutData(EclipseUiUtils.fillAll());
-
-               directoryDisplayViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-
-                       @Override
-                       public void selectionChanged(SelectionChangedEvent event) {
-                               IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
-                               Path selected = null;
-                               if (selection.isEmpty())
-                                       setSelected(null);
-                               else {
-                                       Object o = selection.getFirstElement();
-                                       if (o instanceof Path)
-                                               selected = (Path) o;
-                                       else if (o instanceof ParentDir)
-                                               selected = ((ParentDir) o).getPath();
-                               }
-                               if (selected != null) {
-                                       // TODO manage multiple selection
-                                       setSelected(selected);
-                               }
-                       }
-               });
-
-               directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
-                       @Override
-                       public void doubleClick(DoubleClickEvent event) {
-                               IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
-                               Path selected = null;
-                               if (!selection.isEmpty()) {
-                                       Object o = selection.getFirstElement();
-                                       if (o instanceof Path)
-                                               selected = (Path) o;
-                                       else if (o instanceof ParentDir)
-                                               selected = ((ParentDir) o).getPath();
-                               }
-                               if (selected != null) {
-                                       if (Files.isDirectory(selected))
-                                               setInput(selected);
-                                       else
-                                               externalNavigateTo(selected);
-                               }
-                       }
-               });
-
-               // The context menu
-               contextMenu = new DocumentsContextMenu(this,  documentUiService);
-
-               table.addMouseListener(new MouseAdapter() {
-                       private static final long serialVersionUID = 6737579410648595940L;
-
-                       @Override
-                       public void mouseDown(MouseEvent e) {
-                               if (e.button == 3) {
-                                       // contextMenu.setCurrFolderPath(currDisplayedFolder);
-                                       contextMenu.show(table, new Point(e.x, e.y),
-                                                       (IStructuredSelection) directoryDisplayViewer.getSelection(), currentFolder);
-                               }
-                       }
-               });
-
-               FileDrop fileDrop = new FileDrop() {
-
-                       @Override
-                       protected void processFileUpload(InputStream in, String fileName, String contetnType) throws IOException {
-                               Path file = currentFolder.resolve(fileName);
-                               Files.copy(in, file);
-                               refresh();
-                       }
-               };
-               fileDrop.createDropTarget(directoryDisplayViewer.getTable());
-       }
-
-       /**
-        * Overwrite to enable single sourcing between workbench and CMS navigation
-        */
-       protected void externalNavigateTo(Path path) {
-
-       }
-
-       private void addPathElementBtn(Path path) {
-               Button elemBtn = new Button(breadCrumbCmp, SWT.PUSH);
-               String nameStr;
-               if (path.toString().equals("/"))
-                       nameStr = "[jcr:root]";
-               else
-                       nameStr = path.getFileName().toString();
-//             elemBtn.setText(nameStr + " >> ");
-               elemBtn.setText(nameStr);
-               CmsSwtUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN);
-               elemBtn.addSelectionListener(new SelectionAdapter() {
-                       private static final long serialVersionUID = -4103695476023480651L;
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               setInput(path);
-                       }
-               });
-       }
-
-       public void setInput(Path path) {
-               if (path.equals(currentFolder))
-                       return;
-               // below initial path
-               if (!initialPath.equals(path) && initialPath.startsWith(path))
-                       return;
-               currentFolder = path;
-
-               Path diff = initialPath.relativize(currentFolder);
-
-               for (Control child : filterCmp.getChildren())
-                       if (!child.equals(filterTxt))
-                               child.dispose();
-
-               // Bread crumbs
-               breadCrumbCmp = new Composite(filterCmp, SWT.NO_FOCUS);
-               CmsSwtUtils.style(breadCrumbCmp, FsStyles.BREAD_CRUMB_BTN);
-               RowLayout breadCrumbLayout = new RowLayout();
-               breadCrumbLayout.spacing = 0;
-               breadCrumbLayout.marginTop = 0;
-               breadCrumbLayout.marginBottom = 0;
-               breadCrumbLayout.marginRight = 0;
-               breadCrumbLayout.marginLeft = 0;
-               breadCrumbCmp.setLayout(breadCrumbLayout);
-               addPathElementBtn(initialPath);
-               Path currTarget = initialPath;
-               if (!diff.toString().equals(""))
-                       for (Path pathElem : diff) {
-                               currTarget = currTarget.resolve(pathElem);
-                               addPathElementBtn(currTarget);
-                       }
-
-               if (filterTxt != null) {
-                       filterTxt.setText("");
-                       filterTxt.moveBelow(null);
-               } else {
-                       modifyFilter(false);
-               }
-               setSelected(null);
-               filterCmp.getParent().layout(true, true);
-       }
-
-       private void setSelected(Path path) {
-               if (path == null)
-                       setOverviewInput(currentFolder);
-               else
-                       setOverviewInput(path);
-       }
-
-       public Viewer getViewer() {
-               return directoryDisplayViewer;
-       }
-
-       /**
-        * Recreates the content of the box that displays information about the current
-        * selected Path.
-        */
-       private void setOverviewInput(Path path) {
-               try {
-                       EclipseUiUtils.clear(rightPanelCmp);
-                       rightPanelCmp.setLayout(new GridLayout());
-                       if (path != null) {
-                               // if (isImg(context)) {
-                               // EditableImage image = new Img(parent, RIGHT, context,
-                               // imageWidth);
-                               // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
-                               // true, false,
-                               // 2, 1));
-                               // }
-
-                               Label contextL = new Label(rightPanelCmp, SWT.NONE);
-                               contextL.setText(path.getFileName().toString());
-                               contextL.setFont(EclipseUiUtils.getBoldFont(rightPanelCmp));
-                               FileTime lastModified = Files.getLastModifiedTime(path);
-                               if (lastModified.toMillis() != 0)
-                                       try {
-                                               String lastModifiedStr = dateFormat.format(new Date(lastModified.toMillis()));
-                                               addProperty(rightPanelCmp, "Last modified", lastModifiedStr);
-                                       } catch (Exception e) {
-                                               log.error("Workarounded issue while getting last update date for " + path, e);
-                                               addProperty(rightPanelCmp, "Last modified", "-");
-                                       }
-                               // addProperty(rightPannelCmp, "Owner",
-                               // Files.getOwner(path).getName());
-                               if (Files.isDirectory(path)) {
-                                       addProperty(rightPanelCmp, "Type", "Folder");
-                               } else {
-                                       String mimeType = Files.probeContentType(path);
-                                       if (EclipseUiUtils.isEmpty(mimeType))
-                                               mimeType = "<i>Unknown</i>";
-                                       addProperty(rightPanelCmp, "Type", mimeType);
-                                       addProperty(rightPanelCmp, "Size", FsUiUtils.humanReadableByteCount(Files.size(path), false));
-                               }
-
-                               // read all attributes
-//                             Map<String, Object> attrs = Files.readAttributes(path, "*");
-//                             for (String attr : attrs.keySet()) {
-//                                     Object value = attrs.get(attr);
-//                                     String str;
-//                                     if (value instanceof Calendar) {
-//                                             str = dateFormat.format(((Calendar) value).getTime());
-//                                     } else {
-//                                             str = value.toString();
-//                                     }
-//                                     addProperty(rightPanelCmp, attr, str);
-//
-//                             }
-                       }
-                       rightPanelCmp.layout(true, true);
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot display details for " + path.toString(), e);
-               }
-       }
-
-       private void addFilterPanel(Composite parent) {
-               // parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
-               // false)));
-
-               filterTxt = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL);
-               filterTxt.setMessage("Search current folder");
-               filterTxt.setLayoutData(new RowData(250, SWT.DEFAULT));
-               filterTxt.addModifyListener(new ModifyListener() {
-                       private static final long serialVersionUID = 1L;
-
-                       public void modifyText(ModifyEvent event) {
-                               modifyFilter(false);
-                       }
-               });
-               filterTxt.addKeyListener(new KeyListener() {
-                       private static final long serialVersionUID = 2533535233583035527L;
-
-                       @Override
-                       public void keyReleased(KeyEvent e) {
-                       }
-
-                       @Override
-                       public void keyPressed(KeyEvent e) {
-                               // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
-                               // // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
-                               // FilterEntitiesVirtualTable currTable = null;
-                               // if (currEdited != null) {
-                               // FilterEntitiesVirtualTable table =
-                               // browserCols.get(currEdited);
-                               // if (table != null && !table.isDisposed())
-                               // currTable = table;
-                               // }
-                               //
-                               // if (e.keyCode == SWT.ARROW_DOWN)
-                               // currTable.setFocus();
-                               // else if (e.keyCode == SWT.BS) {
-                               // if (filterTxt.getText().equals("")
-                               // && !(currEdited.getNameCount() == 1 ||
-                               // currEdited.equals(initialPath))) {
-                               // Path oldEdited = currEdited;
-                               // Path parentPath = currEdited.getParent();
-                               // setEdited(parentPath);
-                               // if (browserCols.containsKey(parentPath))
-                               // browserCols.get(parentPath).setSelected(oldEdited);
-                               // filterTxt.setFocus();
-                               // e.doit = false;
-                               // }
-                               // } else if (e.keyCode == SWT.TAB && !shiftPressed) {
-                               // Path uniqueChild = getOnlyChild(currEdited,
-                               // filterTxt.getText());
-                               // if (uniqueChild != null) {
-                               // // Highlight the unique chosen child
-                               // currTable.setSelected(uniqueChild);
-                               // setEdited(uniqueChild);
-                               // }
-                               // filterTxt.setFocus();
-                               // e.doit = false;
-                               // }
-                       }
-               });
-       }
-
-       // private Path getOnlyChild(Path parent, String filter) {
-       // try (DirectoryStream<Path> stream =
-       // Files.newDirectoryStream(currDisplayedFolder, filter + "*")) {
-       // Path uniqueChild = null;
-       // boolean moreThanOne = false;
-       // loop: for (Path entry : stream) {
-       // if (uniqueChild == null) {
-       // uniqueChild = entry;
-       // } else {
-       // moreThanOne = true;
-       // break loop;
-       // }
-       // }
-       // if (!moreThanOne)
-       // return uniqueChild;
-       // return null;
-       // } catch (IOException ioe) {
-       // throw new DocumentsException(
-       // "Unable to determine unique child existence and get it under " + parent +
-       // " with filter " + filter,
-       // ioe);
-       // }
-       // }
-
-       private void modifyFilter(boolean fromOutside) {
-               if (!fromOutside)
-                       if (currentFolder != null) {
-                               String filter;
-                               if (filterTxt != null)
-                                       filter = filterTxt.getText() + "*";
-                               else
-                                       filter = "*";
-                               directoryDisplayViewer.setInput(currentFolder, filter);
-                       }
-       }
-
-       // Simplify UI implementation
-       private void addProperty(Composite parent, String propName, String value) {
-               Label propLbl = new Label(parent, SWT.NONE);
-               //propLbl.setText(ConnectUtils.replaceAmpersand(propName + ": " + value));
-               propLbl.setText(value);
-               //CmsUiUtils.markup(propLbl);
-       }
-
-       public Path getCurrentFolder() {
-               return currentFolder;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFolderUiProvider.java b/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsFolderUiProvider.java
deleted file mode 100644 (file)
index 41fc823..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.argeo.library.ui;
-
-import java.nio.file.Path;
-import java.nio.file.spi.FileSystemProvider;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsView;
-import org.argeo.cms.fs.CmsFsUtils;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.jcr.Jcr;
-import org.argeo.suite.ui.SuiteEvent;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** UI provider of a document folder. */
-public class DocumentsFolderUiProvider implements CmsUiProvider {
-       private FileSystemProvider nodeFileSystemProvider;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
-               DocumentsFolderComposite dfc = new DocumentsFolderComposite(parent, SWT.NONE, context) {
-
-                       @Override
-                       protected void externalNavigateTo(Path path) {
-                               Node folderNode = cmsView.doAs(() -> CmsFsUtils.getNode(Jcr.getSession(context).getRepository(), path));
-                               parent.addDisposeListener((e1) -> Jcr.logout(folderNode));
-                               cmsView.sendEvent(SuiteEvent.openNewPart.topic(), SuiteEvent.eventProperties(folderNode));
-                       }
-               };
-               dfc.setLayoutData(CmsSwtUtils.fillAll());
-               dfc.populate(cmsView.doAs(() -> CmsFsUtils.getPath(nodeFileSystemProvider, context)));
-               return dfc;
-       }
-
-       public void setNodeFileSystemProvider(FileSystemProvider nodeFileSystemProvider) {
-               this.nodeFileSystemProvider = nodeFileSystemProvider;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsTreeUiProvider.java b/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsTreeUiProvider.java
deleted file mode 100644 (file)
index b2483a9..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-package org.argeo.library.ui;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.spi.FileSystemProvider;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsView;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.fs.CmsFsUtils;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.eclipse.ui.fs.FsTreeViewer;
-import org.argeo.jcr.Jcr;
-import org.argeo.suite.ui.SuiteEvent;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Tree view of a user root folders. */
-public class DocumentsTreeUiProvider implements CmsUiProvider {
-       private FileSystemProvider nodeFileSystemProvider;
-       private Repository repository;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               parent.setLayout(new GridLayout());
-               FsTreeViewer fsTreeViewer = new FsTreeViewer(parent, SWT.NONE);
-               fsTreeViewer.configureDefaultSingleColumnTable(500);
-               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
-               Node homeNode = CmsJcrUtils.getUserHome(cmsView.doAs(() -> Jcr.login(repository, CmsConstants.HOME_WORKSPACE)));
-               parent.addDisposeListener((e1) -> Jcr.logout(homeNode));
-               Path homePath = CmsFsUtils.getPath(nodeFileSystemProvider, homeNode);
-               fsTreeViewer.addSelectionChangedListener((e) -> {
-                       IStructuredSelection selection = (IStructuredSelection) fsTreeViewer.getSelection();
-                       if (selection.isEmpty())
-                               return;
-                       else {
-                               Path newSelected = (Path) selection.getFirstElement();
-                               if (Files.isDirectory(newSelected)) {
-                                       Node folderNode = cmsView.doAs(() -> CmsFsUtils.getNode(repository, newSelected));
-                                       parent.addDisposeListener((e1) -> Jcr.logout(folderNode));
-                                       cmsView.sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(folderNode));
-                               }
-                       }
-               });
-               fsTreeViewer.addDoubleClickListener((e) -> {
-                       IStructuredSelection selection = (IStructuredSelection) fsTreeViewer.getSelection();
-                       if (selection.isEmpty())
-                               return;
-                       else {
-                               Path newSelected = (Path) selection.getFirstElement();
-                               if (Files.isDirectory(newSelected)) {
-                                       Node folderNode = cmsView.doAs(() -> CmsFsUtils.getNode(repository, newSelected));
-                                       parent.addDisposeListener((e1) -> Jcr.logout(folderNode));
-                                       cmsView.sendEvent(SuiteEvent.openNewPart.topic(), SuiteEvent.eventProperties(folderNode));
-                               }
-                       }
-               });
-               fsTreeViewer.setPathsInput(homePath);
-               fsTreeViewer.getControl().setLayoutData(CmsSwtUtils.fillAll());
-               fsTreeViewer.getControl().getParent().layout(true, true);
-               return fsTreeViewer.getControl();
-       }
-
-       public void setNodeFileSystemProvider(FileSystemProvider nodeFileSystemProvider) {
-               this.nodeFileSystemProvider = nodeFileSystemProvider;
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsUiService.java b/org.argeo.app.ui/src/org/argeo/library/ui/DocumentsUiService.java
deleted file mode 100644 (file)
index 9084e86..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-package org.argeo.library.ui;
-
-import static org.argeo.cms.swt.dialogs.CmsMessageDialog.openConfirm;
-import static org.argeo.cms.swt.dialogs.CmsMessageDialog.openError;
-import static org.argeo.cms.swt.dialogs.SingleValueDialog.ask;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.nio.file.DirectoryNotEmptyException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.swt.dialogs.CmsFeedback;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Shell;
-
-public class DocumentsUiService {
-       private final static CmsLog log = CmsLog.getLog(DocumentsUiService.class);
-
-       // Default known actions
-       public final static String ACTION_ID_CREATE_FOLDER = "createFolder";
-       public final static String ACTION_ID_BOOKMARK_FOLDER = "bookmarkFolder";
-       public final static String ACTION_ID_SHARE_FOLDER = "shareFolder";
-       public final static String ACTION_ID_DOWNLOAD_FOLDER = "downloadFolder";
-       public final static String ACTION_ID_RENAME = "rename";
-       public final static String ACTION_ID_DELETE = "delete";
-       public final static String ACTION_ID_UPLOAD_FILE = "uploadFiles";
-       // public final static String ACTION_ID_OPEN = "open";
-       public final static String ACTION_ID_DELETE_BOOKMARK = "deleteBookmark";
-       public final static String ACTION_ID_RENAME_BOOKMARK = "renameBookmark";
-
-       public String getLabel(String actionId) {
-               switch (actionId) {
-               case ACTION_ID_CREATE_FOLDER:
-                       return "Create Folder";
-               case ACTION_ID_BOOKMARK_FOLDER:
-                       return "Bookmark Folder";
-               case ACTION_ID_SHARE_FOLDER:
-                       return "Share Folder";
-               case ACTION_ID_DOWNLOAD_FOLDER:
-                       return "Download as zip archive";
-               case ACTION_ID_RENAME:
-                       return "Rename";
-               case ACTION_ID_DELETE:
-                       return "Delete";
-               case ACTION_ID_UPLOAD_FILE:
-                       return "Upload Files";
-//             case ACTION_ID_OPEN:
-//                     return "Open";
-               case ACTION_ID_DELETE_BOOKMARK:
-                       return "Delete bookmark";
-               case ACTION_ID_RENAME_BOOKMARK:
-                       return "Rename bookmark";
-               default:
-                       throw new IllegalArgumentException("Unknown action ID " + actionId);
-               }
-       }
-
-       public void openFile(Path toOpenPath) {
-               try {
-                       String name = toOpenPath.getFileName().toString();
-                       File tmpFile = File.createTempFile("tmp", name);
-                       tmpFile.deleteOnExit();
-                       try (OutputStream os = new FileOutputStream(tmpFile)) {
-                               Files.copy(toOpenPath, os);
-                       } catch (IOException e) {
-                               throw new IllegalStateException("Cannot open copy " + name + " to tmpFile.", e);
-                       }
-                       String uri = Paths.get(tmpFile.getAbsolutePath()).toUri().toString();
-                       Map<String, String> params = new HashMap<String, String>();
-//                     params.put(OpenFile.PARAM_FILE_NAME, name);
-//                     params.put(OpenFile.PARAM_FILE_URI, uri);
-                       // FIXME open file without a command
-                       // CommandUtils.callCommand(OpenFile.ID, params);
-               } catch (IOException e1) {
-                       throw new IllegalStateException("Cannot create tmp copy of " + toOpenPath, e1);
-               }
-       }
-
-       public boolean deleteItems(Shell shell, IStructuredSelection selection) {
-               if (selection.isEmpty())
-                       return false;
-
-               StringBuilder builder = new StringBuilder();
-               @SuppressWarnings("unchecked")
-               Iterator<Object> iterator = selection.iterator();
-               List<Path> paths = new ArrayList<>();
-
-               while (iterator.hasNext()) {
-                       Path path = (Path) iterator.next();
-                       builder.append(path.getFileName() + ", ");
-                       paths.add(path);
-               }
-               String msg = "You are about to delete following elements: " + builder.substring(0, builder.length() - 2)
-                               + ". Are you sure?";
-               if (openConfirm(msg)) {
-                       for (Path path : paths) {
-                               try {
-                                       // recursively delete directory and its content
-                                       Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
-                                               @Override
-                                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                                                       Files.delete(file);
-                                                       return FileVisitResult.CONTINUE;
-                                               }
-
-                                               @Override
-                                               public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
-                                                       Files.delete(dir);
-                                                       return FileVisitResult.CONTINUE;
-                                               }
-                                       });
-                               } catch (DirectoryNotEmptyException e) {
-                                       String errMsg = path.getFileName() + " cannot be deleted: directory is not empty.";
-                                       openError( errMsg);
-                                       throw new IllegalArgumentException("Cannot delete path " + path, e);
-                               } catch (IOException e) {
-                                       String errMsg = e.toString();
-                                       openError(errMsg);
-                                       throw new IllegalArgumentException("Cannot delete path " + path, e);
-                               }
-                       }
-                       return true;
-               }
-               return false;
-       }
-
-       public boolean renameItem(Shell shell, Path parentFolderPath, Path toRenamePath) {
-               String msg = "Enter a new name:";
-               String name = ask( msg, toRenamePath.getFileName().toString());
-               // TODO enhance check of name validity
-               if (EclipseUiUtils.notEmpty(name)) {
-                       try {
-                               Path child = parentFolderPath.resolve(name);
-                               if (Files.exists(child)) {
-                                       String errMsg = "An object named " + name + " already exists at " + parentFolderPath.toString()
-                                                       + ", please provide another name";
-                                       openError( errMsg);
-                                       throw new IllegalArgumentException(errMsg);
-                               } else {
-                                       Files.move(toRenamePath, child);
-                                       return true;
-                               }
-                       } catch (IOException e) {
-                               throw new IllegalStateException("Cannot rename " + name + " at " + parentFolderPath.toString(), e);
-                       }
-               }
-               return false;
-       }
-
-       public boolean createFolder(Shell shell, Path currFolderPath) {
-               String msg = "Enter a name:";
-               String name = ask( msg);
-               // TODO enhance check of name validity
-               if (EclipseUiUtils.notEmpty(name)) {
-                       name = name.trim();
-                       try {
-                               Path child = currFolderPath.resolve(name);
-                               if (Files.exists(child)) {
-                                       String errMsg = "A folder named " + name + " already exists at " + currFolderPath.toString()
-                                                       + ", cannot create";
-                                       openError(errMsg);
-                                       throw new IllegalArgumentException(errMsg);
-                               } else {
-                                       Files.createDirectories(child);
-                                       return true;
-                               }
-                       } catch (IOException e) {
-                               throw new IllegalStateException("Cannot create folder " + name + " at " + currFolderPath.toString(), e);
-                       }
-               }
-               return false;
-       }
-
-//     public void bookmarkFolder(Path toBookmarkPath, Repository repository, DocumentsService documentsService) {
-//             String msg = "Provide a name:";
-//             String name = SingleQuestion.ask("Create bookmark", msg, toBookmarkPath.getFileName().toString());
-//             if (EclipseUiUtils.notEmpty(name))
-//                     documentsService.createFolderBookmark(toBookmarkPath, name, repository);
-//     }
-
-       public boolean uploadFiles(Shell shell, Path currFolderPath) {
-//             shell = Display.getCurrent().getActiveShell();// ignore argument
-               try {
-                       FileDialog dialog = new FileDialog(shell, SWT.MULTI);
-                       dialog.setText("Choose one or more files to upload");
-
-                       if (EclipseUiUtils.notEmpty(dialog.open())) {
-                               String[] names = dialog.getFileNames();
-                               // Workaround small differences between RAP and RCP
-                               // 1. returned names are absolute path on RAP and
-                               // relative in RCP
-                               // 2. in RCP we must use getFilterPath that does not
-                               // exists on RAP
-                               Method filterMethod = null;
-                               Path parPath = null;
-                               try {
-                                       filterMethod = dialog.getClass().getDeclaredMethod("getFilterPath");
-                                       String filterPath = (String) filterMethod.invoke(dialog);
-                                       parPath = Paths.get(filterPath);
-                               } catch (NoSuchMethodException nsme) { // RAP
-                               }
-                               if (names.length == 0)
-                                       return false;
-                               else {
-                                       loop: for (String name : names) {
-                                               Path tmpPath = Paths.get(name);
-                                               if (parPath != null)
-                                                       tmpPath = parPath.resolve(tmpPath);
-                                               if (Files.exists(tmpPath)) {
-                                                       URI uri = tmpPath.toUri();
-                                                       String uriStr = uri.toString();
-
-                                                       if (Files.isDirectory(tmpPath)) {
-                                                               openError(
-                                                                               "Upload of directories in the system is not yet implemented");
-                                                               continue loop;
-                                                       }
-                                                       Path targetPath = currFolderPath.resolve(tmpPath.getFileName().toString());
-                                                       try (InputStream in = new FileInputStream(tmpPath.toFile())) {
-                                                               Files.copy(in, targetPath);
-                                                               Files.delete(tmpPath);
-                                                       }
-                                                       if (log.isDebugEnabled())
-                                                               log.debug("copied uploaded file " + uriStr + " to " + targetPath.toString());
-                                               } else {
-                                                       String msg = "Cannot copy tmp file from " + tmpPath.toString();
-                                                       if (parPath != null)
-                                                               msg += "\nPlease remember that file upload fails when choosing files from the \"Recently Used\" bookmarks on some OS";
-                                                       openError( msg);
-                                                       continue loop;
-                                               }
-                                       }
-                                       return true;
-                               }
-                       }
-               } catch (Exception e) {
-                       CmsFeedback.show("Cannot import files to " + currFolderPath,e);
-               }
-               return false;
-       }
-
-//     public boolean deleteBookmark(Shell shell, IStructuredSelection selection, Node bookmarkParent) {
-//             if (selection.isEmpty())
-//                     return false;
-//
-//             StringBuilder builder = new StringBuilder();
-//             @SuppressWarnings("unchecked")
-//             Iterator<Object> iterator = selection.iterator();
-//             List<Node> nodes = new ArrayList<>();
-//
-//             while (iterator.hasNext()) {
-//                     Node node = (Node) iterator.next();
-//                     builder.append(Jcr.get(node, Property.JCR_TITLE) + ", ");
-//                     nodes.add(node);
-//             }
-//             String msg = "You are about to delete following bookmark: " + builder.substring(0, builder.length() - 2)
-//                             + ". Are you sure?";
-//             if (MessageDialog.openConfirm(shell, "Confirm deletion", msg)) {
-//                     Session session = Jcr.session(bookmarkParent);
-//                     try {
-//                             if (session.hasPendingChanges())
-//                                     throw new DocumentsException("Cannot remove bookmarks, session is not clean");
-//                             for (Node path : nodes)
-//                                     path.remove();
-//                             bookmarkParent.getSession().save();
-//                             return true;
-//                     } catch (RepositoryException e) {
-//                             JcrUtils.discardQuietly(session);
-//                             throw new DocumentsException("Cannot delete bookmarks " + builder.toString(), e);
-//                     }
-//             }
-//             return false;
-//     }
-
-//     public boolean renameBookmark(IStructuredSelection selection) {
-//             if (selection.isEmpty() || selection.size() > 1)
-//                     return false;
-//             Node toRename = (Node) selection.getFirstElement();
-//             String msg = "Please provide a new name.";
-//             String name = SingleQuestion.ask("Rename bookmark", msg, ConnectJcrUtils.get(toRename, Property.JCR_TITLE));
-//             if (EclipseUiUtils.notEmpty(name)
-//                             && ConnectJcrUtils.setJcrProperty(toRename, Property.JCR_TITLE, PropertyType.STRING, name)) {
-//                     ConnectJcrUtils.saveIfNecessary(toRename);
-//                     return true;
-//             }
-//             return false;
-//     }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/people/ui/PeopleEntryArea.java b/org.argeo.app.ui/src/org/argeo/people/ui/PeopleEntryArea.java
deleted file mode 100644 (file)
index 1843ea8..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package org.argeo.people.ui;
-
-import java.util.Set;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsTheme;
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.Selected;
-import org.argeo.cms.swt.dialogs.CmsWizardDialog;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.suite.SuiteRole;
-import org.argeo.suite.ui.SuiteEvent;
-import org.argeo.suite.ui.SuiteIcon;
-import org.argeo.suite.ui.dialogs.NewUserWizard;
-import org.argeo.util.naming.LdapAttrs;
-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 PeopleEntryArea implements CmsUiProvider {
-
-       private CmsUserManager cmsUserManager;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsTheme theme = CmsSwtUtils.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(CmsSwtUtils.fillWidth());
-               bottom.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
-               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
-               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               deleteItem.setEnabled(false);
-//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
-               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
-               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
-               usersViewer.addDoubleClickListener(new IDoubleClickListener() {
-
-                       @Override
-                       public void doubleClick(DoubleClickEvent event) {
-                               User user = (User) usersViewer.getStructuredSelection().getFirstElement();
-                               if (user != null) {
-//                                     Node userNode = getOrCreateUserNode(user, context);
-                                       CmsSwtUtils.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);
-                                       CmsSwtUtils.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(CmsSwtUtils.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.app.ui/src/org/argeo/people/ui/PersonUiProvider.java b/org.argeo.app.ui/src/org/argeo/people/ui/PersonUiProvider.java
deleted file mode 100644 (file)
index 8a5476d..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.argeo.people.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.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.suite.ui.SuiteMsg;
-import org.argeo.suite.ui.SuiteUiUtils;
-import org.argeo.util.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 PersonUiProvider 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(CmsSwtUtils.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(CmsSwtUtils.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.app.ui/src/org/argeo/people/ui/SuiteUserUiProvider.java b/org.argeo.app.ui/src/org/argeo/people/ui/SuiteUserUiProvider.java
deleted file mode 100644 (file)
index 07c326b..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.argeo.people.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.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.suite.ui.SuiteMsg;
-import org.argeo.suite.ui.SuiteUiUtils;
-import org.argeo.util.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(CmsSwtUtils.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(CmsSwtUtils.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.app.ui/src/org/argeo/people/ui/SuiteUsersEntryArea.java b/org.argeo.app.ui/src/org/argeo/people/ui/SuiteUsersEntryArea.java
deleted file mode 100644 (file)
index 6cb83d1..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package org.argeo.people.ui;
-
-import java.util.Set;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsTheme;
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.Selected;
-import org.argeo.cms.swt.dialogs.CmsWizardDialog;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.suite.SuiteRole;
-import org.argeo.suite.ui.SuiteEvent;
-import org.argeo.suite.ui.SuiteIcon;
-import org.argeo.suite.ui.dialogs.NewUserWizard;
-import org.argeo.util.naming.LdapAttrs;
-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 SuiteUsersEntryArea implements CmsUiProvider {
-
-       private CmsUserManager cmsUserManager;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsTheme theme = CmsSwtUtils.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(CmsSwtUtils.fillWidth());
-               bottom.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
-               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
-               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               deleteItem.setEnabled(false);
-//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
-               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
-               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
-               usersViewer.addDoubleClickListener(new IDoubleClickListener() {
-
-                       @Override
-                       public void doubleClick(DoubleClickEvent event) {
-                               User user = (User) usersViewer.getStructuredSelection().getFirstElement();
-                               if (user != null) {
-//                                     Node userNode = getOrCreateUserNode(user, context);
-                                       CmsSwtUtils.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);
-                                       CmsSwtUtils.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(CmsSwtUtils.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.app.ui/src/org/argeo/publishing/ui/DocumentUiProvider.java b/org.argeo.app.ui/src/org/argeo/publishing/ui/DocumentUiProvider.java
deleted file mode 100644 (file)
index bd331ce..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.argeo.publishing.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
-import org.argeo.api.cms.CmsEditable;
-import org.argeo.api.cms.CmsView;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsLink;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.viewers.JcrVersionCmsEditable;
-import org.argeo.cms.ui.widgets.ScrolledPage;
-import org.argeo.docbook.DbkType;
-import org.argeo.docbook.ui.AbstractDbkViewer;
-import org.argeo.docbook.ui.DocumentTextEditor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.browser.Browser;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-public class DocumentUiProvider implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
-               CmsEditable cmsEditable = new JcrVersionCmsEditable(context);
-               if (context.hasNode(DbkType.article.get())) {
-                       Node textNode = context.getNode(DbkType.article.get());
-                       // Title
-                       parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-                       CmsLink toHtml = new CmsLink("To HTML", "/html/dbk" + context.getPath()+"/index.html");
-                       toHtml.createUiPart(parent, context);
-
-                       ScrolledPage page = new ScrolledPage(parent, SWT.NONE);
-                       page.setLayoutData(CmsSwtUtils.fillAll());
-                       page.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-                       cmsView.runAs(() -> {
-                               AbstractDbkViewer dbkEditor = new DocumentTextEditor(page, SWT.NONE, textNode, cmsEditable);
-                               dbkEditor.refresh();
-                       });
-                       return page;
-
-               } else if (context.isNodeType(NodeType.NT_FILE)) {
-                       String fileName = context.getName();
-                       if (fileName.endsWith(".pdf")) {
-                               Browser browser = new Browser(parent, SWT.NONE);
-                               String dataPath = CmsUiUtils.getDataPath(context);
-                               browser.setUrl(dataPath);
-                               browser.setLayoutData(CmsSwtUtils.fillAll());
-                               return browser;
-                       }
-               }
-               return null;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/publishing/ui/PublishingApp.java b/org.argeo.app.ui/src/org/argeo/publishing/ui/PublishingApp.java
deleted file mode 100644 (file)
index 464f0c9..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-package org.argeo.publishing.ui;
-
-import static org.argeo.suite.ui.SuiteApp.DEFAULT_THEME_ID_PROPERTY;
-import static org.argeo.suite.ui.SuiteApp.DEFAULT_UI_NAME_PROPERTY;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.api.cms.CmsUi;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.AbstractCmsApp;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.jcr.Jcr;
-import org.argeo.suite.ui.SuiteApp;
-import org.argeo.util.LangUtils;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.Constants;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
-
-/**
- * A {@link CmsApp} dedicated to publishing, typically a public or internal web
- * site.
- */
-public class PublishingApp extends AbstractCmsApp implements EventHandler {
-       private final static CmsLog log = CmsLog.getLog(PublishingApp.class);
-
-       private String pid;
-       private String defaultThemeId;
-       private String defaultUiName = "";
-
-       private String publicBasePath = null;
-
-       private CmsUiProvider landingPage;
-       private CmsUiProvider defaultProvider = new DocumentUiProvider();
-
-       private Repository repository;
-
-       public void init(Map<String, String> properties) {
-               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, SuiteApp.PUBLIC_BASE_PATH_PROPERTY);
-               pid = properties.get(Constants.SERVICE_PID);
-
-               if (log.isDebugEnabled())
-                       log.info("Publishing App " + pid + " started");
-       }
-
-       public void destroy(Map<String, String> properties) {
-               if (log.isDebugEnabled())
-                       log.info("Publishing App " + pid + " stopped");
-
-       }
-
-       @Override
-       public Set<String> getUiNames() {
-               Set<String> uiNames = new HashSet<>();
-               uiNames.add(defaultUiName);
-               return uiNames;
-       }
-
-       @Override
-       public CmsUi initUi(Object uiParent) {
-               Composite parent = (Composite) uiParent;
-//             Session adminSession = NodeUtils.openDataAdminSession(getRepository(), null);
-               Session session = Jcr.login(getRepository(), null);
-               parent.setLayout(new GridLayout());
-               Node indexNode = Jcr.getNode(session, publicBasePath + "/index");
-//             try {
-//                     indexNode = JcrUtils.getOrAdd(Jcr.getRootNode(adminSession), DocumentPage.WWW, DbkType.article.get());
-//                     adminSession.save();
-//             } catch (RepositoryException e) {
-//                     throw new IllegalStateException(e);
-//             }
-
-               Control page;
-               if (landingPage != null) {
-                       page = landingPage.createUiPart(parent, indexNode);
-               } else {
-                       page = defaultProvider.createUiPart(parent, indexNode);
-               }
-               return (CmsUi) page;
-       }
-
-       @Override
-       public void refreshUi(CmsUi cmsUi, String state) {
-               Composite parent = (Composite) cmsUi;
-               parent.setLayout(new GridLayout());
-               if (landingPage != null)
-                       landingPage.createUiPart(parent, null);
-               else
-                       defaultProvider.createUiPart(parent, null);
-       }
-
-       @Override
-       public void setState(CmsUi cmsUi, String state) {
-
-       }
-
-       @Override
-       protected String getThemeId(String uiName) {
-               return defaultThemeId;
-       }
-
-       public void setLandingPage(CmsUiProvider landingPage) {
-               this.landingPage = landingPage;
-       }
-
-       @Override
-       public void handleEvent(Event event) {
-               // TODO listen to some events
-
-       }
-
-       public Repository getRepository() {
-               return repository;
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/publishing/ui/PublishingStyle.java b/org.argeo.app.ui/src/org/argeo/publishing/ui/PublishingStyle.java
deleted file mode 100644 (file)
index 199d726..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.argeo.publishing.ui;
-
-import org.argeo.api.cms.CmsStyle;
-
-/** Publishing styles. */
-public enum PublishingStyle implements CmsStyle {
-       // general
-       page, coverTitle, coverSubTitle, coverTagline, bannerLine1, bannerLine2,
-       // meta data
-       tag, menu,
-       // text style
-       title, subTitle, chapo, para, sectionTitle, subSectionTitle,
-       // links
-       internalLink,
-       // composite style
-       framed, line;
-
-       @Override
-       public String getClassPrefix() {
-               return "argeo-publishing";
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultDashboard.java b/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultDashboard.java
deleted file mode 100644 (file)
index 80069d5..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsView;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** Provides a dashboard. */
-public class DefaultDashboard implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               parent.setLayout(new GridLayout());
-               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
-               if (cmsView.isAnonymous())
-                       throw new IllegalStateException("No user is not logged in");
-
-               Label lbl = new Label(parent, SWT.NONE);
-               lbl.setText("Welcome " + CurrentUser.getDisplayName() + "!");
-
-               return lbl;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java b/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java
deleted file mode 100644 (file)
index b36778c..0000000
+++ /dev/null
@@ -1,286 +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.api.cms.CmsTheme;
-import org.argeo.cms.Localized;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.jcr.JcrException;
-import org.argeo.suite.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;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.wiring.BundleWiring;
-
-/** An app layer based on an entry area and an editor area. */
-public class DefaultEditionLayer implements SuiteLayer {
-       private CmsUiProvider entryArea;
-       private CmsUiProvider defaultView;
-       private CmsUiProvider workArea;
-       private List<String> weights = new ArrayList<>();
-       private boolean startMaximized = false;
-       private boolean fixedEntryArea = false;
-       private boolean singleTab = false;
-       private Localized title = null;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               // TODO Factorize more, or split into more specialised classes?
-               if (entryArea != null) {
-                       if (fixedEntryArea) {
-                               FixedEditionArea editionArea = new FixedEditionArea(parent, parent.getStyle());
-                               Control entryAreaC = entryArea.createUi(editionArea.getEntryArea(), context);
-                               CmsSwtUtils.style(entryAreaC, SuiteStyle.entryArea);
-                               if (this.defaultView != null) {
-                                       editionArea.getTabbedArea().view(defaultView, context);
-                               }
-                               return editionArea;
-                       } else {
-                               SashFormEditionArea editionArea = new SashFormEditionArea(parent, parent.getStyle());
-                               entryArea.createUi(editionArea.getEntryArea(), context);
-                               if (this.defaultView != null) {
-                                       editionArea.getTabbedArea().view(defaultView, context);
-                               }
-                               return editionArea;
-                       }
-               } else {
-                       if (this.workArea != null) {
-                               Composite area = new Composite(parent, SWT.NONE);
-                               this.workArea.createUi(area, context);
-                               return area;
-                       }
-                       CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
-                       TabbedArea tabbedArea = createTabbedArea(parent, theme);
-                       return tabbedArea;
-               }
-       }
-
-       @Override
-       public void view(CmsUiProvider uiProvider, Composite workAreaC, Node context) {
-               if (workArea != null) {
-                       try {
-                               CmsSwtUtils.clear(workAreaC);
-                               workArea.createUi(workAreaC, context);
-                               workAreaC.layout(true, true);
-                               return;
-                       } catch (RepositoryException e) {
-                               throw new JcrException("Cannot rebuild work area", e);
-                       }
-               }
-
-               // tabbed area
-               TabbedArea tabbedArea = findTabbedArea(workAreaC);
-               if (tabbedArea == null)
-                       throw new IllegalArgumentException("Unsupported work area " + workAreaC.getClass().getName());
-               if (uiProvider == null) {
-                       // reset
-                       tabbedArea.closeAllTabs();
-                       if (this.defaultView != null) {
-                               tabbedArea.view(defaultView, context);
-                       }
-               } else {
-                       tabbedArea.view(uiProvider, context);
-               }
-       }
-
-       @Override
-       public Node getCurrentContext(Composite workArea) {
-               TabbedArea tabbedArea = findTabbedArea(workArea);
-               if (tabbedArea == null)
-                       return null;
-               return tabbedArea.getCurrentContext();
-       }
-
-       private TabbedArea findTabbedArea(Composite workArea) {
-               TabbedArea tabbedArea = null;
-               if (workArea instanceof SashFormEditionArea) {
-                       tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
-               } else if (workArea instanceof FixedEditionArea) {
-                       tabbedArea = ((FixedEditionArea) workArea).getTabbedArea();
-               } else if (workArea instanceof TabbedArea) {
-                       tabbedArea = (TabbedArea) workArea;
-               }
-               return tabbedArea;
-       }
-
-       @Override
-       public void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
-               TabbedArea tabbedArea = ((SashFormEditionArea) workArea).getTabbedArea();
-               tabbedArea.open(uiProvider, context);
-       }
-
-       @Override
-       public Localized getTitle() {
-               return title;
-       }
-
-       public void init(BundleContext bundleContext, Map<String, Object> properties) {
-               weights = LangUtils.toStringList(properties.get(Property.weights.name()));
-               startMaximized = properties.containsKey(Property.startMaximized.name())
-                               && "true".equals(properties.get(Property.startMaximized.name()));
-               fixedEntryArea = properties.containsKey(Property.fixedEntryArea.name())
-                               && "true".equals(properties.get(Property.fixedEntryArea.name()));
-               if (fixedEntryArea && weights.size() != 0) {
-                       throw new IllegalArgumentException("Property " + Property.weights.name() + " should not be set if property "
-                                       + Property.fixedEntryArea.name() + " is set.");
-               }
-               singleTab = properties.containsKey(Property.singleTab.name())
-                               && "true".equals(properties.get(Property.singleTab.name()));
-
-               String titleStr = (String) properties.get(SuiteLayer.Property.title.name());
-               if (titleStr != null) {
-                       if (titleStr.startsWith("%")) {
-                               title = new Localized() {
-
-                                       @Override
-                                       public String name() {
-                                               return titleStr;
-                                       }
-
-                                       @Override
-                                       public ClassLoader getL10nClassLoader() {
-                                               return bundleContext != null
-                                                               ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader()
-                                                               : getClass().getClassLoader();
-                                       }
-                               };
-                       } else {
-                               title = new Localized.Untranslated(titleStr);
-                       }
-               }
-       }
-
-       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
-
-       }
-
-       public void setEntryArea(CmsUiProvider entryArea) {
-               this.entryArea = entryArea;
-       }
-
-       public void setWorkArea(CmsUiProvider workArea) {
-               this.workArea = workArea;
-       }
-
-       public void setDefaultView(CmsUiProvider defaultView) {
-               this.defaultView = defaultView;
-       }
-
-       TabbedArea createTabbedArea(Composite parent, CmsTheme theme) {
-               TabbedArea tabbedArea = new TabbedArea(parent, SWT.NONE);
-               tabbedArea.setSingleTab(singleTab);
-               tabbedArea.setBodyStyle(SuiteStyle.mainTabBody.style());
-               tabbedArea.setTabStyle(SuiteStyle.mainTab.style());
-               tabbedArea.setTabSelectedStyle(SuiteStyle.mainTabSelected.style());
-               tabbedArea.setCloseIcon(SuiteIcon.close.getSmallIcon(theme));
-               tabbedArea.setLayoutData(CmsSwtUtils.fillAll());
-               return tabbedArea;
-       }
-
-//     /** A work area based on an entry area and and a tabbed area. */
-       class SashFormEditionArea extends SashForm {
-               private static final long serialVersionUID = 2219125778722702618L;
-               private TabbedArea tabbedArea;
-               private Composite entryC;
-
-               SashFormEditionArea(Composite parent, int style) {
-                       super(parent, SWT.HORIZONTAL);
-                       CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
-
-                       Composite editorC;
-                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
-                               editorC = new Composite(this, SWT.BORDER);
-                               entryC = new Composite(this, SWT.BORDER);
-                       } else {
-                               entryC = new Composite(this, SWT.NONE);
-                               editorC = new Composite(this, SWT.NONE);
-                       }
-
-                       // sash form specific
-                       if (weights.size() != 0) {
-                               int[] actualWeight = new int[weights.size()];
-                               for (int i = 0; i < weights.size(); i++) {
-                                       actualWeight[i] = Integer.parseInt(weights.get(i));
-                               }
-                               setWeights(actualWeight);
-                       } else {
-                               int[] actualWeights = new int[] { 3000, 7000 };
-                               setWeights(actualWeights);
-                       }
-                       if (startMaximized)
-                               setMaximizedControl(editorC);
-
-                       GridLayout editorAreaLayout = CmsSwtUtils.noSpaceGridLayout();
-//                     editorAreaLayout.verticalSpacing = 0;
-//                     editorAreaLayout.marginBottom = 0;
-//                     editorAreaLayout.marginHeight = 0;
-//                     editorAreaLayout.marginLeft = 0;
-//                     editorAreaLayout.marginRight = 0;
-                       editorC.setLayout(editorAreaLayout);
-
-                       tabbedArea = createTabbedArea(editorC, theme);
-               }
-
-               TabbedArea getTabbedArea() {
-                       return tabbedArea;
-               }
-
-               Composite getEntryArea() {
-                       return entryC;
-               }
-
-       }
-
-       class FixedEditionArea extends Composite {
-               private static final long serialVersionUID = -5525672639277322465L;
-               private TabbedArea tabbedArea;
-               private Composite entryC;
-
-               public FixedEditionArea(Composite parent, int style) {
-                       super(parent, style);
-                       CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
-
-                       setLayout(CmsSwtUtils.noSpaceGridLayout(2));
-
-                       Composite editorC;
-                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
-                               editorC = new Composite(this, SWT.NONE);
-                               entryC = new Composite(this, SWT.NONE);
-                       } else {
-                               entryC = new Composite(this, SWT.NONE);
-                               editorC = new Composite(this, SWT.NONE);
-                       }
-                       entryC.setLayoutData(CmsSwtUtils.fillHeight());
-
-                       GridLayout editorAreaLayout = CmsSwtUtils.noSpaceGridLayout();
-//                     editorAreaLayout.verticalSpacing = 0;
-//                     editorAreaLayout.marginBottom = 0;
-//                     editorAreaLayout.marginHeight = 0;
-//                     editorAreaLayout.marginLeft = 0;
-//                     editorAreaLayout.marginRight = 0;
-                       editorC.setLayout(editorAreaLayout);
-                       editorC.setLayoutData(CmsSwtUtils.fillAll());
-
-                       tabbedArea = createTabbedArea(editorC, theme);
-               }
-
-               TabbedArea getTabbedArea() {
-                       return tabbedArea;
-               }
-
-               Composite getEntryArea() {
-                       return entryC;
-               }
-       }
-
-}
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultFooter.java b/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultFooter.java
deleted file mode 100644 (file)
index 9739f29..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.BundleContext;
-
-/** Footer of a standard Argeo Suite application. */
-public class DefaultFooter implements CmsUiProvider {
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               Composite content = new Composite(parent, SWT.NONE);
-               content.setLayoutData(new GridData(0, 0));
-               Control contentControl = createContent(content, context);
-
-               // TODO support and guarantee
-
-               return contentControl;
-       }
-
-       protected Control createContent(Composite parent, Node context) throws RepositoryException {
-               return parent;
-       }
-
-       public void init(BundleContext bundleContext, Map<String, String> properties) {
-       }
-
-       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
-
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultHeader.java b/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultHeader.java
deleted file mode 100644 (file)
index fd8be4e..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsTheme;
-import org.argeo.api.cms.CmsView;
-import org.argeo.cms.Localized;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.wiring.BundleWiring;
-
-/** Header of a standard Argeo Suite application. */
-public class DefaultHeader implements CmsUiProvider {
-       public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title";
-       private Localized title = null;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
-               CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
-
-               parent.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, true)));
-
-               // TODO right to left
-               Composite lead = new Composite(parent, SWT.NONE);
-               CmsSwtUtils.style(lead, SuiteStyle.header);
-               lead.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false));
-               lead.setLayout(new GridLayout());
-               Label lbl = new Label(lead, SWT.NONE);
-//             String title = properties.get(TITLE_PROPERTY);
-//             // TODO expose the localized
-//             lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString()
-//                             : title);
-               lbl.setText(title.lead());
-               CmsSwtUtils.style(lbl, SuiteStyle.headerTitle);
-               lbl.setLayoutData(CmsSwtUtils.fillWidth());
-
-               Composite middle = new Composite(parent, SWT.NONE);
-               CmsSwtUtils.style(middle, SuiteStyle.header);
-               middle.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
-               middle.setLayout(new GridLayout());
-
-               Composite end = new Composite(parent, SWT.NONE);
-               CmsSwtUtils.style(end, SuiteStyle.header);
-               end.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, false));
-
-               if (!cmsView.isAnonymous()) {
-                       end.setLayout(new GridLayout(2, false));
-                       Label userL = new Label(end, SWT.NONE);
-                       CmsSwtUtils.style(userL, SuiteStyle.header);
-                       userL.setText(CurrentUser.getDisplayName());
-                       Button logoutB = new Button(end, SWT.FLAT);
-//                     CmsUiUtils.style(logoutB, SuiteStyle.header);
-                       logoutB.setImage(SuiteIcon.logout.getSmallIcon(theme));
-                       logoutB.addSelectionListener(new SelectionAdapter() {
-                               private static final long serialVersionUID = 7116760083964201233L;
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       cmsView.logout();
-                               }
-
-                       });
-               } else {
-                       end.setLayout(new GridLayout(1, false));
-                       // required in order to avoid wrong height after logout
-                       new Label(end, SWT.NONE).setText("");
-
-               }
-               return lbl;
-       }
-
-       public void init(BundleContext bundleContext, Map<String, String> properties) {
-               String titleStr = (String) properties.get(TITLE_PROPERTY);
-               if (titleStr != null) {
-                       if (titleStr.startsWith("%")) {
-                               title = new Localized() {
-
-                                       @Override
-                                       public String name() {
-                                               return titleStr;
-                                       }
-
-                                       @Override
-                                       public ClassLoader getL10nClassLoader() {
-                                               return bundleContext != null
-                                                               ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader()
-                                                               : getClass().getClassLoader();
-                                       }
-                               };
-                       } else {
-                               title = new Localized.Untranslated(titleStr);
-                       }
-               }
-       }
-
-       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
-
-       }
-
-       public Localized getTitle() {
-               return title;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultLeadPane.java b/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultLeadPane.java
deleted file mode 100644 (file)
index 2eaba61..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-package org.argeo.suite.ui;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsView;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.Localized;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.suite.RankedObject;
-import org.argeo.suite.SuiteUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.wiring.BundleWiring;
-
-/** Side pane listing various perspectives. */
-public class DefaultLeadPane implements CmsUiProvider {
-       private final static CmsLog log = CmsLog.getLog(DefaultLeadPane.class);
-
-       public static enum Property {
-               defaultLayers, adminLayers;
-       }
-
-       private Map<String, RankedObject<SuiteLayer>> layers = Collections.synchronizedSortedMap(new TreeMap<>());
-       private List<String> defaultLayers;
-       private List<String> adminLayers = new ArrayList<>();
-
-       private ClassLoader l10nClassLoader;
-
-       @Override
-       public Control createUi(Composite parent, Node node) throws RepositoryException {
-               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
-               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               Composite appLayersC = new Composite(parent, SWT.NONE);
-               CmsSwtUtils.style(appLayersC, SuiteStyle.leadPane);
-               GridLayout layout = new GridLayout();
-               layout.verticalSpacing = 10;
-               layout.marginTop = 10;
-               layout.marginLeft = 10;
-               layout.marginRight = 10;
-               appLayersC.setLayout(layout);
-               appLayersC.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
-
-               Composite adminLayersC;
-               if (!adminLayers.isEmpty()) {
-                       adminLayersC = new Composite(parent, SWT.NONE);
-                       CmsSwtUtils.style(adminLayersC, SuiteStyle.leadPane);
-                       GridLayout adminLayout = new GridLayout();
-                       adminLayout.verticalSpacing = 10;
-                       adminLayout.marginBottom = 10;
-                       adminLayout.marginLeft = 10;
-                       adminLayout.marginRight = 10;
-                       adminLayersC.setLayout(adminLayout);
-                       adminLayersC.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, false, true));
-               } else {
-                       adminLayersC = null;
-               }
-
-//             boolean isAdmin = cmsView.doAs(() -> CurrentUser.isInRole(NodeConstants.ROLE_USER_ADMIN));
-               Set<String> userRoles = cmsView.doAs(() -> CurrentUser.roles());
-               Button first = null;
-               layers: for (String layerDef : defaultLayers) {
-                       layerDef = layerDef.trim();
-                       if ("".equals(layerDef))
-                               continue layers;// skip empty lines
-                       String[] semiColArr = layerDef.split(";");
-                       String layerId = semiColArr[0];
-                       Set<String> layerRoles = SuiteUtils.extractRoles(semiColArr);
-                       if (layers.containsKey(layerId)) {
-                               if (!layerRoles.isEmpty()) {
-                                       Set<String> intersection = new HashSet<String>(layerRoles);
-                                       intersection.retainAll(userRoles);
-                                       if (intersection.isEmpty())
-                                               continue layers;// skip unauthorized layer
-                               }
-                               RankedObject<SuiteLayer> layerObj = layers.get(layerId);
-
-                               Localized title = null;
-                               if (!adminLayers.contains(layerId)) {
-                                       String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name());
-                                       if (titleStr != null) {
-                                               if (titleStr.startsWith("%")) {
-                                                       // LocaleUtils.local(titleStr, getClass().getClassLoader());
-                                                       title = () -> titleStr;
-                                               } else {
-                                                       title = new Localized.Untranslated(titleStr);
-                                               }
-                                       }
-                               }
-
-                               String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name());
-                               SuiteIcon icon = null;
-                               if (iconName != null)
-                                       icon = SuiteIcon.valueOf(iconName);
-
-                               Composite buttonParent;
-                               if (adminLayers.contains(layerId))
-                                       buttonParent = adminLayersC;
-                               else
-                                       buttonParent = appLayersC;
-                               Button b = SuiteUiUtils.createLayerButton(buttonParent, layerId, title, icon, l10nClassLoader);
-                               if (first == null)
-                                       first = b;
-                       }
-               }
-               return first;
-       }
-
-       public void init(BundleContext bundleContext, Map<String, Object> properties) {
-               l10nClassLoader = bundleContext != null ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader()
-                               : getClass().getClassLoader();
-
-               String[] defaultLayers = (String[]) properties.get(Property.defaultLayers.toString());
-               if (defaultLayers == null)
-                       throw new IllegalArgumentException("Default layers must be set.");
-               this.defaultLayers = Arrays.asList(defaultLayers);
-               if (log.isDebugEnabled())
-                       log.debug("Default layers: " + Arrays.asList(defaultLayers));
-               String[] adminLayers = (String[]) properties.get(Property.adminLayers.toString());
-               if (adminLayers != null) {
-                       this.adminLayers = Arrays.asList(adminLayers);
-                       if (log.isDebugEnabled())
-                               log.debug("Admin layers: " + Arrays.asList(adminLayers));
-               }
-       }
-
-       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
-
-       }
-
-       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);
-                               }
-                       }
-               }
-       }
-
-//     protected Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon) {
-//             CmsTheme theme = CmsTheme.getCmsTheme(parent);
-//             Button button = new Button(parent, SWT.PUSH);
-//             CmsUiUtils.style(button, SuiteStyle.leadPane);
-//             if (icon != null)
-//                     button.setImage(icon.getBigIcon(theme));
-//             button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false));
-//             // button.setToolTipText(msg.lead());
-//             if (msg != null) {
-//                     Label lbl = new Label(parent, SWT.CENTER);
-//                     CmsUiUtils.style(lbl, SuiteStyle.leadPane);
-//                     // CmsUiUtils.markup(lbl);
-//                     ClassLoader l10nClassLoader = getClass().getClassLoader();
-//                     String txt = LocaleUtils.lead(msg, l10nClassLoader);
-////                   String txt = msg.lead();
-//                     lbl.setText(txt);
-//                     lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
-//             }
-//             CmsUiUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer);
-//             return button;
-//     }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java b/org.argeo.app.ui/src/org/argeo/suite/ui/DefaultLoginScreen.java
deleted file mode 100644 (file)
index a44acf9..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsView;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.auth.CmsLogin;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Provides a login screen. */
-public class DefaultLoginScreen implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsView cmsView = CmsSwtUtils.getCmsView(parent);
-               if (!cmsView.isAnonymous())
-                       throw new IllegalStateException(CurrentUser.getUsername() + " is already logged in");
-
-               parent.setLayout(new GridLayout());
-               Composite loginArea = new Composite(parent, SWT.NONE);
-               loginArea.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
-               
-               CmsLogin cmsLogin = new CmsLogin(cmsView);
-               cmsLogin.createUi(loginArea);
-               return cmsLogin.getCredentialsBlock();
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/EventRecorder.java b/org.argeo.app.ui/src/org/argeo/suite/ui/EventRecorder.java
deleted file mode 100644 (file)
index c578816..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.argeo.suite.ui;
-
-import org.argeo.api.cms.CmsLog;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
-
-/** Record UI events. */
-public class EventRecorder implements EventHandler {
-       private final static CmsLog log = CmsLog.getLog(EventRecorder.class);
-
-       public void init() {
-
-       }
-
-       public void destroy() {
-
-       }
-
-       @Override
-       public void handleEvent(Event event) {
-               if (log.isTraceEnabled())
-                       log.trace(event);
-
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/RecentItems.java b/org.argeo.app.ui/src/org/argeo/suite/ui/RecentItems.java
deleted file mode 100644 (file)
index 66f2dc5..0000000
+++ /dev/null
@@ -1,365 +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.api.cms.CmsTheme;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-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 = CmsSwtUtils.getCmsTheme(parent);
-               parent.setLayout(new GridLayout());
-//             parent.setLayout(CmsUiUtils.noSpaceGridLayout());
-               parent.setLayout(new GridLayout());
-
-//             Composite top = new Composite(parent, SWT.BORDER);
-//             CmsUiUtils.style(top, SuiteStyle.recentItems);
-//             top.setLayoutData(CmsUiUtils.fillWidth());
-//             top.setLayout(CmsUiUtils.noSpaceGridLayout(2));
-//             Label lbl = new Label(top, SWT.FLAT);
-//             lbl.setLayoutData(CmsUiUtils.fillWidth());
-//             lbl.setText(SuiteMsg.recentItems.lead());
-//             CmsUiUtils.style(lbl, SuiteStyle.recentItems);
-//
-//             ToolBar topToolBar = new ToolBar(top, SWT.NONE);
-//             ToolItem addItem = new ToolItem(topToolBar, SWT.FLAT);
-////           CmsUiUtils.style(addItem, SuiteStyle.recentItems);
-//             addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
-
-               if (context == null)
-                       return null;
-               SingleEntityViewer entityViewer = new SingleEntityViewer(parent, SWT.NONE, context.getSession());
-               entityViewer.createUi();
-               entityViewer.getViewer().getTable().setLayoutData(CmsSwtUtils.fillAll());
-
-               Composite bottom = new Composite(parent, SWT.NONE);
-               bottom.setLayoutData(CmsSwtUtils.fillWidth());
-               bottom.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
-               bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
-               ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               deleteItem.setEnabled(false);
-//             CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
-               deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
-               ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
-               addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
-               entityViewer.getViewer().addDoubleClickListener(new IDoubleClickListener() {
-
-                       @Override
-                       public void doubleClick(DoubleClickEvent event) {
-                               Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
-                               if (node != null)
-                                       CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
-                                                       SuiteEvent.eventProperties(node));
-
-                       }
-               });
-               entityViewer.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
-                       public void selectionChanged(SelectionChangedEvent event) {
-                               Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
-                               if (node != null) {
-                                       CmsSwtUtils.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
-                                                       SuiteEvent.eventProperties(node));
-                                       deleteItem.setEnabled(true);
-                               } else {
-                                       deleteItem.setEnabled(false);
-                               }
-                       }
-               });
-
-               return entityViewer.filterTxt;
-
-       }
-
-       public void init(Map<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.app.ui/src/org/argeo/suite/ui/SuiteApp.java b/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteApp.java
deleted file mode 100644 (file)
index 118555a..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-package org.argeo.suite.ui;
-
-import static org.argeo.api.cms.CmsView.CMS_VIEW_UID_PROPERTY;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.api.cms.CmsSession;
-import org.argeo.api.cms.CmsTheme;
-import org.argeo.api.cms.CmsUi;
-import org.argeo.api.cms.CmsView;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.AbstractCmsApp;
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.Localized;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.dialogs.CmsFeedback;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.entity.EntityConstants;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-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 CmsLog log = CmsLog.getLog(SuiteApp.class);
-
-       public final static String PUBLIC_BASE_PATH_PROPERTY = "publicBasePath";
-       public final static String DEFAULT_UI_NAME_PROPERTY = "defaultUiName";
-       public final static String DEFAULT_THEME_ID_PROPERTY = "defaultThemeId";
-       public final static String DEFAULT_LAYER_PROPERTY = "defaultLayer";
-       private final static String LOGIN = "login";
-       private final static String HOME_STATE = "~";
-
-       private String publicBasePath = null;
-
-       private String pidPrefix;
-       private String headerPid;
-       private String footerPid;
-       private String leadPanePid;
-       private String adminLeadPanePid;
-       private String loginScreenPid;
-
-       private String defaultLayerPid = "argeo.suite.ui.dashboardLayer";
-
-       private String defaultUiName = "app";
-       private String adminUiName = "admin";
-       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 Repository repository;
-
-
-       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);
-               if (properties.containsKey(DEFAULT_LAYER_PROPERTY))
-                       defaultLayerPid = LangUtils.get(properties, DEFAULT_LAYER_PROPERTY);
-               publicBasePath = LangUtils.get(properties, PUBLIC_BASE_PATH_PROPERTY);
-
-               if (properties.containsKey(Constants.SERVICE_PID)) {
-                       String servicePid = properties.get(Constants.SERVICE_PID).toString();
-                       if (servicePid.endsWith(".app")) {
-                               pidPrefix = servicePid.substring(0, servicePid.length() - "app".length());
-                       }
-               }
-
-               if (pidPrefix == null)
-                       throw new IllegalArgumentException("PID prefix must be set.");
-
-               headerPid = pidPrefix + "header";
-               footerPid = pidPrefix + "footer";
-               leadPanePid = pidPrefix + "leadPane";
-               adminLeadPanePid = pidPrefix + "adminLeadPane";
-               loginScreenPid = pidPrefix + "loginScreen";
-       }
-
-       public void destroy(Map<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);
-               uiNames.add(adminUiName);
-               return uiNames;
-       }
-
-       @Override
-       public CmsUi initUi(Object parent) {
-               Composite uiParent =(Composite) parent;
-               String uiName = uiParent.getData(UI_NAME_PROPERTY) != null ? uiParent.getData(UI_NAME_PROPERTY).toString() : null;
-               CmsView cmsView = CmsSwtUtils.getCmsView(uiParent);
-               if (cmsView == null)
-                       throw new IllegalStateException("No CMS view is registered.");
-               CmsTheme theme = getTheme(uiName);
-               if (theme != null)
-                       CmsSwtUtils.registerCmsTheme(uiParent.getShell(), theme);
-               SuiteUi argeoSuiteUi = new SuiteUi(uiParent, SWT.INHERIT_DEFAULT);
-               String uid = cmsView.getUid();
-               managedUis.put(uid, argeoSuiteUi);
-               argeoSuiteUi.addDisposeListener((e) -> {
-                       managedUis.remove(uid);
-                       if (log.isDebugEnabled())
-                               log.debug("Suite UI " + uid + " has been disposed.");
-               });
-               return argeoSuiteUi;
-       }
-
-       @Override
-       public String getThemeId(String uiName) {
-               return defaultThemeId;
-       }
-
-       @Override
-       public void refreshUi(CmsUi cmsUi, String state) {
-               try {
-                       Node context = null;
-                       SuiteUi ui = (SuiteUi) cmsUi;
-
-                       String uiName = Objects.toString(ui.getParent().getData(UI_NAME_PROPERTY), null);
-                       if (uiName == null)
-                               throw new IllegalStateException("UI name should not be null");
-                       CmsView cmsView = CmsSwtUtils.getCmsView(ui);
-                       CmsUiProvider headerUiProvider = findUiProvider(headerPid);
-                       CmsUiProvider footerUiProvider = findUiProvider(footerPid);
-                       CmsUiProvider leadPaneUiProvider;
-                       if (adminUiName.equals(uiName)) {
-                               leadPaneUiProvider = findUiProvider(adminLeadPanePid);
-                       } else {
-                               leadPaneUiProvider = findUiProvider(leadPanePid);
-                       }
-
-                       Localized appTitle = null;
-                       if (headerUiProvider instanceof DefaultHeader) {
-                               appTitle = ((DefaultHeader) headerUiProvider).getTitle();
-                       }
-                       ui.setTitle(appTitle);
-
-                       if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login
-                               ui.logout();
-                               if (headerUiProvider != null)
-                                       refreshPart(headerUiProvider, ui.getHeader(), context);
-                               ui.refreshBelowHeader(false);
-                               refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context);
-                               if (footerUiProvider != null)
-                                       refreshPart(footerUiProvider, ui.getFooter(), context);
-                               ui.layout(true, true);
-                               setState(ui, LOGIN);
-                       } else {
-                               if (LOGIN.equals(state))
-                                       state = null;
-                               CmsSession cmsSession = cmsView.getCmsSession();
-                               if (ui.getUserDir() == null) {
-                                       // FIXME NPE on CMSSession when logging in from anonymous
-                                       if (cmsSession == null || cmsView.isAnonymous()) {
-                                               assert publicBasePath != null;
-                                               ui.initSessions(getRepository(), publicBasePath);
-                                       } else {
-                                               Session adminSession = null;
-                                               try {
-                                                       adminSession = CmsJcrUtils.openDataAdminSession(getRepository(), null);
-                                                       Node userDir = SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
-                                                       ui.initSessions(getRepository(), userDir.getPath());
-                                               } finally {
-                                                       Jcr.logout(adminSession);
-                                               }
-                                       }
-                               }
-                               initLocale(cmsSession);
-                               context = stateToNode(ui, state);
-                               if (context == null)
-                                       context = ui.getUserDir();
-
-                               if (headerUiProvider != null)
-                                       refreshPart(headerUiProvider, ui.getHeader(), context);
-                               ui.refreshBelowHeader(true);
-                               for (String key : layersByPid.keySet()) {
-                                       SuiteLayer layer = layersByPid.get(key).get();
-                                       ui.addLayer(key, layer);
-                               }
-
-                               if (leadPaneUiProvider != null)
-                                       refreshPart(leadPaneUiProvider, ui.getLeadPane(), context);
-                               if (footerUiProvider != null)
-                                       refreshPart(footerUiProvider, ui.getFooter(), context);
-                               ui.layout(true, true);
-                               setState(ui, state != null ? state : defaultLayerPid);
-                       }
-               } catch (Exception e) {
-                       CmsFeedback.show("Unexpected exception", e);
-               }
-       }
-
-       private void initLocale(CmsSession cmsSession) {
-               if (cmsSession == null)
-                       return;
-               Locale locale = cmsSession.getLocale();
-               UiContext.setLocale(locale);
-               LocaleUtils.setThreadLocale(locale);
-
-       }
-
-       private void refreshPart(CmsUiProvider uiProvider, Composite part, Node context) {
-               CmsSwtUtils.clear(part);
-               uiProvider.createUiPart(part, context);
-       }
-
-       private CmsUiProvider findUiProvider(String pid) {
-               if (!uiProvidersByPid.containsKey(pid))
-                       return null;
-               return uiProvidersByPid.get(pid).get();
-       }
-
-       private SuiteLayer findLayer(String pid) {
-               if (!layersByPid.containsKey(pid))
-                       return null;
-               return layersByPid.get(pid).get();
-       }
-
-       private <T> 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 mixinType : context.getMixinNodeTypes()) {
-                               String mixinTypeName = mixinType.getName();
-                               if (byType.containsKey(mixinTypeName)) {
-                                       types.add(mixinTypeName);
-                               }
-                               for (NodeType superType : mixinType.getDeclaredSupertypes()) {
-                                       if (byType.containsKey(superType.getName())) {
-                                               types.add(superType.getName());
-                                       }
-                               }
-                       }
-                       // primary node type
-                       NodeType primaryType = context.getPrimaryNodeType();
-                       String primaryTypeName = primaryType.getName();
-                       if (byType.containsKey(primaryTypeName)) {
-                               types.add(primaryTypeName);
-                       }
-                       for (NodeType superType : primaryType.getDeclaredSupertypes()) {
-                               if (byType.containsKey(superType.getName())) {
-                                       types.add(superType.getName());
-                               }
-                       }
-                       // entity type
-                       if (context.isNodeType(EntityType.entity.get())) {
-                               if (context.hasProperty(EntityNames.ENTITY_TYPE)) {
-                                       String entityTypeName = context.getProperty(EntityNames.ENTITY_TYPE).getString();
-                                       if (byType.containsKey(entityTypeName)) {
-                                               types.add(entityTypeName);
-                                       }
-                               }
-                       }
-
-//                     if (context.getPath().equals("/")) {// root node
-//                             types.add("nt:folder");
-//                     }
-                       if (CmsJcrUtils.isUserHome(context) && byType.containsKey("nt:folder")) {// home node
-                               types.add("nt:folder");
-                       }
-
-                       if (types.size() == 0)
-                               throw new IllegalArgumentException("No type found for " + context + " (" + listTypes(context) + ")");
-                       String type = types.iterator().next();
-                       if (!byType.containsKey(type))
-                               throw new IllegalArgumentException("No component found for " + context + " with type " + type);
-                       return byType.get(type).get();
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException(e);
-               }
-       }
-
-       private static String listTypes(Node context) {
-               try {
-                       StringBuilder sb = new StringBuilder();
-                       sb.append(context.getPrimaryNodeType().getName());
-                       for (NodeType superType : context.getPrimaryNodeType().getDeclaredSupertypes()) {
-                               sb.append(' ');
-                               sb.append(superType.getName());
-                       }
-
-                       for (NodeType nodeType : context.getMixinNodeTypes()) {
-                               sb.append(' ');
-                               sb.append(nodeType.getName());
-                               if (nodeType.getName().equals(EntityType.local.get()))
-                                       sb.append('/').append(context.getProperty(EntityNames.ENTITY_TYPE).getString());
-                               for (NodeType superType : nodeType.getDeclaredSupertypes()) {
-                                       sb.append(' ');
-                                       sb.append(superType.getName());
-                               }
-                       }
-                       return sb.toString();
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-       }
-
-       @Override
-       public void setState(CmsUi cmsUi, String state) {
-               if (state == null)
-                       return;
-               if (!state.startsWith("/")) {
-                       if (cmsUi instanceof SuiteUi) {
-                               SuiteUi ui = (SuiteUi) cmsUi;
-                               if (LOGIN.equals(state)) {
-                                       String appTitle = "";
-                                       if (ui.getTitle() != null)
-                                               appTitle = ui.getTitle().lead();
-                                       ui.getCmsView().stateChanged(state, appTitle);
-                                       return;
-                               }
-                               Map<String, Object> properties = new HashMap<>();
-                               String layerId = HOME_STATE.equals(state) ? defaultLayerPid : state;
-                               properties.put(SuiteEvent.LAYER, layerId);
-                               properties.put(SuiteEvent.NODE_PATH, HOME_STATE);
-                               ui.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), properties);
-                       }
-                       return;
-               }
-               SuiteUi suiteUi = (SuiteUi) cmsUi;
-               Node node = stateToNode(suiteUi, state);
-               if (node == null) {
-                       suiteUi.getCmsView().navigateTo(HOME_STATE);
-               } else {
-                       suiteUi.getCmsView().sendEvent(SuiteEvent.switchLayer.topic(), SuiteEvent.eventProperties(node));
-                       suiteUi.getCmsView().sendEvent(SuiteEvent.refreshPart.topic(), SuiteEvent.eventProperties(node));
-               }
-       }
-
-       // TODO move it to an internal package?
-       static String nodeToState(Node node) {
-               return '/' + Jcr.getWorkspaceName(node) + Jcr.getPath(node);
-       }
-
-       private Node stateToNode(SuiteUi suiteUi, String state) {
-               if (suiteUi == null)
-                       return null;
-               if (state == null || !state.startsWith("/"))
-                       return null;
-
-               String path = state.substring(1);
-               String workspace;
-               if (path.equals("")) {
-                       workspace = null;
-                       path = "/";
-               } else {
-                       int index = path.indexOf('/');
-                       if (index == 0) {
-                               log.error("Cannot interpret " + state);
-//                             cmsView.navigateTo("~");
-                               return null;
-                       } else if (index > 0) {
-                               workspace = path.substring(0, index);
-                               path = path.substring(index);
-                       } else {// index<0, assuming root node
-                               workspace = path;
-                               path = "/";
-                       }
-               }
-               Session session = suiteUi.getSession(workspace);
-               if (session == null)
-                       return null;
-               Node node = Jcr.getNode(session, path);
-               return node;
-       }
-
-       /*
-        * Events management
-        */
-
-       @Override
-       public void handleEvent(Event event) {
-
-               // Specific UI related events
-               SuiteUi ui = getRelatedUi(event);
-               if (ui == null)
-                       return;
-               try {
-                       String appTitle = "";
-                       if (ui.getTitle() != null)
-                               appTitle = ui.getTitle().lead() + " - ";
-
-//                     String currentLayerId = ui.getCurrentLayerId();
-//                     SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null;
-                       if (SuiteUiUtils.isTopic(event, SuiteEvent.refreshPart)) {
-                               Node node = getNode(ui, event);
-                               if (node == null)
-                                       return;
-                               CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
-                               SuiteLayer layer = findByType(layersByType, node);
-                               ui.switchToLayer(layer, node);
-                               ui.getCmsView().runAs(() -> layer.view(uiProvider, ui.getCurrentWorkArea(), node));
-                               ui.getCmsView().stateChanged(nodeToState(node), appTitle + Jcr.getTitle(node));
-                       } else if (SuiteUiUtils.isTopic(event, SuiteEvent.openNewPart)) {
-                               Node node = getNode(ui, event);
-                               if (node == null)
-                                       return;
-                               CmsUiProvider uiProvider = findByType(uiProvidersByType, node);
-                               SuiteLayer layer = findByType(layersByType, node);
-                               ui.switchToLayer(layer, node);
-                               ui.getCmsView().runAs(() -> layer.open(uiProvider, ui.getCurrentWorkArea(), node));
-                               ui.getCmsView().stateChanged(nodeToState(node), appTitle + Jcr.getTitle(node));
-                       } else if (SuiteUiUtils.isTopic(event, SuiteEvent.switchLayer)) {
-                               String layerId = get(event, SuiteEvent.LAYER);
-                               if (layerId != null) {
-//                                     ui.switchToLayer(layerId, ui.getUserDir());
-                                       SuiteLayer suiteLayer = findLayer(layerId);
-                                       if (suiteLayer == null)
-                                               throw new IllegalArgumentException("No layer '" + layerId + "' available.");
-                                       Localized layerTitle = suiteLayer.getTitle();
-                                       // FIXME make sure we don't rebuild the work area twice
-                                       Composite workArea = ui.getCmsView().doAs(() -> ui.switchToLayer(layerId, ui.getUserDir()));
-                                       String title = null;
-                                       if (layerTitle != null)
-                                               title = layerTitle.lead();
-                                       Node nodeFromState = getNode(ui, event);
-                                       if (nodeFromState != null && nodeFromState.getPath().equals(ui.getUserDir().getPath())) {
-                                               // default layer view is forced
-                                               String state = defaultLayerPid.equals(layerId) ? "~" : layerId;
-                                               ui.getCmsView().stateChanged(state, appTitle + title);
-                                               suiteLayer.view(null, workArea, nodeFromState);
-                                       } else {
-                                               Node layerCurrentContext = suiteLayer.getCurrentContext(workArea);
-                                               if (layerCurrentContext != null) {
-                                                       // layer was already showing a context so we set the state to it
-                                                       ui.getCmsView().stateChanged(nodeToState(layerCurrentContext),
-                                                                       appTitle + Jcr.getTitle(layerCurrentContext));
-                                               } else {
-                                                       // no context was shown
-                                                       ui.getCmsView().stateChanged(layerId, appTitle + title);
-                                               }
-                                       }
-                               } else {
-                                       Node node = getNode(ui, event);
-                                       if (node != null) {
-                                               SuiteLayer layer = findByType(layersByType, node);
-                                               ui.getCmsView().runAs(() -> ui.switchToLayer(layer, node));
-                                       }
-                               }
-                       }
-               } catch (Exception e) {
-                       log.error("Cannot handle event " + event, e);
-//                     CmsView.getCmsView(ui).exception(e);
-               }
-
-       }
-
-       private Node getNode(SuiteUi ui, Event event) {
-               String nodePath = get(event, SuiteEvent.NODE_PATH);
-               if (nodePath != null && nodePath.equals(HOME_STATE))
-                       return ui.getUserDir();
-               String workspaceName = get(event, SuiteEvent.WORKSPACE);
-               Session session = ui.getSession(workspaceName);
-               Node node;
-               if (nodePath == null) {
-                       // look for a user
-                       String username = get(event, SuiteEvent.USERNAME);
-                       if (username == null)
-                               return null;
-                       User user = cmsUserManager.getUser(username);
-                       if (user == null)
-                               return null;
-                       LdapName userDn;
-                       try {
-                               userDn = new LdapName(user.getName());
-                       } catch (InvalidNameException e) {
-                               throw new IllegalArgumentException("Badly formatted username", e);
-                       }
-                       String userNodePath = SuiteUtils.getUserNodePath(userDn);
-                       if (Jcr.itemExists(session, userNodePath))
-                               node = Jcr.getNode(session, userNodePath);
-                       else {
-                               Session adminSession = null;
-                               try {
-                                       adminSession = CmsJcrUtils.openDataAdminSession(getRepository(), workspaceName);
-                                       SuiteUtils.getOrCreateUserNode(adminSession, userDn);
-                               } finally {
-                                       Jcr.logout(adminSession);
-                               }
-                               node = Jcr.getNode(session, userNodePath);
-                       }
-               } else {
-                       node = Jcr.getNode(session, nodePath);
-               }
-               return node;
-       }
-
-       private SuiteUi getRelatedUi(Event event) {
-               return managedUis.get(get(event, CMS_VIEW_UID_PROPERTY));
-       }
-
-       public static String get(Event event, String key) {
-               Object value = event.getProperty(key);
-               if (value == null)
-                       return null;
-//                     throw new IllegalArgumentException("Property " + key + " must be set");
-               return value.toString();
-
-       }
-
-       /*
-        * Dependency injection.
-        */
-
-       public void addUiProvider(CmsUiProvider uiProvider, Map<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;
-       }
-
-       public Repository getRepository() {
-               return repository;
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-       
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteEvent.java b/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteEvent.java
deleted file mode 100644 (file)
index 9963856..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.api.cms.CmsEvent;
-import org.argeo.jcr.Jcr;
-import org.osgi.service.useradmin.User;
-
-/** Events specific to Argeo Suite. */
-public enum SuiteEvent implements CmsEvent {
-       openNewPart, refreshPart, switchLayer;
-
-       public final static String LAYER = "layer";
-//     public final static String NODE_ID = "nodeId";
-       public final static String NODE_PATH = "path";
-       public final static String USERNAME = "username";
-       public final static String WORKSPACE = "workspace";
-
-       public String getTopicBase() {
-               return "argeo/suite/ui";
-       }
-
-       public static Map<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.app.ui/src/org/argeo/suite/ui/SuiteIcon.java b/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteIcon.java
deleted file mode 100644 (file)
index b4cc1bb..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.argeo.suite.ui;
-
-import org.argeo.cms.swt.CmsIcon;
-
-/** Icon names used by Argeo Suite. */
-public enum SuiteIcon implements CmsIcon {
-       add, save, close, closeAll, search, delete, logout, dashboard,
-       // people
-       people, person, organisation,
-       // library
-       documents, document, folder,
-       // admin and settings
-       settings, user,
-       // misc
-       task, tag, location, inbox, map;
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteLayer.java b/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteLayer.java
deleted file mode 100644 (file)
index d18192f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.Localized;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.widgets.Composite;
-
-/** An UI layer for the main work area. */
-public interface SuiteLayer extends CmsUiProvider {
-       static enum Property {
-               title, icon, weights, startMaximized, singleTab, fixedEntryArea;
-       }
-
-       void view(CmsUiProvider uiProvider, Composite workArea, Node context);
-       
-       Node getCurrentContext(Composite workArea);
-
-       default void open(CmsUiProvider uiProvider, Composite workArea, Node context) {
-               view(uiProvider, workArea, context);
-       }
-
-       default Localized getTitle() {
-               return null;
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteMsg.java b/org.argeo.app.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.app.ui/src/org/argeo/suite/ui/SuiteStyle.java b/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteStyle.java
deleted file mode 100644 (file)
index 345ae30..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.argeo.suite.ui;
-
-import org.argeo.api.cms.CmsStyle;
-
-/** Styles used by Argeo Suite work UI. */
-public enum SuiteStyle implements CmsStyle {
-       // header
-       header, headerTitle, headerMenu, headerMenuItem,
-       // footer
-       footer,
-       // recent items
-       recentItems,
-       // lead pane
-       leadPane, leadPaneItem, leadPaneSectionTitle, leadPaneSubSectionTitle,
-       // entry area
-       entryArea,
-       // group composite
-       titleContainer, titleLabel, subTitleLabel, formLine, formColumn, navigationBar, navigationTitle, navigationButton,
-       // forms elements
-       simpleLabel, simpleText, simpleInput,
-       // table
-       titleCell,
-       // layers
-       workArea,
-       // tabbed area
-       mainTabBody, mainTabSelected, mainTab,
-       // buttons
-       inlineButton;
-
-       @Override
-       public String getClassPrefix() {
-               return "argeo-suite";
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteUi.java b/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteUi.java
deleted file mode 100644 (file)
index dc2ef50..0000000
+++ /dev/null
@@ -1,258 +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.argeo.api.cms.CmsUi;
-import org.argeo.api.cms.CmsView;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.Localized;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.jcr.Jcr;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FormLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** The view for the default ergonomics of Argeo Suite. */
-class SuiteUi extends Composite implements CmsUi {
-       private static final long serialVersionUID = 6207018859086689108L;
-       private final static CmsLog log = CmsLog.getLog(SuiteUi.class);
-
-       private Localized title;
-       private Composite header;
-       private Composite footer;
-       private Composite belowHeader;
-       private Composite leadPane;
-       private Composite sidePane;
-       private Composite dynamicArea;
-
-       private Session sysSession;
-       private Session homeSession;
-       private Node userDir;
-
-       private Map<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 = CmsSwtUtils.getCmsView(parent);
-               this.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               header = new Composite(this, SWT.NONE);
-               header.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               CmsSwtUtils.style(header, SuiteStyle.header);
-               header.setLayoutData(CmsSwtUtils.fillWidth());
-
-               belowHeader = new Composite(this, SWT.NONE);
-               belowHeader.setLayoutData(CmsSwtUtils.fillAll());
-
-               footer = new Composite(this, SWT.NONE);
-               footer.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               CmsSwtUtils.style(footer, SuiteStyle.footer);
-               footer.setLayoutData(CmsSwtUtils.fillWidth());
-       }
-
-       public void refreshBelowHeader(boolean initApp) {
-               CmsSwtUtils.clear(belowHeader);
-               int style = getStyle();
-               if (initApp) {
-                       belowHeader.setLayout(CmsSwtUtils.noSpaceGridLayout(3));
-
-                       if (SWT.RIGHT_TO_LEFT == (style & SWT.RIGHT_TO_LEFT)) {// arabic, hebrew, etc.
-                               sidePane = new Composite(belowHeader, SWT.NONE);
-                               sidePane.setLayout(CmsSwtUtils.noSpaceGridLayout());
-                               sidePane.setLayoutData(CmsSwtUtils.fillHeight());
-                               dynamicArea = new Composite(belowHeader, SWT.NONE);
-                               leadPane = new Composite(belowHeader, SWT.NONE);
-                       } else {
-                               leadPane = new Composite(belowHeader, SWT.NONE);
-                               dynamicArea = new Composite(belowHeader, SWT.NONE);
-                               sidePane = new Composite(belowHeader, SWT.NONE);
-                               sidePane.setLayout(CmsSwtUtils.noSpaceGridLayout());
-                               sidePane.setLayoutData(CmsSwtUtils.fillHeight());
-                       }
-                       leadPane.setLayoutData(CmsSwtUtils.fillHeight());
-                       leadPane.setLayout(CmsSwtUtils.noSpaceGridLayout());
-                       CmsSwtUtils.style(leadPane, SuiteStyle.leadPane);
-
-                       dynamicArea.setLayoutData(CmsSwtUtils.fillAll());
-                       dynamicArea.setLayout(new FormLayout());
-
-               } else {
-                       belowHeader.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               }
-       }
-
-       /*
-        * LAYERS
-        */
-
-       Composite getCurrentWorkArea() {
-               if (currentLayerId == null)
-                       throw new IllegalStateException("No current layer");
-               return workAreas.get(currentLayerId);
-       }
-
-       String getCurrentLayerId() {
-               return currentLayerId;
-       }
-
-       private Composite getLayer(String id, Node context) {
-               if (!layers.containsKey(id))
-                       return null;
-               if (!workAreas.containsKey(id))
-                       initLayer(id, layers.get(id), context);
-               return workAreas.get(id);
-       }
-
-       Composite switchToLayer(String layerId, Node context) {
-               Composite current = null;
-               if (currentLayerId != null) {
-                       current = getCurrentWorkArea();
-                       if (currentLayerId.equals(layerId))
-                               return current;
-               }
-               if (context == null) {
-                       if (!cmsView.isAnonymous())
-                               context = userDir;
-               }
-               Composite toShow = getLayer(layerId, context);
-               if (toShow != null) {
-                       currentLayerId = layerId;
-                       if (!isDisposed()) {
-//                             getDisplay().syncExec(() -> {
-                               if (!toShow.isDisposed()) {
-                                       toShow.moveAbove(null);
-                               } else {
-                                       log.warn("Cannot show work area because it is disposed.");
-                                       toShow = initLayer(layerId, layers.get(layerId), context);
-                                       toShow.moveAbove(null);
-                               }
-                               dynamicArea.layout(true, true);
-//                             });
-                       }
-                       return toShow;
-               } else {
-                       return current;
-               }
-       }
-
-       Composite switchToLayer(SuiteLayer layer, Node context) {
-               // TODO make it more robust
-               for (String layerId : layers.keySet()) {
-                       SuiteLayer l = layers.get(layerId);
-                       if (layer == l) {
-                               return switchToLayer(layerId, context);
-                       }
-               }
-               throw new IllegalArgumentException("Layer is not registered.");
-       }
-
-       void addLayer(String id, SuiteLayer layer) {
-               layers.put(id, layer);
-       }
-
-       void removeLayer(String id) {
-               layers.remove(id);
-               if (workAreas.containsKey(id)) {
-                       Composite workArea = workAreas.remove(id);
-                       if (!workArea.isDisposed())
-                               workArea.dispose();
-               }
-       }
-
-       protected Composite initLayer(String id, SuiteLayer layer, Node context) {
-               Composite workArea = cmsView.doAs(() -> (Composite) layer.createUiPart(dynamicArea, context));
-               CmsSwtUtils.style(workArea, SuiteStyle.workArea);
-               workArea.setLayoutData(CmsSwtUtils.coverAll());
-               workAreas.put(id, workArea);
-               return workArea;
-       }
-
-       synchronized void logout() {
-               userDir = null;
-               Jcr.logout(sysSession);
-               Jcr.logout(homeSession);
-               currentLayerId = null;
-               workAreas.clear();
-       }
-
-       /*
-        * GETTERS / SETTERS
-        */
-
-       Composite getHeader() {
-               return header;
-       }
-
-       Composite getFooter() {
-               return footer;
-       }
-
-       Composite getLeadPane() {
-               return leadPane;
-       }
-
-       Composite getSidePane() {
-               return sidePane;
-       }
-
-       Composite getBelowHeader() {
-               return belowHeader;
-       }
-
-//     Session getSysSession() {
-//             return sysSession;
-//     }
-//
-       synchronized void initSessions(Repository repository, String userDirPath) throws RepositoryException {
-               this.sysSession = repository.login();
-               this.homeSession = repository.login(CmsConstants.HOME_WORKSPACE);
-               userDir = sysSession.getNode(userDirPath);
-               addDisposeListener((e) -> {
-                       Jcr.logout(sysSession);
-                       Jcr.logout(homeSession);
-               });
-       }
-
-       Node getUserDir() {
-               return userDir;
-       }
-
-       Session getSysSession() {
-               return sysSession;
-       }
-
-       Session getSession(String workspaceName) {
-               if (workspaceName == null)
-                       return sysSession;
-               if (CmsConstants.SYS_WORKSPACE.equals(workspaceName))
-                       return sysSession;
-               else if (CmsConstants.HOME_WORKSPACE.equals(workspaceName))
-                       return homeSession;
-               else
-                       throw new IllegalArgumentException("Unknown workspace " + workspaceName);
-       }
-
-       public CmsView getCmsView() {
-               return cmsView;
-       }
-
-       public Localized getTitle() {
-               return title;
-       }
-
-       public void setTitle(Localized title) {
-               this.title = title;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteUiUtils.java b/org.argeo.app.ui/src/org/argeo/suite/ui/SuiteUiUtils.java
deleted file mode 100644 (file)
index 21d8d93..0000000
+++ /dev/null
@@ -1,432 +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.api.cms.CmsEditable;
-import org.argeo.api.cms.CmsEvent;
-import org.argeo.api.cms.CmsStyle;
-import org.argeo.api.cms.CmsTheme;
-import org.argeo.api.cms.CmsView;
-import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.Localized;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsIcon;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.dialogs.LightweightDialog;
-import org.argeo.cms.ui.util.CmsLink;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.suite.SuiteRole;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.event.Event;
-
-/** UI utilities related to the APAF project. */
-public class SuiteUiUtils {
-
-       /** Singleton. */
-       private SuiteUiUtils() {
-       }
-
-       /** creates a title bar composite with label and optional button */
-       public static void addTitleBar(Composite parent, String title, Boolean isEditable) {
-               Composite titleBar = new Composite(parent, SWT.NONE);
-               titleBar.setLayoutData(CmsSwtUtils.fillWidth());
-               CmsSwtUtils.style(titleBar, SuiteStyle.titleContainer);
-
-               titleBar.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(2, false)));
-               Label titleLbl = new Label(titleBar, SWT.NONE);
-               titleLbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
-               CmsSwtUtils.style(titleLbl, SuiteStyle.titleLabel);
-               titleLbl.setText(title);
-
-               if (isEditable) {
-                       Button editBtn = new Button(titleBar, SWT.PUSH);
-                       editBtn.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
-                       CmsSwtUtils.style(editBtn, SuiteStyle.inlineButton);
-                       editBtn.setText("Edit");
-               }
-       }
-
-       public static Label addFormLabel(Composite parent, String label) {
-               Label lbl = new Label(parent, SWT.WRAP);
-               lbl.setText(label);
-               // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
-               CmsSwtUtils.style(lbl, SuiteStyle.simpleLabel);
-               return lbl;
-       }
-
-       public static Text addFormTextField(Composite parent, String text, String message) {
-               return addFormTextField(parent, text, message, SWT.NONE);
-       }
-
-       public static Text addFormTextField(Composite parent, String text, String message, int style) {
-               Text txt = new Text(parent, style);
-               if (text != null)
-                       txt.setText(text);
-               if (message != null)
-                       txt.setMessage(message);
-               txt.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, true));
-               CmsSwtUtils.style(txt, SuiteStyle.simpleText);
-               return txt;
-       }
-
-       public static Text addFormInputField(Composite parent, String placeholder) {
-               Text txt = new Text(parent, SWT.BORDER);
-
-               GridData gridData = CmsSwtUtils.fillWidth();
-               txt.setLayoutData(gridData);
-
-               if (placeholder != null)
-                       txt.setText(placeholder);
-
-               CmsSwtUtils.style(txt, SuiteStyle.simpleInput);
-               return txt;
-       }
-
-       /** creates a single horizontal-block composite for key:value display */
-       public static Text addFormLine(Composite parent, String label, String text) {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(2, false));
-               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
-               addFormLabel(lineComposite, label);
-               Text txt = addFormTextField(lineComposite, text, null);
-               txt.setEditable(false);
-               txt.setLayoutData(CmsSwtUtils.fillWidth());
-               return txt;
-       }
-
-       public static Text addFormLine(Composite parent, String label, Node node, String property,
-                       CmsEditable cmsEditable) {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(2, false));
-               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
-               addFormLabel(lineComposite, label);
-               String text = Jcr.get(node, property);
-//             int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
-               Text txt = addFormTextField(lineComposite, text, null, SWT.WRAP);
-               if (cmsEditable != null && cmsEditable.isEditing()) {
-                       txt.addModifyListener((e) -> {
-                               Jcr.set(node, property, txt.getText());
-                               Jcr.save(node);
-                       });
-               } else {
-                       txt.setEditable(false);
-               }
-               txt.setLayoutData(CmsSwtUtils.fillWidth());
-               return txt;
-       }
-
-       public static Text addFormInput(Composite parent, String label, String placeholder) {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(2, false));
-               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
-               addFormLabel(lineComposite, label);
-               Text txt = addFormInputField(lineComposite, placeholder);
-               txt.setLayoutData(CmsSwtUtils.fillWidth());
-               return txt;
-       }
-
-       /**
-        * creates a single horizontal-block composite for key:value display, with
-        * offset value
-        */
-       public static Text addFormLine(Composite parent, String label, String text, Integer offset) {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(3, false));
-               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
-               Label offsetLbl = new Label(lineComposite, SWT.NONE);
-               GridData gridData = new GridData();
-               gridData.widthHint = offset;
-               offsetLbl.setLayoutData(gridData);
-               addFormLabel(lineComposite, label);
-               Text txt = addFormTextField(lineComposite, text, null);
-               txt.setLayoutData(CmsSwtUtils.fillWidth());
-               return txt;
-       }
-
-       /** creates a single vertical-block composite for key:value display */
-       public static Text addFormColumn(Composite parent, String label, String text) {
-//             Composite columnComposite = new Composite(parent, SWT.NONE);
-//             columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-//             columnComposite.setLayout(new GridLayout(1, false));
-               addFormLabel(parent, label);
-               Text txt = addFormTextField(parent, text, null);
-               txt.setEditable(false);
-               txt.setLayoutData(CmsSwtUtils.fillWidth());
-               return txt;
-       }
-
-       public static Text addFormColumn(Composite parent, String label, Node node, String property,
-                       CmsEditable cmsEditable) {
-//             Composite columnComposite = new Composite(parent, SWT.NONE);
-//             columnComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-//             columnComposite.setLayout(new GridLayout(1, false));
-               addFormLabel(parent, label);
-               String text = Jcr.get(node, property);
-//             int style = cmsEditable.isEditing() ? SWT.WRAP : SWT.WRAP;
-               Text txt = addFormTextField(parent, text, null, SWT.WRAP);
-               if (cmsEditable != null && cmsEditable.isEditing()) {
-                       txt.addModifyListener((e) -> {
-                               Jcr.set(node, property, txt.getText());
-                               Jcr.save(node);
-                       });
-               } else {
-                       txt.setEditable(false);
-               }
-               txt.setLayoutData(CmsSwtUtils.fillWidth());
-               return txt;
-       }
-
-       public static Label createBoldLabel(Composite parent, Localized localized) {
-               Label label = new Label(parent, SWT.LEAD);
-               label.setText(localized.lead());
-               label.setFont(EclipseUiUtils.getBoldFont(parent));
-               label.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
-               return label;
-       }
-
-       public static Label addFormPicture(Composite parent, String label, Node fileNode) throws RepositoryException {
-               Composite lineComposite = new Composite(parent, SWT.NONE);
-               lineComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-               lineComposite.setLayout(new GridLayout(2, true));
-               CmsSwtUtils.style(lineComposite, SuiteStyle.formLine);
-               addFormLabel(lineComposite, label);
-
-               return addPicture(lineComposite, fileNode);
-       }
-
-       public static Label addPicture(Composite parent, Node fileNode) throws RepositoryException {
-               return addPicture(parent, fileNode, null);
-       }
-
-       public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth) throws RepositoryException {
-               return addPicture(parent, fileNode, maxWidth, null);
-       }
-
-       public static Label addPicture(Composite parent, Node fileNode, Integer maxWidth, Node link)
-                       throws RepositoryException {
-               Node content = fileNode.getNode(Node.JCR_CONTENT);
-               // TODO move it deeper in the middleware.
-               if (!content.isNodeType(EntityType.box.get())) {
-                       if (content.getSession().hasPermission(content.getPath(), Session.ACTION_SET_PROPERTY)) {
-                               try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
-                                       ImageData imageData = new ImageData(in);
-                                       content.addMixin(EntityType.box.get());
-                                       content.setProperty(EntityNames.SVG_WIDTH, imageData.width);
-                                       content.setProperty(EntityNames.SVG_HEIGHT, imageData.height);
-                                       content.getSession().save();
-                               } catch (IOException e) {
-                                       throw new RuntimeException(e);
-                               }
-                       }
-               }
-
-               // TODO optimise
-               Long width;
-               Long height;
-               if (content.isNodeType(EntityType.box.get())) {
-                       width = content.getProperty(EntityNames.SVG_WIDTH).getLong();
-                       height = content.getProperty(EntityNames.SVG_HEIGHT).getLong();
-               } else {
-                       try (InputStream in = JcrUtils.getFileAsStream(fileNode)) {
-                               ImageData imageData = new ImageData(in);
-                               width = Long.valueOf(imageData.width);
-                               height = Long.valueOf(imageData.height);
-                       } catch (IOException e) {
-                               throw new RuntimeException(e);
-                       }
-               }
-
-               if (maxWidth != null && width > maxWidth) {
-                       Double ratio = maxWidth.doubleValue() / width.doubleValue();
-                       width = maxWidth.longValue();
-                       height = Math.round(ratio * height);
-               }
-               Label img = new Label(parent, SWT.NONE);
-               CmsSwtUtils.markup(img);
-               StringBuffer txt = new StringBuffer();
-               String target = toLink(link);
-               if (target != null)
-                       txt.append("<a href='").append(target).append("'>");
-               txt.append(CmsUiUtils.img(fileNode, width.toString(), height.toString()));
-               if (target != null)
-                       txt.append("</a>");
-               img.setText(txt.toString());
-               if (parent.getLayout() instanceof GridLayout) {
-                       GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
-                       gd.widthHint = width.intValue();
-                       gd.heightHint = height.intValue();
-                       img.setLayoutData(gd);
-               }
-
-               if (target == null)
-                       img.addMouseListener(new MouseListener() {
-                               private static final long serialVersionUID = -1362242049325206168L;
-
-                               @Override
-                               public void mouseUp(MouseEvent e) {
-                               }
-
-                               @Override
-                               public void mouseDown(MouseEvent e) {
-                               }
-
-                               @Override
-                               public void mouseDoubleClick(MouseEvent e) {
-                                       LightweightDialog dialog = new LightweightDialog(img.getShell()) {
-
-                                               @Override
-                                               protected Control createDialogArea(Composite parent) {
-                                                       parent.setLayout(new GridLayout());
-                                                       ScrolledComposite scroll = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
-                                                       scroll.setLayoutData(CmsSwtUtils.fillAll());
-                                                       scroll.setLayout(CmsSwtUtils.noSpaceGridLayout());
-                                                       scroll.setExpandHorizontal(true);
-                                                       scroll.setExpandVertical(true);
-                                                       // scroll.setAlwaysShowScrollBars(true);
-
-                                                       Composite c = new Composite(scroll, SWT.NONE);
-                                                       scroll.setContent(c);
-                                                       c.setLayout(new GridLayout());
-                                                       c.setLayoutData(CmsSwtUtils.fillAll());
-                                                       Label bigImg = new Label(c, SWT.NONE);
-                                                       CmsSwtUtils.markup(bigImg);
-                                                       bigImg.setText(CmsUiUtils.img(fileNode, Jcr.get(content, EntityNames.SVG_WIDTH),
-                                                                       Jcr.get(content, EntityNames.SVG_HEIGHT)));
-                                                       bigImg.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
-                                                       return bigImg;
-                                               }
-
-                                               @Override
-                                               protected Point getInitialSize() {
-                                                       Point shellSize = img.getShell().getSize();
-                                                       return new Point(shellSize.x - 100, shellSize.y - 100);
-                                               }
-
-                                       };
-                                       dialog.open();
-                               }
-                       });
-               return img;
-       }
-
-       public static String toLink(Node node) {
-                       return node != null ? "#" + CmsUiUtils.cleanPathForUrl(SuiteApp.nodeToState(node)) : null;
-       }
-
-       public static Control addLink(Composite parent, String label, Node node, CmsStyle style)
-                       throws RepositoryException {
-               String target = toLink(node);
-               CmsLink link = new CmsLink(label, target, style);
-               return link.createUi(parent, node);
-       }
-
-       public static Control addExternalLink(Composite parent, String label, String url, String plainCssAnchorClass,
-                       boolean newWindow) throws RepositoryException {
-               Label lbl = new Label(parent, SWT.NONE);
-               CmsSwtUtils.markup(lbl);
-               StringBuilder txt = new StringBuilder();
-               txt.append("<a class='" + plainCssAnchorClass + "'");
-               txt.append(" href='").append(url).append("'");
-               if (newWindow) {
-                       txt.append(" target='blank_'");
-               }
-               txt.append(">");
-               txt.append(label);
-               txt.append("</a>");
-               lbl.setText(txt.toString());
-               return lbl;
-       }
-
-       public static boolean isCoworker(CmsView cmsView) {
-               boolean coworker = cmsView.doAs(() -> CurrentUser.isInRole(SuiteRole.coworker.dn()));
-               return coworker;
-       }
-
-       public static boolean isTopic(Event event, CmsEvent cmsEvent) {
-               return event.getTopic().equals(cmsEvent.topic());
-       }
-
-       public static Button createLayerButton(Composite parent, String layer, Localized msg, CmsIcon icon,
-                       ClassLoader l10nClassLoader) {
-               CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
-               Button button = new Button(parent, SWT.PUSH);
-               CmsSwtUtils.style(button, SuiteStyle.leadPane);
-               if (icon != null)
-                       button.setImage(icon.getBigIcon(theme));
-               button.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, false));
-               // button.setToolTipText(msg.lead());
-               if (msg != null) {
-                       Label lbl = new Label(parent, SWT.CENTER);
-                       CmsSwtUtils.style(lbl, SuiteStyle.leadPane);
-                       String txt = LocaleUtils.lead(msg, l10nClassLoader);
-//                     String txt = msg.lead();
-                       lbl.setText(txt);
-                       lbl.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
-               }
-               CmsSwtUtils.sendEventOnSelect(button, SuiteEvent.switchLayer.topic(), SuiteEvent.LAYER, layer);
-               return button;
-       }
-
-//     public static String createAndConfigureEntity(Shell shell, Session referenceSession, String mainMixin,
-//                     String... additionnalProps) {
-//
-//             Session tmpSession = null;
-//             Session mainSession = null;
-//             try {
-//                     // FIXME would not work if home is another physical workspace
-//                     tmpSession = referenceSession.getRepository().login(NodeConstants.HOME_WORKSPACE);
-//                     Node draftNode = null;
-//                     for (int i = 0; i < additionnalProps.length - 1; i += 2) {
-//                             draftNode.setProperty(additionnalProps[i], additionnalProps[i + 1]);
-//                     }
-//                     Wizard wizard = null;
-//                     CmsWizardDialog dialog = new CmsWizardDialog(shell, wizard);
-//                     // WizardDialog dialog = new WizardDialog(shell, wizard);
-//                     if (dialog.open() == Window.OK) {
-//                             String parentPath = null;// "/" + appService.getBaseRelPath(mainMixin);
-//                             // FIXME it should be possible to specify the workspace
-//                             mainSession = referenceSession.getRepository().login();
-//                             Node parent = mainSession.getNode(parentPath);
-//                             Node task = null;// appService.publishEntity(parent, mainMixin, draftNode);
-////                           task = appService.saveEntity(task, false);
-//                             referenceSession.refresh(true);
-//                             return task.getPath();
-//                     }
-//                     return null;
-//             } catch (RepositoryException e1) {
-//                     throw new JcrException(
-//                                     "Unable to create " + mainMixin + " entity with session " + referenceSession.toString(), e1);
-//             } finally {
-//                     JcrUtils.logoutQuietly(tmpSession);
-//                     JcrUtils.logoutQuietly(mainSession);
-//             }
-//     }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/TermsEntryArea.java b/org.argeo.app.ui/src/org/argeo/suite/ui/TermsEntryArea.java
deleted file mode 100644 (file)
index 0f7e927..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.argeo.suite.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** Entry area for managing th etypologies. */
-public class TermsEntryArea implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               parent.setLayout(new GridLayout());
-               Label lbl = new Label(parent, SWT.NONE);
-               lbl.setText("Typologies");
-               return lbl;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/dialogs/NewPersonPage.java b/org.argeo.app.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.app.ui/src/org/argeo/suite/ui/dialogs/NewPersonWizard.java b/org.argeo.app.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.app.ui/src/org/argeo/suite/ui/dialogs/NewUserWizard.java b/org.argeo.app.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.app.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java b/org.argeo.app.ui/src/org/argeo/suite/ui/widgets/AbstractConnectContextMenu.java
deleted file mode 100644 (file)
index 08f74e3..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.swt.CmsSwtUtils;
-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());
-                       CmsSwtUtils.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.app.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java b/org.argeo.app.ui/src/org/argeo/suite/ui/widgets/ConnectAbstractDropDown.java
deleted file mode 100644 (file)
index e562fcc..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.swt.CmsSwtUtils;
-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)
-                       CmsSwtUtils.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.app.ui/src/org/argeo/suite/ui/widgets/DelayedText.java b/org.argeo.app.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/org.argeo.app.ui/src/org/argeo/suite/ui/widgets/TabbedArea.java b/org.argeo.app.ui/src/org/argeo/suite/ui/widgets/TabbedArea.java
deleted file mode 100644 (file)
index 4b97b9a..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-package org.argeo.suite.ui.widgets;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.Selected;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.jcr.Jcr;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.StackLayout;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** Manages {@link Section} in a tab-like structure. */
-public class TabbedArea extends Composite {
-       private static final long serialVersionUID = 8659669229482033444L;
-
-       private Composite headers;
-       private Composite body;
-
-       private List<Section> sections = new ArrayList<>();
-
-       private Node previousNode;
-       private CmsUiProvider previousUiProvider;
-       private CmsUiProvider currentUiProvider;
-
-       private String tabStyle;
-       private String tabSelectedStyle;
-       private String bodyStyle;
-       private Image closeIcon;
-
-       private StackLayout stackLayout;
-
-       private boolean singleTab = false;
-
-       public TabbedArea(Composite parent, int style) {
-               super(parent, SWT.NONE);
-               CmsSwtUtils.style(parent, bodyStyle);
-
-               setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               // TODO manage tabs at bottom or sides
-               headers = new Composite(this, SWT.NONE);
-               headers.setLayoutData(CmsSwtUtils.fillWidth());
-               body = new Composite(this, SWT.NONE);
-               body.setLayoutData(CmsSwtUtils.fillAll());
-               // body.setLayout(new FormLayout());
-               stackLayout = new StackLayout();
-               body.setLayout(stackLayout);
-               emptyState();
-       }
-
-       protected void refreshTabHeaders() {
-               int tabCount = sections.size() > 0 ? sections.size() : 1;
-               for (Control tab : headers.getChildren())
-                       tab.dispose();
-
-               headers.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(tabCount, true)));
-
-               if (sections.size() == 0) {
-                       Composite emptyHeader = new Composite(headers, SWT.NONE);
-                       emptyHeader.setLayoutData(CmsSwtUtils.fillAll());
-                       emptyHeader.setLayout(new GridLayout());
-                       Label lbl = new Label(emptyHeader, SWT.NONE);
-                       lbl.setText("");
-                       lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
-
-               }
-
-               Section currentSection = getCurrentSection();
-               for (Section section : sections) {
-                       boolean selected = section == currentSection;
-                       Composite sectionHeader = section.createHeader(headers);
-                       CmsSwtUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle);
-                       int headerColumns = singleTab ? 1 : 2;
-                       sectionHeader.setLayout(new GridLayout(headerColumns, false));
-                       sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout(headerColumns));
-                       Button title = new Button(sectionHeader, SWT.FLAT);
-                       CmsSwtUtils.style(title, selected ? tabSelectedStyle : tabStyle);
-                       title.setLayoutData(CmsSwtUtils.fillWidth());
-                       title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode())));
-                       Node node = section.getNode();
-                       String titleStr = Jcr.getTitle(node);
-                       // TODO internationalize
-                       title.setText(titleStr);
-                       if (!singleTab) {
-                               ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
-                               ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT);
-                               if (closeIcon != null)
-                                       closeItem.setImage(closeIcon);
-                               else
-                                       closeItem.setText("X");
-                               CmsSwtUtils.style(closeItem, selected ? tabSelectedStyle : tabStyle);
-                               closeItem.addSelectionListener((Selected) (e) -> closeTab(section));
-                       }
-               }
-
-       }
-
-       public void view(CmsUiProvider uiProvider, Node context) {
-               if (body.isDisposed())
-                       return;
-               int index = tabIndex(context);
-               if (index >= 0) {
-                       showTab(index);
-                       previousNode = context;
-                       previousUiProvider = uiProvider;
-                       return;
-               }
-               Section section = (Section) body.getChildren()[0];
-               previousNode = section.getNode();
-               if (previousNode == null) {// empty state
-                       previousNode = context;
-                       previousUiProvider = uiProvider;
-               } else {
-                       previousUiProvider = currentUiProvider;
-               }
-               currentUiProvider = uiProvider;
-               section.setNode(context);
-               // section.setLayoutData(CmsUiUtils.coverAll());
-               build(section, uiProvider, context);
-               if (sections.size() == 0)
-                       sections.add(section);
-               refreshTabHeaders();
-               index = tabIndex(context);
-               showTab(index);
-               layout(true, true);
-       }
-
-       public void open(CmsUiProvider uiProvider, Node context) {
-               if (singleTab)
-                       throw new UnsupportedOperationException("Open is not supported in single tab mode.");
-
-               if (previousNode != null && Jcr.getIdentifier(previousNode).equals(Jcr.getIdentifier(context))) {
-                       // does nothing
-                       return;
-               }
-               if (sections.size() == 0)
-                       CmsSwtUtils.clear(body);
-               Section currentSection = getCurrentSection();
-               int currentIndex = sections.indexOf(currentSection);
-               Section previousSection = new Section(body, SWT.NONE, context);
-               build(previousSection, previousUiProvider, previousNode);
-               // previousSection.setLayoutData(CmsUiUtils.coverAll());
-               int index = currentIndex + 1;
-               sections.add(index, previousSection);
-               showTab(index);
-               refreshTabHeaders();
-               layout(true, true);
-       }
-
-       public void showTab(int index) {
-               Section sectionToShow = sections.get(index);
-               // sectionToShow.moveAbove(null);
-               stackLayout.topControl = sectionToShow;
-               refreshTabHeaders();
-               layout(true, true);
-       }
-
-       protected void build(Section section, CmsUiProvider uiProvider, Node context) {
-               for (Control child : section.getChildren())
-                       child.dispose();
-               CmsSwtUtils.style(section, bodyStyle);
-               section.setNode(context);
-               uiProvider.createUiPart(section, context);
-
-       }
-
-       private int tabIndex(Node node) {
-               for (int i = 0; i < sections.size(); i++) {
-                       Section section = sections.get(i);
-                       if (Jcr.getIdentifier(section.getNode()).equals(Jcr.getIdentifier(node)))
-                               return i;
-               }
-               return -1;
-       }
-
-       public void closeTab(Section section) {
-               int currentIndex = sections.indexOf(section);
-               int nextIndex = currentIndex == 0 ? 0 : currentIndex - 1;
-               sections.remove(section);
-               section.dispose();
-               if (sections.size() == 0) {
-                       emptyState();
-                       refreshTabHeaders();
-                       layout(true, true);
-                       return;
-               }
-               refreshTabHeaders();
-               showTab(nextIndex);
-       }
-       
-       public void closeAllTabs() {
-               for(Section section:sections) {
-                       section.dispose();                      
-               }
-               sections.clear();
-               emptyState();
-               refreshTabHeaders();
-               layout(true, true);
-       }
-
-       protected void emptyState() {
-               new Section(body, SWT.NONE, null);
-               refreshTabHeaders();
-       }
-
-       public Composite getCurrent() {
-               return getCurrentSection();
-       }
-
-       protected Section getCurrentSection() {
-               return (Section) stackLayout.topControl;
-       }
-
-       public Node getCurrentContext() {
-               Section section = getCurrentSection();
-               if (section != null) {
-                       return section.getNode();
-               } else {
-                       return null;
-               }
-       }
-
-       public void setTabStyle(String tabStyle) {
-               this.tabStyle = tabStyle;
-       }
-
-       public void setTabSelectedStyle(String tabSelectedStyle) {
-               this.tabSelectedStyle = tabSelectedStyle;
-       }
-
-       public void setBodyStyle(String bodyStyle) {
-               this.bodyStyle = bodyStyle;
-       }
-
-       public void setCloseIcon(Image closeIcon) {
-               this.closeIcon = closeIcon;
-       }
-
-       public void setSingleTab(boolean singleTab) {
-               this.singleTab = singleTab;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/suite/ui/widgets/TreeOrSearchArea.java b/org.argeo.app.ui/src/org/argeo/suite/ui/widgets/TreeOrSearchArea.java
deleted file mode 100644 (file)
index 81cfbb7..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.argeo.suite.ui.widgets;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.StackLayout;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Displays a tree by default, which becomes a list if the search text field is
- * used.
- */
-public class TreeOrSearchArea extends Composite {
-       private static final long serialVersionUID = -1302546480076719532L;
-
-       private Text searchT;
-       private StackLayout bodyLayout;
-
-       private TreeViewer treeViewer;
-       private TreeViewer searchResultsViewer;
-
-       public TreeOrSearchArea(Composite parent, int style) {
-               super(parent, style);
-               createUi(this);
-       }
-
-       protected void createUi(Composite parent) {
-               parent.setLayout(new GridLayout());
-               Composite searchC = new Composite(parent, SWT.NONE);
-               searchC.setLayout(new GridLayout());
-               searchC.setLayoutData(CmsSwtUtils.fillWidth());
-               createSearchUi(searchC);
-
-               Composite bodyC = new Composite(parent, SWT.NONE);
-               bodyC.setLayoutData(CmsSwtUtils.fillAll());
-               bodyLayout = new StackLayout();
-               bodyC.setLayout(bodyLayout);
-               Composite treeC = new Composite(bodyC, SWT.NONE);
-               createTreeUi(treeC);
-               Composite searchResultsC = new Composite(bodyC, SWT.NONE);
-               createSearchResultsUi(searchResultsC);
-
-               bodyLayout.topControl = treeC;
-       }
-
-       protected void createSearchUi(Composite parent) {
-               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               searchT = new Text(parent, SWT.MULTI | SWT.BORDER);
-               searchT.setLayoutData(CmsSwtUtils.fillWidth());
-       }
-
-       protected void createTreeUi(Composite parent) {
-               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               treeViewer = new TreeViewer(parent);
-               treeViewer.getTree().setLayoutData(CmsSwtUtils.fillAll());
-       }
-
-       protected void createSearchResultsUi(Composite parent) {
-               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               searchResultsViewer = new TreeViewer(parent);
-               searchResultsViewer.getTree().setLayoutData(CmsSwtUtils.fillAll());
-       }
-
-       public TreeViewer getTreeViewer() {
-               return treeViewer;
-       }
-
-       public TreeViewer getSearchResultsViewer() {
-               return searchResultsViewer;
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/support/openlayers/OLMap.java b/org.argeo.app.ui/src/org/argeo/support/openlayers/OLMap.java
deleted file mode 100644 (file)
index 3bcf488..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.argeo.support.openlayers;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-
-public class OLMap extends Composite {
-       private Label div;
-
-       public OLMap(Composite parent, int style) {
-               super(parent, style);
-               setLayout(CmsSwtUtils.noSpaceGridLayout());
-               div = new Label(this, SWT.NONE);
-               CmsSwtUtils.markup(div);
-               CmsSwtUtils.disableMarkupValidation(div);
-               div.setText("<div id='map'></div>");
-               div.setLayoutData(CmsSwtUtils.fillAll());
-       }
-
-}
diff --git a/org.argeo.app.ui/src/org/argeo/support/openlayers/OpenLayersMap.java b/org.argeo.app.ui/src/org/argeo/support/openlayers/OpenLayersMap.java
deleted file mode 100644 (file)
index dac7bea..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-package org.argeo.support.openlayers;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.api.cms.CmsView;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.entity.EntityNames;
-import org.argeo.entity.EntityType;
-import org.argeo.suite.ui.SuiteEvent;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.browser.Browser;
-import org.eclipse.swt.browser.BrowserFunction;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** Display a map. */
-public class OpenLayersMap extends Composite {
-       private static final long serialVersionUID = 1055893020490283622L;
-
-       private final static CmsLog log = CmsLog.getLog(OpenLayersMap.class);
-
-       private Browser browser;
-       private boolean renderCompleted = false;
-
-       private Double centerLng = null, centerLat = null;
-       private Integer zoom = null;
-       private String vectorSource = null;
-       private String gpxSource = null;
-
-       private String vectorSourceStyle;
-
-       private List<String> geoJsonSources = new ArrayList<>();
-       private Map<String, String> vectorSources = new HashMap<>();
-       private Map<String, String> layerStyles = new HashMap<>();
-
-       private CmsView cmsView;
-
-       public OpenLayersMap(Composite parent, int style, URL mapHtml) {
-               super(parent, style);
-               cmsView = CmsSwtUtils.getCmsView(parent);
-               setLayout(new GridLayout());
-
-               browser = new Browser(this, SWT.BORDER);
-               browser.setLayoutData(CmsSwtUtils.fillAll());
-               String html;
-               try (InputStream in = mapHtml.openStream()) {
-                       html = IOUtils.toString(in, StandardCharsets.UTF_8);
-               } catch (IOException e) {
-                       throw new RuntimeException(e);
-               }
-               new RenderCompleted(browser, "renderCompleted");
-               new OnFeatureSelect(browser, "onFeatureSelect");
-               new OnFeatureUnselect(browser, "onFeatureUnselect");
-               new OnFeatureClick(browser, "onFeatureClick");
-               browser.setText(html);
-       }
-
-       public void setCenter(Double lng, Double lat) {
-               if (isRenderCompleted())
-                       browser.evaluate("map.getView().setCenter(ol.proj.fromLonLat([" + lng + ", " + lat + "]))");
-               this.centerLat = lat;
-               this.centerLng = lng;
-       }
-
-       public synchronized void setRenderCompleted(boolean renderCompleted) {
-               this.renderCompleted = renderCompleted;
-               notifyAll();
-       }
-
-       public synchronized boolean isRenderCompleted() {
-               return renderCompleted;
-       }
-
-       @Override
-       public synchronized void dispose() {
-               long timeout = 500;
-               long begin = System.currentTimeMillis();
-               while (!isRenderCompleted() && ((System.currentTimeMillis() - begin) < timeout)) {
-                       try {
-                               wait(50);
-                       } catch (InterruptedException e) {
-                               // silent
-                       }
-               }
-               super.dispose();
-       }
-
-       public void setZoom(int zoom) {
-               if (isRenderCompleted())
-                       browser.evaluate("map.getView().setZoom(" + zoom + ")");
-               this.zoom = zoom;
-       }
-
-       protected String asVectorSource(List<Node> geoPoints) throws RepositoryException {
-               boolean first = true;
-               StringBuffer sb = new StringBuffer("new ol.source.Vector({ features: [");
-               for (int i = 0; i < geoPoints.size(); i++) {
-                       Node node = geoPoints.get(i);
-                       if (node.isNodeType(EntityType.geopoint.get())) {
-                               if (first)
-                                       first = false;
-                               else
-                                       sb.append(",");
-                               Double lng = node.getProperty(EntityNames.GEO_LONG).getDouble();
-                               Double lat = node.getProperty(EntityNames.GEO_LAT).getDouble();
-                               sb.append("new ol.Feature({ geometry:");
-                               sb.append("new ol.geom.Point(ol.proj.fromLonLat([");
-                               sb.append(lng).append(',').append(lat);
-                               sb.append("]))");
-                               sb.append(",path:\"").append(node.getPath()).append("\"");
-                               sb.append(",name:\"").append(node.getName()).append("\"");
-                               String entityType = null;
-                               if (node.isNodeType(EntityType.local.get())) {
-                                       entityType = node.getProperty(EntityNames.ENTITY_TYPE).getString();
-                                       sb.append(", type:'").append(entityType).append("'");
-                               }
-                               sb.append("})");
-                       }
-               }
-               sb.append("]");
-               sb.append(" })");
-               return sb.toString();
-       }
-
-       public void addPoints(List<Node> geoPoints) throws RepositoryException {
-               this.vectorSource = asVectorSource(geoPoints);
-               if (log.isTraceEnabled())
-                       log.trace("Vector source: " + vectorSource);
-               renderVectorSource();
-       }
-
-       public void addPoints(String layerName, List<Node> geoPoints, String style) throws RepositoryException {
-               this.vectorSources.put(layerName, asVectorSource(geoPoints));
-               if (style != null) {
-                       layerStyles.put(layerName, style);
-               }
-               renderVectorSources();
-       }
-
-       protected void renderVectorSource() {
-               if (vectorSource == null)
-                       return;
-               if (isRenderCompleted()) {
-//                     String style = ", style: new ol.style.Style({  image: new ol.style.Icon({ src: '/pkg/org.djapps.on.openheritage.ui/map_oc.png' }) })";
-                       String style = vectorSourceStyle != null ? ", style: " + vectorSourceStyle : "";
-//                     String style = "";
-                       String toEvaluate = "map.addLayer(new ol.layer.Vector({ source: " + vectorSource + style + "}));";
-//                     System.out.println(toEvaluate);
-                       browser.execute(toEvaluate);
-               }
-       }
-
-       protected void renderVectorSources() {
-               if (vectorSources.isEmpty())
-                       return;
-               if (isRenderCompleted()) {
-                       StringBuilder toExecute = new StringBuilder();
-                       for (String name : vectorSources.keySet()) {
-                               String style = layerStyles.containsKey(name) ? ", style: " + layerStyles.get(name) : "";
-                               String toEvaluate = "map.addLayer(new ol.layer.Vector({ source: " + vectorSources.get(name) + style
-                                               + ",name: '" + name + "'}));";
-                               toExecute.append(toEvaluate);
-                       }
-                       System.out.println(toExecute);
-                       browser.execute(toExecute.toString());
-               }
-       }
-
-       public void addPoint(Double lng, Double lat) {
-               this.vectorSource = "new ol.source.Vector({ features: [ new ol.Feature({ geometry:"
-                               + " new ol.geom.Point(ol.proj.fromLonLat([" + lng + ", " + lat + "])) }) ] })";
-//             if (renderCompleted) {
-//                     browser.evaluate(
-//                                     "map.addLayer(new ol.layer.Vector({ source: new ol.source.Vector({ features: [ new ol.Feature({ geometry:"
-//                                                     + " new ol.geom.Point(ol.proj.fromLonLat([" + lng + ", " + lat + "])) }) ] }) }));");
-//             }
-               renderVectorSource();
-       }
-
-       public void addGpx(String path) {
-               this.gpxSource = "new ol.source.Vector({ url: '" + path + "', format: new ol.format.GPX() })";
-               renderGpxSource();
-       }
-
-       protected void renderGpxSource() {
-               if (gpxSource == null)
-                       return;
-               if (isRenderCompleted())
-                       browser.evaluate("map.addLayer(new ol.layer.Vector({ source: " + gpxSource + "}));");
-       }
-
-       public void addGeoJson(String path) {
-               String geoJsonSource = "new ol.source.Vector({ url: '" + path + "', format: new ol.format.GeoJSON() })";
-               geoJsonSources.add(geoJsonSource);
-               renderGeoJsonSources();
-       }
-
-       protected void renderGeoJsonSources() {
-               if (geoJsonSources.isEmpty())
-                       return;
-               if (isRenderCompleted()) {
-                       for (String geoJson : geoJsonSources) {
-                               browser.evaluate("map.addLayer(new ol.layer.Vector({ source: " + geoJson + "}));");
-                       }
-               }
-       }
-
-       public void setVectorSourceStyle(String vectorSourceStyle) {
-               this.vectorSourceStyle = vectorSourceStyle;
-       }
-
-       private class RenderCompleted extends BrowserFunction {
-
-               RenderCompleted(Browser browser, String name) {
-                       super(browser, name);
-               }
-
-               @Override
-               public Object function(Object[] arguments) {
-                       try {
-                               if (!isRenderCompleted()) {
-                                       setRenderCompleted(true);
-                                       if (zoom != null)
-                                               setZoom(zoom);
-                                       if (centerLat != null && centerLng != null) {
-                                               setCenter(centerLng, centerLat);
-                                       }
-                                       if (!geoJsonSources.isEmpty())
-                                               renderGeoJsonSources();
-                                       if (gpxSource != null)
-                                               renderGpxSource();
-                                       if (vectorSource != null)
-                                               renderVectorSource();
-                                       if (!vectorSources.isEmpty())
-                                               renderVectorSources();
-                               }
-                               return null;
-                       } catch (Exception e) {
-                               log.error("Cannot render map", e);
-                               return null;
-                       }
-               }
-       }
-
-       private class OnFeatureSelect extends BrowserFunction {
-
-               OnFeatureSelect(Browser browser, String name) {
-                       super(browser, name);
-               }
-
-               @Override
-               public Object function(Object[] arguments) {
-                       if (arguments.length == 0)
-                               return null;
-                       String path = arguments[0].toString();
-                       Map<String, Object> properties = new HashMap<>();
-                       properties.put(SuiteEvent.NODE_PATH, path);
-                       properties.put(SuiteEvent.WORKSPACE, CmsConstants.SYS_WORKSPACE);
-                       cmsView.sendEvent(SuiteEvent.refreshPart.topic(), properties);
-                       return null;
-               }
-       }
-
-       private class OnFeatureUnselect extends BrowserFunction {
-
-               OnFeatureUnselect(Browser browser, String name) {
-                       super(browser, name);
-               }
-
-               @Override
-               public Object function(Object[] arguments) {
-                       return null;
-               }
-       }
-
-       private class OnFeatureClick extends BrowserFunction {
-
-               OnFeatureClick(Browser browser, String name) {
-                       super(browser, name);
-               }
-
-               @Override
-               public Object function(Object[] arguments) {
-                       return null;
-               }
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/support/openlayers/OverviewMap.java b/org.argeo.app.ui/src/org/argeo/support/openlayers/OverviewMap.java
deleted file mode 100644 (file)
index 11d92e1..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.argeo.support.openlayers;
-
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.EventListener;
-import javax.jcr.query.Query;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.entity.EntityType;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Displays an overview map. */
-public class OverviewMap implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               parent.setLayout(new GridLayout());
-               refreshUi(parent, context);
-
-               try {
-                       String[] nodeTypes = { EntityType.geopoint.get() };
-                       context.getSession().getWorkspace().getObservationManager().addEventListener(new EventListener() {
-
-                               @Override
-                               public void onEvent(EventIterator events) {
-                                       if (!parent.isDisposed())
-                                               parent.getDisplay().asyncExec(() -> {
-                                                       try {
-                                                               refreshUi(parent, context);
-                                                       } catch (RepositoryException e) {
-                                                               throw new JcrException(e);
-                                                       }
-                                               });
-                               }
-                       }, 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);
-               }
-
-               return parent;
-       }
-
-       protected void refreshUi(Composite parent, Node context) throws RepositoryException {
-               CmsSwtUtils.clear(parent);
-               Query query = context.getSession().getWorkspace().getQueryManager()
-                               .createQuery("SELECT * FROM [" + EntityType.geopoint.get() + "]", Query.JCR_SQL2);
-               List<Node> geoPoints = JcrUtils.nodeIteratorToList(query.execute().getNodes());
-               OpenLayersMap map = new OpenLayersMap(parent, SWT.NONE, getClass().getResource("map-osm.html"));
-               map.setLayoutData(CmsSwtUtils.fillAll());
-
-               // apafMap.setZoom(7);
-               // apafMap.setCenter(-2.472, 8.010);
-               map.addPoints(geoPoints);
-       }
-}
diff --git a/org.argeo.app.ui/src/org/argeo/support/openlayers/map-osm.html b/org.argeo.app.ui/src/org/argeo/support/openlayers/map-osm.html
deleted file mode 100644 (file)
index 157d708..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<html lang="en">
-<head>
-<link rel="stylesheet"
-       href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css"
-       type="text/css">
-<style>
-</style>
-<script
-       src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script>
-</head>
-<body>
-       <div id="map" class="map"></div>
-       <script type="text/javascript">
-       // default OSM
-       var source_OSM = new ol.source.OSM();
-       
-       var map = new ol.Map({
-                       target : 'map',
-                       layers : [ new ol.layer.Tile({
-                               source : source_OSM
-                       }) ],
-                       view : new ol.View({
-                               center : ol.proj.fromLonLat([ 34, 34 ]),
-                               zoom : 4
-                       })
-               });
-               map.on('rendercomplete', e => {
-                       console.log('Render completed.');
-                       renderCompleted();
-               });
-               var select = new ol.interaction.Select();
-               map.addInteraction(select);
-           select.on('select',function (e) {
-               if(e.selected.length>0){
-                               console.log('Feature selected: '+e.selected[0].get('path'));
-                       onFeatureSelect(e.selected[0].get('path'));
-               }
-           });
-       </script>
-</body>
-</html>
\ No newline at end of file
diff --git a/org.argeo.app.ui/src/org/argeo/support/openlayers/map.js b/org.argeo.app.ui/src/org/argeo/support/openlayers/map.js
deleted file mode 100644 (file)
index 68489fb..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-var map = new ol.Map({
-       target : 'map',
-       layers : [ new ol.layer.Tile({
-               source : new ol.source.OSM()
-       }) ],
-       view : new ol.View({
-               center : ol.proj.fromLonLat([ 34, 34 ]),
-               zoom : 4
-       })
-});
-               
\ No newline at end of file